@things-factory/notification 10.1.256 → 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.
@@ -19,14 +19,15 @@ declare const NoticeChannelSettingLet_base: (new (...args: any[]) => LitElement)
19
19
  */
20
20
  export declare class NoticeChannelSettingLet extends NoticeChannelSettingLet_base {
21
21
  static styles: import("lit").CSSResult[];
22
- setting?: NoticeChannelSetting;
23
22
  entries: {
24
23
  teamsChannelWebhook: string;
25
24
  };
26
- busy: boolean;
25
+ private settingRead;
26
+ private saving;
27
+ get setting(): NoticeChannelSetting | undefined;
28
+ get busy(): boolean;
27
29
  render(): import("lit-html").TemplateResult<1> | typeof nothing;
28
30
  private webhookRow;
29
- connectedCallback(): Promise<void>;
30
31
  private save;
31
32
  }
32
33
  export {};
@@ -6,7 +6,7 @@ import '@things-factory/setting-base';
6
6
  import gql from 'graphql-tag';
7
7
  import { css, html, LitElement, nothing } from 'lit';
8
8
  import { customElement, state } from 'lit/decorators.js';
9
- import { client } from '@operato/graphql';
9
+ import { MutationController, QueryController } from '@operato/graphql';
10
10
  import { i18next, localize } from '@operato/i18n';
11
11
  import { notify } from '@operato/layout';
12
12
  const SETTING = `email teamsChannel { set host }`;
@@ -19,7 +19,9 @@ let NoticeChannelSettingLet = class NoticeChannelSettingLet extends localize(i18
19
19
  constructor() {
20
20
  super(...arguments);
21
21
  this.entries = { teamsChannelWebhook: '' };
22
- this.busy = false;
22
+ /* Refused for one who may not change the domain's attributes - the card then stays empty. */
23
+ this.settingRead = new QueryController(this, gql `query { noticeChannelSetting { ${SETTING} } }`);
24
+ this.saving = new MutationController(this, gql `mutation ($patch: NoticeChannelSettingPatch!) { updateNoticeChannelSetting(patch: $patch) { ${SETTING} } }`, { refetch: () => [this.settingRead] });
23
25
  }
24
26
  static { this.styles = [
25
27
  css `
@@ -74,6 +76,12 @@ let NoticeChannelSettingLet = class NoticeChannelSettingLet extends localize(i18
74
76
  }
75
77
  `
76
78
  ]; }
79
+ get setting() {
80
+ return this.settingRead.data?.noticeChannelSetting || undefined;
81
+ }
82
+ get busy() {
83
+ return this.saving.pending;
84
+ }
77
85
  render() {
78
86
  const setting = this.setting;
79
87
  if (!setting)
@@ -121,53 +129,19 @@ let NoticeChannelSettingLet = class NoticeChannelSettingLet extends localize(i18
121
129
  </div>
122
130
  `;
123
131
  }
124
- async connectedCallback() {
125
- super.connectedCallback();
126
- const response = await client
127
- .query({ query: gql `query { noticeChannelSetting { ${SETTING} } }`, fetchPolicy: 'no-cache', errorPolicy: 'all' })
128
- .catch(() => undefined);
129
- /* refused - this person may not change the domain's attributes, so the card stays empty */
130
- this.setting = response?.data?.noticeChannelSetting || undefined;
131
- }
132
132
  async save(patch) {
133
- this.busy = true;
134
- try {
135
- const response = await client.mutate({
136
- mutation: gql `mutation ($patch: NoticeChannelSettingPatch!) { updateNoticeChannelSetting(patch: $patch) { ${SETTING} } }`,
137
- variables: { patch },
138
- errorPolicy: 'all'
139
- });
140
- if (response.errors?.length) {
141
- notify({ level: 'error', message: response.errors[0].message });
142
- this.requestUpdate();
143
- return;
144
- }
145
- this.setting = response.data.updateNoticeChannelSetting;
146
- const cleared = Object.keys(patch).filter(field => field in this.entries);
147
- if (cleared.length)
148
- this.entries = { ...this.entries, ...Object.fromEntries(cleared.map(field => [field, ''])) };
149
- notify({ level: 'info', message: i18next.t('text.notice channels saved') });
150
- }
151
- catch (error) {
152
- notify({ level: 'error', message: String(error?.message || error) });
153
- }
154
- finally {
155
- this.busy = false;
156
- }
133
+ if (!(await this.saving.run({ patch })))
134
+ return;
135
+ const cleared = Object.keys(patch).filter(field => field in this.entries);
136
+ if (cleared.length)
137
+ this.entries = { ...this.entries, ...Object.fromEntries(cleared.map(field => [field, ''])) };
138
+ notify({ level: 'info', message: i18next.t('text.notice channels saved') });
157
139
  }
158
140
  };
159
- __decorate([
160
- state(),
161
- __metadata("design:type", Object)
162
- ], NoticeChannelSettingLet.prototype, "setting", void 0);
163
141
  __decorate([
164
142
  state(),
165
143
  __metadata("design:type", Object)
166
144
  ], NoticeChannelSettingLet.prototype, "entries", void 0);
167
- __decorate([
168
- state(),
169
- __metadata("design:type", Object)
170
- ], NoticeChannelSettingLet.prototype, "busy", void 0);
171
145
  NoticeChannelSettingLet = __decorate([
172
146
  customElement('notice-channel-setting-let')
173
147
  ], NoticeChannelSettingLet);
@@ -1 +1 @@
1
- {"version":3,"file":"notice-channel-setting-let.js","sourceRoot":"","sources":["../../client/viewparts/notice-channel-setting-let.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/outlined-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/switch/switch.js'\nimport '@things-factory/setting-base'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\n\ntype SecretState = { set: boolean; host?: string }\ntype NoticeChannelSetting = { email: boolean; teamsChannel: SecretState }\n\nconst SETTING = `email teamsChannel { set host }`\n\n/**\n * Where notices go beyond the app and web push in this domain (ADR-0164): mail, and the Teams channel that takes a\n * notice to everyone. Shown to those who may change the domain's attributes; for anyone else the card stays empty. The\n * webhook address goes in and never comes back - the card shows only that it is set, and its host.\n */\n@customElement('notice-channel-setting-let')\nexport class NoticeChannelSettingLet extends localize(i18next)(LitElement) {\n static styles = [\n css`\n div[row] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small, 4px);\n border-bottom: var(--border-dim-color);\n margin-bottom: var(--spacing-medium);\n padding-bottom: var(--spacing-medium);\n }\n\n div[row]:last-child {\n border-bottom: none;\n margin-bottom: 0;\n }\n\n label {\n display: flex;\n gap: 10px;\n align-items: center;\n\n font: var(--label-font);\n color: var(--md-sys-color-on-surface);\n text-transform: var(--label-text-transform);\n }\n\n [state] {\n font: var(--input-font);\n color: var(--md-sys-color-on-surface-variant);\n /* a host is data - the card's capitalized labels must not reach it */\n text-transform: none;\n }\n\n div[entry] {\n display: flex;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n\n input {\n background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));\n color: var(--input-field-color, var(--md-sys-color-on-surface));\n border: var(--border-dim-color);\n border-radius: var(--border-radius);\n margin: var(--input-margin);\n padding: var(--input-padding);\n font: var(--input-font);\n\n flex: 1;\n min-width: 0;\n }\n `\n ]\n\n @state() setting?: NoticeChannelSetting\n @state() entries: { teamsChannelWebhook: string } = { teamsChannelWebhook: '' }\n @state() busy = false\n\n render() {\n const setting = this.setting\n if (!setting) return nothing\n\n return html`\n <setting-let>\n <span slot=\"title\">${i18next.t('title.notice channels')}</span>\n\n <div slot=\"content\" row>\n <label>\n <md-switch ?selected=${setting.email} ?disabled=${this.busy} @change=${e => this.save({ email: e.target.selected })}></md-switch>\n ${i18next.t('label.notice by email')}\n </label>\n </div>\n\n ${this.webhookRow('teamsChannelWebhook', i18next.t('label.teams channel webhook'), setting.teamsChannel)}\n </setting-let>\n `\n }\n\n private webhookRow(field: 'teamsChannelWebhook', label: string, secret: SecretState) {\n const entry = this.entries[field]\n\n return html`\n <div slot=\"content\" row>\n <label>${label}</label>\n <span state>\n ${secret.set ? i18next.t('text.notice webhook set', { host: secret.host || '-' }) : i18next.t('text.notice webhook not set')}\n </span>\n <div entry>\n <input\n type=\"url\"\n placeholder=\"https://\"\n autocomplete=\"off\"\n .value=${entry}\n @input=${e => (this.entries = { ...this.entries, [field]: e.target.value })}\n />\n <md-outlined-button ?disabled=${this.busy || !entry.trim()} @click=${() => this.save({ [field]: entry.trim() })}\n >${i18next.t('button.notice webhook save')}</md-outlined-button\n >\n ${secret.set\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.save({ [field]: '' })}\n >${i18next.t('button.notice webhook clear')}</md-text-button\n >`\n : nothing}\n </div>\n </div>\n `\n }\n\n async connectedCallback() {\n super.connectedCallback()\n\n const response = await client\n .query({ query: gql`query { noticeChannelSetting { ${SETTING} } }`, fetchPolicy: 'no-cache', errorPolicy: 'all' })\n .catch(() => undefined)\n\n /* refused - this person may not change the domain's attributes, so the card stays empty */\n this.setting = response?.data?.noticeChannelSetting || undefined\n }\n\n private async save(patch: Record<string, unknown>) {\n this.busy = true\n try {\n const response = await client.mutate({\n mutation: gql`mutation ($patch: NoticeChannelSettingPatch!) { updateNoticeChannelSetting(patch: $patch) { ${SETTING} } }`,\n variables: { patch },\n errorPolicy: 'all'\n })\n\n if (response.errors?.length) {\n notify({ level: 'error', message: response.errors[0].message })\n this.requestUpdate()\n return\n }\n\n this.setting = response.data.updateNoticeChannelSetting\n const cleared = Object.keys(patch).filter(field => field in this.entries)\n if (cleared.length) this.entries = { ...this.entries, ...Object.fromEntries(cleared.map(field => [field, ''])) }\n notify({ level: 'info', message: i18next.t('text.notice channels saved') })\n } catch (error) {\n notify({ level: 'error', message: String((error as any)?.message || error) })\n } finally {\n this.busy = false\n }\n }\n}\n"]}
1
+ {"version":3,"file":"notice-channel-setting-let.js","sourceRoot":"","sources":["../../client/viewparts/notice-channel-setting-let.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/outlined-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/switch/switch.js'\nimport '@things-factory/setting-base'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { MutationController, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\n\ntype SecretState = { set: boolean; host?: string }\ntype NoticeChannelSetting = { email: boolean; teamsChannel: SecretState }\n\nconst SETTING = `email teamsChannel { set host }`\n\n/**\n * Where notices go beyond the app and web push in this domain (ADR-0164): mail, and the Teams channel that takes a\n * notice to everyone. Shown to those who may change the domain's attributes; for anyone else the card stays empty. The\n * webhook address goes in and never comes back - the card shows only that it is set, and its host.\n */\n@customElement('notice-channel-setting-let')\nexport class NoticeChannelSettingLet extends localize(i18next)(LitElement) {\n static styles = [\n css`\n div[row] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small, 4px);\n border-bottom: var(--border-dim-color);\n margin-bottom: var(--spacing-medium);\n padding-bottom: var(--spacing-medium);\n }\n\n div[row]:last-child {\n border-bottom: none;\n margin-bottom: 0;\n }\n\n label {\n display: flex;\n gap: 10px;\n align-items: center;\n\n font: var(--label-font);\n color: var(--md-sys-color-on-surface);\n text-transform: var(--label-text-transform);\n }\n\n [state] {\n font: var(--input-font);\n color: var(--md-sys-color-on-surface-variant);\n /* a host is data - the card's capitalized labels must not reach it */\n text-transform: none;\n }\n\n div[entry] {\n display: flex;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n\n input {\n background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));\n color: var(--input-field-color, var(--md-sys-color-on-surface));\n border: var(--border-dim-color);\n border-radius: var(--border-radius);\n margin: var(--input-margin);\n padding: var(--input-padding);\n font: var(--input-font);\n\n flex: 1;\n min-width: 0;\n }\n `\n ]\n\n @state() entries: { teamsChannelWebhook: string } = { teamsChannelWebhook: '' }\n\n /* Refused for one who may not change the domain's attributes - the card then stays empty. */\n private settingRead = new QueryController(this, gql`query { noticeChannelSetting { ${SETTING} } }`)\n private saving = new MutationController(\n this,\n gql`mutation ($patch: NoticeChannelSettingPatch!) { updateNoticeChannelSetting(patch: $patch) { ${SETTING} } }`,\n { refetch: () => [this.settingRead] }\n )\n\n get setting(): NoticeChannelSetting | undefined {\n return this.settingRead.data?.noticeChannelSetting || undefined\n }\n\n get busy() {\n return this.saving.pending\n }\n\n render() {\n const setting = this.setting\n if (!setting) return nothing\n\n return html`\n <setting-let>\n <span slot=\"title\">${i18next.t('title.notice channels')}</span>\n\n <div slot=\"content\" row>\n <label>\n <md-switch ?selected=${setting.email} ?disabled=${this.busy} @change=${e => this.save({ email: e.target.selected })}></md-switch>\n ${i18next.t('label.notice by email')}\n </label>\n </div>\n\n ${this.webhookRow('teamsChannelWebhook', i18next.t('label.teams channel webhook'), setting.teamsChannel)}\n </setting-let>\n `\n }\n\n private webhookRow(field: 'teamsChannelWebhook', label: string, secret: SecretState) {\n const entry = this.entries[field]\n\n return html`\n <div slot=\"content\" row>\n <label>${label}</label>\n <span state>\n ${secret.set ? i18next.t('text.notice webhook set', { host: secret.host || '-' }) : i18next.t('text.notice webhook not set')}\n </span>\n <div entry>\n <input\n type=\"url\"\n placeholder=\"https://\"\n autocomplete=\"off\"\n .value=${entry}\n @input=${e => (this.entries = { ...this.entries, [field]: e.target.value })}\n />\n <md-outlined-button ?disabled=${this.busy || !entry.trim()} @click=${() => this.save({ [field]: entry.trim() })}\n >${i18next.t('button.notice webhook save')}</md-outlined-button\n >\n ${secret.set\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.save({ [field]: '' })}\n >${i18next.t('button.notice webhook clear')}</md-text-button\n >`\n : nothing}\n </div>\n </div>\n `\n }\n\n private async save(patch: Record<string, unknown>) {\n if (!(await this.saving.run({ patch }))) return\n const cleared = Object.keys(patch).filter(field => field in this.entries)\n if (cleared.length) this.entries = { ...this.entries, ...Object.fromEntries(cleared.map(field => [field, ''])) }\n notify({ level: 'info', message: i18next.t('text.notice channels saved') })\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/notification",
3
- "version": "10.1.256",
3
+ "version": "10.1.257",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -28,13 +28,15 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@material/web": "^2.0.0",
31
+ "@operato/graphql": "^10.29.69",
31
32
  "@operato/layout": "^10.0.0",
33
+ "@operato/shell": "^10.29.69",
32
34
  "@operato/styles": "^10.0.0",
33
- "@things-factory/auth-base": "^10.1.256",
35
+ "@things-factory/auth-base": "^10.1.257",
34
36
  "@things-factory/email-base": "^10.1.254",
35
- "@things-factory/i18n-base": "^10.1.256",
36
- "@things-factory/organization": "^10.1.256",
37
- "@things-factory/setting-base": "^10.1.256",
37
+ "@things-factory/i18n-base": "^10.1.257",
38
+ "@things-factory/organization": "^10.1.257",
39
+ "@things-factory/setting-base": "^10.1.257",
38
40
  "@things-factory/shell": "^10.1.254",
39
41
  "clipboard": "^2.0.6",
40
42
  "firebase": "^9.14.0",
@@ -42,5 +44,5 @@
42
44
  "google": "^2.1.0",
43
45
  "marked": "^15.0.0"
44
46
  },
45
- "gitHead": "2fd641697190ce6e87bcf454a60b2321553e8110"
47
+ "gitHead": "885b594299601ca4936f4f39701d6713273bbf1e"
46
48
  }