mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 11:46:42 +00:00
Add Cloud Webhook management (#2102)
* Add Cloud Webhook support * Lint * Tweak text * Rename it to cloudhook * Fix final type * fix type * Catch null
This commit is contained in:
parent
8ad5280501
commit
07b65f37db
19
src/data/cloud.ts
Normal file
19
src/data/cloud.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export interface CloudWebhook {
|
||||||
|
webhook_id: string;
|
||||||
|
cloudhook_id: string;
|
||||||
|
cloudhook_url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createCloudhook = (hass: HomeAssistant, webhookId: string) =>
|
||||||
|
hass.callWS<CloudWebhook>({
|
||||||
|
type: "cloud/cloudhook/create",
|
||||||
|
webhook_id: webhookId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const deleteCloudhook = (hass: HomeAssistant, webhookId: string) =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "cloud/cloudhook/delete",
|
||||||
|
webhook_id: webhookId,
|
||||||
|
});
|
12
src/data/webhook.ts
Normal file
12
src/data/webhook.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export interface Webhook {
|
||||||
|
webhook_id: string;
|
||||||
|
domain: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchWebhooks = (hass: HomeAssistant): Promise<Webhook[]> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "webhook/list",
|
||||||
|
});
|
@ -24,6 +24,10 @@ export class CloudAlexaPref extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this.cloudStatus) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
const enabled = this.cloudStatus!.prefs.alexa_enabled;
|
const enabled = this.cloudStatus!.prefs.alexa_enabled;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
@ -25,7 +25,11 @@ export class CloudGooglePref extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const { google_enabled, google_allow_unlock } = this.cloudStatus!.prefs;
|
if (!this.cloudStatus) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { google_enabled, google_allow_unlock } = this.cloudStatus.prefs;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyle()}
|
${this.renderStyle()}
|
||||||
|
142
src/panels/config/cloud/cloud-webhook-manage-dialog.ts
Normal file
142
src/panels/config/cloud/cloud-webhook-manage-dialog.ts
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||||
|
|
||||||
|
import "@polymer/paper-button/paper-button";
|
||||||
|
import "@polymer/paper-input/paper-input";
|
||||||
|
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||||
|
import "@polymer/paper-dialog/paper-dialog";
|
||||||
|
// This is not a duplicate import, one is for types, one is for element.
|
||||||
|
// tslint:disable-next-line
|
||||||
|
import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||||
|
// tslint:disable-next-line
|
||||||
|
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
|
|
||||||
|
import { buttonLink } from "../../../resources/ha-style";
|
||||||
|
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { WebhookDialogParams } from "./types";
|
||||||
|
|
||||||
|
const inputLabel = "Public URL – Click to copy to clipboard";
|
||||||
|
|
||||||
|
export class CloudWebhookManageDialog extends LitElement {
|
||||||
|
protected hass?: HomeAssistant;
|
||||||
|
private _params?: WebhookDialogParams;
|
||||||
|
|
||||||
|
static get properties(): PropertyDeclarations {
|
||||||
|
return {
|
||||||
|
_params: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async showDialog(params: WebhookDialogParams) {
|
||||||
|
this._params = params;
|
||||||
|
// Wait till dialog is rendered.
|
||||||
|
await this.updateComplete;
|
||||||
|
this._dialog.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this._params) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
const { webhook, cloudhook } = this._params;
|
||||||
|
const docsUrl =
|
||||||
|
webhook.domain === "automation"
|
||||||
|
? "https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger"
|
||||||
|
: `https://www.home-assistant.io/components/${webhook.domain}/`;
|
||||||
|
return html`
|
||||||
|
${this._renderStyle()}
|
||||||
|
<paper-dialog with-backdrop>
|
||||||
|
<h2>Webhook for ${webhook.name}</h2>
|
||||||
|
<div>
|
||||||
|
<p>The webhook is available at the following url:</p>
|
||||||
|
<paper-input
|
||||||
|
label="${inputLabel}"
|
||||||
|
value="${cloudhook.cloudhook_url}"
|
||||||
|
@click="${this._copyClipboard}"
|
||||||
|
@blur="${this._restoreLabel}"
|
||||||
|
></paper-input>
|
||||||
|
<p>
|
||||||
|
If you no longer want to use this webhook, you can
|
||||||
|
<button class="link" @click="${this._disableWebhook}">
|
||||||
|
disable it</button
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="paper-dialog-buttons">
|
||||||
|
<a href="${docsUrl}" target="_blank"
|
||||||
|
><paper-button>VIEW DOCUMENTATION</paper-button></a
|
||||||
|
>
|
||||||
|
<paper-button @click="${this._closeDialog}">CLOSE</paper-button>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _dialog(): PaperDialogElement {
|
||||||
|
return this.shadowRoot!.querySelector("paper-dialog")!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _paperInput(): PaperInputElement {
|
||||||
|
return this.shadowRoot!.querySelector("paper-input")!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _closeDialog() {
|
||||||
|
this._dialog.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _disableWebhook() {
|
||||||
|
if (!confirm("Are you sure you want to disable this webhook?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._params!.disableHook();
|
||||||
|
this._closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _copyClipboard(ev: FocusEvent) {
|
||||||
|
// paper-input -> iron-input -> input
|
||||||
|
const paperInput = ev.currentTarget as PaperInputElement;
|
||||||
|
const input = (paperInput.inputElement as any)
|
||||||
|
.inputElement as HTMLInputElement;
|
||||||
|
input.setSelectionRange(0, input.value.length);
|
||||||
|
try {
|
||||||
|
document.execCommand("copy");
|
||||||
|
paperInput.label = "COPIED TO CLIPBOARD";
|
||||||
|
} catch (err) {
|
||||||
|
// Copying failed. Oh no
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _restoreLabel() {
|
||||||
|
this._paperInput.label = inputLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderStyle() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
paper-dialog {
|
||||||
|
width: 650px;
|
||||||
|
}
|
||||||
|
paper-input {
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
${buttonLink} button.link {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
paper-button {
|
||||||
|
color: var(--primary-color);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"cloud-webhook-manage-dialog": CloudWebhookManageDialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("cloud-webhook-manage-dialog", CloudWebhookManageDialog);
|
234
src/panels/config/cloud/cloud-webhooks.ts
Normal file
234
src/panels/config/cloud/cloud-webhooks.ts
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyDeclarations,
|
||||||
|
PropertyValues,
|
||||||
|
} from "@polymer/lit-element";
|
||||||
|
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-item/paper-item-body";
|
||||||
|
import "@polymer/paper-spinner/paper-spinner";
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
import { HomeAssistant, WebhookError } from "../../../types";
|
||||||
|
import { WebhookDialogParams, CloudStatusLoggedIn } from "./types";
|
||||||
|
import { Webhook, fetchWebhooks } from "../../../data/webhook";
|
||||||
|
import {
|
||||||
|
createCloudhook,
|
||||||
|
deleteCloudhook,
|
||||||
|
CloudWebhook,
|
||||||
|
} from "../../../data/cloud";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// for fire event
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"manage-cloud-webhook": WebhookDialogParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CloudWebhooks extends LitElement {
|
||||||
|
public hass?: HomeAssistant;
|
||||||
|
public cloudStatus?: CloudStatusLoggedIn;
|
||||||
|
private _cloudHooks?: { [webhookId: string]: CloudWebhook };
|
||||||
|
private _localHooks?: Webhook[];
|
||||||
|
private _progress: string[];
|
||||||
|
|
||||||
|
static get properties(): PropertyDeclarations {
|
||||||
|
return {
|
||||||
|
hass: {},
|
||||||
|
cloudStatus: {},
|
||||||
|
_cloudHooks: {},
|
||||||
|
_localHooks: {},
|
||||||
|
_progress: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this._progress = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this._fetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
${this.renderStyle()}
|
||||||
|
<ha-card header="Webhooks">
|
||||||
|
<div class="body">
|
||||||
|
Anything that is configured to be triggered by a webhook can be given
|
||||||
|
a publicly accessible URL to allow you to send data back to Home
|
||||||
|
Assistant from anywhere, without exposing your instance to the
|
||||||
|
internet.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${this._renderBody()}
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<a href="https://www.nabucasa.com/config/webhooks" target="_blank">
|
||||||
|
Learn more about creating webhook-powered automations.
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
if (changedProps.has("cloudStatus") && this.cloudStatus) {
|
||||||
|
this._cloudHooks = this.cloudStatus.prefs.cloudhooks || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderBody() {
|
||||||
|
if (!this.cloudStatus || !this._localHooks || !this._cloudHooks) {
|
||||||
|
return html`
|
||||||
|
<div class="loading">Loading…</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._localHooks.map(
|
||||||
|
(entry) => html`
|
||||||
|
<div class="webhook" .entry="${entry}">
|
||||||
|
<paper-item-body two-line>
|
||||||
|
<div>
|
||||||
|
${entry.name}
|
||||||
|
${
|
||||||
|
entry.domain === entry.name.toLowerCase()
|
||||||
|
? ""
|
||||||
|
: ` (${entry.domain})`
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div secondary>${entry.webhook_id}</div>
|
||||||
|
</paper-item-body>
|
||||||
|
${
|
||||||
|
this._progress.includes(entry.webhook_id)
|
||||||
|
? html`
|
||||||
|
<div class="progress">
|
||||||
|
<paper-spinner active></paper-spinner>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: this._cloudHooks![entry.webhook_id]
|
||||||
|
? html`
|
||||||
|
<paper-button @click="${this._handleManageButton}"
|
||||||
|
>Manage</paper-button
|
||||||
|
>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<paper-toggle-button
|
||||||
|
@click="${this._enableWebhook}"
|
||||||
|
></paper-toggle-button>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _showDialog(webhookId: string) {
|
||||||
|
const webhook = this._localHooks!.find(
|
||||||
|
(ent) => ent.webhook_id === webhookId
|
||||||
|
);
|
||||||
|
const cloudhook = this._cloudHooks![webhookId];
|
||||||
|
const params: WebhookDialogParams = {
|
||||||
|
webhook: webhook!,
|
||||||
|
cloudhook,
|
||||||
|
disableHook: () => this._disableWebhook(webhookId),
|
||||||
|
};
|
||||||
|
fireEvent(this, "manage-cloud-webhook", params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleManageButton(ev: MouseEvent) {
|
||||||
|
const entry = (ev.currentTarget as any).parentElement.entry as Webhook;
|
||||||
|
this._showDialog(entry.webhook_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _enableWebhook(ev: MouseEvent) {
|
||||||
|
const entry = (ev.currentTarget as any).parentElement.entry;
|
||||||
|
this._progress = [...this._progress, entry.webhook_id];
|
||||||
|
let updatedWebhook;
|
||||||
|
|
||||||
|
try {
|
||||||
|
updatedWebhook = await createCloudhook(this.hass!, entry.webhook_id);
|
||||||
|
} catch (err) {
|
||||||
|
alert((err as WebhookError).message);
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
this._progress = this._progress.filter((wid) => wid !== entry.webhook_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cloudHooks = {
|
||||||
|
...this._cloudHooks,
|
||||||
|
[entry.webhook_id]: updatedWebhook,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only open dialog if we're not also enabling others, otherwise it's confusing
|
||||||
|
if (this._progress.length === 0) {
|
||||||
|
this._showDialog(entry.webhook_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _disableWebhook(webhookId: string) {
|
||||||
|
this._progress = [...this._progress, webhookId];
|
||||||
|
try {
|
||||||
|
await deleteCloudhook(this.hass!, webhookId!);
|
||||||
|
} catch (err) {
|
||||||
|
alert(`Failed to disable webhook: ${(err as WebhookError).message}`);
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
this._progress = this._progress.filter((wid) => wid !== webhookId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove cloud related parts from entry.
|
||||||
|
const { [webhookId]: disabledHook, ...newHooks } = this._cloudHooks!;
|
||||||
|
this._cloudHooks = newHooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fetchData() {
|
||||||
|
this._localHooks = await fetchWebhooks(this.hass!);
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderStyle() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
.body {
|
||||||
|
padding: 0 16px 8px;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
.webhook {
|
||||||
|
display: flex;
|
||||||
|
padding: 4px 16px;
|
||||||
|
}
|
||||||
|
.progress {
|
||||||
|
margin-right: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
paper-button {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"cloud-webhooks": CloudWebhooks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("cloud-webhooks", CloudWebhooks);
|
@ -10,15 +10,19 @@ import "../../../layouts/hass-subpage";
|
|||||||
import "../../../resources/ha-style";
|
import "../../../resources/ha-style";
|
||||||
|
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
|
import "./cloud-webhooks";
|
||||||
|
|
||||||
import formatDateTime from "../../../common/datetime/format_date_time";
|
import formatDateTime from "../../../common/datetime/format_date_time";
|
||||||
import EventsMixin from "../../../mixins/events-mixin";
|
import EventsMixin from "../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
|
||||||
import { fetchSubscriptionInfo } from "./data";
|
import { fetchSubscriptionInfo } from "./data";
|
||||||
import "./cloud-alexa-pref";
|
import "./cloud-alexa-pref";
|
||||||
import "./cloud-google-pref";
|
import "./cloud-google-pref";
|
||||||
|
|
||||||
|
let registeredWebhookDialog = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @appliesMixin EventsMixin
|
* @appliesMixin EventsMixin
|
||||||
* @appliesMixin LocalizeMixin
|
* @appliesMixin LocalizeMixin
|
||||||
@ -129,6 +133,11 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
cloud-status="[[cloudStatus]]"
|
cloud-status="[[cloudStatus]]"
|
||||||
></cloud-google-pref>
|
></cloud-google-pref>
|
||||||
|
|
||||||
|
<cloud-webhooks
|
||||||
|
hass="[[hass]]"
|
||||||
|
cloud-status="[[cloudStatus]]"
|
||||||
|
></cloud-webhooks>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
</div>
|
</div>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
@ -152,9 +161,26 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
this._fetchSubscriptionInfo();
|
this._fetchSubscriptionInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
|
||||||
|
if (!registeredWebhookDialog) {
|
||||||
|
registeredWebhookDialog = true;
|
||||||
|
fireEvent(this, "register-dialog", {
|
||||||
|
dialogShowEvent: "manage-cloud-webhook",
|
||||||
|
dialogTag: "cloud-webhook-manage-dialog",
|
||||||
|
dialogImport: () => import("./cloud-webhook-manage-dialog"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async _fetchSubscriptionInfo() {
|
async _fetchSubscriptionInfo() {
|
||||||
this._subscription = await fetchSubscriptionInfo(this.hass);
|
this._subscription = await fetchSubscriptionInfo(this.hass);
|
||||||
if (this._subscription.provider && this.cloudStatus.cloud !== "connected") {
|
if (
|
||||||
|
this._subscription.provider &&
|
||||||
|
this.cloudStatus &&
|
||||||
|
this.cloudStatus.cloud !== "connected"
|
||||||
|
) {
|
||||||
this.fire("ha-refresh-cloud-status");
|
this.fire("ha-refresh-cloud-status");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import { CloudWebhook } from "../../../data/cloud";
|
||||||
|
import { Webhook } from "../../../data/webhook";
|
||||||
|
|
||||||
export interface EntityFilter {
|
export interface EntityFilter {
|
||||||
include_domains: string[];
|
include_domains: string[];
|
||||||
include_entities: string[];
|
include_entities: string[];
|
||||||
@ -19,6 +22,7 @@ export type CloudStatusLoggedIn = CloudStatusBase & {
|
|||||||
google_enabled: boolean;
|
google_enabled: boolean;
|
||||||
alexa_enabled: boolean;
|
alexa_enabled: boolean;
|
||||||
google_allow_unlock: boolean;
|
google_allow_unlock: boolean;
|
||||||
|
cloudhooks: { [webhookId: string]: CloudWebhook };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,3 +31,9 @@ export type CloudStatus = CloudStatusBase | CloudStatusLoggedIn;
|
|||||||
export interface SubscriptionInfo {
|
export interface SubscriptionInfo {
|
||||||
human_description: string;
|
human_description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WebhookDialogParams {
|
||||||
|
webhook: Webhook;
|
||||||
|
cloudhook: CloudWebhook;
|
||||||
|
disableHook: () => void;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,19 @@
|
|||||||
import "@polymer/paper-styles/paper-styles";
|
import "@polymer/paper-styles/paper-styles";
|
||||||
import "@polymer/polymer/polymer-legacy";
|
import "@polymer/polymer/polymer-legacy";
|
||||||
|
|
||||||
|
export const buttonLink = `
|
||||||
|
button.link {
|
||||||
|
background: none;
|
||||||
|
color: inherit;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
font: inherit;
|
||||||
|
text-align: left;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const documentContainer = document.createElement("template");
|
const documentContainer = document.createElement("template");
|
||||||
documentContainer.setAttribute("style", "display: none;");
|
documentContainer.setAttribute("style", "display: none;");
|
||||||
|
|
||||||
@ -162,16 +175,7 @@ documentContainer.innerHTML = `<custom-style>
|
|||||||
@apply --paper-font-title;
|
@apply --paper-font-title;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.link {
|
${buttonLink}
|
||||||
background: none;
|
|
||||||
color: inherit;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
font: inherit;
|
|
||||||
text-align: left;
|
|
||||||
text-decoration: underline;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-actions a {
|
.card-actions a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -15,6 +15,11 @@ declare global {
|
|||||||
var __VERSION__: string;
|
var __VERSION__: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WebhookError {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Credential {
|
export interface Credential {
|
||||||
auth_provider_type: string;
|
auth_provider_type: string;
|
||||||
auth_provider_id: string;
|
auth_provider_id: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user