@things-factory/board-ui 8.0.0-beta.8 → 8.0.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.
Files changed (55) hide show
  1. package/client/apptools/favorite-tool.ts +124 -0
  2. package/client/board-list/board-tile-list.ts +272 -0
  3. package/client/board-list/group-bar-styles.ts +63 -0
  4. package/client/board-list/group-bar.ts +99 -0
  5. package/client/board-list/play-group-bar.ts +88 -0
  6. package/client/board-provider.ts +92 -0
  7. package/client/bootstrap.ts +39 -0
  8. package/client/data-grist/board-editor.ts +113 -0
  9. package/client/data-grist/board-renderer.ts +134 -0
  10. package/client/data-grist/color-map-editor.ts +17 -0
  11. package/client/data-grist/color-ranges-editor.ts +17 -0
  12. package/client/graphql/board-template.ts +141 -0
  13. package/client/graphql/board.ts +273 -0
  14. package/client/graphql/favorite-board.ts +25 -0
  15. package/client/graphql/group.ts +138 -0
  16. package/client/graphql/index.ts +6 -0
  17. package/client/graphql/my-board.ts +25 -0
  18. package/client/graphql/play-group.ts +189 -0
  19. package/client/index.ts +10 -0
  20. package/client/pages/attachment-list-page.ts +142 -0
  21. package/client/pages/board-list-page.ts +603 -0
  22. package/client/pages/board-modeller-page.ts +288 -0
  23. package/client/pages/board-player-by-name-page.ts +29 -0
  24. package/client/pages/board-player-page.ts +241 -0
  25. package/client/pages/board-template/board-template-list-page.ts +248 -0
  26. package/client/pages/board-viewer-by-name-page.ts +24 -0
  27. package/client/pages/board-viewer-page.ts +271 -0
  28. package/client/pages/font-list-page.ts +31 -0
  29. package/client/pages/play-list-page.ts +400 -0
  30. package/client/pages/printable-board-viewer-page.ts +54 -0
  31. package/client/pages/theme/theme-editors.ts +56 -0
  32. package/client/pages/theme/theme-list-page.ts +313 -0
  33. package/client/pages/things-scene-components-with-tools.import +0 -0
  34. package/client/pages/things-scene-components.import +0 -0
  35. package/client/route.ts +51 -0
  36. package/client/setting-let/board-view-setting-let.ts +68 -0
  37. package/client/themes/board-theme.css +77 -0
  38. package/client/things-scene-import.d.ts +4 -0
  39. package/client/viewparts/board-basic-info.ts +646 -0
  40. package/client/viewparts/board-info-link.ts +56 -0
  41. package/client/viewparts/board-info.ts +85 -0
  42. package/client/viewparts/board-template-builder.ts +134 -0
  43. package/client/viewparts/board-versions.ts +172 -0
  44. package/client/viewparts/group-info-basic.ts +267 -0
  45. package/client/viewparts/group-info-import.ts +132 -0
  46. package/client/viewparts/group-info.ts +87 -0
  47. package/client/viewparts/index.ts +3 -0
  48. package/client/viewparts/link-builder.ts +210 -0
  49. package/client/viewparts/play-group-info-basic.ts +268 -0
  50. package/client/viewparts/play-group-info-link.ts +46 -0
  51. package/client/viewparts/play-group-info.ts +81 -0
  52. package/dist-client/tsconfig.tsbuildinfo +1 -1
  53. package/dist-server/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +19 -19
  55. package/server/index.ts +0 -0
@@ -0,0 +1,313 @@
1
+ import '@operato/data-grist'
2
+
3
+ import { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
4
+ import { PageView, store } from '@operato/shell'
5
+ import { css, html } from 'lit'
6
+ import { useMutation } from '@apollo/client'
7
+
8
+ import { customElement, property, query } from 'lit/decorators.js'
9
+ import { connect } from 'pwa-helpers/connect-mixin'
10
+ import gql from 'graphql-tag'
11
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements'
12
+ import { DataGrist, FetchOption, getEditor, getRenderer } from '@operato/data-grist'
13
+
14
+ import { client } from '@operato/graphql'
15
+ import { i18next, localize } from '@operato/i18n'
16
+ import { notify } from '@operato/layout'
17
+ import { isMobileDevice } from '@operato/utils'
18
+
19
+ // export interface ThemeType {
20
+ // name: string
21
+ // propType: string
22
+ // }
23
+
24
+ // var ThemeTypes: { [name: string]: ThemeType } = {
25
+ // Legend: {
26
+ // name: 'Legend',
27
+ // propType: 'legend'
28
+ // }
29
+ // }
30
+
31
+ @customElement('theme-list-page')
32
+ export class ThemeListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
33
+ static styles = [
34
+ ScrollbarStyles,
35
+ CommonGristStyles,
36
+ CommonHeaderStyles,
37
+ css`
38
+ :host {
39
+ display: flex;
40
+
41
+ width: 100%;
42
+
43
+ --grid-record-emphasized-background-color: #8b0000;
44
+ --grid-record-emphasized-color: #ff6b6b;
45
+ }
46
+
47
+ ox-grist {
48
+ overflow-y: auto;
49
+ flex: 1;
50
+ }
51
+
52
+ ox-filters-form {
53
+ flex: 1;
54
+ }
55
+ `
56
+ ]
57
+
58
+ @property({ type: Object }) gristConfig: any
59
+ @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'
60
+
61
+ @query('ox-grist') private grist!: DataGrist
62
+
63
+ get context() {
64
+ return {
65
+ title: i18next.t('title.theme list'),
66
+ search: {
67
+ handler: (search: string) => {
68
+ this.grist.searchText = search
69
+ },
70
+ value: this.grist?.searchText || ''
71
+ },
72
+ filter: {
73
+ handler: () => {
74
+ this.grist.toggleHeadroom()
75
+ }
76
+ },
77
+ help: 'board-service/theme',
78
+ actions: [
79
+ {
80
+ title: i18next.t('button.save'),
81
+ action: this._updateTheme.bind(this),
82
+ ...CommonButtonStyles.save
83
+ },
84
+ {
85
+ title: i18next.t('button.delete'),
86
+ action: this._deleteTheme.bind(this),
87
+ ...CommonButtonStyles.delete
88
+ }
89
+ ]
90
+ }
91
+ }
92
+
93
+ render() {
94
+ const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')
95
+
96
+ return html`
97
+ <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
98
+ <div slot="headroom" class="header">
99
+ <div class="filters">
100
+ <ox-filters-form autofocus without-search></ox-filters-form>
101
+
102
+ <div id="modes">
103
+ <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</md-icon>
104
+ <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</md-icon>
105
+ <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </ox-grist>
110
+ `
111
+ }
112
+
113
+ async pageInitialized(lifecycle: any) {
114
+ this.gristConfig = {
115
+ list: {
116
+ fields: ['name', 'description'],
117
+ details: ['type', 'updatedAt']
118
+ },
119
+ columns: [
120
+ { type: 'gutter', gutterName: 'sequence' },
121
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
122
+ {
123
+ type: 'string',
124
+ name: 'name',
125
+ header: i18next.t('field.name'),
126
+ record: {
127
+ editable: true
128
+ },
129
+ filter: 'search',
130
+ sortable: true,
131
+ width: 150
132
+ },
133
+ {
134
+ type: 'string',
135
+ name: 'description',
136
+ header: i18next.t('field.description'),
137
+ record: {
138
+ editable: true
139
+ },
140
+ filter: 'search',
141
+ width: 200
142
+ },
143
+ {
144
+ type: 'checkbox',
145
+ name: 'active',
146
+ header: i18next.t('field.active'),
147
+ record: {
148
+ editable: true
149
+ },
150
+ width: 60
151
+ },
152
+ {
153
+ type: 'select',
154
+ name: 'type',
155
+ header: i18next.t('field.type'),
156
+ record: {
157
+ options: ['', 'color-map', 'color-ranges', 'color', 'text'],
158
+ editable: true
159
+ },
160
+ width: 120
161
+ },
162
+ {
163
+ type: 'object',
164
+ name: 'value',
165
+ header: i18next.t('field.value'),
166
+ record: {
167
+ editor: function (value, column, record, rowIndex, field) {
168
+ return getEditor(record.type || 'text')(value, column, record, rowIndex, field)
169
+ },
170
+ renderer: function (value, column, record, rowIndex, field) {
171
+ return getRenderer(record.type || 'text')(value, column, record, rowIndex, field)
172
+ },
173
+ editable: true,
174
+ options: {
175
+ objectified: true
176
+ }
177
+ },
178
+ sortable: true,
179
+ width: 180
180
+ },
181
+ {
182
+ type: 'resource-object',
183
+ name: 'updater',
184
+ header: i18next.t('field.updater'),
185
+ record: {
186
+ editable: false
187
+ },
188
+ sortable: true,
189
+ width: 120
190
+ },
191
+ {
192
+ type: 'datetime',
193
+ name: 'updatedAt',
194
+ header: i18next.t('field.updated_at'),
195
+ record: {
196
+ editable: false
197
+ },
198
+ sortable: true,
199
+ width: 180
200
+ }
201
+ ],
202
+ rows: {
203
+ selectable: {
204
+ multiple: true
205
+ }
206
+ },
207
+ sorters: [
208
+ {
209
+ name: 'name'
210
+ }
211
+ ]
212
+ }
213
+ }
214
+
215
+ async pageUpdated(changes: any, lifecycle: any) {
216
+ if (this.active) {
217
+ // do something here when this page just became as active
218
+ }
219
+ }
220
+
221
+ async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
222
+ const response = await client.query({
223
+ query: gql`
224
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
225
+ responses: themes(filters: $filters, pagination: $pagination, sortings: $sortings) {
226
+ items {
227
+ id
228
+ name
229
+ description
230
+ active
231
+ type
232
+ value
233
+ updater {
234
+ id
235
+ name
236
+ }
237
+ updatedAt
238
+ }
239
+ total
240
+ }
241
+ }
242
+ `,
243
+ variables: {
244
+ filters,
245
+ pagination: { page, limit },
246
+ sortings
247
+ }
248
+ })
249
+
250
+ return {
251
+ total: response.data.responses.total || 0,
252
+ records: response.data.responses.items || []
253
+ }
254
+ }
255
+
256
+ async _deleteTheme() {
257
+ if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
258
+ const ids = this.grist.selected.map(record => record.id)
259
+ if (ids && ids.length > 0) {
260
+ const [mutateFunction, { error }] = useMutation(`
261
+ mutation ($ids: [String!]!) {
262
+ deleteThemes(ids: $ids)
263
+ }`)
264
+
265
+ useMutation({
266
+ variables: {
267
+ ids
268
+ }
269
+ })
270
+
271
+ if (!error) {
272
+ this.grist.fetch()
273
+ notify({
274
+ message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
275
+ })
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ async _updateTheme() {
282
+ let patches = this.grist.dirtyRecords
283
+ if (patches && patches.length) {
284
+ patches = patches.map(patch => {
285
+ let patchField: any = patch.id ? { id: patch.id } : {}
286
+ const dirtyFields = patch.__dirtyfields__
287
+ for (let key in dirtyFields) {
288
+ patchField[key] = dirtyFields[key].after
289
+ }
290
+ patchField.cuFlag = patch.__dirty__
291
+
292
+ return patchField
293
+ })
294
+
295
+ const [mutateFunction, { error }] = useMutation(`
296
+ mutation ($patches: [ThemePatch!]!) {
297
+ updateMultipleTheme(patches: $patches) {
298
+ name
299
+ }
300
+ }`)
301
+
302
+ mutateFunction({
303
+ variables: {
304
+ patches
305
+ }
306
+ })
307
+
308
+ if (!error) {
309
+ this.grist.fetch()
310
+ }
311
+ }
312
+ }
313
+ }
File without changes
@@ -0,0 +1,51 @@
1
+ export default function route(page) {
2
+ switch (page) {
3
+ case 'board-viewer':
4
+ import('./pages/board-viewer-page')
5
+ return page
6
+
7
+ case 'board-viewer-by-name':
8
+ import('./pages/board-viewer-by-name-page')
9
+ return page
10
+
11
+ case 'board-player':
12
+ import('./pages/board-player-page')
13
+ return page
14
+
15
+ case 'board-player-by-name':
16
+ import('./pages/board-player-by-name-page')
17
+ return page
18
+
19
+ case 'board-modeller':
20
+ import('./pages/board-modeller-page')
21
+ return page
22
+
23
+ case 'board-list':
24
+ import('./pages/board-list-page')
25
+ return page
26
+
27
+ case 'play-list':
28
+ import('./pages/play-list-page')
29
+ return page
30
+
31
+ case 'attachment-list':
32
+ import('./pages/attachment-list-page')
33
+ return page
34
+
35
+ case 'font-list':
36
+ import('./pages/font-list-page')
37
+ return page
38
+
39
+ case 'printable-board-viewer':
40
+ import('./pages/printable-board-viewer-page')
41
+ return page
42
+
43
+ case 'theme-list':
44
+ import('./pages/theme/theme-list-page')
45
+ return page
46
+
47
+ case 'board-template-list':
48
+ import('./pages/board-template/board-template-list-page')
49
+ return page
50
+ }
51
+ }
@@ -0,0 +1,68 @@
1
+ import '@material/web/checkbox/checkbox.js'
2
+ import '@operato/i18n/ox-i18n.js'
3
+ import '@things-factory/setting-base'
4
+
5
+ import { css, html, LitElement } from 'lit'
6
+ import { customElement, property } from 'lit/decorators.js'
7
+
8
+ import { i18next, localize } from '@operato/i18n'
9
+ import { clientSettingStore } from '@operato/shell/object-store.js'
10
+
11
+ @customElement('board-view-setting-let')
12
+ export class BoardViewSettingLet extends localize(i18next)(LitElement) {
13
+ static styles = [
14
+ css`
15
+ label {
16
+ display: flex;
17
+ gap: 10px;
18
+ align-items: center;
19
+
20
+ font: var(--label-font);
21
+ color: var(--md-sys-color-on-surface);
22
+ text-transform: var(--label-text-transform);
23
+ }
24
+ `
25
+ ]
26
+
27
+ @property({ type: Boolean }) autoRefresh?: boolean
28
+
29
+ render() {
30
+ return html`
31
+ <setting-let>
32
+ <ox-i18n slot="title" msgid="title.board view setting"></ox-i18n>
33
+
34
+ <div slot="content">
35
+ <label>
36
+ <md-checkbox id="auto-refresh" @change=${e => this.onChange(e)} ?checked=${this.autoRefresh}></md-checkbox>
37
+ ${String(i18next.t('label.auto refresh board view'))}
38
+ </label>
39
+ </div>
40
+ </setting-let>
41
+ `
42
+ }
43
+
44
+ async firstUpdated() {
45
+ const { autoRefresh = true } = (await clientSettingStore.get('board-view'))?.value || {}
46
+ this.autoRefresh = autoRefresh
47
+ }
48
+
49
+ async onChange(e) {
50
+ this.autoRefresh = e.target.checked
51
+
52
+ const { autoRefresh: valueFromStore } = (await clientSettingStore.get('board-view'))?.value || {}
53
+ if (this.autoRefresh === valueFromStore) {
54
+ return
55
+ }
56
+
57
+ try {
58
+ await clientSettingStore.put({
59
+ key: 'board-view',
60
+ value: {
61
+ autoRefresh: this.autoRefresh
62
+ }
63
+ })
64
+ } catch (e) {
65
+ console.error(e)
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,77 @@
1
+ body {
2
+ --board-renderer-border: 1px solid rgba(0, 0, 0, 0.1);
3
+ --board-renderer-max-width: 120px;
4
+ --board-renderer-name-background-color: var(--secondary-text-color);
5
+ --board-renderer-name-font: normal 13px var(--theme-font);
6
+ --board-renderer-icon-size: 24px;
7
+ --board-renderer-icon-border-radius: 10px;
8
+ --board-renderer-font: bold 16px/25px var(--md-icon-font, 'Material Symbols Outlined');
9
+ --board-renderer-icon-edit-background-color: #95d40f;
10
+ --board-renderer-icon-view-background-color: #27a1de;
11
+
12
+ /* list page style*/
13
+ --board-list-background-color: var(--md-sys-color-background);
14
+ --board-list-border-radius: var(--border-radius);
15
+ --board-list-box-border: var(--margin-default) solid #fff;
16
+ --board-list-box-shadow: var(--box-shadow);
17
+ --board-list-margin: var(--margin-default);
18
+ --board-list-tile-background-color: #fff;
19
+ --board-list-tile-name-font: bold 14px/18px var(--theme-font);
20
+ --board-list-tile-name-color: var(--md-sys-color-secondary);
21
+ --board-list-tile-description-font: 12px/14px var(--theme-font);
22
+ --board-list-tile-description-color: var(--secondary-text-color);
23
+ --board-list-tile-icon-color: rgba(0, 0, 0, 0.4);
24
+ --board-list-star-color: rgba(0, 0, 0, 0.4);
25
+ --board-list-star-active-color: var(--status-warning-color);
26
+
27
+ --card-list-rows-height: 180px;
28
+ --card-list-color: var(--md-sys-color-on-surface);
29
+ --card-list-background-color: var(--md-sys-color-surface-container-lowest);
30
+ --card-list-border-radius: var(--border-radius);
31
+ --card-list-flip-transform: rotateX(180deg);
32
+ --card-list-create-border: 1px dashed var(--md-sys-color-primary);
33
+ --card-list-create-border-radius: var(--border-radius);
34
+ --card-list-create-icon-color: var(--md-sys-color-primary);
35
+ --card-list-create-color: var(--md-sys-color-secondary);
36
+ --card-list-create-form-padding: 15px;
37
+ --card-list-create-label-font: normal 14px var(--theme-font);
38
+ --card-list-create-label-color: var(--md-sys-color-secondary);
39
+ --card-list-create-input-font: normal 14px var(--theme-font);
40
+ --card-list-create-input-color: var();
41
+ --card-list-create-input-border: 1px solid rgba(0, 0, 0, 0.2);
42
+ --card-list-create-input-border-radius: var(--border-radius);
43
+ --card-list-create-input-padding: 2px 9px;
44
+ --card-list-create-margin: 0 0 7px 0;
45
+
46
+ /* board modeler page style */
47
+ --edit-toolbar-background-color: var(--md-sys-color-secondary);
48
+ --edit-toolbar-bigger-icon-size: 45px;
49
+ --edit-toolbar-bigger-icon-line: 1px solid rgba(0, 0, 0, 0.1);
50
+ --component-toolbar-background-color: var(--md-sys-color-background);
51
+ --component-toolbar-icon-size: 45px;
52
+ --component-toolbar-border: 1px solid rgba(0, 0, 0, 0.1);
53
+ --component-menu-background-color: var(--md-sys-color-secondary-container);
54
+ --component-menu-border-color: var(--md-sys-color-secondary);
55
+ --component-menu-title: bold 11px/16px var(--theme-font);
56
+ --component-menu-item-color: var(--md-sys-color-secondary);
57
+ --component-menu-item-hover-color: var(--md-sys-color-secondary);
58
+ --component-menu-item-icon-size: 20px;
59
+ --property-sidebar-background-color: var(--md-sys-color-secondary-container);
60
+ --property-sidebar-tab-icon-color: var(--md-sys-color-secondary);
61
+ --property-sidebar-fieldset-border: 1px solid rgba(0, 0, 0, 0.2);
62
+ --property-sidebar-fieldset-label-color: var(--md-sys-color-secondary);
63
+ --property-sidebar-fieldset-label: normal 12px/16px var(--theme-font);
64
+ --property-sidebar-fieldset-legend-color: var(--md-sys-color-on-secondary-container);
65
+ --property-sidebar-fieldset-legend: bold 13px var(--theme-font);
66
+ --scene-inspector-color: var(--md-sys-color-secondary);
67
+ --scene-inspector-selected-background-color: rgba(115, 188, 28, 0.2);
68
+ --scene-inspector-selected-border: 1px solid rgba(115, 188, 28, 1);
69
+ --scene-inspector-name-background-color: var(--md-sys-color-primary);
70
+ --scene-inspector-eye-icon-color: var(--md-sys-color-on-secondary-container);
71
+ }
72
+
73
+ @media (min-width: 461px) and (max-width: 1024px) {
74
+ body {
75
+ --card-list-create-form-padding: 7px;
76
+ }
77
+ }
@@ -0,0 +1,4 @@
1
+ declare module '*.import' {
2
+ const components: any
3
+ export default components
4
+ }