@things-factory/board-ui 10.1.41 → 10.1.44
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.
- package/dist-client/board-list/board-thumb.d.ts +33 -0
- package/dist-client/board-list/board-thumb.js +119 -0
- package/dist-client/board-list/board-thumb.js.map +1 -0
- package/dist-client/graphql/favorite-board.js +3 -0
- package/dist-client/graphql/favorite-board.js.map +1 -1
- package/dist-client/graphql/my-board.js +3 -0
- package/dist-client/graphql/my-board.js.map +1 -1
- package/dist-client/graphql/play-group.js +2 -0
- package/dist-client/graphql/play-group.js.map +1 -1
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +1 -0
- package/dist-client/index.js.map +1 -1
- package/dist-client/pages/board-list-page.d.ts +39 -42
- package/dist-client/pages/board-list-page.js +388 -284
- package/dist-client/pages/board-list-page.js.map +1 -1
- package/dist-client/pages/board-modeller-page.d.ts +2 -0
- package/dist-client/pages/board-modeller-page.js +18 -1
- package/dist-client/pages/board-modeller-page.js.map +1 -1
- package/dist-client/pages/board-template/board-template-list-page.d.ts +21 -10
- package/dist-client/pages/board-template/board-template-list-page.js +147 -136
- package/dist-client/pages/board-template/board-template-list-page.js.map +1 -1
- package/dist-client/pages/play-list-page.d.ts +22 -12
- package/dist-client/pages/play-list-page.js +264 -113
- package/dist-client/pages/play-list-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/setting-let/board-modeller-setting-let.d.ts +21 -0
- package/dist-client/setting-let/board-modeller-setting-let.js +144 -0
- package/dist-client/setting-let/board-modeller-setting-let.js.map +1 -0
- package/dist-client/styles/board-card-styles.d.ts +11 -0
- package/dist-client/styles/board-card-styles.js +90 -0
- package/dist-client/styles/board-card-styles.js.map +1 -0
- package/dist-client/themes/board-theme.css +32 -19
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/board-meta.d.ts +10 -0
- package/dist-client/utils/board-meta.js +34 -0
- package/dist-client/utils/board-meta.js.map +1 -0
- package/dist-client/viewparts/board-basic-info.d.ts +38 -7
- package/dist-client/viewparts/board-basic-info.js +378 -349
- package/dist-client/viewparts/board-basic-info.js.map +1 -1
- package/dist-client/viewparts/board-info-link.d.ts +5 -1
- package/dist-client/viewparts/board-info-link.js +79 -21
- package/dist-client/viewparts/board-info-link.js.map +1 -1
- package/dist-client/viewparts/board-info-template.d.ts +15 -0
- package/dist-client/viewparts/board-info-template.js +97 -0
- package/dist-client/viewparts/board-info-template.js.map +1 -0
- package/dist-client/viewparts/board-info.d.ts +5 -0
- package/dist-client/viewparts/board-info.js +24 -73
- package/dist-client/viewparts/board-info.js.map +1 -1
- package/dist-client/viewparts/board-template-builder.d.ts +1 -0
- package/dist-client/viewparts/board-template-builder.js +37 -65
- package/dist-client/viewparts/board-template-builder.js.map +1 -1
- package/dist-client/viewparts/board-template-info.d.ts +3 -0
- package/dist-client/viewparts/board-template-info.js +75 -134
- package/dist-client/viewparts/board-template-info.js.map +1 -1
- package/dist-client/viewparts/group-info-basic.d.ts +8 -3
- package/dist-client/viewparts/group-info-basic.js +54 -190
- package/dist-client/viewparts/group-info-basic.js.map +1 -1
- package/dist-client/viewparts/group-info-import.d.ts +3 -1
- package/dist-client/viewparts/group-info-import.js +29 -62
- package/dist-client/viewparts/group-info-import.js.map +1 -1
- package/dist-client/viewparts/group-info.d.ts +4 -0
- package/dist-client/viewparts/group-info.js +21 -55
- package/dist-client/viewparts/group-info.js.map +1 -1
- package/dist-client/viewparts/info-dialog-styles.d.ts +19 -0
- package/dist-client/viewparts/info-dialog-styles.js +194 -0
- package/dist-client/viewparts/info-dialog-styles.js.map +1 -0
- package/dist-client/viewparts/link-builder.d.ts +3 -0
- package/dist-client/viewparts/link-builder.js +87 -81
- package/dist-client/viewparts/link-builder.js.map +1 -1
- package/dist-client/viewparts/play-group-info-basic.d.ts +4 -3
- package/dist-client/viewparts/play-group-info-basic.js +49 -188
- package/dist-client/viewparts/play-group-info-basic.js.map +1 -1
- package/dist-client/viewparts/play-group-info.d.ts +4 -0
- package/dist-client/viewparts/play-group-info.js +22 -53
- package/dist-client/viewparts/play-group-info.js.map +1 -1
- package/package.json +6 -6
- package/translations/en.json +30 -0
- package/translations/ja.json +9 -0
- package/translations/ko.json +35 -5
- package/translations/ms.json +8 -1
- package/translations/zh.json +9 -0
|
@@ -1,164 +1,233 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import '@material/web/icon/icon.js';
|
|
3
|
-
import '@material/web/
|
|
4
|
-
import '@material/web/
|
|
5
|
-
import '@material/web/button/
|
|
3
|
+
import '@material/web/iconbutton/icon-button.js';
|
|
4
|
+
import '@material/web/button/filled-button.js';
|
|
5
|
+
import '@material/web/button/outlined-button.js';
|
|
6
|
+
import '@material/web/button/text-button.js';
|
|
6
7
|
import '@material/web/chips/chip-set.js';
|
|
7
|
-
import '@material/web/chips/assist-chip.js';
|
|
8
8
|
import '@material/web/chips/filter-chip.js';
|
|
9
|
-
import '@material/web/
|
|
9
|
+
import '@material/web/menu/menu.js';
|
|
10
|
+
import '@material/web/menu/menu-item.js';
|
|
11
|
+
import '@material/web/divider/divider.js';
|
|
12
|
+
import '@operato/input/ox-input-select-buttons.js';
|
|
10
13
|
import gql from 'graphql-tag';
|
|
11
14
|
import { css, html, LitElement, nothing } from 'lit';
|
|
12
|
-
import { customElement, property, state } from 'lit/decorators.js';
|
|
15
|
+
import { customElement, property, query, state } from 'lit/decorators.js';
|
|
13
16
|
import { i18next } from '@operato/i18n';
|
|
14
17
|
import { client } from '@operato/graphql';
|
|
15
18
|
import { navigate, AppController } from '@operato/shell';
|
|
16
19
|
import { OxPrompt } from '@operato/popup/ox-prompt.js';
|
|
20
|
+
import { CommonPopupStyles } from '@operato/styles';
|
|
17
21
|
import { hasPrivilege } from '@things-factory/auth-base/dist-client';
|
|
18
|
-
import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles';
|
|
19
22
|
import { notify } from '../utils/notify-helper.js';
|
|
23
|
+
import { timeAgo } from '../utils/board-meta.js';
|
|
24
|
+
import { InfoFormStyles } from './info-dialog-styles.js';
|
|
25
|
+
/**
|
|
26
|
+
* The basic tab of the board dialog.
|
|
27
|
+
*
|
|
28
|
+
* ## The shape, and why
|
|
29
|
+
*
|
|
30
|
+
* Three kinds of thing used to share one scrolling form: fields that wait for Save, actions that
|
|
31
|
+
* happen the moment you touch them (release, join a play group), and a copy-to-domain panel hidden
|
|
32
|
+
* behind a caret next to the name. The Save button sat in the middle of all that and scrolled out
|
|
33
|
+
* of view on a short screen.
|
|
34
|
+
*
|
|
35
|
+
* Now the dialog reads top to bottom as: what this is (a status band), what you can change (the
|
|
36
|
+
* form, committed by Save), where it plays (membership chips, which apply at once and say so), and
|
|
37
|
+
* a footer that never scrolls away: the primary Save, the way into the modeller, and everything
|
|
38
|
+
* else - duplicate, export, release, delete - behind one "more" menu so the footer stays two
|
|
39
|
+
* buttons wide. Duplicate opens its own small panel with its own Copy and Cancel.
|
|
40
|
+
*
|
|
41
|
+
* ## Colour
|
|
42
|
+
*
|
|
43
|
+
* The accent (board's earth brown) is spent on three things only: the filled Save, the selected
|
|
44
|
+
* segment, and the pressed play-group chip. Everything else is the neutral scale - the status band
|
|
45
|
+
* is a low surface, the draft pill a warm secondary container, released a soft tertiary green -
|
|
46
|
+
* so the one thing you are meant to press is the one thing in colour.
|
|
47
|
+
*/
|
|
20
48
|
let BoardInfo = class BoardInfo extends LitElement {
|
|
21
49
|
constructor() {
|
|
22
50
|
super(...arguments);
|
|
23
51
|
this.boardGroupList = [];
|
|
24
52
|
this.playGroupList = [];
|
|
25
|
-
this.
|
|
53
|
+
this.duplicating = false;
|
|
26
54
|
this.enableModeller = false;
|
|
27
55
|
this._appCtrl = new AppController(this);
|
|
28
56
|
this.targetDomains = [];
|
|
29
57
|
this.targetGroups = [];
|
|
30
58
|
}
|
|
31
59
|
static { this.styles = [
|
|
32
|
-
|
|
60
|
+
CommonPopupStyles,
|
|
61
|
+
InfoFormStyles,
|
|
33
62
|
css `
|
|
34
63
|
:host {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
height: 100%;
|
|
67
|
+
min-height: 0;
|
|
68
|
+
padding: 0;
|
|
69
|
+
gap: 0;
|
|
70
|
+
background: var(--info-dialog-surface, var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface)));
|
|
71
|
+
}
|
|
39
72
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
73
|
+
/* What this is: state, version, freshness, home group - one quiet line under the tabs. */
|
|
74
|
+
.what {
|
|
75
|
+
flex: none;
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-wrap: wrap;
|
|
78
|
+
align-items: center;
|
|
79
|
+
gap: 6px 10px;
|
|
80
|
+
margin: var(--spacing-medium, 8px) var(--popup-padding) 0;
|
|
81
|
+
padding: 7px 10px;
|
|
82
|
+
border-radius: var(--md-sys-shape-corner-small, 6px);
|
|
83
|
+
background: var(--md-sys-color-surface-container-low);
|
|
84
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
85
|
+
font-size: var(--popup-font-size-small);
|
|
86
|
+
}
|
|
44
87
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
88
|
+
.what [pill] {
|
|
89
|
+
padding: 1px 8px;
|
|
90
|
+
border-radius: 999px;
|
|
91
|
+
font-size: 0.66rem;
|
|
92
|
+
font-weight: 600;
|
|
93
|
+
letter-spacing: 0.06em;
|
|
94
|
+
text-transform: uppercase;
|
|
95
|
+
color: var(--md-sys-color-on-secondary-container);
|
|
96
|
+
background: var(--md-sys-color-secondary-container);
|
|
49
97
|
}
|
|
50
98
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* 이전에는 max-width: 100% 만 있어서, 원본이 패널보다 작은 보드는 원본 크기로 그려졌다.
|
|
55
|
-
* 그래서 보드마다 이미지 폭이 달라지고 오른쪽에 빈 공간이 남았다(꽉 찬 보드도 있고
|
|
56
|
-
* 절반만 차는 보드도 있었다).
|
|
57
|
-
*
|
|
58
|
-
* width: 100% + aspect-ratio 로 자리를 고정하고, 이미지는 그 안에서 **가운데** 놓는다.
|
|
59
|
-
* 남는 여백은 흰색이 아니라 표면 토큰으로 채운다.
|
|
60
|
-
*
|
|
61
|
-
* contain 이 아니라 scale-down 인 이유: contain 은 작은 이미지를 자리에 맞게 **확대**해서
|
|
62
|
-
* 흐려진다. scale-down 은 큰 이미지는 줄이고 작은 이미지는 원본 크기를 지키며, 어느 쪽이든
|
|
63
|
-
* object-position 기본값(50% 50%)으로 가운데 놓인다.
|
|
64
|
-
*/
|
|
65
|
-
img {
|
|
66
|
-
display: block;
|
|
67
|
-
width: 100%;
|
|
68
|
-
aspect-ratio: 16 / 9;
|
|
69
|
-
object-fit: scale-down;
|
|
70
|
-
object-position: center;
|
|
71
|
-
background-color: var(--md-sys-color-surface-container-low);
|
|
72
|
-
/* rgba(0,0,0,.1) 은 다크에서 보이지 않는다 */
|
|
73
|
-
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
99
|
+
.what [pill][released] {
|
|
100
|
+
color: var(--md-sys-color-on-tertiary-container);
|
|
101
|
+
background: var(--md-sys-color-tertiary-container);
|
|
74
102
|
}
|
|
75
103
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
grid-auto-rows: minmax(24px, auto);
|
|
81
|
-
padding: var(--spacing-large);
|
|
82
|
-
align-items: center;
|
|
104
|
+
.what [dot]::before {
|
|
105
|
+
content: '·';
|
|
106
|
+
margin-right: 10px;
|
|
107
|
+
color: var(--md-sys-color-outline);
|
|
83
108
|
}
|
|
84
109
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
padding: 4px 0;
|
|
89
|
-
min-width: unset;
|
|
110
|
+
.what b {
|
|
111
|
+
font-weight: 500;
|
|
112
|
+
color: var(--md-sys-color-on-surface);
|
|
90
113
|
}
|
|
91
114
|
|
|
92
|
-
|
|
115
|
+
[body] {
|
|
93
116
|
flex: 1;
|
|
117
|
+
min-height: 0;
|
|
118
|
+
overflow-y: auto;
|
|
94
119
|
display: flex;
|
|
95
|
-
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
gap: var(--spacing-medium, 8px);
|
|
122
|
+
padding: var(--spacing-medium, 8px) var(--popup-padding) var(--popup-padding);
|
|
96
123
|
}
|
|
97
124
|
|
|
98
|
-
|
|
99
|
-
display:
|
|
125
|
+
.fields .row {
|
|
126
|
+
display: flex;
|
|
127
|
+
gap: var(--spacing-medium, 8px);
|
|
100
128
|
}
|
|
101
129
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
color: var(--md-sys-color-on-surface);
|
|
106
|
-
text-transform: capitalize;
|
|
130
|
+
.fields .row > label {
|
|
131
|
+
flex: 1;
|
|
132
|
+
min-width: 0;
|
|
107
133
|
}
|
|
108
134
|
|
|
109
|
-
|
|
110
|
-
|
|
135
|
+
/* A choice of three reads faster as a segmented row than as three radios with labels. */
|
|
136
|
+
ox-input-select-buttons {
|
|
137
|
+
--md-filter-chip-container-height: 30px;
|
|
138
|
+
--md-filter-chip-label-text-size: 0.76rem;
|
|
111
139
|
}
|
|
112
140
|
|
|
113
|
-
|
|
114
|
-
|
|
141
|
+
.chips {
|
|
142
|
+
--md-filter-chip-container-height: 28px;
|
|
143
|
+
--md-filter-chip-label-text-size: 0.74rem;
|
|
144
|
+
--md-filter-chip-outline-color: var(--md-sys-color-outline-variant);
|
|
145
|
+
--md-filter-chip-label-text-color: var(--md-sys-color-on-surface-variant);
|
|
146
|
+
--md-filter-chip-selected-container-color: var(--md-sys-color-primary-container);
|
|
147
|
+
--md-filter-chip-selected-label-text-color: var(--md-sys-color-on-primary-container);
|
|
148
|
+
--md-filter-chip-selected-leading-icon-color: var(--md-sys-color-on-primary-container);
|
|
115
149
|
}
|
|
116
150
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
151
|
+
/* The duplicate panel is a small task inside the dialog: inset, with its own commit. */
|
|
152
|
+
[duplicate] {
|
|
153
|
+
display: flex;
|
|
154
|
+
flex-direction: column;
|
|
155
|
+
gap: var(--spacing-medium, 8px);
|
|
156
|
+
padding: var(--spacing-medium, 8px) var(--spacing-medium, 8px) var(--spacing-small, 4px);
|
|
157
|
+
border: 1px solid var(--md-sys-color-outline-variant);
|
|
158
|
+
border-radius: var(--md-sys-shape-corner-small, 6px);
|
|
159
|
+
background: var(--md-sys-color-surface-container-low);
|
|
121
160
|
}
|
|
122
161
|
|
|
123
|
-
[
|
|
124
|
-
|
|
125
|
-
overflow: hidden;
|
|
126
|
-
text-overflow: ellipsis;
|
|
162
|
+
[duplicate] .section {
|
|
163
|
+
margin-top: 0;
|
|
127
164
|
}
|
|
128
165
|
|
|
129
|
-
[
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
--md-assist-chip-leading-icon-color: var(--md-sys-color-on-error);
|
|
166
|
+
[duplicate] .buttons {
|
|
167
|
+
border-top: 0;
|
|
168
|
+
padding-top: 0;
|
|
133
169
|
}
|
|
134
170
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
171
|
+
/* The footer stays put while the body scrolls. */
|
|
172
|
+
[footer] {
|
|
173
|
+
flex: none;
|
|
174
|
+
padding: var(--spacing-medium, 8px) var(--popup-padding);
|
|
175
|
+
border-top: 1px solid var(--md-sys-color-outline-variant);
|
|
176
|
+
background: var(--info-dialog-surface, var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface)));
|
|
140
177
|
}
|
|
141
178
|
|
|
142
|
-
[
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
gap: 4px;
|
|
179
|
+
[footer] .buttons {
|
|
180
|
+
border-top: 0;
|
|
181
|
+
padding-top: 0;
|
|
182
|
+
margin-top: 0;
|
|
147
183
|
align-items: center;
|
|
148
184
|
}
|
|
149
185
|
|
|
150
|
-
[
|
|
151
|
-
|
|
152
|
-
flex: 1;
|
|
186
|
+
[footer] [more] {
|
|
187
|
+
position: relative;
|
|
153
188
|
}
|
|
154
189
|
|
|
155
|
-
|
|
156
|
-
|
|
190
|
+
md-menu {
|
|
191
|
+
min-width: 220px;
|
|
192
|
+
--md-menu-container-color: var(--md-sys-color-surface-container-lowest, #fff);
|
|
193
|
+
--md-menu-container-shape: 10px;
|
|
194
|
+
--md-menu-item-one-line-container-height: 40px;
|
|
195
|
+
--md-menu-item-two-line-container-height: 52px;
|
|
196
|
+
--md-menu-item-label-text-size: 0.84rem;
|
|
197
|
+
--md-menu-item-supporting-text-size: 0.72rem;
|
|
198
|
+
--md-menu-item-leading-space: 14px;
|
|
199
|
+
--md-menu-item-trailing-space: 14px;
|
|
157
200
|
}
|
|
158
201
|
|
|
159
|
-
|
|
160
|
-
:
|
|
161
|
-
|
|
202
|
+
md-menu-item[cap] [slot='headline'] {
|
|
203
|
+
text-transform: capitalize;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
md-menu-item md-icon[slot='start'] {
|
|
207
|
+
--md-icon-size: 18px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
md-menu-item[danger] {
|
|
211
|
+
--md-menu-item-label-text-color: var(--md-sys-color-error);
|
|
212
|
+
--md-menu-item-leading-icon-color: var(--md-sys-color-error);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
md-icon-button {
|
|
216
|
+
--md-icon-button-icon-color: var(--md-sys-color-on-surface-variant);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@media (pointer: coarse) {
|
|
220
|
+
[footer] {
|
|
221
|
+
padding: 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
[footer] .buttons {
|
|
225
|
+
margin: 0;
|
|
226
|
+
border-top: 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
[footer] [more] {
|
|
230
|
+
flex: 0 0 auto;
|
|
162
231
|
}
|
|
163
232
|
}
|
|
164
233
|
`
|
|
@@ -166,255 +235,200 @@ let BoardInfo = class BoardInfo extends LitElement {
|
|
|
166
235
|
render() {
|
|
167
236
|
const board = this.board || { name: '', description: '', playGroups: [] };
|
|
168
237
|
const boardGroupList = this.boardGroupList || [];
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
...group,
|
|
172
|
-
checked: false
|
|
173
|
-
};
|
|
174
|
-
});
|
|
175
|
-
(board.playGroups || []).map(group => {
|
|
176
|
-
const playGroup = playGroupList.find(g => g.id == group.id);
|
|
177
|
-
if (playGroup) {
|
|
178
|
-
playGroup.checked = true;
|
|
179
|
-
}
|
|
180
|
-
});
|
|
238
|
+
const memberOf = new Set((board.playGroups || []).map(group => group.id));
|
|
239
|
+
const editable = !!this.enableModeller;
|
|
181
240
|
return html `
|
|
182
|
-
${
|
|
183
|
-
|
|
184
|
-
<
|
|
185
|
-
<
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
<
|
|
189
|
-
label=${String(i18next.t('label.name'))}
|
|
241
|
+
${this.renderWhat(board, boardGroupList)}
|
|
242
|
+
|
|
243
|
+
<div body>
|
|
244
|
+
<div class="fields">
|
|
245
|
+
<label>
|
|
246
|
+
${i18next.t('label.name')}
|
|
247
|
+
<input
|
|
190
248
|
type="text"
|
|
191
|
-
.value=${board.name}
|
|
249
|
+
.value=${board.name || ''}
|
|
192
250
|
@change=${e => (this.board = { ...this.board, name: e.target.value })}
|
|
193
|
-
?disabled=${!
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
${this.enableModeller
|
|
197
|
-
? html `
|
|
198
|
-
<md-icon
|
|
199
|
-
@click=${() => {
|
|
200
|
-
this.showTarget = !this.showTarget;
|
|
201
|
-
}}
|
|
202
|
-
tail
|
|
203
|
-
>${this.showTarget ? 'arrow_drop_up' : 'arrow_drop_down'}</md-icon
|
|
204
|
-
>
|
|
205
|
-
`
|
|
206
|
-
: nothing}
|
|
207
|
-
</div>
|
|
208
|
-
${this.showTarget
|
|
209
|
-
? html `
|
|
210
|
-
<div fullwidth target>
|
|
211
|
-
<label class="md-typescale-label-meium-prominent">${i18next.t('label.board-copy')}</label>
|
|
212
|
-
<div oneline>
|
|
213
|
-
<md-outlined-select
|
|
214
|
-
label=${String(i18next.t('label.domain'))}
|
|
215
|
-
@change=${e => {
|
|
216
|
-
this.targetSubdomain = e.target.value;
|
|
217
|
-
this.getGroupsByDomain(this.targetSubdomain);
|
|
218
|
-
}}
|
|
219
|
-
.value=${this.targetSubdomain || ''}
|
|
220
|
-
?disabled=${!this.enableModeller}
|
|
221
|
-
>
|
|
222
|
-
<md-select-option aria-label="blank"></md-select-option>
|
|
223
|
-
${this.targetDomains.map(domain => html `
|
|
224
|
-
<md-select-option
|
|
225
|
-
value=${domain.subdomain}
|
|
226
|
-
?selected=${domain.subdomain == this.targetSubdomain}
|
|
227
|
-
>
|
|
228
|
-
<div slot="headline">${domain.name}</div>
|
|
229
|
-
</md-select-option>
|
|
230
|
-
`)}
|
|
231
|
-
</md-outlined-select>
|
|
232
|
-
|
|
233
|
-
<md-outlined-select
|
|
234
|
-
label=${String(i18next.t('label.group'))}
|
|
235
|
-
@change=${e => (this.targetGroupId = e.target.value)}
|
|
236
|
-
.value=${this.targetGroupId || ''}
|
|
237
|
-
?disabled=${!this.enableModeller}
|
|
238
|
-
>
|
|
239
|
-
<md-select-option aria-label="blank"></md-select-option>
|
|
240
|
-
${this.targetGroups.map(group => html `
|
|
241
|
-
<md-select-option value=${group.id} ?selected=${group.id == this.targetGroupId}>
|
|
242
|
-
<div slot="headline">${group.name}</div>
|
|
243
|
-
</md-select-option>
|
|
244
|
-
`)}
|
|
245
|
-
</md-outlined-select>
|
|
246
|
-
</div>
|
|
247
|
-
|
|
248
|
-
<md-chip-set oneline>
|
|
249
|
-
<md-assist-chip
|
|
250
|
-
elevated
|
|
251
|
-
label=${String(i18next.t('button.copy'))}
|
|
252
|
-
?disabled=${!this.enableModeller ||
|
|
253
|
-
!this.original?.name ||
|
|
254
|
-
!this.board.name ||
|
|
255
|
-
!this.targetSubdomain ||
|
|
256
|
-
(this.original.name == this.board.name && this._appCtrl.domain?.subdomain == this.targetSubdomain)}
|
|
257
|
-
@click=${this.cloneBoard.bind(this)}
|
|
258
|
-
right
|
|
259
|
-
>
|
|
260
|
-
<md-icon slot="icon">content_copy</md-icon>
|
|
261
|
-
</md-assist-chip>
|
|
262
|
-
|
|
263
|
-
<md-assist-chip
|
|
264
|
-
elevated
|
|
265
|
-
label=${String(i18next.t('button.export'))}
|
|
266
|
-
@click=${this.exportBoard.bind(this)}
|
|
267
|
-
>
|
|
268
|
-
<md-icon slot="icon">download</md-icon>
|
|
269
|
-
</md-assist-chip>
|
|
270
|
-
</md-chip-set>
|
|
271
|
-
</div>
|
|
272
|
-
`
|
|
273
|
-
: nothing}
|
|
274
|
-
|
|
275
|
-
<md-filled-text-field
|
|
276
|
-
oneline
|
|
277
|
-
label=${String(i18next.t('label.description'))}
|
|
278
|
-
.value=${board.description}
|
|
279
|
-
@change=${e => (this.board = { ...this.board, description: e.target.value })}
|
|
280
|
-
?disabled=${!this.enableModeller}
|
|
281
|
-
></md-filled-text-field>
|
|
282
|
-
|
|
283
|
-
<div oneline>
|
|
284
|
-
<label>${i18next.t('label.board-type')}</label>
|
|
285
|
-
<div role="radiogroup" aria-labelledby="board-type" right>
|
|
286
|
-
<md-radio
|
|
287
|
-
id="board-type-main"
|
|
288
|
-
name="board-type"
|
|
289
|
-
value="main"
|
|
290
|
-
?checked=${board.type === 'main'}
|
|
291
|
-
@change=${e => (this.board = { ...this.board, type: e.target.value })}
|
|
292
|
-
?disabled=${!this.enableModeller}
|
|
293
|
-
></md-radio>
|
|
294
|
-
<label for="board-type-main">${i18next.t('label.board-type-main')}</label>
|
|
295
|
-
|
|
296
|
-
<md-radio
|
|
297
|
-
id="board-type-sub"
|
|
298
|
-
name="board-type"
|
|
299
|
-
value="sub"
|
|
300
|
-
?checked=${board.type === 'sub'}
|
|
301
|
-
@change=${e => (this.board = { ...this.board, type: e.target.value })}
|
|
302
|
-
?disabled=${!this.enableModeller}
|
|
303
|
-
></md-radio>
|
|
304
|
-
<label for="board-type-sub">${i18next.t('label.board-type-sub')}</label>
|
|
305
|
-
|
|
306
|
-
<md-radio
|
|
307
|
-
id="board-type-popup"
|
|
308
|
-
name="board-type"
|
|
309
|
-
value="popup"
|
|
310
|
-
?checked=${board.type === 'popup'}
|
|
311
|
-
@change=${e => (this.board = { ...this.board, type: e.target.value })}
|
|
312
|
-
?disabled=${!this.enableModeller}
|
|
313
|
-
></md-radio>
|
|
314
|
-
<label for="board-type-popup">${i18next.t('label.board-type-popup')}</label>
|
|
315
|
-
</div>
|
|
316
|
-
</div>
|
|
251
|
+
?disabled=${!editable}
|
|
252
|
+
/>
|
|
253
|
+
</label>
|
|
317
254
|
|
|
318
|
-
<
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
>
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
@click=${this.updateBoard.bind(this)}
|
|
350
|
-
right
|
|
351
|
-
>
|
|
352
|
-
<md-icon slot="icon">save</md-icon>
|
|
353
|
-
</md-assist-chip>
|
|
354
|
-
<md-assist-chip
|
|
355
|
-
elevated
|
|
356
|
-
?disabled=${!this.enableModeller}
|
|
357
|
-
label=${String(i18next.t('button.edit'))}
|
|
358
|
-
@click=${() => navigate(`${'board-modeller/' + this.boardId}`)}
|
|
359
|
-
>
|
|
360
|
-
<md-icon slot="icon">drive_file_rename_outline</md-icon>
|
|
361
|
-
</md-assist-chip>
|
|
362
|
-
</md-chip-set>
|
|
363
|
-
</fieldset>
|
|
364
|
-
|
|
365
|
-
<fieldset>
|
|
366
|
-
<legend class="md-typescale-label-large-prominent">${i18next.t('label.status')}</legend>
|
|
367
|
-
<div oneline>
|
|
368
|
-
<label class="md-typescale-label-meium">${i18next.t('label.creator')}</label>
|
|
369
|
-
<md-icon dim>person</md-icon>
|
|
370
|
-
<div name title=${(board.creator && board.creator.name) || 'anonymous'}>
|
|
371
|
-
${(board.creator && board.creator.name) || 'anonymous'}
|
|
372
|
-
</div>
|
|
373
|
-
<md-icon dim right>schedule</md-icon> ${new Date(board.createdAt).toLocaleString()}
|
|
374
|
-
</div>
|
|
375
|
-
|
|
376
|
-
<div oneline>
|
|
377
|
-
<label class="md-typescale-label-meium">${i18next.t('label.updater')}</label>
|
|
378
|
-
<md-icon dim>person</md-icon>
|
|
379
|
-
<div name title=${(board.updater && board.updater.name) || 'anonymouse'}>
|
|
380
|
-
${(board.updater && board.updater.name) || 'anonymouse'}
|
|
381
|
-
</div>
|
|
382
|
-
<md-icon dim right>schedule</md-icon> ${new Date(board.updatedAt).toLocaleString()}
|
|
383
|
-
</div>
|
|
384
|
-
|
|
385
|
-
<div oneline>
|
|
386
|
-
<label class="md-typescale-label-meium">${i18next.t('label.state')}</label>
|
|
387
|
-
<md-icon dim>signpost</md-icon> ${(board.state || '').toUpperCase()}
|
|
388
|
-
<md-icon dim>pin</md-icon> ${board.version}
|
|
389
|
-
<md-chip-set>
|
|
390
|
-
<md-assist-chip
|
|
391
|
-
elevated
|
|
392
|
-
label=${String(i18next.t('button.release'))}
|
|
393
|
-
?disabled=${!this.enableModeller || !this.isReleasable}
|
|
394
|
-
@click=${this.releaseBoard.bind(this)}
|
|
395
|
-
right
|
|
255
|
+
<label>
|
|
256
|
+
${i18next.t('label.description')}
|
|
257
|
+
<input
|
|
258
|
+
type="text"
|
|
259
|
+
.value=${board.description || ''}
|
|
260
|
+
@change=${e => (this.board = { ...this.board, description: e.target.value })}
|
|
261
|
+
?disabled=${!editable}
|
|
262
|
+
/>
|
|
263
|
+
</label>
|
|
264
|
+
|
|
265
|
+
<div class="row">
|
|
266
|
+
<label>
|
|
267
|
+
${i18next.t('label.board-type')}
|
|
268
|
+
<ox-input-select-buttons
|
|
269
|
+
.value=${board.type || 'main'}
|
|
270
|
+
.options=${[
|
|
271
|
+
{ display: i18next.t('label.board-type-main'), value: 'main' },
|
|
272
|
+
{ display: i18next.t('label.board-type-sub'), value: 'sub' },
|
|
273
|
+
{ display: i18next.t('label.board-type-popup'), value: 'popup' }
|
|
274
|
+
]}
|
|
275
|
+
@change=${(e) => e.detail && (this.board = { ...this.board, type: e.detail })}
|
|
276
|
+
?disabled=${!editable}
|
|
277
|
+
></ox-input-select-buttons>
|
|
278
|
+
</label>
|
|
279
|
+
|
|
280
|
+
<label>
|
|
281
|
+
${i18next.t('label.group')}
|
|
282
|
+
<select
|
|
283
|
+
.value=${this.board?.groupId || ''}
|
|
284
|
+
@change=${e => (this.board = { ...this.board, groupId: e.target.value })}
|
|
285
|
+
?disabled=${!editable}
|
|
396
286
|
>
|
|
397
|
-
<
|
|
398
|
-
|
|
399
|
-
|
|
287
|
+
<option value=""></option>
|
|
288
|
+
${boardGroupList.map(item => html `<option value=${item.id} ?selected=${item.id == this.board?.groupId}>${item.name}</option>`)}
|
|
289
|
+
</select>
|
|
290
|
+
</label>
|
|
400
291
|
</div>
|
|
401
|
-
</
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
292
|
+
</div>
|
|
293
|
+
|
|
294
|
+
${this.duplicating ? this.renderDuplicate(board) : nothing}
|
|
295
|
+
|
|
296
|
+
<div class="section">${i18next.t('text.plays in', { defaultValue: 'Plays in' })}</div>
|
|
297
|
+
<div class="note">
|
|
298
|
+
${i18next.t('text.play-group membership applies at once', {
|
|
299
|
+
defaultValue: 'Tap a play group to add or remove this board. This applies right away.'
|
|
300
|
+
})}
|
|
301
|
+
</div>
|
|
302
|
+
<md-chip-set class="chips">
|
|
303
|
+
${(this.playGroupList || []).map(item => html `
|
|
304
|
+
<md-filter-chip
|
|
305
|
+
label=${item.name}
|
|
306
|
+
?selected=${memberOf.has(item.id)}
|
|
307
|
+
@click=${e => {
|
|
411
308
|
e.target.selected ? this.joinPlayGroup(item) : this.leavePlayGroup(item);
|
|
412
309
|
}}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
310
|
+
></md-filter-chip>
|
|
311
|
+
`)}
|
|
312
|
+
</md-chip-set>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<div footer>
|
|
316
|
+
<div class="buttons">
|
|
317
|
+
<span more>
|
|
318
|
+
<md-icon-button id="more-anchor" ?disabled=${!editable} @click=${() => (this.menu.open = !this.menu.open)}>
|
|
319
|
+
<md-icon>more_vert</md-icon>
|
|
320
|
+
</md-icon-button>
|
|
321
|
+
<md-menu anchor="more-anchor" positioning="popover" anchor-corner="start-start" menu-corner="end-start">
|
|
322
|
+
<md-menu-item @click=${() => (this.duplicating = true)}>
|
|
323
|
+
<md-icon slot="start">content_copy</md-icon>
|
|
324
|
+
<div slot="headline">${i18next.t('button.duplicate', { defaultValue: 'Duplicate…' })}</div>
|
|
325
|
+
</md-menu-item>
|
|
326
|
+
<md-menu-item @click=${this.exportBoard.bind(this)}>
|
|
327
|
+
<md-icon slot="start">download</md-icon>
|
|
328
|
+
<div slot="headline">${i18next.t('button.export-json', { defaultValue: 'Export as JSON' })}</div>
|
|
329
|
+
</md-menu-item>
|
|
330
|
+
<md-menu-item cap ?disabled=${!this.isReleasable} @click=${this.releaseBoard.bind(this)}>
|
|
331
|
+
<md-icon slot="start">new_releases</md-icon>
|
|
332
|
+
<div slot="headline">${i18next.t('button.release')}</div>
|
|
333
|
+
${this.isReleasable || board.state === 'released'
|
|
334
|
+
? nothing
|
|
335
|
+
: html `<div slot="supporting-text">
|
|
336
|
+
${i18next.t('text.save before release', { defaultValue: 'Save your changes first' })}
|
|
337
|
+
</div>`}
|
|
338
|
+
</md-menu-item>
|
|
339
|
+
<md-divider></md-divider>
|
|
340
|
+
<md-menu-item cap danger @click=${this.deleteBoard.bind(this)}>
|
|
341
|
+
<md-icon slot="start">delete_outline</md-icon>
|
|
342
|
+
<div slot="headline">${i18next.t('button.delete')}</div>
|
|
343
|
+
</md-menu-item>
|
|
344
|
+
</md-menu>
|
|
345
|
+
</span>
|
|
346
|
+
<div filler></div>
|
|
347
|
+
<md-outlined-button ?disabled=${!editable} @click=${() => navigate(`board-modeller/${this.boardId}`)}>
|
|
348
|
+
<md-icon slot="icon">design_services</md-icon>${i18next.t('button.open-modeller', {
|
|
349
|
+
defaultValue: 'Open in modeller'
|
|
350
|
+
})}
|
|
351
|
+
</md-outlined-button>
|
|
352
|
+
<md-filled-button cap ?disabled=${!editable || !this.isDirty} @click=${this.updateBoard.bind(this)}>
|
|
353
|
+
<md-icon slot="icon">save</md-icon>${i18next.t('button.save')}
|
|
354
|
+
</md-filled-button>
|
|
355
|
+
</div>
|
|
356
|
+
</div>
|
|
357
|
+
`;
|
|
358
|
+
}
|
|
359
|
+
renderWhat(board, boardGroupList) {
|
|
360
|
+
if (!this.board) {
|
|
361
|
+
return nothing;
|
|
362
|
+
}
|
|
363
|
+
const released = board.state === 'released';
|
|
364
|
+
const group = boardGroupList.find(item => item.id == this.original?.groupId);
|
|
365
|
+
const updater = board.updater?.name || board.creator?.name || '';
|
|
366
|
+
const ago = timeAgo(board.updatedAt || board.createdAt);
|
|
367
|
+
return html `
|
|
368
|
+
<div class="what">
|
|
369
|
+
<span pill ?released=${released}>
|
|
370
|
+
${released
|
|
371
|
+
? i18next.t('label.released', { defaultValue: 'released' })
|
|
372
|
+
: i18next.t('label.draft', { defaultValue: 'draft' })}
|
|
373
|
+
</span>
|
|
374
|
+
<span>v${board.version ?? 0}</span>
|
|
375
|
+
${group ? html `<span dot><b>${group.name}</b></span>` : nothing}
|
|
376
|
+
${updater
|
|
377
|
+
? html `<span dot>${i18next.t('text.updated by', { defaultValue: 'updated by' })} <b>${updater}</b> ${ago}</span>`
|
|
378
|
+
: ago
|
|
379
|
+
? html `<span dot>${i18next.t('text.updated', { defaultValue: 'updated' })} ${ago}</span>`
|
|
380
|
+
: nothing}
|
|
381
|
+
</div>
|
|
382
|
+
`;
|
|
383
|
+
}
|
|
384
|
+
renderDuplicate(board) {
|
|
385
|
+
const sameAsSource = this.original?.name == board.name && this._appCtrl.domain?.subdomain == this.targetSubdomain;
|
|
386
|
+
return html `
|
|
387
|
+
<div duplicate>
|
|
388
|
+
<div class="section">${i18next.t('text.duplicate', { defaultValue: 'Duplicate' })}</div>
|
|
389
|
+
<div class="note">
|
|
390
|
+
${i18next.t('text.duplicate hint', {
|
|
391
|
+
defaultValue: 'Copies this board into a domain and group. Give it a new name when copying within this domain.'
|
|
392
|
+
})}
|
|
393
|
+
</div>
|
|
394
|
+
<div class="fields">
|
|
395
|
+
<div class="row">
|
|
396
|
+
<label>
|
|
397
|
+
${i18next.t('label.domain')}
|
|
398
|
+
<select
|
|
399
|
+
@change=${e => {
|
|
400
|
+
this.targetSubdomain = e.target.value;
|
|
401
|
+
this.getGroupsByDomain(this.targetSubdomain);
|
|
402
|
+
}}
|
|
403
|
+
.value=${this.targetSubdomain || ''}
|
|
404
|
+
>
|
|
405
|
+
<option value=""></option>
|
|
406
|
+
${this.targetDomains.map(domain => html `<option value=${domain.subdomain} ?selected=${domain.subdomain == this.targetSubdomain}>
|
|
407
|
+
${domain.name}
|
|
408
|
+
</option>`)}
|
|
409
|
+
</select>
|
|
410
|
+
</label>
|
|
411
|
+
<label>
|
|
412
|
+
${i18next.t('label.group')}
|
|
413
|
+
<select @change=${e => (this.targetGroupId = e.target.value)} .value=${this.targetGroupId || ''}>
|
|
414
|
+
<option value=""></option>
|
|
415
|
+
${this.targetGroups.map(group => html `<option value=${group.id} ?selected=${group.id == this.targetGroupId}>${group.name}</option>`)}
|
|
416
|
+
</select>
|
|
417
|
+
</label>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
<div class="buttons">
|
|
421
|
+
<div filler></div>
|
|
422
|
+
<md-text-button cap @click=${() => (this.duplicating = false)}>${i18next.t('button.cancel')}</md-text-button>
|
|
423
|
+
<md-filled-button
|
|
424
|
+
cap
|
|
425
|
+
?disabled=${!this.original?.name || !board.name || !this.targetSubdomain || sameAsSource}
|
|
426
|
+
@click=${this.cloneBoard.bind(this)}
|
|
427
|
+
>
|
|
428
|
+
<md-icon slot="icon">content_copy</md-icon>${i18next.t('button.copy')}
|
|
429
|
+
</md-filled-button>
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
418
432
|
`;
|
|
419
433
|
}
|
|
420
434
|
async firstUpdated() {
|
|
@@ -480,11 +494,12 @@ let BoardInfo = class BoardInfo extends LitElement {
|
|
|
480
494
|
`,
|
|
481
495
|
variables: { id: this.boardId }
|
|
482
496
|
})).data;
|
|
483
|
-
|
|
497
|
+
const board = response.board;
|
|
498
|
+
this.groupId = board.group?.id;
|
|
499
|
+
this.board = { ...board, groupId: this.groupId };
|
|
500
|
+
this.original = { ...this.board };
|
|
484
501
|
this.boardGroupList = response.groups.items;
|
|
485
502
|
this.playGroupList = response.playGroups.items;
|
|
486
|
-
this.original = { ...this.board };
|
|
487
|
-
this.groupId = this.board.group?.id;
|
|
488
503
|
this.targetDomains = response.domainsWithPrivilege;
|
|
489
504
|
this.targetGroups = response.groups.items;
|
|
490
505
|
this.targetGroupId = this.groupId;
|
|
@@ -516,15 +531,22 @@ let BoardInfo = class BoardInfo extends LitElement {
|
|
|
516
531
|
})).data;
|
|
517
532
|
this.targetGroups = response2.groups.items;
|
|
518
533
|
}
|
|
534
|
+
/** Something in the form differs from what the server has. */
|
|
535
|
+
get isDirty() {
|
|
536
|
+
if (!this.board || !this.original) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
const { name, description, groupId, type } = this.board;
|
|
540
|
+
return (this.original.name != name ||
|
|
541
|
+
(this.original.description || '') != (description || '') ||
|
|
542
|
+
(this.original.groupId || '') != (groupId || '') ||
|
|
543
|
+
this.original.type != type);
|
|
544
|
+
}
|
|
519
545
|
get isReleasable() {
|
|
520
546
|
if (!this.board || this.board.state == 'released') {
|
|
521
547
|
return false;
|
|
522
548
|
}
|
|
523
|
-
|
|
524
|
-
return (this.original &&
|
|
525
|
-
this.original.name == name &&
|
|
526
|
-
this.original.description == description &&
|
|
527
|
-
this.original.groupId == groupId);
|
|
549
|
+
return !this.isDirty;
|
|
528
550
|
}
|
|
529
551
|
async cloneBoard() {
|
|
530
552
|
if (!this.original.name || (this.board.name == this.original.name && this._appCtrl.domain?.subdomain == this.targetSubdomain)) {
|
|
@@ -588,6 +610,9 @@ let BoardInfo = class BoardInfo extends LitElement {
|
|
|
588
610
|
bubbles: true,
|
|
589
611
|
composed: true
|
|
590
612
|
}));
|
|
613
|
+
/* The form is what the server now has; Save goes quiet until the next edit. */
|
|
614
|
+
this.original = { ...this.board };
|
|
615
|
+
this.requestUpdate();
|
|
591
616
|
}
|
|
592
617
|
async deleteBoard() {
|
|
593
618
|
if (await OxPrompt.open({
|
|
@@ -651,7 +676,7 @@ __decorate([
|
|
|
651
676
|
__decorate([
|
|
652
677
|
state(),
|
|
653
678
|
__metadata("design:type", Boolean)
|
|
654
|
-
], BoardInfo.prototype, "
|
|
679
|
+
], BoardInfo.prototype, "duplicating", void 0);
|
|
655
680
|
__decorate([
|
|
656
681
|
state(),
|
|
657
682
|
__metadata("design:type", Boolean)
|
|
@@ -672,6 +697,10 @@ __decorate([
|
|
|
672
697
|
state(),
|
|
673
698
|
__metadata("design:type", String)
|
|
674
699
|
], BoardInfo.prototype, "targetGroupId", void 0);
|
|
700
|
+
__decorate([
|
|
701
|
+
query('md-menu'),
|
|
702
|
+
__metadata("design:type", Object)
|
|
703
|
+
], BoardInfo.prototype, "menu", void 0);
|
|
675
704
|
BoardInfo = __decorate([
|
|
676
705
|
customElement('board-basic-info')
|
|
677
706
|
], BoardInfo);
|