@things-factory/auth-ui 6.0.99 → 6.0.104

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 (42) hide show
  1. package/client/bootstrap.ts +2 -1
  2. package/client/index.ts +11 -0
  3. package/client/pages/attribute/attribute-set-item-list.ts +242 -0
  4. package/client/pages/attribute/attribute-set-management.ts +289 -0
  5. package/client/pages/domain/domain-management.ts +68 -0
  6. package/client/route.ts +4 -0
  7. package/dist-client/bootstrap.d.ts +1 -0
  8. package/dist-client/bootstrap.js +2 -1
  9. package/dist-client/bootstrap.js.map +1 -1
  10. package/dist-client/index.js +10 -0
  11. package/dist-client/index.js.map +1 -1
  12. package/dist-client/pages/attribute/attribute-item-list.d.ts +1 -0
  13. package/dist-client/pages/attribute/attribute-item-list.js +228 -0
  14. package/dist-client/pages/attribute/attribute-item-list.js.map +1 -0
  15. package/dist-client/pages/attribute/attribute-management.d.ts +49 -0
  16. package/dist-client/pages/attribute/attribute-management.js +282 -0
  17. package/dist-client/pages/attribute/attribute-management.js.map +1 -0
  18. package/dist-client/pages/attribute/attribute-set-item-list.d.ts +1 -0
  19. package/dist-client/pages/attribute/attribute-set-item-list.js +237 -0
  20. package/dist-client/pages/attribute/attribute-set-item-list.js.map +1 -0
  21. package/dist-client/pages/attribute/attribute-set-management.d.ts +49 -0
  22. package/dist-client/pages/attribute/attribute-set-management.js +283 -0
  23. package/dist-client/pages/attribute/attribute-set-management.js.map +1 -0
  24. package/dist-client/pages/attribute/attribute-view.d.ts +1 -0
  25. package/dist-client/pages/attribute/attribute-view.js +53 -0
  26. package/dist-client/pages/attribute/attribute-view.js.map +1 -0
  27. package/dist-client/pages/domain/data-sample-view.d.ts +1 -0
  28. package/dist-client/pages/domain/data-sample-view.js +111 -0
  29. package/dist-client/pages/domain/data-sample-view.js.map +1 -0
  30. package/dist-client/pages/domain/domain-management.d.ts +2 -0
  31. package/dist-client/pages/domain/domain-management.js +63 -0
  32. package/dist-client/pages/domain/domain-management.js.map +1 -1
  33. package/dist-client/route.js +3 -0
  34. package/dist-client/route.js.map +1 -1
  35. package/dist-client/tsconfig.tsbuildinfo +1 -1
  36. package/dist-server/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +7 -5
  38. package/things-factory.config.js +2 -1
  39. package/translations/en.json +7 -0
  40. package/translations/ko.json +7 -0
  41. package/translations/ms.json +7 -0
  42. package/translations/zh.json +7 -0
@@ -1,12 +1,13 @@
1
1
  import '@material/mwc-icon'
2
2
  import '@operato/i18n/ox-i18n.js'
3
+ import '@operato/attribute/grist-editor' /* for register data-grist editor type 'attributes' */
3
4
 
4
5
  import { html } from 'lit-html'
5
6
 
7
+ import { navigate, store } from '@operato/shell'
6
8
  import { TOOL_POSITION } from '@operato/layout'
7
9
  import { auth } from '@things-factory/auth-base/dist-client'
8
10
  import { ADD_MORENDA } from '@things-factory/more-base'
9
- import { navigate, store } from '@things-factory/shell/client'
10
11
 
11
12
  export default function bootstrap() {
12
13
  /* add user profile morenda */
package/client/index.ts CHANGED
@@ -68,5 +68,16 @@ export function setAuthManagementMenus(credential) {
68
68
  }
69
69
  }
70
70
  })
71
+
72
+ store.dispatch({
73
+ type: ADD_MORENDA,
74
+ morenda: {
75
+ icon: html` <mwc-icon>business</mwc-icon> `,
76
+ name: html` <ox-i18n msgid="text.attribute management"></ox-i18n> `,
77
+ action: () => {
78
+ navigate('attributes')
79
+ }
80
+ }
81
+ })
71
82
  }
72
83
  }
@@ -0,0 +1,242 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ import { css, html, LitElement } from 'lit'
4
+ import { customElement, property, query, state } from 'lit/decorators.js'
5
+
6
+ import { client } from '@operato/graphql'
7
+ import { i18next, localize } from '@operato/i18n'
8
+ import { isMobileDevice } from '@operato/utils'
9
+ import { ColumnConfig, DataGrist, FetchOption, SortersControl } from '@operato/data-grist'
10
+
11
+ @customElement('attribute-set-item-list')
12
+ class AttributeSetItemList extends localize(i18next)(LitElement) {
13
+ @property({ type: Object }) attribute: any
14
+
15
+ @state() gristConfig: any
16
+
17
+ static styles = [
18
+ css`
19
+ :host {
20
+ display: flex;
21
+ flex-direction: column;
22
+
23
+ background-color: #fff;
24
+ }
25
+
26
+ ox-grist {
27
+ flex: 1;
28
+ }
29
+
30
+ .button-container {
31
+ display: flex;
32
+ margin-left: auto;
33
+ padding: var(--padding-default);
34
+ }
35
+
36
+ [danger] {
37
+ --mdc-theme-primary: var(--mdc-danger-button-primary-color);
38
+ }
39
+ mwc-button {
40
+ margin-left: var(--margin-default);
41
+ }
42
+ `
43
+ ]
44
+
45
+ @query('ox-grist') private grist!: DataGrist
46
+
47
+ render() {
48
+ return html`
49
+ <ox-grist
50
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
51
+ .config=${this.gristConfig}
52
+ .fetchHandler=${this.fetchHandler.bind(this)}
53
+ ></ox-grist>
54
+ <div class="button-container">
55
+ <mwc-button raised danger @click=${this.deleteAttributeSetItems.bind(this)}
56
+ >${i18next.t('button.delete')}</mwc-button
57
+ >
58
+ <mwc-button raised @click=${this.updateAttributeSetItems.bind(this)}>${i18next.t('button.save')}</mwc-button>
59
+ </div>
60
+ `
61
+ }
62
+
63
+ async firstUpdated() {
64
+ this.gristConfig = {
65
+ list: { fields: ['name', 'description', 'active'] },
66
+ columns: [
67
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
68
+ {
69
+ type: 'gutter',
70
+ gutterName: 'button',
71
+ icon: 'add',
72
+ handlers: {
73
+ click: 'record-copy'
74
+ }
75
+ },
76
+ { type: 'gutter', gutterName: 'sequence' },
77
+ {
78
+ type: 'gutter',
79
+ gutterName: 'button',
80
+ icon: 'arrow_upward',
81
+ handlers: {
82
+ click: 'move-up'
83
+ }
84
+ },
85
+ {
86
+ type: 'gutter',
87
+ gutterName: 'button',
88
+ icon: 'arrow_downward',
89
+ handlers: {
90
+ click: 'move-down'
91
+ }
92
+ },
93
+ {
94
+ type: 'string',
95
+ name: 'name',
96
+ header: i18next.t('field.name'),
97
+ record: {
98
+ editable: true
99
+ },
100
+ width: 140
101
+ },
102
+ {
103
+ type: 'string',
104
+ name: 'description',
105
+ header: i18next.t('field.description'),
106
+ record: {
107
+ editable: true
108
+ },
109
+ width: 180
110
+ },
111
+ {
112
+ type: 'string',
113
+ name: 'tag',
114
+ header: i18next.t('field.tag'),
115
+ record: {
116
+ editable: true
117
+ },
118
+ width: 180
119
+ },
120
+ {
121
+ type: 'checkbox',
122
+ name: 'active',
123
+ label: true,
124
+ header: i18next.t('field.active'),
125
+ record: {
126
+ editable: true
127
+ },
128
+ sortable: true,
129
+ width: 60
130
+ },
131
+ {
132
+ type: 'checkbox',
133
+ name: 'hidden',
134
+ label: true,
135
+ header: i18next.t('field.hidden'),
136
+ record: {
137
+ editable: true
138
+ },
139
+ sortable: true,
140
+ width: 60
141
+ },
142
+ {
143
+ type: 'select',
144
+ name: 'type',
145
+ header: i18next.t('field.type'),
146
+ record: {
147
+ options: ['', 'number', 'text', 'select', 'boolean', 'date', 'datetime', 'file'],
148
+ editable: true
149
+ },
150
+ width: 120
151
+ },
152
+ {
153
+ type: 'parameters',
154
+ name: 'options',
155
+ header: i18next.t('field.options'),
156
+ record: {
157
+ editable: true,
158
+ renderer: 'json5',
159
+ options: async (value, column, record, row, field) => {
160
+ return {
161
+ name: record.type,
162
+ help: '',
163
+ spec:
164
+ record.type === 'select'
165
+ ? [
166
+ {
167
+ type: 'options' /* property-editor type */,
168
+ name: 'options',
169
+ label: 'options'
170
+ }
171
+ ]
172
+ : [],
173
+ context: this.grist,
174
+ objectified: true
175
+ }
176
+ }
177
+ },
178
+ width: 120
179
+ }
180
+ ],
181
+ rows: {
182
+ selectable: {
183
+ multiple: true
184
+ }
185
+ },
186
+ pagination: {
187
+ infinite: true
188
+ },
189
+ sorters: []
190
+ }
191
+ }
192
+
193
+ async fetchHandler({ filters, page, limit, sortings = [] }: FetchOption) {
194
+ const attributes = this.attribute.items || []
195
+
196
+ return {
197
+ total: attributes.length,
198
+ records: attributes
199
+ }
200
+ }
201
+
202
+ private async updateAttributeSetItems() {
203
+ this.grist.commit()
204
+
205
+ const response = await client.mutate({
206
+ mutation: gql`
207
+ mutation ($id: String!, $patch: AttributeSetPatch!) {
208
+ updateAttributeSet(id: $id, patch: $patch) {
209
+ entity
210
+ }
211
+ }
212
+ `,
213
+ variables: {
214
+ id: this.attribute.id,
215
+ patch: {
216
+ items: this.grist.data.records,
217
+ cuFlag: 'M'
218
+ }
219
+ }
220
+ })
221
+
222
+ if (!response.errors) {
223
+ await document.dispatchEvent(
224
+ new CustomEvent('notify', {
225
+ detail: {
226
+ message: i18next.t('text.info_x_successfully', {
227
+ x: i18next.t('button.save')
228
+ })
229
+ }
230
+ })
231
+ )
232
+ }
233
+ }
234
+
235
+ private async deleteAttributeSetItems() {
236
+ if (!confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
237
+ return
238
+ }
239
+
240
+ this.grist.deleteSelectedRecords(false)
241
+ }
242
+ }
@@ -0,0 +1,289 @@
1
+ import '@operato/data-grist'
2
+ import './attribute-set-item-list.js'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html } from 'lit'
6
+ import { customElement, property, query, state } from 'lit/decorators.js'
7
+ import { connect } from 'pwa-helpers/connect-mixin'
8
+
9
+ import { getEditor, getRenderer, ColumnConfig, DataGrist, FetchOption, SortersControl } from '@operato/data-grist'
10
+ import { client } from '@operato/graphql'
11
+ import { i18next, localize } from '@operato/i18n'
12
+ import { notify, openPopup } from '@operato/layout'
13
+ import { PageView, store } from '@operato/shell'
14
+ import { CommonButtonStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
15
+ import { isMobileDevice, sleep } from '@operato/utils'
16
+ import { OxPopup } from '@operato/popup'
17
+
18
+ @customElement('attribute-set-management')
19
+ export class AttributeSetManagementPage extends connect(store)(localize(i18next)(PageView)) {
20
+ static styles = [
21
+ ScrollbarStyles,
22
+ CommonGristStyles,
23
+ css`
24
+ :host {
25
+ display: flex;
26
+
27
+ width: 100%;
28
+
29
+ --grid-record-emphasized-background-color: red;
30
+ --grid-record-emphasized-color: yellow;
31
+ }
32
+ `
33
+ ]
34
+
35
+ @state() gristConfig: any
36
+ @state() mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'
37
+
38
+ @query('ox-grist') private grist!: DataGrist
39
+ @query('#sorter-control') private sortersControl!: OxPopup
40
+
41
+ get context() {
42
+ return {
43
+ search: {
44
+ handler: (search: string) => {
45
+ this.grist.searchText = search
46
+ },
47
+ placeholder: i18next.t('title.attributes'),
48
+ value: this.grist.searchText
49
+ },
50
+ filter: {
51
+ handler: () => {
52
+ this.grist.toggleHeadroom()
53
+ }
54
+ },
55
+ help: 'dataset/attribute',
56
+ actions: [
57
+ {
58
+ title: i18next.t('button.save'),
59
+ action: this.updateAttributeSet.bind(this),
60
+ ...CommonButtonStyles.save
61
+ },
62
+ {
63
+ title: i18next.t('button.delete'),
64
+ action: this.deleteAttributeSet.bind(this),
65
+ ...CommonButtonStyles.delete
66
+ }
67
+ ]
68
+ }
69
+ }
70
+
71
+ render() {
72
+ const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')
73
+
74
+ return html`
75
+ <ox-grist
76
+ .mode=${mode}
77
+ .config=${this.gristConfig}
78
+ .fetchHandler=${this.fetchHandler.bind(this)}
79
+ ?url-params-sensitive=${this.active}
80
+ >
81
+ <div slot="headroom">
82
+ <div id="filters">
83
+ <ox-filters-form autofocus without-search></ox-filters-form>
84
+ </div>
85
+
86
+ <div id="sorters">
87
+ Sort
88
+ <mwc-icon
89
+ @click=${e => {
90
+ const target = e.currentTarget
91
+ this.sortersControl.open({
92
+ right: 0,
93
+ top: target.offsetTop + target.offsetHeight
94
+ })
95
+ }}
96
+ >expand_more</mwc-icon
97
+ >
98
+ <ox-popup id="sorter-control">
99
+ <ox-sorters-control> </ox-sorters-control>
100
+ </ox-popup>
101
+ </div>
102
+
103
+ <div id="modes">
104
+ <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</mwc-icon>
105
+ <mwc-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</mwc-icon>
106
+ <mwc-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</mwc-icon>
107
+ </div>
108
+ </div>
109
+ </ox-grist>
110
+ `
111
+ }
112
+
113
+ async pageInitialized(lifecycle) {
114
+ this.gristConfig = {
115
+ list: {
116
+ fields: ['entity', 'description']
117
+ },
118
+ columns: [
119
+ { type: 'gutter', gutterName: 'sequence' },
120
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
121
+ {
122
+ type: 'gutter',
123
+ gutterName: 'button',
124
+ title: i18next.t('title.attribute model'),
125
+ icon: 'reorder',
126
+ handlers: {
127
+ click: (columns, data, column, record, rowIndex) => {
128
+ if (!record.id) return
129
+ const popup = openPopup(
130
+ html` <attribute-set-item-list .attribute=${record}></attribute-set-item-list> `,
131
+ {
132
+ backdrop: true,
133
+ help: 'attribute/ui/attribute-set-item-list',
134
+ size: 'large',
135
+ title: i18next.t('title.attribute-item list')
136
+ }
137
+ )
138
+ popup.onclosed = () => {
139
+ this.grist.fetch()
140
+ }
141
+ }
142
+ }
143
+ },
144
+ {
145
+ type: 'string',
146
+ name: 'entity',
147
+ header: i18next.t('field.entity'),
148
+ record: {
149
+ editable: true
150
+ },
151
+ filter: 'search',
152
+ sortable: true,
153
+ width: 150
154
+ },
155
+ {
156
+ type: 'string',
157
+ name: 'description',
158
+ header: i18next.t('field.description'),
159
+ record: {
160
+ editable: true
161
+ },
162
+ filter: 'search',
163
+ width: 200
164
+ },
165
+ {
166
+ type: 'datetime',
167
+ name: 'updatedAt',
168
+ header: i18next.t('field.updated_at'),
169
+ record: {
170
+ editable: false
171
+ },
172
+ sortable: true,
173
+ width: 180
174
+ }
175
+ ],
176
+ rows: {
177
+ selectable: {
178
+ multiple: true
179
+ }
180
+ },
181
+ sorters: [
182
+ {
183
+ name: 'name'
184
+ }
185
+ ]
186
+ }
187
+ }
188
+
189
+ async fetchHandler({ page, limit, sortings = [], filters = [] }: FetchOption) {
190
+ const response = await client.query({
191
+ query: gql`
192
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
193
+ responses: attributeSets(filters: $filters, pagination: $pagination, sortings: $sortings) {
194
+ items {
195
+ id
196
+ entity
197
+ description
198
+ updatedAt
199
+ items {
200
+ name
201
+ description
202
+ tag
203
+ active
204
+ hidden
205
+ type
206
+ options
207
+ }
208
+ }
209
+ total
210
+ }
211
+ }
212
+ `,
213
+ variables: {
214
+ filters,
215
+ pagination: { page, limit },
216
+ sortings
217
+ }
218
+ })
219
+
220
+ return {
221
+ total: response.data.responses.total || 0,
222
+ records: response.data.responses.items || []
223
+ }
224
+ }
225
+
226
+ private async deleteAttributeSet() {
227
+ if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
228
+ const ids = this.grist.selected.map(record => record.id)
229
+ if (ids && ids.length > 0) {
230
+ const response = await client.mutate({
231
+ mutation: gql`
232
+ mutation ($ids: [String!]!) {
233
+ deleteAttributeSets(ids: $ids)
234
+ }
235
+ `,
236
+ variables: {
237
+ ids
238
+ }
239
+ })
240
+
241
+ if (!response.errors) {
242
+ this.grist.fetch()
243
+ notify({
244
+ message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
245
+ })
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ private async updateAttributeSet() {
252
+ let patches = this.grist.dirtyRecords
253
+ if (patches && patches.length) {
254
+ patches = patches.map(patch => {
255
+ let patchField: any = patch.id ? { id: patch.id } : {}
256
+ const dirtyFields = patch.__dirtyfields__
257
+ for (let key in dirtyFields) {
258
+ patchField[key] = dirtyFields[key].after
259
+ }
260
+ if (patchField['reportTemplate'] instanceof FileList) {
261
+ patchField['reportTemplate'] = patchField['reportTemplate'][0]
262
+ }
263
+ patchField.cuFlag = patch.__dirty__
264
+
265
+ return patchField
266
+ })
267
+
268
+ const response = await client.mutate({
269
+ mutation: gql`
270
+ mutation ($patches: [AttributeSetPatch!]!) {
271
+ updateMultipleAttributeSet(patches: $patches) {
272
+ entity
273
+ }
274
+ }
275
+ `,
276
+ variables: {
277
+ patches
278
+ },
279
+ context: {
280
+ hasUpload: true
281
+ }
282
+ })
283
+
284
+ if (!response.errors) {
285
+ this.grist.fetch()
286
+ }
287
+ }
288
+ }
289
+ }
@@ -1,6 +1,7 @@
1
1
  import '@operato/data-grist/ox-grist.js'
2
2
  import '@operato/data-grist/ox-filters-form.js'
3
3
  import '@operato/data-grist/ox-sorters-control.js'
4
+ import '@operato/attribute/ox-attribute-view.js'
4
5
  import '../../components/create-domain-popup'
5
6
 
6
7
  import gql from 'graphql-tag'
@@ -113,10 +114,37 @@ export class DomainManagement extends connect(store)(localize(i18next)(PageView)
113
114
  },
114
115
  columns: [
115
116
  { type: 'gutter', gutterName: 'sequence' },
117
+ {
118
+ type: 'gutter',
119
+ gutterName: 'button',
120
+ icon: 'assignment',
121
+ title: i18next.t('title.open attributes view'),
122
+ handlers: {
123
+ click: async (columns, data, column, record, rowIndex) => {
124
+ const attributeSet = await this.getAttributeSetForDomain()
125
+
126
+ openPopup(
127
+ html`
128
+ <ox-attribute-view
129
+ .attributeSet=${attributeSet}
130
+ .value=${record.attributes}
131
+ style="background-color: white;"
132
+ ></ox-attribute-view>
133
+ `,
134
+ {
135
+ backdrop: true,
136
+ size: 'large',
137
+ title: record.name + ' ' + i18next.t('title.attributes')
138
+ }
139
+ )
140
+ }
141
+ }
142
+ },
116
143
  {
117
144
  type: 'gutter',
118
145
  gutterName: 'button',
119
146
  icon: 'domain',
147
+ title: i18next.t('title.move to this domain'),
120
148
  handlers: {
121
149
  click: (_columns, _data, _column, record, _rowIndex) => {
122
150
  if (record.id) {
@@ -188,6 +216,21 @@ export class DomainManagement extends connect(store)(localize(i18next)(PageView)
188
216
  },
189
217
  width: 120
190
218
  },
219
+ {
220
+ type: 'attributes',
221
+ name: 'attributes',
222
+ header: i18next.t('field.attributes'),
223
+ record: {
224
+ editable: true,
225
+ options: async () => {
226
+ return {
227
+ objectified: true,
228
+ attributeSet: await this.getAttributeSetForDomain()
229
+ }
230
+ }
231
+ },
232
+ width: 120
233
+ },
191
234
  {
192
235
  type: 'datetime',
193
236
  name: 'updatedAt',
@@ -226,6 +269,7 @@ export class DomainManagement extends connect(store)(localize(i18next)(PageView)
226
269
  }
227
270
  extType
228
271
  timezone
272
+ attributes
229
273
  updatedAt
230
274
  }
231
275
  total
@@ -293,6 +337,30 @@ export class DomainManagement extends connect(store)(localize(i18next)(PageView)
293
337
  )
294
338
  }
295
339
 
340
+ async getAttributeSetForDomain() {
341
+ const response = await client.query({
342
+ query: gql`
343
+ query {
344
+ attributeSet: attributeSetByEntity(entity: "Domain") {
345
+ entity
346
+ description
347
+ items {
348
+ name
349
+ description
350
+ tag
351
+ type
352
+ active
353
+ hidden
354
+ options
355
+ }
356
+ }
357
+ }
358
+ `
359
+ })
360
+
361
+ return response.data?.attributeSet || {}
362
+ }
363
+
296
364
  showToast(message) {
297
365
  document.dispatchEvent(new CustomEvent('notify', { detail: { message } }))
298
366
  }
package/client/route.ts CHANGED
@@ -55,5 +55,9 @@ export default function route(page) {
55
55
  case 'domains':
56
56
  import('./pages/domain/domain-management')
57
57
  return page
58
+
59
+ case 'attributes':
60
+ import('./pages/attribute/attribute-set-management.js')
61
+ return page
58
62
  }
59
63
  }
@@ -1,3 +1,4 @@
1
1
  import '@material/mwc-icon';
2
2
  import '@operato/i18n/ox-i18n.js';
3
+ import '@operato/attribute/grist-editor';
3
4
  export default function bootstrap(): void;
@@ -1,10 +1,11 @@
1
1
  import '@material/mwc-icon';
2
2
  import '@operato/i18n/ox-i18n.js';
3
+ import '@operato/attribute/grist-editor'; /* for register data-grist editor type 'attributes' */
3
4
  import { html } from 'lit-html';
5
+ import { navigate, store } from '@operato/shell';
4
6
  import { TOOL_POSITION } from '@operato/layout';
5
7
  import { auth } from '@things-factory/auth-base/dist-client';
6
8
  import { ADD_MORENDA } from '@things-factory/more-base';
7
- import { navigate, store } from '@things-factory/shell/client';
8
9
  export default function bootstrap() {
9
10
  /* add user profile morenda */
10
11
  store.dispatch({