@things-factory/setting-ui 8.0.37 → 9.0.0-9.0.0-beta.59.0

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.
@@ -1,379 +0,0 @@
1
- import '@things-factory/form-ui'
2
- import '../components/partner-selector'
3
-
4
- import gql from 'graphql-tag'
5
- import { css, html } from 'lit'
6
- import { customElement, query, state } from 'lit/decorators.js'
7
- import { connect } from 'pwa-helpers/connect-mixin'
8
-
9
- import { openPopup } from '@operato/layout'
10
- import { i18next, localize } from '@operato/i18n'
11
- import { PageView, store } from '@operato/shell'
12
- import { client, gqlContext } from '@operato/graphql'
13
- import { CommonButtonStyles, CommonHeaderStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
14
- import { OxPrompt } from '@operato/popup/ox-prompt.js'
15
- import { FetchOption, getEditor, getRenderer } from '@operato/data-grist'
16
- import { isMobileDevice } from '@operato/utils'
17
-
18
- @customElement('partner-setting-list')
19
- export class PartnerSettingList extends connect(store)(localize(i18next)(PageView)) {
20
- static styles = [
21
- CommonGristStyles,
22
- ScrollbarStyles,
23
- CommonHeaderStyles,
24
- css`
25
- :host {
26
- display: flex;
27
- flex-direction: column;
28
- overflow: hidden;
29
- }
30
-
31
- fieldset {
32
- max-width: var(--input-container-max-width);
33
- border: none;
34
- }
35
-
36
- label {
37
- font: var(--label-font);
38
- color: var(--label-color, var(--md-sys-color-on-surface));
39
- text-transform: var(--label-text-transform);
40
- }
41
-
42
- input {
43
- border: var(--border-dim-color);
44
- border-radius: var(--border-radius);
45
- margin: var(--input-margin);
46
- padding: var(--input-padding);
47
- background-color: var(--md-sys-color-surface);
48
- font: var(--input-font);
49
- }
50
-
51
- ox-grist {
52
- overflow-y: auto;
53
- flex: 1;
54
- }
55
-
56
- ox-filters-form {
57
- flex: 1;
58
- }
59
- `
60
- ]
61
-
62
- @state() private config: any
63
- @state() private partnerDomain: any
64
- @state() private mode: 'GRID' | 'LIST' | 'CARD' = isMobileDevice() ? 'LIST' : 'GRID'
65
-
66
- @query('ox-grist') private dataGrist: any
67
-
68
- render() {
69
- return html`
70
- <form class="multi-column-form">
71
- <fieldset>
72
- <label>${i18next.t('label.partner')}</label>
73
- <input
74
- readonly
75
- name="partnerDomain"
76
- value="${this.partnerDomain?.name ? this.partnerDomain.name : ''}"
77
- @click="${this.openPartnerSelector.bind(this)}"
78
- placeholder=${String(i18next.t('text.please_choose_partner') || '')}
79
- />
80
- </fieldset>
81
- </form>
82
-
83
- <ox-grist
84
- .mode=${this.mode}
85
- .config=${this.config}
86
- .fetchHandler="${this.fetchHandler.bind(this)}"
87
- @record-change="${this.onRecordChangeHandler.bind(this)}"
88
- >
89
- <div slot="headroom" class="header">
90
- <div class="filters">
91
- <ox-filters-form></ox-filters-form>
92
- </div>
93
- </div>
94
- </ox-grist>
95
- `
96
- }
97
-
98
- get context() {
99
- return {
100
- title: i18next.t('title.partner_setting'),
101
- help: 'setting/partner-setting',
102
- actions: [
103
- {
104
- title: i18next.t('button.save'),
105
- action: this.save.bind(this),
106
- ...CommonButtonStyles.save
107
- },
108
- {
109
- title: i18next.t('button.delete'),
110
- action: this.delete.bind(this),
111
- ...CommonButtonStyles.delete
112
- }
113
- ]
114
- }
115
- }
116
-
117
- pageInitialized() {
118
- this.config = {
119
- list: {
120
- fields: ['name', 'description', 'value']
121
- },
122
- rows: { selectable: { multiple: true } },
123
- columns: [
124
- { type: 'gutter', gutterName: 'dirty' },
125
- { type: 'gutter', gutterName: 'sequence' },
126
- { type: 'gutter', gutterName: 'row-selector', multiple: true },
127
- {
128
- type: 'object',
129
- name: 'setting',
130
- header: i18next.t('label.setting'),
131
- width: 280,
132
- record: {
133
- editable: true,
134
- options: {
135
- queryName: 'settings',
136
- select: [
137
- { name: 'id', hidden: true },
138
- { name: 'name', header: i18next.t('field.name') },
139
- { name: 'description', header: i18next.t('field.description') },
140
- { name: 'category', header: i18next.t('field.category') }
141
- ],
142
- list: { fields: ['name', 'description', 'category'] }
143
- }
144
- }
145
- },
146
- {
147
- type: 'string',
148
- name: 'name',
149
- header: i18next.t('field.name'),
150
- record: { editable: false, align: 'left' },
151
- sortable: true,
152
- filter: 'search',
153
- width: 200
154
- },
155
- {
156
- type: 'string',
157
- name: 'description',
158
- header: i18next.t('field.description'),
159
- record: { editable: false, align: 'left' },
160
- sortable: true,
161
- filter: 'search',
162
- width: 200
163
- },
164
- {
165
- type: 'code',
166
- name: 'category',
167
- header: i18next.t('field.category'),
168
- record: { editable: false, codeName: 'SETTING_CATEGORIES' },
169
- sortable: true,
170
- width: 150
171
- },
172
- {
173
- type: 'string',
174
- name: 'value',
175
- header: i18next.t('field.value'),
176
- record: {
177
- editor: function (value, column, record, rowIndex, field) {
178
- return getEditor(record.category)(value, column, record, rowIndex, field)
179
- },
180
- renderer: function (value, column, record, rowIndex, field) {
181
- return getRenderer(record.category)(value, column, record, rowIndex, field)
182
- },
183
- editable: true
184
- },
185
- sortable: true,
186
- width: 180
187
- },
188
- {
189
- type: 'datetime',
190
- name: 'updatedAt',
191
- header: i18next.t('field.updated_at'),
192
- record: { editable: false, align: 'left' },
193
- sortable: true,
194
- width: 150
195
- },
196
- {
197
- type: 'object',
198
- name: 'updater',
199
- header: i18next.t('field.updater'),
200
- record: { editable: false, align: 'left' },
201
- sortable: true,
202
- width: 150
203
- }
204
- ]
205
- }
206
- }
207
-
208
- pageUpdated() {
209
- if (this.active) {
210
- this.partnerDomain = null
211
- this.dataGrist.data = { records: [], total: 0 }
212
- }
213
- }
214
-
215
- async fetchHandler({ filters, page, limit, sorters = [] }: FetchOption) {
216
- if (!this.partnerDomain) return { total: 0, records: [] }
217
-
218
- const pagination = { page, limit }
219
- const sortings = sorters
220
-
221
- const response = await client.query({
222
- query: gql`
223
- query partnerSettings(
224
- $filters: [Filter!]!
225
- $pagination: Pagination!
226
- $sortings: [Sorting!]!
227
- $partnerDomain: ObjectRef!
228
- ) {
229
- partnerSettings(
230
- filters: $filters
231
- pagination: $pagination
232
- sortings: $sortings
233
- partnerDomain: $partnerDomain
234
- ) {
235
- items {
236
- id
237
- setting {
238
- id
239
- name
240
- description
241
- category
242
- }
243
- name
244
- description
245
- category
246
- value
247
- updatedAt
248
- updater {
249
- id
250
- name
251
- description
252
- }
253
- }
254
- total
255
- }
256
- }
257
- `,
258
- variables: { filters, pagination, sortings, partnerDomain: { id: this.partnerDomain.id } },
259
- context: gqlContext()
260
- })
261
-
262
- return {
263
- records:
264
- response.data.partnerSettings.items.map(item => {
265
- return { ...item, description: item.setting.description, category: item.setting.category }
266
- }) || [],
267
- total: response.data.partnerSettings.total || 0
268
- }
269
- }
270
-
271
- async save() {
272
- let patches = this.dataGrist.dirtyRecords
273
-
274
- if (!patches?.length) {
275
- return this.showToast(i18next.t('text.nothing_changed'))
276
- }
277
-
278
- patches = patches.map(partnerSetting => {
279
- let patchField: any = {
280
- cuFlag: partnerSetting.__dirty__,
281
- setting: { id: partnerSetting.setting.id },
282
- partnerDomain: { id: this.partnerDomain.id }
283
- }
284
- if (partnerSetting.id) patchField.id = partnerSetting.id
285
- if (partnerSetting.value) patchField.value = partnerSetting.value
286
-
287
- return patchField
288
- })
289
-
290
- const response = await client.mutate({
291
- mutation: gql`
292
- mutation updateMultiplePartnerSetting($patches: [PartnerSettingPatch!]!) {
293
- updateMultiplePartnerSetting(patches: $patches) {
294
- name
295
- }
296
- }
297
- `,
298
- variables: { patches },
299
- context: gqlContext()
300
- })
301
-
302
- if (!response.errors?.length) {
303
- this.showToast(i18next.t('text.data_updated_successfully'))
304
- this.dataGrist.fetch()
305
- }
306
- }
307
-
308
- async delete() {
309
- if (!this.dataGrist.selected?.length) {
310
- return this.showToast(i18next.t('text.there_is_nothing_to_delete'))
311
- }
312
-
313
- const ids = this.dataGrist.selected.map(record => record.id)
314
-
315
- if (
316
- await OxPrompt.open({
317
- type: 'warning',
318
- title: i18next.t('button.delete'),
319
- text: i18next.t('text.are_you_sure'),
320
- confirmButton: { text: i18next.t('button.delete') },
321
- cancelButton: { text: i18next.t('button.cancel') }
322
- })
323
- ) {
324
- const response = await client.mutate({
325
- mutation: gql`
326
- mutation deletePartnerSettings($ids: [String!]!) {
327
- deletePartnerSettings(ids: $ids)
328
- }
329
- `,
330
- variables: { ids },
331
- context: gqlContext()
332
- })
333
-
334
- if (!response.errors) {
335
- await OxPrompt.open({
336
- type: 'success',
337
- title: i18next.t('text.completed'),
338
- text: i18next.t('text.data_deleted_successfully'),
339
- confirmButton: { text: i18next.t('button.confirm') }
340
- })
341
-
342
- this.dataGrist.fetch()
343
- }
344
- }
345
- }
346
-
347
- openPartnerSelector() {
348
- openPopup(
349
- html`
350
- <partner-selector
351
- @select="${e => {
352
- this.partnerDomain = e.detail
353
- this.dataGrist.fetch()
354
- }}"
355
- ></partner-selector>
356
- `,
357
- {
358
- backdrop: true,
359
- title: i18next.t('label.partner')
360
- }
361
- )
362
- }
363
-
364
- onRecordChangeHandler({ detail: { after, column } }) {
365
- if (column.name === 'setting') {
366
- this.fillUpFields(after)
367
- }
368
- }
369
-
370
- fillUpFields(record) {
371
- record.name = record.setting.name
372
- record.description = record.setting.description
373
- record.category = record.setting.category
374
- }
375
-
376
- showToast(message) {
377
- document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))
378
- }
379
- }
@@ -1,299 +0,0 @@
1
- import '@operato/data-grist/ox-grist.js'
2
- import '@operato/data-grist/ox-filters-form.js'
3
- import '@operato/data-grist/ox-sorters-control.js'
4
- import '@operato/data-grist/ox-record-creator.js'
5
-
6
- import { getEditor, getRenderer } from '@operato/data-grist'
7
- import { i18next, localize } from '@operato/i18n'
8
- import { PageView, store } from '@operato/shell'
9
- import { client, gqlContext } from '@operato/graphql'
10
- import { CommonButtonStyles, CommonHeaderStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
11
- import { OxPrompt } from '@operato/popup/ox-prompt.js'
12
- import { isMobileDevice } from '@operato/utils'
13
-
14
- import gql from 'graphql-tag'
15
- import { css, html } from 'lit'
16
- import { customElement, property, query, state } from 'lit/decorators.js'
17
- import { connect } from 'pwa-helpers/connect-mixin'
18
-
19
- @customElement('setting-list')
20
- export class SettingList extends connect(store)(localize(i18next)(PageView)) {
21
- static styles = [
22
- CommonGristStyles,
23
- ScrollbarStyles,
24
- CommonHeaderStyles,
25
- css`
26
- :host {
27
- display: flex;
28
- flex-direction: column;
29
- overflow: hidden;
30
- }
31
-
32
- ox-grist {
33
- overflow-y: auto;
34
- flex: 1;
35
- }
36
-
37
- ox-filters-form {
38
- flex: 1;
39
- }
40
- `
41
- ]
42
-
43
- @state() private config: any
44
- @state() private data: any
45
- @state() private mode: string = isMobileDevice() ? 'LIST' : 'GRID'
46
- @state() private refreshHandlers: any[] = []
47
-
48
- @query('ox-grist') private dataGrist: any
49
-
50
- render() {
51
- return html`
52
- <ox-grist .mode=${this.mode} auto-fetch .config=${this.config} .fetchHandler=${this.fetchHandler.bind(this)}>
53
- <div slot="headroom" class="header">
54
- <div class="filters">
55
- <ox-filters-form></ox-filters-form>
56
- </div>
57
- </div>
58
- </ox-grist>
59
- `
60
- }
61
-
62
- get context() {
63
- return {
64
- title: i18next.t('title.setting'),
65
- help: 'setting/settings',
66
- actions: [
67
- {
68
- title: i18next.t('button.save'),
69
- action: this._saveSettings.bind(this),
70
- ...CommonButtonStyles.save
71
- },
72
- {
73
- title: i18next.t('button.delete'),
74
- action: this._deleteSettings.bind(this),
75
- ...CommonButtonStyles.delete
76
- }
77
- ],
78
- exportable: {
79
- name: i18next.t('title.setting'),
80
- data: this._exportableData.bind(this)
81
- },
82
- importable: {
83
- handler: () => {}
84
- }
85
- }
86
- }
87
-
88
- pageUpdated(changes, lifecycle) {
89
- if (this.active) {
90
- this.dataGrist.fetch()
91
-
92
- this.config = {
93
- list: {
94
- fields: ['name', 'description', 'value']
95
- },
96
- rows: { selectable: { multiple: true } },
97
- columns: [
98
- { type: 'gutter', gutterName: 'dirty' },
99
- { type: 'gutter', gutterName: 'sequence' },
100
- { type: 'gutter', gutterName: 'row-selector', multiple: true },
101
- {
102
- type: 'string',
103
- name: 'name',
104
- header: i18next.t('field.name'),
105
- record: { editable: true, align: 'left' },
106
- sortable: true,
107
- filter: 'search',
108
- width: 235
109
- },
110
- {
111
- type: 'string',
112
- name: 'description',
113
- header: i18next.t('field.description'),
114
- record: { editable: true, align: 'left' },
115
- sortable: true,
116
- filter: 'search',
117
- width: 275
118
- },
119
- {
120
- type: 'code',
121
- name: 'category',
122
- header: i18next.t('field.category'),
123
- record: { editable: true, codeName: 'SETTING_CATEGORIES' },
124
- sortable: true,
125
- filter: 'search',
126
- width: 100
127
- },
128
- {
129
- type: 'string',
130
- name: 'value',
131
- header: i18next.t('field.value'),
132
- record: {
133
- editor: function (value, column, record, rowIndex, field) {
134
- return getEditor(record.category)(value, column, record, rowIndex, field)
135
- },
136
- renderer: function (value, column, record, rowIndex, field) {
137
- return getRenderer(record.category)(value, column, record, rowIndex, field)
138
- },
139
- editable: true
140
- },
141
- sortable: true,
142
- width: 180
143
- },
144
- {
145
- type: 'object',
146
- name: 'updater',
147
- header: i18next.t('field.updater'),
148
- record: { editable: false, align: 'left' },
149
- sortable: true,
150
- width: 90
151
- },
152
- {
153
- type: 'datetime',
154
- name: 'updatedAt',
155
- header: i18next.t('field.updated_at'),
156
- record: { editable: false, align: 'left' },
157
- sortable: true,
158
- width: 180
159
- }
160
- ]
161
- }
162
- }
163
- }
164
-
165
- async fetchHandler({ filters, page, limit, sorters = [] }) {
166
- const pagination = { page, limit }
167
- const sortings = sorters
168
-
169
- const response = await client.query({
170
- query: gql`
171
- query settings($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
172
- settings(filters: $filters, pagination: $pagination, sortings: $sortings) {
173
- items {
174
- id
175
- name
176
- description
177
- category
178
- value
179
- updatedAt
180
- updater {
181
- id
182
- name
183
- description
184
- }
185
- }
186
- total
187
- }
188
- }
189
- `,
190
- variables: { filters, pagination, sortings },
191
- context: gqlContext()
192
- })
193
-
194
- return {
195
- total: response.data.settings.total || 0,
196
- records: response.data.settings.items || []
197
- }
198
- }
199
-
200
- async _saveSettings() {
201
- let patches = this.dataGrist.dirtyRecords
202
-
203
- if (!patches?.length) {
204
- return this.showToast(i18next.t('text.nothing_changed'))
205
- }
206
-
207
- patches = patches.map(setting => {
208
- let patchField: any = setting.id ? { id: setting.id } : {}
209
- const dirtyFields = setting.__dirtyfields__
210
- for (let key in dirtyFields) {
211
- patchField[key] = dirtyFields[key].after
212
- }
213
- patchField.cuFlag = setting.__dirty__
214
-
215
- return patchField
216
- })
217
-
218
- let checkValidation = true
219
- patches.forEach(patch => {
220
- if (patch.cuFlag === '+' && (!patch.name || !patch.category)) return (checkValidation = false)
221
- })
222
-
223
- if (!checkValidation) return this.showToast(i18next.t('error.value is empty', { value: 'name or category' }))
224
-
225
- const response = await client.mutate({
226
- mutation: gql`
227
- mutation updateMultipleSetting($patches: [SettingPatch!]!) {
228
- updateMultipleSetting(patches: $patches) {
229
- name
230
- }
231
- }
232
- `,
233
- variables: { patches },
234
- context: gqlContext()
235
- })
236
-
237
- if (!response.errors) {
238
- this.showToast(i18next.t('text.data_updated_successfully'))
239
- this.dataGrist.fetch()
240
- this.applyRefreshHandlers()
241
- }
242
- }
243
-
244
- async _deleteSettings() {
245
- if (!this.dataGrist.selected?.length) {
246
- return this.showToast(i18next.t('text.there_is_nothing_to_delete'))
247
- }
248
-
249
- const names = this.dataGrist.selected.map(record => record.name)
250
-
251
- if (
252
- await OxPrompt.open({
253
- type: 'warning',
254
- title: i18next.t('button.delete'),
255
- text: i18next.t('text.are_you_sure'),
256
- confirmButton: { text: i18next.t('button.delete') },
257
- cancelButton: { text: i18next.t('button.cancel') }
258
- })
259
- ) {
260
- const response = await client.mutate({
261
- mutation: gql`
262
- mutation deleteSettings($names: [String!]!) {
263
- deleteSettings(names: $names)
264
- }
265
- `,
266
- variables: { names },
267
- context: gqlContext()
268
- })
269
-
270
- if (!response.errors) {
271
- await OxPrompt.open({
272
- type: 'success',
273
- title: i18next.t('text.completed'),
274
- text: i18next.t('text.data_deleted_successfully'),
275
- confirmButton: { text: i18next.t('button.confirm') }
276
- })
277
-
278
- this.dataGrist.fetch()
279
- this.applyRefreshHandlers()
280
- }
281
- }
282
- }
283
-
284
- applyRefreshHandlers() {
285
- this.refreshHandlers.forEach(refreshHandler => refreshHandler())
286
- }
287
-
288
- _exportableData() {
289
- return this.dataGrist.exportRecords()
290
- }
291
-
292
- stateChanged(state) {
293
- this.refreshHandlers = state.setting?.refreshHandlers || []
294
- }
295
-
296
- showToast(message) {
297
- document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))
298
- }
299
- }