@things-factory/figure-ui 10.1.178 → 10.1.179

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 (89) hide show
  1. package/client/figure-released.ts +6 -0
  2. package/client/graphql/index.ts +101 -25
  3. package/client/graphql/store.ts +2 -1
  4. package/client/index.ts +1 -0
  5. package/client/modeller/editor.ts +10 -2
  6. package/client/modeller/figure-first-save.ts +23 -3
  7. package/client/modeller/figure-parts.ts +53 -23
  8. package/client/modeller/figure-properties.ts +41 -7
  9. package/client/modeller/first-save.ts +2 -0
  10. package/client/modeller/product-session.ts +5 -3
  11. package/client/modeller/property-sections.ts +45 -0
  12. package/client/pages/figure-list-page.ts +52 -10
  13. package/client/pages/figure-modeller-page.ts +15 -3
  14. package/client/setting-let/figure-namespace-setting-let.ts +113 -31
  15. package/client/types.ts +8 -0
  16. package/client/viewparts/figure-detail-dock.ts +124 -9
  17. package/client/viewparts/figure-thumb.ts +6 -3
  18. package/dist-client/figure-released.d.ts +3 -0
  19. package/dist-client/figure-released.js +5 -0
  20. package/dist-client/figure-released.js.map +1 -0
  21. package/dist-client/graphql/index.d.ts +25 -13
  22. package/dist-client/graphql/index.js +85 -16
  23. package/dist-client/graphql/index.js.map +1 -1
  24. package/dist-client/graphql/store.js +2 -1
  25. package/dist-client/graphql/store.js.map +1 -1
  26. package/dist-client/index.d.ts +1 -0
  27. package/dist-client/index.js +1 -0
  28. package/dist-client/index.js.map +1 -1
  29. package/dist-client/modeller/editor.d.ts +2 -0
  30. package/dist-client/modeller/editor.js +13 -2
  31. package/dist-client/modeller/editor.js.map +1 -1
  32. package/dist-client/modeller/figure-first-save.d.ts +8 -0
  33. package/dist-client/modeller/figure-first-save.js +28 -3
  34. package/dist-client/modeller/figure-first-save.js.map +1 -1
  35. package/dist-client/modeller/figure-parts.d.ts +5 -0
  36. package/dist-client/modeller/figure-parts.js +54 -22
  37. package/dist-client/modeller/figure-parts.js.map +1 -1
  38. package/dist-client/modeller/figure-properties.d.ts +4 -0
  39. package/dist-client/modeller/figure-properties.js +45 -7
  40. package/dist-client/modeller/figure-properties.js.map +1 -1
  41. package/dist-client/modeller/first-save.d.ts +2 -0
  42. package/dist-client/modeller/first-save.js.map +1 -1
  43. package/dist-client/modeller/product-session.d.ts +4 -1
  44. package/dist-client/modeller/product-session.js +3 -3
  45. package/dist-client/modeller/product-session.js.map +1 -1
  46. package/dist-client/modeller/property-sections.d.ts +26 -0
  47. package/dist-client/modeller/property-sections.js +17 -0
  48. package/dist-client/modeller/property-sections.js.map +1 -0
  49. package/dist-client/pages/figure-list-page.d.ts +4 -1
  50. package/dist-client/pages/figure-list-page.js +56 -10
  51. package/dist-client/pages/figure-list-page.js.map +1 -1
  52. package/dist-client/pages/figure-modeller-page.d.ts +2 -0
  53. package/dist-client/pages/figure-modeller-page.js +19 -3
  54. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  55. package/dist-client/setting-let/figure-namespace-setting-let.d.ts +16 -5
  56. package/dist-client/setting-let/figure-namespace-setting-let.js +129 -31
  57. package/dist-client/setting-let/figure-namespace-setting-let.js.map +1 -1
  58. package/dist-client/tsconfig.tsbuildinfo +1 -1
  59. package/dist-client/types.d.ts +12 -0
  60. package/dist-client/types.js.map +1 -1
  61. package/dist-client/viewparts/figure-detail-dock.d.ts +33 -2
  62. package/dist-client/viewparts/figure-detail-dock.js +171 -11
  63. package/dist-client/viewparts/figure-detail-dock.js.map +1 -1
  64. package/dist-client/viewparts/figure-thumb.d.ts +2 -0
  65. package/dist-client/viewparts/figure-thumb.js +13 -3
  66. package/dist-client/viewparts/figure-thumb.js.map +1 -1
  67. package/package.json +8 -7
  68. package/test/browser/category-page.js +28 -0
  69. package/test/browser/category.check.mjs +54 -0
  70. package/test/browser/mesh-select.check.mjs +1 -1
  71. package/test/browser/namespace-page.js +75 -0
  72. package/test/browser/namespace.check.mjs +104 -0
  73. package/test/browser/parts-page.js +8 -2
  74. package/test/browser/places-mesh.check.mjs +30 -2
  75. package/test/browser/property-section-page.js +45 -0
  76. package/test/browser/property-section.check.mjs +48 -0
  77. package/test/browser/props.check.mjs +13 -2
  78. package/test/browser/public-page.js +39 -0
  79. package/test/browser/public.check.mjs +79 -0
  80. package/test/browser/retire-page.js +37 -0
  81. package/test/browser/retire.check.mjs +96 -0
  82. package/test/figure-released.test.ts +54 -0
  83. package/test/modeller-route.test.ts +2 -1
  84. package/translations/en.json +20 -5
  85. package/translations/es.json +20 -5
  86. package/translations/ja.json +20 -5
  87. package/translations/ko.json +20 -5
  88. package/translations/ms.json +20 -5
  89. package/translations/zh.json +20 -5
@@ -1,19 +1,27 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import '@material/web/textfield/filled-text-field.js';
3
+ import '@material/web/button/text-button.js';
3
4
  import '@things-factory/setting-base';
4
- import { css, html, LitElement } from 'lit';
5
- import { customElement, state } from 'lit/decorators.js';
5
+ import { css, html, LitElement, nothing } from 'lit';
6
+ import { customElement, property, state } from 'lit/decorators.js';
6
7
  import { i18next, localize } from '@operato/i18n';
7
- import { fetchFigureNamespace, setFigureNamespace } from '../graphql/index.js';
8
+ import { createFigureNamespace, fetchFigureNamespaces, setDefaultFigureNamespace, setFigureNamespaceState } from '../graphql/index.js';
8
9
  /**
9
- * The domain's figure namespace (ADR-0114): the `{namespace}` of every full name `{namespace}/{type}` a board stores.
10
- * Empty takes the subdomain. It is set once: when the domain's figures carry it, it is shown and no longer edited --
11
- * the server refuses a change either way, and says why.
10
+ * The namespaces the domain owns (LV figure-server design G1): the `{namespace}` of every full name `{namespace}/{type}`
11
+ * a board stores. A namespace is added once and never renamed; the default is the one new figures are created under;
12
+ * a suspended one takes no new figure and no release. The server refuses what it must and says why.
12
13
  */
13
14
  let FigureNamespaceSettingLet = class FigureNamespaceSettingLet extends localize(i18next)(LitElement) {
14
15
  constructor() {
15
16
  super(...arguments);
17
+ /* The server's calls; a check gives its own. */
18
+ this.list = fetchFigureNamespaces;
19
+ this.add = name => createFigureNamespace(name);
20
+ this.makeDefault = setDefaultFigureNamespace;
21
+ this.setState = setFigureNamespaceState;
22
+ this.draft = '';
16
23
  this.refused = '';
24
+ this.busy = false;
17
25
  }
18
26
  static { this.styles = [
19
27
  css `
@@ -23,70 +31,160 @@ let FigureNamespaceSettingLet = class FigureNamespaceSettingLet extends localize
23
31
  gap: var(--spacing-small, 4px);
24
32
  text-transform: none;
25
33
  }
26
- md-filled-text-field {
27
- width: 100%;
34
+ ul {
35
+ list-style: none;
36
+ margin: 0;
37
+ padding: 0;
38
+ display: grid;
39
+ gap: 2px;
28
40
  }
29
- strong {
30
- font: var(--label-font);
41
+ li {
42
+ display: flex;
43
+ flex-wrap: wrap;
44
+ align-items: center;
45
+ gap: 4px 12px;
46
+ min-height: 32px;
47
+ }
48
+ code {
49
+ font-family: var(--ui-mono, ui-monospace, monospace);
31
50
  color: var(--md-sys-color-on-surface);
32
51
  }
33
- p {
34
- margin: 0;
52
+ [mark] {
35
53
  font-size: 0.8rem;
36
54
  color: var(--md-sys-color-on-surface-variant);
37
55
  }
56
+ li[suspended] code {
57
+ color: var(--md-sys-color-on-surface-variant);
58
+ }
59
+ [actions] {
60
+ margin-left: auto;
61
+ display: flex;
62
+ gap: 4px;
63
+ }
64
+ [add] {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 8px;
68
+ }
69
+ md-filled-text-field {
70
+ flex: 1;
71
+ }
38
72
  `
39
73
  ]; }
40
74
  render() {
41
- const now = this.now;
75
+ const namespaces = this.namespaces;
42
76
  return html `
43
77
  <setting-let>
44
78
  <span slot="title">${i18next.t('figure.title.namespace-setting')}</span>
45
79
  <div slot="content">
46
- ${!now
47
- ? html ``
48
- : now.fixed
49
- ? html `<strong>${now.namespace}</strong>
50
- <p>${i18next.t('figure.text.namespace-fixed')}</p>`
51
- : html `<md-filled-text-field
52
- .label=${i18next.t('figure.label.namespace')}
53
- .value=${now.written}
54
- placeholder=${now.subdomain}
55
- ?error=${!!this.refused || !now.namespace}
56
- error-text=${this.refused || i18next.t('figure.text.namespace-subdomain-unusable', { subdomain: now.subdomain })}
57
- supporting-text=${i18next.t('figure.text.namespace-empty-takes-subdomain', { subdomain: now.subdomain })}
58
- @change=${(e) => this.save(e.target.value)}
59
- ></md-filled-text-field>`}
80
+ ${namespaces?.length
81
+ ? html `<ul>
82
+ ${namespaces.map(namespace => html `<li ?suspended=${namespace.state !== 'active'}>
83
+ <code>${namespace.name}</code>
84
+ ${namespace.isDefault ? html `<span mark>${i18next.t('figure.label.namespace-default')}</span>` : nothing}
85
+ ${namespace.state !== 'active' ? html `<span mark>${i18next.t('figure.label.namespace-suspended')}</span>` : nothing}
86
+ ${namespace.isDefault
87
+ ? nothing
88
+ : html `<span actions>
89
+ ${namespace.state === 'active'
90
+ ? html `<md-text-button ?disabled=${this.busy} @click=${() => this.run(() => this.makeDefault(namespace.name))}
91
+ >${i18next.t('figure.button.namespace-make-default')}</md-text-button
92
+ ><md-text-button ?disabled=${this.busy} @click=${() => this.run(() => this.setState(namespace.name, 'suspended'))}
93
+ >${i18next.t('figure.button.namespace-suspend')}</md-text-button
94
+ >`
95
+ : html `<md-text-button ?disabled=${this.busy} @click=${() => this.run(() => this.setState(namespace.name, 'active'))}
96
+ >${i18next.t('figure.button.namespace-activate')}</md-text-button
97
+ >`}
98
+ </span>`}
99
+ </li>`)}
100
+ </ul>`
101
+ : nothing}
102
+ <div add>
103
+ <md-filled-text-field
104
+ .label=${i18next.t('figure.label.namespace')}
105
+ .value=${this.draft}
106
+ ?error=${!!this.refused}
107
+ error-text=${this.refused}
108
+ @input=${(e) => {
109
+ this.draft = e.target.value;
110
+ this.refused = '';
111
+ }}
112
+ @keydown=${(e) => e.key === 'Enter' && !e.isComposing && this.addDraft()}
113
+ ></md-filled-text-field>
114
+ <md-text-button ?disabled=${this.busy || !this.draft.trim()} @click=${() => this.addDraft()}>${i18next.t('figure.button.namespace-add')}</md-text-button>
115
+ </div>
60
116
  </div>
61
117
  </setting-let>
62
118
  `;
63
119
  }
64
120
  async firstUpdated() {
121
+ await this.reload();
122
+ }
123
+ async reload() {
65
124
  try {
66
- this.now = await fetchFigureNamespace();
125
+ this.namespaces = await this.list();
67
126
  }
68
127
  catch (e) {
69
128
  this.refused = e.message;
70
129
  }
71
130
  }
72
- async save(value) {
131
+ async addDraft() {
132
+ const name = this.draft.trim();
133
+ if (!name || this.busy)
134
+ return;
135
+ if (await this.run(() => this.add(name)))
136
+ this.draft = '';
137
+ }
138
+ /** One change, then the list read again. False when the server refused it; its reason is shown. */
139
+ async run(change) {
140
+ this.busy = true;
73
141
  try {
74
- this.now = await setFigureNamespace(value);
142
+ await change();
75
143
  this.refused = '';
144
+ await this.reload();
145
+ return true;
76
146
  }
77
147
  catch (e) {
78
148
  this.refused = e.message;
149
+ return false;
150
+ }
151
+ finally {
152
+ this.busy = false;
79
153
  }
80
154
  }
81
155
  };
156
+ __decorate([
157
+ property({ attribute: false }),
158
+ __metadata("design:type", Function)
159
+ ], FigureNamespaceSettingLet.prototype, "list", void 0);
160
+ __decorate([
161
+ property({ attribute: false }),
162
+ __metadata("design:type", Function)
163
+ ], FigureNamespaceSettingLet.prototype, "add", void 0);
164
+ __decorate([
165
+ property({ attribute: false }),
166
+ __metadata("design:type", Function)
167
+ ], FigureNamespaceSettingLet.prototype, "makeDefault", void 0);
168
+ __decorate([
169
+ property({ attribute: false }),
170
+ __metadata("design:type", Function)
171
+ ], FigureNamespaceSettingLet.prototype, "setState", void 0);
172
+ __decorate([
173
+ state(),
174
+ __metadata("design:type", Array)
175
+ ], FigureNamespaceSettingLet.prototype, "namespaces", void 0);
82
176
  __decorate([
83
177
  state(),
84
178
  __metadata("design:type", Object)
85
- ], FigureNamespaceSettingLet.prototype, "now", void 0);
179
+ ], FigureNamespaceSettingLet.prototype, "draft", void 0);
86
180
  __decorate([
87
181
  state(),
88
182
  __metadata("design:type", Object)
89
183
  ], FigureNamespaceSettingLet.prototype, "refused", void 0);
184
+ __decorate([
185
+ state(),
186
+ __metadata("design:type", Object)
187
+ ], FigureNamespaceSettingLet.prototype, "busy", void 0);
90
188
  FigureNamespaceSettingLet = __decorate([
91
189
  customElement('figure-namespace-setting-let')
92
190
  ], FigureNamespaceSettingLet);
@@ -1 +1 @@
1
- {"version":3,"file":"figure-namespace-setting-let.js","sourceRoot":"","sources":["../../client/setting-let/figure-namespace-setting-let.ts"],"names":[],"mappings":";AAAA,OAAO,8CAA8C,CAAA;AACrD,OAAO,8BAA8B,CAAA;AAErC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAA6B,MAAM,qBAAqB,CAAA;AAEzG;;;;GAIG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAArE;;QAyBY,YAAO,GAAG,EAAE,CAAA;IA2C/B,CAAC;aAnEQ,WAAM,GAAG;QACd,GAAG,CAAA;;;;;;;;;;;;;;;;;;;KAmBF;KACF,AArBY,CAqBZ;IAKD,MAAM;QACJ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;QACpB,OAAO,IAAI,CAAA;;6BAEc,OAAO,CAAC,CAAC,CAAC,gCAAgC,CAAC;;YAE5D,CAAC,GAAG;YACJ,CAAC,CAAC,IAAI,CAAA,EAAE;YACR,CAAC,CAAC,GAAG,CAAC,KAAK;gBACT,CAAC,CAAC,IAAI,CAAA,WAAW,GAAG,CAAC,SAAS;uBACrB,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,MAAM;gBACvD,CAAC,CAAC,IAAI,CAAA;2BACO,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;2BACnC,GAAG,CAAC,OAAO;gCACN,GAAG,CAAC,SAAS;2BAClB,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS;+BAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,0CAA0C,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;oCAC9F,OAAO,CAAC,CAAC,CAAC,6CAA6C,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;4BAC9F,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC;yCAChD;;;KAGpC,CAAA;IACH,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,IAAI,CAAC,GAAG,GAAG,MAAM,oBAAoB,EAAE,CAAA;QACzC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,GAAI,CAAW,CAAC,OAAO,CAAA;QACrC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,KAAa;QAC9B,IAAI,CAAC;YACH,IAAI,CAAC,GAAG,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAA;YAC1C,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACnB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,GAAI,CAAW,CAAC,OAAO,CAAA;QACrC,CAAC;IACH,CAAC;;AA3CgB;IAAhB,KAAK,EAAE;;sDAAmC;AAC1B;IAAhB,KAAK,EAAE;;0DAAqB;AAzBlB,yBAAyB;IADrC,aAAa,CAAC,8BAA8B,CAAC;GACjC,yBAAyB,CAoErC","sourcesContent":["import '@material/web/textfield/filled-text-field.js'\nimport '@things-factory/setting-base'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\nimport { fetchFigureNamespace, setFigureNamespace, type FigureNamespaceState } from '../graphql/index.js'\n\n/**\n * The domain's figure namespace (ADR-0114): the `{namespace}` of every full name `{namespace}/{type}` a board stores.\n * Empty takes the subdomain. It is set once: when the domain's figures carry it, it is shown and no longer edited --\n * the server refuses a change either way, and says why.\n */\n@customElement('figure-namespace-setting-let')\nexport class FigureNamespaceSettingLet extends localize(i18next)(LitElement) {\n static styles = [\n css`\n /* A namespace is lower-case by rule: the card's capitalised words must not reach it, nor what is typed. */\n div[slot='content'] {\n display: grid;\n gap: var(--spacing-small, 4px);\n text-transform: none;\n }\n md-filled-text-field {\n width: 100%;\n }\n strong {\n font: var(--label-font);\n color: var(--md-sys-color-on-surface);\n }\n p {\n margin: 0;\n font-size: 0.8rem;\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n ]\n\n @state() private now?: FigureNamespaceState\n @state() private refused = ''\n\n render() {\n const now = this.now\n return html`\n <setting-let>\n <span slot=\"title\">${i18next.t('figure.title.namespace-setting')}</span>\n <div slot=\"content\">\n ${!now\n ? html``\n : now.fixed\n ? html`<strong>${now.namespace}</strong>\n <p>${i18next.t('figure.text.namespace-fixed')}</p>`\n : html`<md-filled-text-field\n .label=${i18next.t('figure.label.namespace')}\n .value=${now.written}\n placeholder=${now.subdomain}\n ?error=${!!this.refused || !now.namespace}\n error-text=${this.refused || i18next.t('figure.text.namespace-subdomain-unusable', { subdomain: now.subdomain })}\n supporting-text=${i18next.t('figure.text.namespace-empty-takes-subdomain', { subdomain: now.subdomain })}\n @change=${(e: Event) => this.save((e.target as HTMLInputElement).value)}\n ></md-filled-text-field>`}\n </div>\n </setting-let>\n `\n }\n\n async firstUpdated() {\n try {\n this.now = await fetchFigureNamespace()\n } catch (e) {\n this.refused = (e as Error).message\n }\n }\n\n private async save(value: string) {\n try {\n this.now = await setFigureNamespace(value)\n this.refused = ''\n } catch (e) {\n this.refused = (e as Error).message\n }\n }\n}\n"]}
1
+ {"version":3,"file":"figure-namespace-setting-let.js","sourceRoot":"","sources":["../../client/setting-let/figure-namespace-setting-let.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/textfield/filled-text-field.js'\nimport '@material/web/button/text-button.js'\nimport '@things-factory/setting-base'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\nimport {\n createFigureNamespace,\n fetchFigureNamespaces,\n setDefaultFigureNamespace,\n setFigureNamespaceState,\n type FigureNamespace\n} from '../graphql/index.js'\n\n/**\n * The namespaces the domain owns (LV figure-server design G1): the `{namespace}` of every full name `{namespace}/{type}`\n * a board stores. A namespace is added once and never renamed; the default is the one new figures are created under;\n * a suspended one takes no new figure and no release. The server refuses what it must and says why.\n */\n@customElement('figure-namespace-setting-let')\nexport class FigureNamespaceSettingLet extends localize(i18next)(LitElement) {\n static styles = [\n css`\n /* A namespace is lower-case by rule: the card's capitalised words must not reach it, nor what is typed. */\n div[slot='content'] {\n display: grid;\n gap: var(--spacing-small, 4px);\n text-transform: none;\n }\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 2px;\n }\n li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 12px;\n min-height: 32px;\n }\n code {\n font-family: var(--ui-mono, ui-monospace, monospace);\n color: var(--md-sys-color-on-surface);\n }\n [mark] {\n font-size: 0.8rem;\n color: var(--md-sys-color-on-surface-variant);\n }\n li[suspended] code {\n color: var(--md-sys-color-on-surface-variant);\n }\n [actions] {\n margin-left: auto;\n display: flex;\n gap: 4px;\n }\n [add] {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n md-filled-text-field {\n flex: 1;\n }\n `\n ]\n\n /* The server's calls; a check gives its own. */\n @property({ attribute: false }) list: () => Promise<FigureNamespace[]> = fetchFigureNamespaces\n @property({ attribute: false }) add: (name: string) => Promise<FigureNamespace> = name => createFigureNamespace(name)\n @property({ attribute: false }) makeDefault: (name: string) => Promise<FigureNamespace> = setDefaultFigureNamespace\n @property({ attribute: false }) setState: (name: string, state: 'active' | 'suspended') => Promise<FigureNamespace> = setFigureNamespaceState\n\n @state() private namespaces?: FigureNamespace[]\n @state() private draft = ''\n @state() private refused = ''\n @state() private busy = false\n\n render() {\n const namespaces = this.namespaces\n return html`\n <setting-let>\n <span slot=\"title\">${i18next.t('figure.title.namespace-setting')}</span>\n <div slot=\"content\">\n ${namespaces?.length\n ? html`<ul>\n ${namespaces.map(\n namespace => html`<li ?suspended=${namespace.state !== 'active'}>\n <code>${namespace.name}</code>\n ${namespace.isDefault ? html`<span mark>${i18next.t('figure.label.namespace-default')}</span>` : nothing}\n ${namespace.state !== 'active' ? html`<span mark>${i18next.t('figure.label.namespace-suspended')}</span>` : nothing}\n ${namespace.isDefault\n ? nothing\n : html`<span actions>\n ${namespace.state === 'active'\n ? html`<md-text-button ?disabled=${this.busy} @click=${() => this.run(() => this.makeDefault(namespace.name!))}\n >${i18next.t('figure.button.namespace-make-default')}</md-text-button\n ><md-text-button ?disabled=${this.busy} @click=${() => this.run(() => this.setState(namespace.name!, 'suspended'))}\n >${i18next.t('figure.button.namespace-suspend')}</md-text-button\n >`\n : html`<md-text-button ?disabled=${this.busy} @click=${() => this.run(() => this.setState(namespace.name!, 'active'))}\n >${i18next.t('figure.button.namespace-activate')}</md-text-button\n >`}\n </span>`}\n </li>`\n )}\n </ul>`\n : nothing}\n <div add>\n <md-filled-text-field\n .label=${i18next.t('figure.label.namespace')}\n .value=${this.draft}\n ?error=${!!this.refused}\n error-text=${this.refused}\n @input=${(e: Event) => {\n this.draft = (e.target as HTMLInputElement).value\n this.refused = ''\n }}\n @keydown=${(e: KeyboardEvent) => e.key === 'Enter' && !e.isComposing && this.addDraft()}\n ></md-filled-text-field>\n <md-text-button ?disabled=${this.busy || !this.draft.trim()} @click=${() => this.addDraft()}>${i18next.t('figure.button.namespace-add')}</md-text-button>\n </div>\n </div>\n </setting-let>\n `\n }\n\n async firstUpdated() {\n await this.reload()\n }\n\n private async reload() {\n try {\n this.namespaces = await this.list()\n } catch (e) {\n this.refused = (e as Error).message\n }\n }\n\n private async addDraft() {\n const name = this.draft.trim()\n if (!name || this.busy) return\n if (await this.run(() => this.add(name))) this.draft = ''\n }\n\n /** One change, then the list read again. False when the server refused it; its reason is shown. */\n private async run(change: () => Promise<unknown>): Promise<boolean> {\n this.busy = true\n try {\n await change()\n this.refused = ''\n await this.reload()\n return true\n } catch (e) {\n this.refused = (e as Error).message\n return false\n } finally {\n this.busy = false\n }\n }\n}\n"]}