@things-factory/notification 8.0.0 → 9.0.0-beta.3

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/dist-client/tsconfig.tsbuildinfo +1 -1
  2. package/dist-server/tsconfig.tsbuildinfo +1 -1
  3. package/package.json +9 -9
  4. package/client/actions/notification-fcm.ts +0 -148
  5. package/client/bootstrap.ts +0 -135
  6. package/client/index.ts +0 -6
  7. package/client/pages/notification/notification-list-page.ts +0 -258
  8. package/client/pages/notification-rule/notification-rule-importer.ts +0 -87
  9. package/client/pages/notification-rule/notification-rule-list-page.ts +0 -386
  10. package/client/reducers/notification.ts +0 -27
  11. package/client/route.ts +0 -10
  12. package/client/tsconfig.json +0 -13
  13. package/client/viewparts/notification-badge.ts +0 -54
  14. package/client/viewparts/notification-item.ts +0 -246
  15. package/client/viewparts/notification-list.ts +0 -160
  16. package/client/viewparts/notification-sender.ts +0 -142
  17. package/client/viewparts/notification-setting-let.ts +0 -222
  18. package/docs/images/config-app-1.png +0 -0
  19. package/docs/images/config-app-2.png +0 -0
  20. package/docs/images/config-server-key.png +0 -0
  21. package/docs/images/config-service-account.png +0 -0
  22. package/docs/images/config-vapidkey-1.png +0 -0
  23. package/docs/images/config-vapidkey-2-get-public-key.png +0 -0
  24. package/docs/images/config-vapidkey-3-get-private-key.png +0 -0
  25. package/docs/images/element-notification-badge.png +0 -0
  26. package/docs/images/element-notification-list.png +0 -0
  27. package/docs/images/element-notification-setting-let.png +0 -0
  28. package/docs/images/push-test-on-chrome-1.png +0 -0
  29. package/docs/images/push-test-on-chrome-2.png +0 -0
  30. package/docs/images/push-test-on-firebase-1.png +0 -0
  31. package/docs/images/push-test-on-firebase-2.png +0 -0
  32. package/docs/images/push-test-on-firebase-3.png +0 -0
  33. package/docs/images/push-test-on-firebase-4.png +0 -0
  34. package/server/controllers/fcm.ts +0 -214
  35. package/server/controllers/index.ts +0 -1
  36. package/server/index.ts +0 -5
  37. package/server/middlewares/index.ts +0 -5
  38. package/server/middlewares/notification-middleware.ts +0 -73
  39. package/server/routers/notification-router.ts +0 -67
  40. package/server/routes.ts +0 -11
  41. package/server/service/index.ts +0 -42
  42. package/server/service/notification/directive-notification.ts +0 -71
  43. package/server/service/notification/index.ts +0 -14
  44. package/server/service/notification/notification-mutation.ts +0 -119
  45. package/server/service/notification/notification-query.ts +0 -76
  46. package/server/service/notification/notification-subscription.ts +0 -44
  47. package/server/service/notification/notification-type.ts +0 -55
  48. package/server/service/notification/notification.ts +0 -105
  49. package/server/service/notification-rule/event-subscriber.ts +0 -20
  50. package/server/service/notification-rule/index.ts +0 -9
  51. package/server/service/notification-rule/notification-rule-history.ts +0 -136
  52. package/server/service/notification-rule/notification-rule-mutation.ts +0 -203
  53. package/server/service/notification-rule/notification-rule-query.ts +0 -65
  54. package/server/service/notification-rule/notification-rule-type.ts +0 -71
  55. package/server/service/notification-rule/notification-rule.ts +0 -125
  56. package/server/tsconfig.json +0 -9
@@ -1,386 +0,0 @@
1
- import '@operato/data-grist'
2
-
3
- import { CommonButtonStyles, CommonHeaderStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
4
- import { PageView, store } from '@operato/shell'
5
- import { css, html } from 'lit'
6
- import { customElement, property, query } from 'lit/decorators.js'
7
- import { ScopedElementsMixin } from '@open-wc/scoped-elements'
8
- import { ColumnConfig, DataGrist, FetchOption } from '@operato/data-grist'
9
- import { client } from '@operato/graphql'
10
- import { i18next, localize } from '@operato/i18n'
11
- import { notify, openPopup } from '@operato/layout'
12
- import { isMobileDevice } from '@operato/utils'
13
-
14
- import { connect } from 'pwa-helpers/connect-mixin'
15
- import gql from 'graphql-tag'
16
-
17
- import { NotificationRuleImporter } from './notification-rule-importer'
18
-
19
- @customElement('notification-rule-list-page')
20
- export class NotificationRuleListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
21
- static styles = [
22
- ScrollbarStyles,
23
- CommonGristStyles,
24
- CommonHeaderStyles,
25
- css`
26
- :host {
27
- display: flex;
28
-
29
- width: 100%;
30
-
31
- --grid-record-emphasized-background-color: #8b0000;
32
- --grid-record-emphasized-color: #ff6b6b;
33
- }
34
-
35
- ox-grist {
36
- overflow-y: auto;
37
- flex: 1;
38
- }
39
-
40
- ox-filters-form {
41
- flex: 1;
42
- }
43
- `
44
- ]
45
-
46
- static get scopedElements() {
47
- return {
48
- 'notification-rule-importer': NotificationRuleImporter
49
- }
50
- }
51
-
52
- @property({ type: Object }) gristConfig: any
53
- @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'
54
-
55
- @query('ox-grist') private grist!: DataGrist
56
-
57
- get context() {
58
- return {
59
- title: i18next.t('title.notification-rule list'),
60
- search: {
61
- handler: (search: string) => {
62
- this.grist.searchText = search
63
- },
64
- value: this.grist?.searchText || ''
65
- },
66
- filter: {
67
- handler: () => {
68
- this.grist.toggleHeadroom()
69
- }
70
- },
71
- help: 'notification/notification-rule',
72
- actions: [
73
- {
74
- title: i18next.t('button.save'),
75
- action: this._updateNotificationRule.bind(this),
76
- ...CommonButtonStyles.save
77
- },
78
- {
79
- title: i18next.t('button.delete'),
80
- action: this._deleteNotificationRule.bind(this),
81
- ...CommonButtonStyles.delete
82
- }
83
- ],
84
- exportable: {
85
- name: i18next.t('title.notification-rule list'),
86
- data: this.exportHandler.bind(this)
87
- },
88
- importable: {
89
- handler: this.importHandler.bind(this)
90
- }
91
- }
92
- }
93
-
94
- render() {
95
- const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')
96
-
97
- return html`
98
- <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
99
- <div slot="headroom" class="header">
100
- <div class="filters">
101
- <ox-filters-form autofocus></ox-filters-form>
102
-
103
- <div id="modes">
104
- <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</md-icon>
105
- <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</md-icon>
106
- <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>
107
- </div>
108
- </div>
109
- </div>
110
- </ox-grist>
111
- `
112
- }
113
-
114
- async pageInitialized(lifecycle: any) {
115
- this.gristConfig = {
116
- list: {
117
- thumbnail: 'thumbnail',
118
- fields: ['name', 'description'],
119
- details: ['title', 'updatedAt']
120
- },
121
- columns: [
122
- { type: 'gutter', gutterName: 'sequence' },
123
- { type: 'gutter', gutterName: 'row-selector', multiple: true },
124
- {
125
- type: 'string',
126
- name: 'name',
127
- header: i18next.t('field.name'),
128
- record: {
129
- editable: true
130
- },
131
- filter: 'search',
132
- sortable: true,
133
- width: 150
134
- },
135
- {
136
- type: 'string',
137
- name: 'description',
138
- header: i18next.t('field.description'),
139
- record: {
140
- editable: true
141
- },
142
- filter: 'search',
143
- width: 200
144
- },
145
- {
146
- type: 'string',
147
- name: 'title',
148
- header: i18next.t('field.title'),
149
- record: {
150
- editable: true
151
- },
152
- filter: 'search',
153
- sortable: true,
154
- width: 150
155
- },
156
- {
157
- type: 'text',
158
- name: 'body',
159
- header: i18next.t('field.body'),
160
- record: {
161
- editable: true
162
- },
163
- filter: 'search',
164
- sortable: true,
165
- width: 150
166
- },
167
- {
168
- type: 'string',
169
- name: 'url',
170
- header: i18next.t('field.url'),
171
- record: {
172
- editable: true
173
- },
174
- sortable: true,
175
- width: 150
176
- },
177
- {
178
- type: 'image',
179
- name: 'thumbnail',
180
- header: i18next.t('field.thumbnail'),
181
- record: { editable: true },
182
- width: 120
183
- },
184
- {
185
- type: 'select',
186
- name: 'state',
187
- label: true,
188
- header: i18next.t('field.state'),
189
- record: {
190
- options: [
191
- {},
192
- {
193
- display: i18next.t('text.draft'),
194
- value: 'DRAFT'
195
- },
196
- {
197
- display: i18next.t('text.released'),
198
- value: 'RELEASED'
199
- }
200
- ]
201
- },
202
- sortable: true,
203
- filter: true,
204
- width: 60
205
- },
206
- {
207
- type: 'recipients',
208
- name: 'recipients',
209
- header: i18next.t('field.recipients'),
210
- record: {
211
- editable: true
212
- },
213
- width: 50
214
- },
215
- {
216
- type: 'resource-object',
217
- name: 'updater',
218
- header: i18next.t('field.updater'),
219
- record: {
220
- editable: false
221
- },
222
- sortable: true,
223
- width: 120
224
- },
225
- {
226
- type: 'datetime',
227
- name: 'updatedAt',
228
- header: i18next.t('field.updated_at'),
229
- record: {
230
- editable: false
231
- },
232
- sortable: true,
233
- width: 180
234
- }
235
- ],
236
- rows: {
237
- selectable: {
238
- multiple: true
239
- }
240
- },
241
- sorters: [
242
- {
243
- name: 'name'
244
- }
245
- ]
246
- }
247
- }
248
-
249
- async pageUpdated(changes: any, lifecycle: any) {
250
- if (this.active) {
251
- // do something here when this page just became as active
252
- }
253
- }
254
-
255
- async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
256
- const response = await client.query({
257
- query: gql`
258
- query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
259
- responses: notificationRules(filters: $filters, pagination: $pagination, sortings: $sortings) {
260
- items {
261
- id
262
- name
263
- description
264
- title
265
- body
266
- url
267
- thumbnail
268
- state
269
- updater {
270
- id
271
- name
272
- }
273
- updatedAt
274
- }
275
- total
276
- }
277
- }
278
- `,
279
- variables: {
280
- filters,
281
- pagination: { page, limit },
282
- sortings
283
- }
284
- })
285
-
286
- return {
287
- total: response.data.responses.total || 0,
288
- records: response.data.responses.items || []
289
- }
290
- }
291
-
292
- async _deleteNotificationRule() {
293
- if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
294
- const ids = this.grist.selected.map(record => record.id)
295
- if (ids && ids.length > 0) {
296
- const response = await client.mutate({
297
- mutation: gql`
298
- mutation ($ids: [String!]!) {
299
- deleteNotificationRules(ids: $ids)
300
- }
301
- `,
302
- variables: {
303
- ids
304
- }
305
- })
306
-
307
- if (!response.errors) {
308
- this.grist.fetch()
309
- notify({
310
- message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
311
- })
312
- }
313
- }
314
- }
315
- }
316
-
317
- async _updateNotificationRule() {
318
- let patches = this.grist.dirtyRecords
319
- if (patches && patches.length) {
320
- patches = patches.map(patch => {
321
- let patchField: any = patch.id ? { id: patch.id } : {}
322
- const dirtyFields = patch.__dirtyfields__
323
- for (let key in dirtyFields) {
324
- patchField[key] = dirtyFields[key].after
325
- }
326
- patchField.cuFlag = patch.__dirty__
327
-
328
- return patchField
329
- })
330
-
331
- const response = await client.mutate({
332
- mutation: gql`
333
- mutation ($patches: [NotificationRulePatch!]!) {
334
- updateMultipleNotificationRule(patches: $patches) {
335
- name
336
- }
337
- }
338
- `,
339
- variables: {
340
- patches
341
- }
342
- })
343
-
344
- if (!response.errors) {
345
- this.grist.fetch()
346
- }
347
- }
348
- }
349
-
350
- async exportHandler() {
351
- const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records
352
- const targetFieldSet = new Set(['id', 'name', 'description', 'active'])
353
-
354
- return exportTargets.map(notificationRule => {
355
- let tempObj = {}
356
- for (const field of targetFieldSet) {
357
- tempObj[field] = notificationRule[field]
358
- }
359
-
360
- return tempObj
361
- })
362
- }
363
-
364
- async importHandler(records) {
365
- const popup = openPopup(
366
- html`
367
- <notification-rule-importer
368
- .notificationRules=${records}
369
- @imported=${() => {
370
- history.back()
371
- this.grist.fetch()
372
- }}
373
- ></notification-rule-importer>
374
- `,
375
- {
376
- backdrop: true,
377
- size: 'large',
378
- title: i18next.t('title.import notification-rule')
379
- }
380
- )
381
-
382
- popup.onclosed = () => {
383
- this.grist.fetch()
384
- }
385
- }
386
- }
@@ -1,27 +0,0 @@
1
- import { UPDATE_NOTIFICATION, CONFIRM_NOTIFICATION } from '../actions/notification-fcm'
2
-
3
- const INITIAL_STATE = {
4
- badge: 0,
5
- history: []
6
- }
7
-
8
- function countBadge(history) {
9
- return history.filter(notification => !notification.confirmed).length
10
- }
11
-
12
- const notification = (state = INITIAL_STATE, action) => {
13
- switch (action.type) {
14
- case UPDATE_NOTIFICATION:
15
- var history = action.history
16
-
17
- return {
18
- badge: countBadge(history),
19
- history
20
- }
21
-
22
- default:
23
- return state
24
- }
25
- }
26
-
27
- export default notification
package/client/route.ts DELETED
@@ -1,10 +0,0 @@
1
- export default function route(page: string) {
2
- switch (page) {
3
- case 'notification-list':
4
- import('./pages/notification/notification-list-page')
5
- return page
6
- case 'notification-rule-list':
7
- import('./pages/notification-rule/notification-rule-list-page')
8
- return page
9
- }
10
- }
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "../../tsconfig-base.json",
3
- "compilerOptions": {
4
- "experimentalDecorators": true,
5
- "skipLibCheck": true,
6
- "strict": true,
7
- "declaration": true,
8
- "module": "esnext",
9
- "outDir": "../dist-client",
10
- "baseUrl": "./"
11
- },
12
- "include": ["./**/*"]
13
- }
@@ -1,54 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
-
3
- import { LitElement, html, css } from 'lit'
4
- import { customElement, property } from 'lit/decorators.js'
5
-
6
- import { connect } from 'pwa-helpers/connect-mixin.js'
7
- import { store } from '@operato/shell'
8
-
9
- @customElement('notification-badge')
10
- export class NotificationBadge extends connect(store)(LitElement) {
11
- static styles = [
12
- css`
13
- :host {
14
- font-size: 2em;
15
- position: relative;
16
- }
17
-
18
- md-icon {
19
- display: block;
20
- }
21
-
22
- :host::after {
23
- content: attr(data-badge);
24
- position: absolute;
25
- top: 0px;
26
- right: -6px;
27
- font-family: var(--theme-font);
28
- font-size: 0.3em;
29
- background: var(--md-sys-color-error, rgb(186 26 26));
30
- color: var(--md-sys-color-on-primary);
31
- width: 14px;
32
- height: 14px;
33
- text-align: center;
34
- line-height: 14px;
35
- border-radius: 50%;
36
- box-shadow: var(--box-shadow);
37
- }
38
-
39
- :host([data-badge='0'])::after {
40
- display: none;
41
- }
42
- `
43
- ]
44
-
45
- @property({ type: Number, attribute: 'data-badge', reflect: true }) badge?: number
46
-
47
- render() {
48
- return html` <md-icon>notifications_none</md-icon> `
49
- }
50
-
51
- stateChanged(state) {
52
- this.badge = state.notification.badge || 0
53
- }
54
- }