@things-factory/notification 8.0.0-beta.9 → 8.0.2

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.
Files changed (56) hide show
  1. package/client/actions/notification-fcm.ts +148 -0
  2. package/client/bootstrap.ts +135 -0
  3. package/client/index.ts +6 -0
  4. package/client/pages/notification/notification-list-page.ts +258 -0
  5. package/client/pages/notification-rule/notification-rule-importer.ts +87 -0
  6. package/client/pages/notification-rule/notification-rule-list-page.ts +386 -0
  7. package/client/reducers/notification.ts +27 -0
  8. package/client/route.ts +10 -0
  9. package/client/tsconfig.json +13 -0
  10. package/client/viewparts/notification-badge.ts +54 -0
  11. package/client/viewparts/notification-item.ts +246 -0
  12. package/client/viewparts/notification-list.ts +160 -0
  13. package/client/viewparts/notification-sender.ts +142 -0
  14. package/client/viewparts/notification-setting-let.ts +222 -0
  15. package/dist-client/tsconfig.tsbuildinfo +1 -1
  16. package/dist-server/tsconfig.tsbuildinfo +1 -1
  17. package/docs/images/config-app-1.png +0 -0
  18. package/docs/images/config-app-2.png +0 -0
  19. package/docs/images/config-server-key.png +0 -0
  20. package/docs/images/config-service-account.png +0 -0
  21. package/docs/images/config-vapidkey-1.png +0 -0
  22. package/docs/images/config-vapidkey-2-get-public-key.png +0 -0
  23. package/docs/images/config-vapidkey-3-get-private-key.png +0 -0
  24. package/docs/images/element-notification-badge.png +0 -0
  25. package/docs/images/element-notification-list.png +0 -0
  26. package/docs/images/element-notification-setting-let.png +0 -0
  27. package/docs/images/push-test-on-chrome-1.png +0 -0
  28. package/docs/images/push-test-on-chrome-2.png +0 -0
  29. package/docs/images/push-test-on-firebase-1.png +0 -0
  30. package/docs/images/push-test-on-firebase-2.png +0 -0
  31. package/docs/images/push-test-on-firebase-3.png +0 -0
  32. package/docs/images/push-test-on-firebase-4.png +0 -0
  33. package/package.json +9 -9
  34. package/server/controllers/fcm.ts +214 -0
  35. package/server/controllers/index.ts +1 -0
  36. package/server/index.ts +5 -0
  37. package/server/middlewares/index.ts +5 -0
  38. package/server/middlewares/notification-middleware.ts +73 -0
  39. package/server/routers/notification-router.ts +67 -0
  40. package/server/routes.ts +11 -0
  41. package/server/service/index.ts +42 -0
  42. package/server/service/notification/directive-notification.ts +71 -0
  43. package/server/service/notification/index.ts +14 -0
  44. package/server/service/notification/notification-mutation.ts +119 -0
  45. package/server/service/notification/notification-query.ts +76 -0
  46. package/server/service/notification/notification-subscription.ts +44 -0
  47. package/server/service/notification/notification-type.ts +55 -0
  48. package/server/service/notification/notification.ts +105 -0
  49. package/server/service/notification-rule/event-subscriber.ts +20 -0
  50. package/server/service/notification-rule/index.ts +9 -0
  51. package/server/service/notification-rule/notification-rule-history.ts +136 -0
  52. package/server/service/notification-rule/notification-rule-mutation.ts +203 -0
  53. package/server/service/notification-rule/notification-rule-query.ts +65 -0
  54. package/server/service/notification-rule/notification-rule-type.ts +71 -0
  55. package/server/service/notification-rule/notification-rule.ts +125 -0
  56. package/server/tsconfig.json +9 -0
@@ -0,0 +1,222 @@
1
+ import '@material/web/icon/icon.js'
2
+ import '@material/web/switch/switch.js'
3
+ import '@operato/i18n/ox-i18n.js'
4
+ import '@things-factory/setting-base'
5
+ import './notification-sender'
6
+
7
+ import Clipboard from 'clipboard'
8
+ import { css, html, LitElement } from 'lit'
9
+ import { customElement, property } from 'lit/decorators.js'
10
+
11
+ import { notify, openPopup } from '@operato/layout'
12
+ import { i18next, localize } from '@operato/i18n'
13
+
14
+ import { getSubscriptionToken, isSupportingMessaging, subscribe, unsubscribe } from '../actions/notification-fcm'
15
+
16
+ @customElement('notification-setting-let')
17
+ export class NotificationSettingLet extends localize(i18next)(LitElement) {
18
+ static styles = [
19
+ css`
20
+ div[onoff] {
21
+ display: flex;
22
+ align-items: center;
23
+ border-bottom: var(--border-dim-color);
24
+ margin-bottom: var(--spacing-medium);
25
+ padding-bottom: var(--spacing-medium);
26
+ }
27
+
28
+ div[info] {
29
+ display: flex;
30
+ flex-direction: column;
31
+ position: relative;
32
+ }
33
+
34
+ label {
35
+ display: flex;
36
+ gap: 10px;
37
+ align-items: center;
38
+
39
+ font: var(--label-font);
40
+ color: var(--md-sys-color-on-surface);
41
+ text-transform: var(--label-text-transform);
42
+ }
43
+
44
+ [test] {
45
+ margin-left: auto;
46
+ }
47
+
48
+ input {
49
+ border: var(--border-dim-color);
50
+ border-radius: var(--border-radius);
51
+ margin: var(--input-margin);
52
+ padding: var(--input-padding);
53
+ font: var(--input-font);
54
+
55
+ flex: 1;
56
+ }
57
+
58
+ [button-in-field] {
59
+ --md-icon-size: 18px;
60
+ position: absolute;
61
+ top: 24px;
62
+ right: 4px;
63
+ width: 30px;
64
+ padding: 2px;
65
+ border-radius: var(--border-radius, 5px);
66
+ color: var(--md-sys-color-on-secondary, #fff);
67
+ background-color: var(--md-sys-color-secondary, #394e64);
68
+ }
69
+ `
70
+ ]
71
+
72
+ @property({ type: Object }) subscription?: any
73
+ @property({ type: Boolean }) supported?: boolean
74
+
75
+ clipboard: any
76
+
77
+ render() {
78
+ const supported = !!this.supported
79
+
80
+ return html`
81
+ <setting-let>
82
+ <ox-i18n slot="title" msgid="title.notification subscription"></ox-i18n>
83
+
84
+ ${supported
85
+ ? html`
86
+ <div slot="content" onoff>
87
+ <label>
88
+ <md-switch
89
+ label="allow message"
90
+ ?selected=${!!this.subscription}
91
+ @click=${e => this.onClickSwitch(e)}
92
+ ></md-switch>
93
+ ${String(i18next.t('label.allow push message'))}
94
+ </label>
95
+ <md-outlined-button test @click=${e => this.ontest()}
96
+ >${String(i18next.t('button.push message test'))}</md-outlined-button
97
+ >
98
+ </div>
99
+
100
+ <div slot="content" info>
101
+ <label for="subscription-token"><ox-i18n msgid="label.subscription token"></ox-i18n></label>
102
+ <input
103
+ id="subscription-token"
104
+ type="text"
105
+ name="subscription-token"
106
+ .value=${this.subscription || ''}
107
+ readonly
108
+ />
109
+ <md-icon button-in-field clipboard-copy @click=${e => e.preventDefault()}>content_copy</md-icon>
110
+ </div>
111
+ `
112
+ : html` <div slot="content">${i18next.t('text.push notification is not supported in your browser')}</div>`}
113
+ </setting-let>
114
+ `
115
+ }
116
+
117
+ updated(changes) {
118
+ if (changes.has('supported') && this.supported) {
119
+ const copybuttons = this.renderRoot.querySelectorAll('[clipboard-copy]')
120
+
121
+ this.clipboard = new Clipboard(copybuttons, {
122
+ target: trigger => trigger.parentElement!.querySelector('input')!
123
+ })
124
+ }
125
+ }
126
+
127
+ async connectedCallback() {
128
+ super.connectedCallback()
129
+
130
+ if (!('Notification' in window)) {
131
+ return
132
+ }
133
+
134
+ this.supported = await isSupportingMessaging()
135
+ this.subscription = await getSubscriptionToken()
136
+ }
137
+
138
+ async onClickSwitch(e) {
139
+ const target = e.target
140
+ const on = target.selected
141
+
142
+ if (!('Notification' in window)) {
143
+ notify({
144
+ level: 'error',
145
+ message: i18next.t('This browser does not support desktop notification')
146
+ })
147
+
148
+ return
149
+ }
150
+
151
+ try {
152
+ if (Notification.permission !== 'granted') {
153
+ const permission = await Notification.requestPermission()
154
+ if (permission === 'denied') {
155
+ notify({
156
+ level: 'error',
157
+ message: i18next.t('text.web push notification unblock guide')
158
+ })
159
+ }
160
+ return
161
+ }
162
+
163
+ if (Notification.permission === 'granted') {
164
+ if (on) {
165
+ const subscription = await getSubscriptionToken()
166
+
167
+ if (subscription) {
168
+ this.subscription = subscription
169
+ notify({
170
+ level: 'info',
171
+ message: i18next.t('text.notification subscribed already')
172
+ })
173
+ } else {
174
+ this.subscription = await subscribe()
175
+
176
+ this.subscription &&
177
+ notify({
178
+ level: 'info',
179
+ message: i18next.t('text.notification subscribe started')
180
+ })
181
+ }
182
+ } else {
183
+ if (this.subscription) {
184
+ await unsubscribe()
185
+
186
+ this.subscription = await getSubscriptionToken()
187
+
188
+ notify({
189
+ level: 'info',
190
+ message: i18next.t('text.notification unsubscribed')
191
+ })
192
+ } else {
193
+ notify({
194
+ level: 'info',
195
+ message: i18next.t('text.notification unsubscribed already')
196
+ })
197
+ }
198
+ }
199
+ } else {
200
+ notify({
201
+ level: 'error',
202
+ message: i18next.t('text.notification subscribing failed')
203
+ })
204
+ }
205
+ } catch (err) {
206
+ notify({
207
+ level: 'error',
208
+ message: String(err)
209
+ })
210
+ } finally {
211
+ target.checked = !!this.subscription
212
+ }
213
+ }
214
+
215
+ ontest() {
216
+ openPopup(html` <notification-sender></notification-sender> `, {
217
+ backdrop: true,
218
+ size: 'large',
219
+ title: i18next.t('title.notification-sender')
220
+ })
221
+ }
222
+ }