@things-factory/notification 10.1.8 → 10.1.10

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.
@@ -6,6 +6,8 @@ export declare class NotificationItem extends LitElement {
6
6
  notification: any;
7
7
  target?: string;
8
8
  newbie?: boolean;
9
+ private copied;
9
10
  render(): import("lit-html").TemplateResult<1>;
11
+ private copyTechnical;
10
12
  updated(changed: any): void;
11
13
  }
@@ -1,8 +1,9 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import '@material/web/icon/icon.js';
3
3
  import { LitElement, html, css } from 'lit';
4
- import { customElement, property } from 'lit/decorators.js';
4
+ import { customElement, property, state } from 'lit/decorators.js';
5
5
  import { i18next } from '@operato/i18n';
6
+ import { ScrollbarStyles } from '@operato/styles';
6
7
  function isOriginSameAsLocation(url) {
7
8
  function defaultPort(protocol) {
8
9
  return { 'http:': 80, 'https:': 443 }[protocol];
@@ -24,8 +25,20 @@ function isOriginSameAsLocation(url) {
24
25
  console.warn(err, url);
25
26
  }
26
27
  }
28
+ /* 이전 호출부가 message에 HTTP/GraphQL 원문을 넣은 경우에도, 이력에서는 진단 정보로 취급한다. */
29
+ function isTechnicalError(type, value) {
30
+ if (type !== 'ERROR' || typeof value !== 'string')
31
+ return false;
32
+ return /^(\[\s*\d{3}\s*:|(?:Cannot query|Response not successful:)|Error:)/.test(value) ||
33
+ /\n\s*at\s+.+\(.+\)/.test(value);
34
+ }
27
35
  let NotificationItem = class NotificationItem extends LitElement {
36
+ constructor() {
37
+ super(...arguments);
38
+ this.copied = false;
39
+ }
28
40
  static { this.styles = [
41
+ ScrollbarStyles,
29
42
  css `
30
43
  :host {
31
44
  display: block;
@@ -47,14 +60,15 @@ let NotificationItem = class NotificationItem extends LitElement {
47
60
  }
48
61
 
49
62
  [titler] {
50
- white-space: normal;
63
+ display: -webkit-box;
64
+ -webkit-box-orient: vertical;
65
+ -webkit-line-clamp: 2;
51
66
  overflow: hidden;
52
- text-overflow: ellipsis;
53
67
  padding-right: 24px;
54
- font-family: var(--md-sys-typescale-label-large-font, var(--theme-font, inherit));
55
- font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
56
- line-height: var(--md-sys-typescale-label-large-line-height, 1.25rem);
57
- font-weight: var(--md-sys-typescale-label-large-weight, 600);
68
+ font-family: var(--md-sys-typescale-title-small-font, var(--theme-font, inherit));
69
+ font-size: var(--md-sys-typescale-title-small-size, 0.875rem);
70
+ line-height: var(--md-sys-typescale-title-small-line-height, 1.25rem);
71
+ font-weight: var(--md-sys-typescale-title-small-weight, 500);
58
72
  color: var(--md-sys-color-on-surface);
59
73
  }
60
74
 
@@ -82,7 +96,9 @@ let NotificationItem = class NotificationItem extends LitElement {
82
96
  opacity: 1;
83
97
  }
84
98
  [technical] {
99
+ position: relative;
85
100
  margin-top: var(--spacing-small);
101
+ padding-right: 32px;
86
102
  color: var(--md-sys-color-on-surface-variant);
87
103
  font-family: var(--md-sys-typescale-label-small-font, var(--theme-font, inherit));
88
104
  font-size: var(--md-sys-typescale-label-small-size, 0.75rem);
@@ -92,6 +108,28 @@ let NotificationItem = class NotificationItem extends LitElement {
92
108
  [technical] summary {
93
109
  cursor: pointer;
94
110
  }
111
+ [technical] button {
112
+ position: absolute;
113
+ top: -4px;
114
+ right: 0;
115
+ display: inline-flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ width: 28px;
119
+ height: 28px;
120
+ padding: 0;
121
+ border: 0;
122
+ border-radius: 50%;
123
+ background: transparent;
124
+ color: var(--md-sys-color-on-surface-variant);
125
+ cursor: pointer;
126
+ }
127
+ [technical] button:hover {
128
+ background: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface-variant));
129
+ }
130
+ [technical] button md-icon {
131
+ --md-icon-size: 16px;
132
+ }
95
133
  [technical] pre {
96
134
  margin: var(--spacing-small) 0 0;
97
135
  padding: var(--spacing-small);
@@ -146,15 +184,19 @@ let NotificationItem = class NotificationItem extends LitElement {
146
184
  render() {
147
185
  const { title, url, image, timestamp, body, ex } = this.notification;
148
186
  const target = this.target;
149
- const technical = typeof ex === 'string' ? ex : '';
187
+ const legacyTechnical = isTechnicalError(this.type, title);
188
+ const displayTitle = legacyTechnical
189
+ ? i18next.t('text.request failed', { defaultValue: 'Request failed' })
190
+ : title;
191
+ const technical = typeof ex === 'string' ? ex : legacyTechnical ? title : '';
150
192
  return html `
151
- <div titler>
193
+ <div titler title=${displayTitle}>
152
194
  <span></span>
153
195
  ${url
154
196
  ? target
155
- ? html `<a href=${url} target=${target}>${title}</a>`
156
- : html `<a href=${url}>${title}</a>`
157
- : title}
197
+ ? html `<a href=${url} target=${target}>${displayTitle}</a>`
198
+ : html `<a href=${url}>${displayTitle}</a>`
199
+ : displayTitle}
158
200
  </div>
159
201
  <md-icon close @click=${e => this.dispatchEvent(new CustomEvent('close'))}>close</md-icon>
160
202
 
@@ -169,6 +211,13 @@ let NotificationItem = class NotificationItem extends LitElement {
169
211
  ${technical
170
212
  ? html `<details technical>
171
213
  <summary>${i18next.t('text.technical detail', { defaultValue: 'Technical details' })}</summary>
214
+ <button
215
+ title=${i18next.t('button.copy', { defaultValue: 'Copy' })}
216
+ aria-label=${i18next.t('button.copy', { defaultValue: 'Copy' })}
217
+ @click=${event => this.copyTechnical(event, technical)}
218
+ >
219
+ <md-icon>${this.copied ? 'check' : 'content_copy'}</md-icon>
220
+ </button>
172
221
  <pre>${technical}</pre>
173
222
  </details>`
174
223
  : html ``}
@@ -176,6 +225,25 @@ let NotificationItem = class NotificationItem extends LitElement {
176
225
  <div timestamp>${new Date(Number(timestamp)).toLocaleString()}</div>
177
226
  `;
178
227
  }
228
+ async copyTechnical(event, technical) {
229
+ event.preventDefault();
230
+ event.stopPropagation();
231
+ try {
232
+ await navigator.clipboard.writeText(technical);
233
+ }
234
+ catch {
235
+ const textarea = document.createElement('textarea');
236
+ textarea.value = technical;
237
+ textarea.style.position = 'fixed';
238
+ textarea.style.opacity = '0';
239
+ document.body.append(textarea);
240
+ textarea.select();
241
+ document.execCommand('copy');
242
+ textarea.remove();
243
+ }
244
+ this.copied = true;
245
+ window.setTimeout(() => (this.copied = false), 1500);
246
+ }
179
247
  updated(changed) {
180
248
  if (!this.notification?.confirmed) {
181
249
  this.setAttribute('newbie', '');
@@ -203,6 +271,10 @@ __decorate([
203
271
  property({ type: Boolean }),
204
272
  __metadata("design:type", Boolean)
205
273
  ], NotificationItem.prototype, "newbie", void 0);
274
+ __decorate([
275
+ state(),
276
+ __metadata("design:type", Object)
277
+ ], NotificationItem.prototype, "copied", void 0);
206
278
  NotificationItem = __decorate([
207
279
  customElement('notification-item')
208
280
  ], NotificationItem);
@@ -1 +1 @@
1
- {"version":3,"file":"notification-item.js","sourceRoot":"","sources":["../../client/viewparts/notification-item.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { i18next } from '@operato/i18n'\n\nfunction isOriginSameAsLocation(url) {\n function defaultPort(protocol) {\n return { 'http:': 80, 'https:': 443 }[protocol]\n }\n\n function portOf(location) {\n return location.port || defaultPort(location.protocol || pageLocation.protocol)\n }\n\n try {\n var pageLocation = window.location\n var urlparts = new URL(url, pageLocation.href)\n\n return !!(\n urlparts.protocol &&\n urlparts.protocol == pageLocation.protocol &&\n urlparts.host &&\n urlparts.host == pageLocation.host &&\n urlparts.host &&\n portOf(urlparts) == portOf(pageLocation)\n )\n } catch (err) {\n console.warn(err, url)\n }\n}\n\n@customElement('notification-item')\nexport class NotificationItem extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n padding: 12px var(--spacing-medium);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n transition: background-color 120ms ease;\n color: var(--md-sys-color-on-surface);\n\n --type-dot-size: 8px;\n }\n\n :host([newbie]) {\n background-color: var(--md-sys-color-surface-container-low, var(--md-sys-color-surface-variant));\n }\n\n :host(:hover) {\n background-color: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface-variant));\n }\n\n [titler] {\n white-space: normal;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-right: 24px;\n font-family: var(--md-sys-typescale-label-large-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-label-large-size, 0.875rem);\n line-height: var(--md-sys-typescale-label-large-line-height, 1.25rem);\n font-weight: var(--md-sys-typescale-label-large-weight, 600);\n color: var(--md-sys-color-on-surface);\n }\n\n [titler] > span {\n display: inline-block;\n width: var(--type-dot-size);\n height: var(--type-dot-size);\n border-radius: 50%;\n margin-right: var(--spacing-small);\n margin-bottom: var(--spacing-tiny);\n }\n [titler] * {\n vertical-align: middle;\n }\n\n [close] {\n position: absolute;\n top: 12px;\n right: 12px;\n --md-icon-size: 18px;\n opacity: 0.5;\n cursor: pointer;\n }\n [close]:hover {\n opacity: 1;\n }\n [technical] {\n margin-top: var(--spacing-small);\n color: var(--md-sys-color-on-surface-variant);\n font-family: var(--md-sys-typescale-label-small-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-label-small-size, 0.75rem);\n line-height: var(--md-sys-typescale-label-small-line-height, 1rem);\n font-weight: var(--md-sys-typescale-label-small-weight, 400);\n }\n [technical] summary {\n cursor: pointer;\n }\n [technical] pre {\n margin: var(--spacing-small) 0 0;\n padding: var(--spacing-small);\n max-height: 160px;\n overflow: auto;\n border-radius: var(--md-sys-shape-corner-small, 4px);\n background: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface-variant));\n font: inherit;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n }\n :host([type='ERROR']) [titler] > span {\n background-color: var(--status-danger-color);\n }\n :host([type='WARN']) [titler] > span {\n background-color: var(--status-warning-color);\n }\n :host([type='SUCCESS']) [titler] > span {\n background-color: var(--status-success-color);\n }\n :host([type='INFO']) [titler] > span,\n [titler] > span {\n background-color: var(--status-info-color);\n }\n\n img {\n display: block;\n max-width: 100%;\n margin: auto;\n }\n\n [message] {\n margin-top: var(--spacing-small);\n font-family: var(--md-sys-typescale-body-medium-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-body-medium-size, 0.875rem);\n line-height: var(--md-sys-typescale-body-medium-line-height, 1.25rem);\n font-weight: var(--md-sys-typescale-body-medium-weight, 400);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n [timestamp] {\n margin-top: var(--spacing-small);\n white-space: nowrap;\n font-family: var(--md-sys-typescale-label-small-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-label-small-size, 0.75rem);\n line-height: var(--md-sys-typescale-label-small-line-height, 1rem);\n font-weight: var(--md-sys-typescale-label-small-weight, 400);\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n ]\n\n @property({ type: String, reflect: true }) type?: string\n @property({ type: Object }) notification: any\n @property({ type: String }) target?: string\n @property({ type: Boolean }) newbie?: boolean\n\n render() {\n const { title, url, image, timestamp, body, ex } = this.notification\n const target = this.target\n const technical = typeof ex === 'string' ? ex : ''\n\n return html`\n <div titler>\n <span></span>\n ${url\n ? target\n ? html`<a href=${url} target=${target}>${title}</a>`\n : html`<a href=${url}>${title}</a>`\n : title}\n </div>\n <md-icon close @click=${e => this.dispatchEvent(new CustomEvent('close'))}>close</md-icon>\n\n ${image\n ? url\n ? target\n ? html`<a href=${url} target=${target}><img src=${image} /></a>`\n : html`<a href=${url}><img src=${image} /></a>`\n : html`<img src=${image} />`\n : html``}\n <div message>${body}</div>\n ${technical\n ? html`<details technical>\n <summary>${i18next.t('text.technical detail', { defaultValue: 'Technical details' })}</summary>\n <pre>${technical}</pre>\n </details>`\n : html``}\n\n <div timestamp>${new Date(Number(timestamp)).toLocaleString()}</div>\n `\n }\n\n updated(changed) {\n if (!this.notification?.confirmed) {\n this.setAttribute('newbie', '')\n } else {\n this.removeAttribute('newbie')\n }\n\n const url = this.notification?.url\n this.target = url && !isOriginSameAsLocation(url) && '_blank'\n }\n\n}\n"]}
1
+ {"version":3,"file":"notification-item.js","sourceRoot":"","sources":["../../client/viewparts/notification-item.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { i18next } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nfunction isOriginSameAsLocation(url) {\n function defaultPort(protocol) {\n return { 'http:': 80, 'https:': 443 }[protocol]\n }\n\n function portOf(location) {\n return location.port || defaultPort(location.protocol || pageLocation.protocol)\n }\n\n try {\n var pageLocation = window.location\n var urlparts = new URL(url, pageLocation.href)\n\n return !!(\n urlparts.protocol &&\n urlparts.protocol == pageLocation.protocol &&\n urlparts.host &&\n urlparts.host == pageLocation.host &&\n urlparts.host &&\n portOf(urlparts) == portOf(pageLocation)\n )\n } catch (err) {\n console.warn(err, url)\n }\n}\n\n/* 이전 호출부가 message에 HTTP/GraphQL 원문을 넣은 경우에도, 이력에서는 진단 정보로 취급한다. */\nfunction isTechnicalError(type: string | undefined, value: unknown) {\n if (type !== 'ERROR' || typeof value !== 'string') return false\n\n return /^(\\[\\s*\\d{3}\\s*:|(?:Cannot query|Response not successful:)|Error:)/.test(value) ||\n /\\n\\s*at\\s+.+\\(.+\\)/.test(value)\n}\n\n@customElement('notification-item')\nexport class NotificationItem extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n position: relative;\n padding: 12px var(--spacing-medium);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n transition: background-color 120ms ease;\n color: var(--md-sys-color-on-surface);\n\n --type-dot-size: 8px;\n }\n\n :host([newbie]) {\n background-color: var(--md-sys-color-surface-container-low, var(--md-sys-color-surface-variant));\n }\n\n :host(:hover) {\n background-color: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface-variant));\n }\n\n [titler] {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n overflow: hidden;\n padding-right: 24px;\n font-family: var(--md-sys-typescale-title-small-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-title-small-size, 0.875rem);\n line-height: var(--md-sys-typescale-title-small-line-height, 1.25rem);\n font-weight: var(--md-sys-typescale-title-small-weight, 500);\n color: var(--md-sys-color-on-surface);\n }\n\n [titler] > span {\n display: inline-block;\n width: var(--type-dot-size);\n height: var(--type-dot-size);\n border-radius: 50%;\n margin-right: var(--spacing-small);\n margin-bottom: var(--spacing-tiny);\n }\n [titler] * {\n vertical-align: middle;\n }\n\n [close] {\n position: absolute;\n top: 12px;\n right: 12px;\n --md-icon-size: 18px;\n opacity: 0.5;\n cursor: pointer;\n }\n [close]:hover {\n opacity: 1;\n }\n [technical] {\n position: relative;\n margin-top: var(--spacing-small);\n padding-right: 32px;\n color: var(--md-sys-color-on-surface-variant);\n font-family: var(--md-sys-typescale-label-small-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-label-small-size, 0.75rem);\n line-height: var(--md-sys-typescale-label-small-line-height, 1rem);\n font-weight: var(--md-sys-typescale-label-small-weight, 400);\n }\n [technical] summary {\n cursor: pointer;\n }\n [technical] button {\n position: absolute;\n top: -4px;\n right: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--md-sys-color-on-surface-variant);\n cursor: pointer;\n }\n [technical] button:hover {\n background: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface-variant));\n }\n [technical] button md-icon {\n --md-icon-size: 16px;\n }\n [technical] pre {\n margin: var(--spacing-small) 0 0;\n padding: var(--spacing-small);\n max-height: 160px;\n overflow: auto;\n border-radius: var(--md-sys-shape-corner-small, 4px);\n background: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface-variant));\n font: inherit;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n }\n :host([type='ERROR']) [titler] > span {\n background-color: var(--status-danger-color);\n }\n :host([type='WARN']) [titler] > span {\n background-color: var(--status-warning-color);\n }\n :host([type='SUCCESS']) [titler] > span {\n background-color: var(--status-success-color);\n }\n :host([type='INFO']) [titler] > span,\n [titler] > span {\n background-color: var(--status-info-color);\n }\n\n img {\n display: block;\n max-width: 100%;\n margin: auto;\n }\n\n [message] {\n margin-top: var(--spacing-small);\n font-family: var(--md-sys-typescale-body-medium-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-body-medium-size, 0.875rem);\n line-height: var(--md-sys-typescale-body-medium-line-height, 1.25rem);\n font-weight: var(--md-sys-typescale-body-medium-weight, 400);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n [timestamp] {\n margin-top: var(--spacing-small);\n white-space: nowrap;\n font-family: var(--md-sys-typescale-label-small-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-label-small-size, 0.75rem);\n line-height: var(--md-sys-typescale-label-small-line-height, 1rem);\n font-weight: var(--md-sys-typescale-label-small-weight, 400);\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n ]\n\n @property({ type: String, reflect: true }) type?: string\n @property({ type: Object }) notification: any\n @property({ type: String }) target?: string\n @property({ type: Boolean }) newbie?: boolean\n @state() private copied = false\n\n render() {\n const { title, url, image, timestamp, body, ex } = this.notification\n const target = this.target\n const legacyTechnical = isTechnicalError(this.type, title)\n const displayTitle = legacyTechnical\n ? i18next.t('text.request failed', { defaultValue: 'Request failed' })\n : title\n const technical = typeof ex === 'string' ? ex : legacyTechnical ? title : ''\n\n return html`\n <div titler title=${displayTitle}>\n <span></span>\n ${url\n ? target\n ? html`<a href=${url} target=${target}>${displayTitle}</a>`\n : html`<a href=${url}>${displayTitle}</a>`\n : displayTitle}\n </div>\n <md-icon close @click=${e => this.dispatchEvent(new CustomEvent('close'))}>close</md-icon>\n\n ${image\n ? url\n ? target\n ? html`<a href=${url} target=${target}><img src=${image} /></a>`\n : html`<a href=${url}><img src=${image} /></a>`\n : html`<img src=${image} />`\n : html``}\n <div message>${body}</div>\n ${technical\n ? html`<details technical>\n <summary>${i18next.t('text.technical detail', { defaultValue: 'Technical details' })}</summary>\n <button\n title=${i18next.t('button.copy', { defaultValue: 'Copy' })}\n aria-label=${i18next.t('button.copy', { defaultValue: 'Copy' })}\n @click=${event => this.copyTechnical(event, technical)}\n >\n <md-icon>${this.copied ? 'check' : 'content_copy'}</md-icon>\n </button>\n <pre>${technical}</pre>\n </details>`\n : html``}\n\n <div timestamp>${new Date(Number(timestamp)).toLocaleString()}</div>\n `\n }\n\n private async copyTechnical(event: Event, technical: string) {\n event.preventDefault()\n event.stopPropagation()\n\n try {\n await navigator.clipboard.writeText(technical)\n } catch {\n const textarea = document.createElement('textarea')\n textarea.value = technical\n textarea.style.position = 'fixed'\n textarea.style.opacity = '0'\n document.body.append(textarea)\n textarea.select()\n document.execCommand('copy')\n textarea.remove()\n }\n\n this.copied = true\n window.setTimeout(() => (this.copied = false), 1500)\n }\n\n updated(changed) {\n if (!this.notification?.confirmed) {\n this.setAttribute('newbie', '')\n } else {\n this.removeAttribute('newbie')\n }\n\n const url = this.notification?.url\n this.target = url && !isOriginSameAsLocation(url) && '_blank'\n }\n\n}\n"]}
@@ -19,6 +19,7 @@ let NotificationList = class NotificationList extends localize(i18next)(LitEleme
19
19
  max-height: 100%;
20
20
  overflow-x: hidden;
21
21
  overflow-y: auto;
22
+ background-color: var(--md-sys-color-surface, #ffffff);
22
23
  color: var(--md-sys-color-on-surface);
23
24
  }
24
25
 
@@ -26,13 +27,18 @@ let NotificationList = class NotificationList extends localize(i18next)(LitEleme
26
27
  display: flex;
27
28
  flex-direction: column;
28
29
  justify-content: flex-start;
30
+ background-color: var(--md-sys-color-surface, #ffffff);
29
31
  }
30
32
  [header] {
33
+ position: sticky;
34
+ top: 0;
35
+ z-index: 1;
31
36
  display: flex;
32
37
  align-items: center;
33
38
  justify-content: space-between;
34
39
  min-height: 48px;
35
40
  padding: 0 var(--spacing-medium);
41
+ background-color: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface, #ffffff));
36
42
  border-bottom: 1px solid var(--md-sys-color-outline-variant);
37
43
  }
38
44
  [header] strong {
@@ -1 +1 @@
1
- {"version":3,"file":"notification-list.js","sourceRoot":"","sources":["../../client/viewparts/notification-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/button/text-button.js'\nimport './notification-item'\n\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { store, notificationStore } from '@operato/shell'\nimport { i18next, localize } from '@operato/i18n'\nimport { UPDATE_NOTIFICATION } from '../actions/notification-fcm'\n\n@customElement('notification-list')\nexport class NotificationList extends localize(i18next)(LitElement) {\n static styles = [\n css`\n :host {\n display: block;\n max-height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n color: var(--md-sys-color-on-surface);\n }\n\n [notifications-wrap] {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n }\n [header] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: 48px;\n padding: 0 var(--spacing-medium);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n [header] strong {\n font-family: var(--md-sys-typescale-title-small-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-title-small-size, 0.875rem);\n line-height: var(--md-sys-typescale-title-small-line-height, 1.25rem);\n font-weight: var(--md-sys-typescale-title-small-weight, 600);\n color: var(--md-sys-color-on-surface);\n }\n [header] md-text-button {\n --md-text-button-container-height: 32px;\n --md-text-button-label-text-size: 0.8125rem;\n }\n [no-notifications] {\n margin: 0;\n padding: var(--spacing-large);\n text-align: center;\n font-size: var(--fontsize-default);\n font-weight: bold;\n color: var(--md-sys-color-secondary);\n }\n [no-notifications] md-icon {\n display: block;\n opacity: 0.3;\n }\n @media screen and (max-width: 480px) {\n :host {\n height: 100%;\n width: 100vw;\n }\n }\n `\n ]\n\n @property({ type: Array }) history: any[] = []\n\n render() {\n /* reverse()는 store에서 받은 배열 자체를 뒤집는다. 렌더링만 최신순으로 보인다. */\n const history = [...this.history].reverse()\n\n return history.length > 0\n ? html`\n <div notifications-wrap>\n <div header>\n <strong>${i18next.t('label.notification list')}</strong>\n <md-text-button @click=${e => this.onclearall()}\n ><md-icon slot=\"icon\">delete_outline</md-icon>${String(\n i18next.t('label.clear all')\n )}</md-text-button\n >\n </div>\n ${history.map(\n notification => html`\n <notification-item\n @close=${e => {\n this.onClose(notification)\n }}\n .type=${notification.type}\n .notification=${notification}\n ></notification-item>\n `\n )}\n </div>\n `\n : html`\n <div no-notifications @click=${e => window.history.back()}>\n <md-icon>notifications_off</md-icon>${i18next.t('text.no notification available')}\n </div>\n `\n }\n\n onClose(notification) {\n const { id } = notification\n\n store.dispatch((async dispatch => {\n if (notification) {\n await notificationStore.delete(id)\n }\n\n const history = await notificationStore.getAll()\n\n dispatch({\n type: UPDATE_NOTIFICATION,\n history: [...history]\n })\n }) as any)\n }\n\n onclearall() {\n store.dispatch((async dispatch => {\n await notificationStore.clear()\n const history = await notificationStore.getAll()\n\n dispatch({\n type: UPDATE_NOTIFICATION,\n history: [...history]\n })\n }) as any)\n }\n\n private _unsubscribe?: () => void\n\n\n private _applyState() {\n\n const __state__ = store.getState() as any\n this.history = __state__.notification.history\n\n }\n\n\n connectedCallback() {\n\n super.connectedCallback()\n\n this._applyState()\n\n this._unsubscribe = store.subscribe(() => this._applyState())\n\n }\n\n\n async disconnectedCallback() {\n\n super.disconnectedCallback()\n\n this._unsubscribe?.()\n\n await Promise.all(\n this.history\n .filter(notification => !notification.confirmed)\n .map(async notification => {\n return await notificationStore.put({\n ...notification,\n confirmed: true\n })\n })\n )\n\n store.dispatch((async dispatch => {\n const history = await notificationStore.getAll()\n\n dispatch({\n type: UPDATE_NOTIFICATION,\n history: [...history]\n })\n }) as any)\n }\n}\n"]}
1
+ {"version":3,"file":"notification-list.js","sourceRoot":"","sources":["../../client/viewparts/notification-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/button/text-button.js'\nimport './notification-item'\n\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { store, notificationStore } from '@operato/shell'\nimport { i18next, localize } from '@operato/i18n'\nimport { UPDATE_NOTIFICATION } from '../actions/notification-fcm'\n\n@customElement('notification-list')\nexport class NotificationList extends localize(i18next)(LitElement) {\n static styles = [\n css`\n :host {\n display: block;\n max-height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n background-color: var(--md-sys-color-surface, #ffffff);\n color: var(--md-sys-color-on-surface);\n }\n\n [notifications-wrap] {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n background-color: var(--md-sys-color-surface, #ffffff);\n }\n [header] {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: 48px;\n padding: 0 var(--spacing-medium);\n background-color: var(--md-sys-color-surface-container-high, var(--md-sys-color-surface, #ffffff));\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n [header] strong {\n font-family: var(--md-sys-typescale-title-small-font, var(--theme-font, inherit));\n font-size: var(--md-sys-typescale-title-small-size, 0.875rem);\n line-height: var(--md-sys-typescale-title-small-line-height, 1.25rem);\n font-weight: var(--md-sys-typescale-title-small-weight, 600);\n color: var(--md-sys-color-on-surface);\n }\n [header] md-text-button {\n --md-text-button-container-height: 32px;\n --md-text-button-label-text-size: 0.8125rem;\n }\n [no-notifications] {\n margin: 0;\n padding: var(--spacing-large);\n text-align: center;\n font-size: var(--fontsize-default);\n font-weight: bold;\n color: var(--md-sys-color-secondary);\n }\n [no-notifications] md-icon {\n display: block;\n opacity: 0.3;\n }\n @media screen and (max-width: 480px) {\n :host {\n height: 100%;\n width: 100vw;\n }\n }\n `\n ]\n\n @property({ type: Array }) history: any[] = []\n\n render() {\n /* reverse()는 store에서 받은 배열 자체를 뒤집는다. 렌더링만 최신순으로 보인다. */\n const history = [...this.history].reverse()\n\n return history.length > 0\n ? html`\n <div notifications-wrap>\n <div header>\n <strong>${i18next.t('label.notification list')}</strong>\n <md-text-button @click=${e => this.onclearall()}\n ><md-icon slot=\"icon\">delete_outline</md-icon>${String(\n i18next.t('label.clear all')\n )}</md-text-button\n >\n </div>\n ${history.map(\n notification => html`\n <notification-item\n @close=${e => {\n this.onClose(notification)\n }}\n .type=${notification.type}\n .notification=${notification}\n ></notification-item>\n `\n )}\n </div>\n `\n : html`\n <div no-notifications @click=${e => window.history.back()}>\n <md-icon>notifications_off</md-icon>${i18next.t('text.no notification available')}\n </div>\n `\n }\n\n onClose(notification) {\n const { id } = notification\n\n store.dispatch((async dispatch => {\n if (notification) {\n await notificationStore.delete(id)\n }\n\n const history = await notificationStore.getAll()\n\n dispatch({\n type: UPDATE_NOTIFICATION,\n history: [...history]\n })\n }) as any)\n }\n\n onclearall() {\n store.dispatch((async dispatch => {\n await notificationStore.clear()\n const history = await notificationStore.getAll()\n\n dispatch({\n type: UPDATE_NOTIFICATION,\n history: [...history]\n })\n }) as any)\n }\n\n private _unsubscribe?: () => void\n\n\n private _applyState() {\n\n const __state__ = store.getState() as any\n this.history = __state__.notification.history\n\n }\n\n\n connectedCallback() {\n\n super.connectedCallback()\n\n this._applyState()\n\n this._unsubscribe = store.subscribe(() => this._applyState())\n\n }\n\n\n async disconnectedCallback() {\n\n super.disconnectedCallback()\n\n this._unsubscribe?.()\n\n await Promise.all(\n this.history\n .filter(notification => !notification.confirmed)\n .map(async notification => {\n return await notificationStore.put({\n ...notification,\n confirmed: true\n })\n })\n )\n\n store.dispatch((async dispatch => {\n const history = await notificationStore.getAll()\n\n dispatch({\n type: UPDATE_NOTIFICATION,\n history: [...history]\n })\n }) as any)\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/notification",
3
- "version": "10.1.8",
3
+ "version": "10.1.10",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -29,6 +29,7 @@
29
29
  "dependencies": {
30
30
  "@material/web": "^2.0.0",
31
31
  "@operato/layout": "^10.0.0",
32
+ "@operato/styles": "^10.0.0",
32
33
  "@things-factory/auth-base": "^10.1.7",
33
34
  "@things-factory/i18n-base": "^10.1.7",
34
35
  "@things-factory/organization": "^10.1.7",
@@ -39,5 +40,5 @@
39
40
  "firebase-admin": "^11.3.0",
40
41
  "google": "^2.1.0"
41
42
  },
42
- "gitHead": "c402982e29aab3b49e56bea4e41948be6a749c7f"
43
+ "gitHead": "6f3e8480be33889220db17e9f1f4857c62b261b5"
43
44
  }