@things-factory/webhook 10.1.254 → 10.1.257
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/pages/webhook-destinations-page.d.ts +5 -4
- package/dist-client/pages/webhook-destinations-page.js +21 -37
- package/dist-client/pages/webhook-destinations-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -2,10 +2,11 @@ import { LitElement } from 'lit';
|
|
|
2
2
|
declare const WebhookDestinationsPage_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
3
3
|
export declare class WebhookDestinationsPage extends WebhookDestinationsPage_base {
|
|
4
4
|
static styles: import("lit").CSSResult;
|
|
5
|
-
private
|
|
6
|
-
private
|
|
7
|
-
|
|
8
|
-
private
|
|
5
|
+
private destinationsRead;
|
|
6
|
+
private activating;
|
|
7
|
+
private saving;
|
|
8
|
+
private get destinations();
|
|
9
|
+
private get failure();
|
|
9
10
|
private toggle;
|
|
10
11
|
/** Exposed so a host page can add a peer without this component owning a form. */
|
|
11
12
|
save(peer: string, patch: Record<string, unknown>): Promise<void>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { __decorate
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
2
|
import gql from 'graphql-tag';
|
|
3
3
|
import { LitElement, css, html } from 'lit';
|
|
4
|
-
import { customElement
|
|
5
|
-
import {
|
|
4
|
+
import { customElement } from 'lit/decorators.js';
|
|
5
|
+
import { MutationController, QueryController } from '@operato/graphql';
|
|
6
6
|
import { i18next, localize } from '@operato/i18n';
|
|
7
7
|
/*
|
|
8
8
|
* ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -55,7 +55,13 @@ const SET_ACTIVE = gql `
|
|
|
55
55
|
let WebhookDestinationsPage = class WebhookDestinationsPage extends localize(i18next)(LitElement) {
|
|
56
56
|
constructor() {
|
|
57
57
|
super(...arguments);
|
|
58
|
-
|
|
58
|
+
/*
|
|
59
|
+
* `no-cache` (the controller's default) because this page is opened right after someone changed a value, often in
|
|
60
|
+
* another tab. A cached list would show the value they just replaced and read as a failed save.
|
|
61
|
+
*/
|
|
62
|
+
this.destinationsRead = new QueryController(this, DESTINATIONS);
|
|
63
|
+
this.activating = new MutationController(this, SET_ACTIVE, { refetch: () => [this.destinationsRead] });
|
|
64
|
+
this.saving = new MutationController(this, SAVE, { refetch: () => [this.destinationsRead] });
|
|
59
65
|
}
|
|
60
66
|
static { this.styles = css `
|
|
61
67
|
:host {
|
|
@@ -129,37 +135,23 @@ let WebhookDestinationsPage = class WebhookDestinationsPage extends localize(i18
|
|
|
129
135
|
color: var(--webhook-muted, #616161);
|
|
130
136
|
}
|
|
131
137
|
`; }
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
this.reload();
|
|
138
|
+
get destinations() {
|
|
139
|
+
return this.destinationsRead.data?.webhookDestinations ?? [];
|
|
135
140
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
/*
|
|
144
|
-
* This client resolves GraphQL errors instead of rejecting them, so `data?.x ?? []`
|
|
145
|
-
* turns a failure into an empty list and the page says "nothing configured" when the
|
|
146
|
-
* truth is "we could not ask". Check for errors before reading data.
|
|
147
|
-
*/
|
|
148
|
-
if (response.errors?.length) {
|
|
149
|
-
this.failure = response.errors[0].message;
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
this.failure = undefined;
|
|
153
|
-
this.destinations = response.data?.webhookDestinations ?? [];
|
|
141
|
+
/*
|
|
142
|
+
* A failure is not an empty list: the page says "nothing configured" only when the ask answered, and says it could
|
|
143
|
+
* not ask otherwise.
|
|
144
|
+
*/
|
|
145
|
+
get failure() {
|
|
146
|
+
const error = this.destinationsRead.error;
|
|
147
|
+
return error ? (error.message ?? String(error)) : undefined;
|
|
154
148
|
}
|
|
155
149
|
async toggle(peer, active) {
|
|
156
|
-
await
|
|
157
|
-
await this.reload();
|
|
150
|
+
await this.activating.run({ peer, active });
|
|
158
151
|
}
|
|
159
152
|
/** Exposed so a host page can add a peer without this component owning a form. */
|
|
160
153
|
async save(peer, patch) {
|
|
161
|
-
await
|
|
162
|
-
await this.reload();
|
|
154
|
+
await this.saving.run({ peer, patch });
|
|
163
155
|
}
|
|
164
156
|
renderEmpty() {
|
|
165
157
|
return html `
|
|
@@ -213,14 +205,6 @@ let WebhookDestinationsPage = class WebhookDestinationsPage extends localize(i18
|
|
|
213
205
|
`;
|
|
214
206
|
}
|
|
215
207
|
};
|
|
216
|
-
__decorate([
|
|
217
|
-
state(),
|
|
218
|
-
__metadata("design:type", Array)
|
|
219
|
-
], WebhookDestinationsPage.prototype, "destinations", void 0);
|
|
220
|
-
__decorate([
|
|
221
|
-
state(),
|
|
222
|
-
__metadata("design:type", String)
|
|
223
|
-
], WebhookDestinationsPage.prototype, "failure", void 0);
|
|
224
208
|
WebhookDestinationsPage = __decorate([
|
|
225
209
|
customElement('webhook-destinations-page')
|
|
226
210
|
], WebhookDestinationsPage);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-destinations-page.js","sourceRoot":"","sources":["../../client/pages/webhook-destinations-page.ts"],"names":[],"mappings":";AAAA,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"webhook-destinations-page.js","sourceRoot":"","sources":["../../client/pages/webhook-destinations-page.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { LitElement, css, html } from 'lit'\nimport { customElement } from 'lit/decorators.js'\n\nimport { MutationController, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\n\n/*\n * ═══════════════════════════════════════════════════════════════════════════\n * Where this tenant pushes facts — one row per peer.\n *\n * ── Why a list ─────────────────────────────────────────────────────────────\n * The screen this replaces edited a single destination, because the table it read had one\n * row per tenant. A tenant that mirrors into two twins, or pushes to a twin and an ERP, could\n * not enter the second peer at all — there was no field to say which one you meant\n * (ADR-0041).\n *\n * ── The empty screen is the important one ──────────────────────────────────\n * A tenant that has never pushed anywhere sees this page first, and \"no rows\" tells them\n * nothing about what to do. So the empty state names what a destination is for and what a\n * peer name is, rather than showing an empty table with a plus button.\n *\n * ── Secrets are not on this screen ─────────────────────────────────────────\n * Signing and verifying keys come from the environment. The page can say whether one is\n * present, and that is a different fact from the value — a field that accepted the value\n * would put it in a request body and a browser's form history.\n * ═══════════════════════════════════════════════════════════════════════════\n */\n\nconst DESTINATIONS = gql`\n query {\n webhookDestinations {\n id\n peer\n description\n endpoint\n params\n active\n state\n updatedAt\n }\n }\n`\n\nconst SAVE = gql`\n mutation ($peer: String!, $patch: Object!) {\n saveWebhookDestination(peer: $peer, patch: $patch) {\n id\n peer\n }\n }\n`\n\nconst SET_ACTIVE = gql`\n mutation ($peer: String!, $active: Boolean!) {\n setWebhookDestinationActive(peer: $peer, active: $active)\n }\n`\n\ntype Destination = {\n id: string\n peer: string\n description?: string\n endpoint: string\n params?: Record<string, unknown>\n active: boolean\n state?: string\n updatedAt?: string\n}\n\n@customElement('webhook-destinations-page')\nexport class WebhookDestinationsPage extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n padding: 16px;\n font-size: 13px;\n }\n\n h2 {\n margin: 0 0 4px;\n font-size: 18px;\n }\n\n .lede {\n margin: 0 0 16px;\n color: var(--webhook-muted, #616161);\n max-width: 62ch;\n line-height: 1.6;\n }\n\n .empty {\n border: 1px dashed var(--webhook-line, #cfd8dc);\n border-radius: 6px;\n padding: 24px;\n max-width: 62ch;\n line-height: 1.7;\n }\n\n .empty strong {\n display: block;\n margin-bottom: 8px;\n }\n\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 8px;\n }\n\n li {\n border: 1px solid var(--webhook-line, #cfd8dc);\n border-radius: 6px;\n padding: 12px 14px;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 4px 12px;\n align-items: center;\n }\n\n .peer {\n font-weight: 600;\n }\n\n .endpoint {\n grid-column: 1;\n color: var(--webhook-muted, #616161);\n word-break: break-all;\n }\n\n .flags {\n grid-column: 2;\n grid-row: 1 / span 2;\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .off {\n color: var(--webhook-muted, #616161);\n }\n `\n\n /*\n * `no-cache` (the controller's default) because this page is opened right after someone changed a value, often in\n * another tab. A cached list would show the value they just replaced and read as a failed save.\n */\n private destinationsRead = new QueryController(this, DESTINATIONS)\n private activating = new MutationController(this, SET_ACTIVE, { refetch: () => [this.destinationsRead] })\n private saving = new MutationController(this, SAVE, { refetch: () => [this.destinationsRead] })\n\n private get destinations(): Destination[] {\n return this.destinationsRead.data?.webhookDestinations ?? []\n }\n\n /*\n * A failure is not an empty list: the page says \"nothing configured\" only when the ask answered, and says it could\n * not ask otherwise.\n */\n private get failure(): string | undefined {\n const error = this.destinationsRead.error as any\n return error ? (error.message ?? String(error)) : undefined\n }\n\n private async toggle(peer: string, active: boolean) {\n await this.activating.run({ peer, active })\n }\n\n /** Exposed so a host page can add a peer without this component owning a form. */\n async save(peer: string, patch: Record<string, unknown>) {\n await this.saving.run({ peer, patch })\n }\n\n private renderEmpty() {\n return html`\n <div class=\"empty\">\n <strong>${i18next.t('webhook.destinations.empty.title')}</strong>\n ${i18next.t('webhook.destinations.empty.what')}\n <br /><br />\n ${i18next.t('webhook.destinations.empty.two-peers')}\n </div>\n `\n }\n\n render() {\n if (this.failure) {\n /*\n * The message says the ask failed, not that there is nothing — those are different\n * facts and only one of them is the reader's problem to fix here.\n */\n return html`\n <h2>${i18next.t('webhook.destinations.title')}</h2>\n <p class=\"lede\">${i18next.t('webhook.destinations.load-failed')}: ${this.failure}</p>\n `\n }\n\n return html`\n <h2>${i18next.t('webhook.destinations.title')}</h2>\n <p class=\"lede\">\n ${i18next.t('webhook.destinations.lede')}\n </p>\n ${this.destinations.length\n ? html`\n <ul>\n ${this.destinations.map(\n destination => html`\n <li>\n <span class=\"peer\">${destination.peer}</span>\n <span class=\"endpoint\">${destination.endpoint}</span>\n <span class=\"flags\">\n ${destination.state ? html`<span class=\"off\">${destination.state}</span>` : null}\n <label>\n <input\n type=\"checkbox\"\n .checked=${destination.active}\n @change=${(e: Event) =>\n this.toggle(destination.peer, (e.target as HTMLInputElement).checked)}\n />\n ${i18next.t('webhook.field.active')}\n </label>\n </span>\n </li>\n `\n )}\n </ul>\n `\n : this.renderEmpty()}\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'webhook-destinations-page': WebhookDestinationsPage\n }\n}\n"]}
|