@operato/board 10.29.8 → 10.29.10

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 +1 @@
1
- {"version":3,"file":"ox-board-modeller.js","sourceRoot":"","sources":["../../src/ox-board-modeller.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/fab/fab.js'\nimport '@hatiolab/things-scene'\nimport './modeller/scene-viewer/ox-scene-handler.js'\nimport './modeller/scene-viewer/ox-scene-layer.js'\nimport './modeller/scene-viewer/ox-scene-property.js'\nimport './modeller/scene-viewer/ox-scene-viewer.js'\nimport './ox-board-viewer.js'\nimport '@operato/input/ox-input-code.js'\n\nimport { saveAs } from 'file-saver'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { LoadTracker, LoadingOverlay, MODE_EDIT, Scene, SCENE_MODE, SceneMode } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { OxPopup } from '@operato/popup'\nimport { openPopup } from '@operato/layout'\nimport { i18next } from '@operato/i18n'\nimport { isMacOS, togglefullscreen } from '@operato/utils'\n\nimport { ComponentToolbar } from './modeller/component-toolbar/component-toolbar.js'\nimport { EditToolbar } from './modeller/edit-toolbar.js'\nimport { SelectionToolbar } from './modeller/selection-toolbar.js'\nimport { PropertySidebar } from './modeller/property-sidebar.js'\nimport { ComponentGroup, ComponentTemplate } from './types.js'\nimport OxSceneViewer from './modeller/scene-viewer/ox-scene-viewer.js'\n\nconst MACOS = isMacOS()\n\nconst ICON_HTOOLBAR = new URL('../../icons/icon-htoolbar.png', import.meta.url).href\nconst ICON_FULLSCREEN = new URL('../../icons/icon-fullscreen.png', import.meta.url).href\nconst ICON_COLLAPSE = new URL('../../icons/icon-collapse.png', import.meta.url).href\nconst ICON_COLLAPSE_ACTIVE = new URL('../../icons/icon-collapse-active.png', import.meta.url).href\n\nvar Registry: ComponentGroup[] = []\n\n@customElement('ox-board-modeller')\nexport class BoardModeller extends ScopedElementsMixin(LitElement) {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n height: 100%;\n overflow: hidden;\n }\n\n edit-toolbar {\n flex: 45px;\n max-height: 45px;\n }\n\n div[content] {\n flex: 1;\n max-height: calc(100% - 45px);\n\n display: flex;\n flex-direction: row;\n }\n\n component-toolbar {\n max-height: 100%;\n }\n\n property-sidebar {\n overflow: hidden;\n }\n\n #scene-wrap {\n position: relative;\n\n flex: 1;\n display: flex;\n flex-direction: row;\n }\n\n ox-scene-viewer {\n flex: 1;\n width: 100%;\n height: 100%;\n }\n\n md-fab {\n position: absolute;\n right: 15px;\n bottom: 15px;\n z-index: 1000;\n }\n\n ox-popup {\n width: 90%;\n height: 90%;\n left: 50%;\n top: 50%;\n transform: translateX(-50%) translateY(-50%);\n background: var(--md-sys-color-on-secondary-container, black);\n\n display: flex;\n justify-content: center;\n flex-direction: column;\n }\n\n ox-board-viewer {\n width: 98%;\n height: 98%;\n margin: auto;\n padding: 0;\n }\n `\n ]\n\n static registerGroup(group: ComponentGroup) {\n var found = Registry.find(inRegisterGroup => inRegisterGroup.name == group.name)\n\n if (found) {\n found = {\n ...found,\n ...group\n }\n } else {\n Registry.push(group)\n }\n }\n\n static registerTemplate(templates: ComponentTemplate[]): void {\n templates &&\n templates.forEach(template => {\n var groups: string[] = typeof template.group == 'string' ? [template.group] : template.group\n\n Registry.filter(group => groups.includes(group.name)).forEach(group => {\n if (!group.templates.find(inGroupTemplate => inGroupTemplate.type == template.type)) {\n group.templates.push(template)\n }\n })\n })\n }\n\n static get groups(): ComponentGroup[] {\n return Registry\n }\n\n static getGroup(name: string) {\n return Registry.find(group => group.name === name)\n }\n\n @property({ type: String }) boardName: string = ''\n @property({ type: Object }) model: any = null\n @property({ type: String }) baseUrl: string = ''\n @property({ type: Array }) selected: any[] = []\n @property({ type: Number }) mode: SceneMode = SCENE_MODE.EDIT\n @property({ type: Object }) provider: any = null\n @property({ type: Boolean }) hideProperty: boolean = false\n /* Selection verbs float next to the selection (SelectionToolbar) and the top bar keeps only\n * the board verbs. Set false to get the old one-row-of-everything toolbar back. */\n @property({ type: Boolean }) contextualToolbar: boolean = true\n /* Where the contextual bar lives when it is on: floating by the selection, or docked at the\n * top of the canvas. */\n @property({ type: String }) contextualToolbarPlacement: 'floating' | 'docked' = 'floating'\n @property({ type: String }) overlay: string = ''\n @property({ type: Object }) scene?: Scene\n @property({ type: Object }) loadTracker?: LoadTracker\n @property({ type: Array }) componentGroupList: any[] = []\n @property({ type: Array }) fonts: any[] = []\n @property({ type: Array }) propertyEditor: any[] = []\n\n @query('edit-toolbar') private editToolbar!: EditToolbar\n @query('ox-scene-viewer') private viewer!: OxSceneViewer\n\n private group: string = ''\n private shortcutHandler?: (e: KeyboardEvent) => void\n private _loadingOverlay?: LoadingOverlay\n\n constructor() {\n super()\n\n document.addEventListener('get-all-scene-component-ids', (e: Event) => {\n var { component, callback } = (e as CustomEvent).detail\n\n if (!this.scene) return\n\n var ids\n if (component) {\n ids = this.scene.findAll(component).map((c: any) => c.model.id)\n } else {\n // @ts-ignore\n ids = this.scene.ids.map(({ key }) => key)\n }\n\n ids = ids.filter(Boolean).sort()\n callback(ids)\n })\n\n this.style.setProperty('--url-icon-htoolbar', `url(${ICON_HTOOLBAR})`)\n this.style.setProperty('--url-icon-fullscreen', `url(${ICON_FULLSCREEN})`)\n this.style.setProperty('--url-icon-collapse', `url(${ICON_COLLAPSE})`)\n this.style.setProperty('--url-icon-collapse-active', `url(${ICON_COLLAPSE_ACTIVE})`)\n }\n\n static get scopedElements() {\n return {\n 'edit-toolbar': EditToolbar,\n 'selection-toolbar': SelectionToolbar,\n 'property-sidebar': PropertySidebar,\n 'component-toolbar': ComponentToolbar\n }\n }\n\n render() {\n return html`\n <edit-toolbar\n .scene=${this.scene}\n .selected=${this.selected}\n .compact=${this.contextualToolbar}\n @hide-property-changed=${(e: CustomEvent) => (this.hideProperty = e.detail.value)}\n @open-preview=${() => this.preview()}\n @open-data-binding=${() => this.openDataBinding()}\n @download-model=${() => this.downloadModel()}\n @edit-model=${() => this.editModel()}\n @modeller-fullscreen=${() => togglefullscreen(this)}\n >\n ${this.renderBrandingZone()}\n </edit-toolbar>\n\n <div content>\n <component-toolbar\n .scene=${this.scene}\n .mode=${this.mode}\n @mode-changed=${(e: CustomEvent) => {\n this.mode = e.detail.value\n }}\n .componentGroupList=${this.componentGroupList}\n .group=${this.group}\n >\n </component-toolbar>\n\n <div id=\"scene-wrap\">\n <ox-scene-viewer\n id=\"scene\"\n .scene=${this.scene}\n .loadTracker=${this.loadTracker}\n @scene-changed=${(e: CustomEvent) => {\n this.scene = e.detail.value\n }}\n .model=${this.model}\n .selected=${this.selected}\n @selected-changed=${(e: CustomEvent) => {\n this.selected = e.detail.value\n }}\n .mode=${this.mode}\n @mode-changed=${(e: CustomEvent) => {\n this.mode = e.detail.value\n }}\n fit=\"ratio\"\n .baseUrl=${this.baseUrl}\n @contextmenu=${() => this.onContextMenu()}\n .provider=${this.provider}\n name=\"modeller\"\n >\n <ox-scene-layer type=\"snap-guide-layer\"></ox-scene-layer>\n <ox-scene-layer type=\"selection-layer\"></ox-scene-layer>\n <ox-scene-layer type=\"modeling-layer\"></ox-scene-layer>\n <ox-scene-layer type=\"add-layer\"> </ox-scene-layer>\n <ox-scene-layer type=\"shift-layer\">\n <ox-scene-property name=\"text\" value=\"${this.overlay}\"></ox-scene-property>\n <ox-scene-property name=\"alpha\" value=\"0.3\"></ox-scene-property>\n <ox-scene-property name=\"fontFamily\" value=\"arial\"></ox-scene-property>\n <ox-scene-property name=\"fontSize\" value=\"30\" type=\"number\"></ox-scene-property>\n <ox-scene-property name=\"fontColor\" value=\"navy\"></ox-scene-property>\n <ox-scene-property name=\"textBaseline\" value=\"top\"></ox-scene-property>\n <ox-scene-property name=\"textAlign\" value=\"left\"></ox-scene-property>\n <ox-scene-property name=\"paddingTop\" value=\"50\" type=\"number\"></ox-scene-property>\n <ox-scene-property name=\"paddingLeft\" value=\"50\" type=\"number\"></ox-scene-property>\n </ox-scene-layer>\n <ox-scene-handler type=\"text-editor\"></ox-scene-handler>\n <ox-scene-handler type=\"move-handler\"></ox-scene-handler>\n <ox-scene-handler type=\"paste-handler\"></ox-scene-handler>\n </ox-scene-viewer>\n\n ${this.contextualToolbar\n ? html`<selection-toolbar\n .scene=${this.scene}\n .selected=${this.selected}\n .placement=${this.contextualToolbarPlacement}\n ></selection-toolbar>`\n : ''}\n\n <md-fab @click=${() => this.onTapSave()} title=\"save\">\n <md-icon slot=\"icon\">save</md-icon>\n </md-fab>\n </div>\n\n <property-sidebar\n .scene=${this.scene}\n .selected=${this.selected}\n .heading=${this.boardName}\n .collapsed=${this.hideProperty}\n .fonts=${this.fonts}\n .propertyEditor=${this.propertyEditor}\n >\n </property-sidebar>\n </div>\n `\n }\n\n connectedCallback(): void {\n super.connectedCallback()\n this.bindShortcutEvent()\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback()\n this.unbindShortcutEvent()\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('loadTracker') && this.loadTracker) {\n if (!this._loadingOverlay) {\n this._loadingOverlay = new LoadingOverlay()\n }\n this._loadingOverlay.attach(this.renderRoot as HTMLElement, this.loadTracker)\n }\n\n if (changes.has('scene') && this.scene) {\n this.scene.mode = MODE_EDIT\n ;(this.scene as any).onDataBindingToggle = () => this.openDataBinding()\n }\n }\n\n close() {\n this.model = null\n this.requestUpdate()\n }\n\n onShortcut(e: KeyboardEvent) {\n if (MACOS) var ctrlKey = e.metaKey\n else var ctrlKey = e.ctrlKey\n\n switch (e.code) {\n case 'KeyS':\n if (ctrlKey) {\n this.onTapSave()\n e.preventDefault()\n }\n break\n }\n }\n\n preview() {\n const board = {\n id: 'preview',\n model: this.scene?.model ? JSON.parse(JSON.stringify(this.scene.model)) : null\n }\n\n OxPopup.open({\n template: html` <ox-board-viewer style=\"flex: 1;\" .provider=${this.provider} .board=${board}></ox-board-viewer> `,\n style: 'width: 80vw; height: 80vh;',\n backdrop: true,\n preventCloseOnBlur: true\n })\n\n requestAnimationFrame(() => {\n dispatchEvent(new Event('resize'))\n })\n }\n\n private _dataBindingPopup?: any\n\n openDataBinding() {\n // 토글: 이미 열려있으면 닫기\n if (this._dataBindingPopup) {\n this._dataBindingPopup.close()\n this._dataBindingPopup = null\n return\n }\n\n if (!this.scene) return\n\n const selected = this.scene.selected?.[0]\n if (!selected) return\n\n import('@operato/property-panel/data-binding-popup.js')\n\n const PROPS = [\n '',\n 'text',\n 'fillStyle',\n 'strokeStyle',\n 'fontColor',\n 'value',\n 'data',\n 'source',\n 'hidden',\n 'started',\n 'play',\n 'ref',\n 'action',\n 'options',\n 'rotate',\n 'dimension',\n 'location',\n 'accessor',\n 'appendum',\n 'tag',\n 'tap',\n '(action)'\n ].map(p => ({ name: p, label: p }))\n\n const template = html`\n <data-binding-popup\n .mappings=${[...(selected.model.mappings || [])]}\n .properties=${PROPS}\n .selected=${selected}\n ></data-binding-popup>\n `\n\n // document 레벨에서 mappings-change 이벤트 수신 (openPopup 컨텍스트에서 Lit 이벤트 바인딩 불가)\n const onMappingsChange = (e: Event) => {\n const detail = (e as CustomEvent).detail\n if (detail?.mappings) {\n selected.set('mappings', detail.mappings)\n }\n }\n document.addEventListener('mappings-change', onMappingsChange)\n\n this._dataBindingPopup = openPopup(template, {\n backdrop: true,\n size: 'large',\n title: `${i18next.t('label.data-spread')} — ${selected.get('id') || selected.get('type')}`\n })\n\n // 팝업이 외부에서 닫힐 때 참조 정리\n this._dataBindingPopup?.addEventListener?.('closed', () => {\n document.removeEventListener('mappings-change', onMappingsChange)\n this._dataBindingPopup = null\n })\n }\n\n downloadModel() {\n if (!this.scene) return\n\n var model = JSON.stringify(this.model, null, 2)\n var filename = (this.boardName || 'NONAME') + '-' + Date.now() + '.json'\n saveAs(new Blob([model], { type: 'application/octet-stream' }), filename)\n }\n\n private _modelEditorHandle?: any\n\n editModel() {\n if (this._modelEditorHandle && !this._modelEditorHandle.closed) {\n this._modelEditorHandle.close()\n this._modelEditorHandle = undefined\n return\n }\n\n if (!this.scene) return\n\n const modelJson = JSON.stringify(this.scene.model, null, 2)\n let currentValue = modelJson\n\n const handle = this._modelEditorHandle = openPopup(html`\n <div style=\"display:flex;flex-direction:column;height:100%;\">\n <ox-input-code\n .value=${modelJson}\n language=\"json\"\n show-line-numbers\n style=\"flex:1;overflow:auto;\"\n @change=${(e: CustomEvent) => { currentValue = e.detail }}\n ></ox-input-code>\n <div style=\"display:flex;justify-content:flex-end;gap:8px;padding:8px;background:var(--md-sys-color-surface-container, #f0f0f0);\">\n <button @click=${() => {\n try {\n const model = JSON.parse(currentValue)\n this.scene!.model = model\n this.requestUpdate()\n handle.close()\n } catch (err) {\n alert('Invalid JSON: ' + (err as Error).message)\n }\n }} style=\"padding:4px 16px;cursor:pointer;\">Apply</button>\n </div>\n </div>\n `, {\n backdrop: true,\n title: 'Edit Board Model',\n size: 'large'\n })\n handle.onclosed = () => { this._modelEditorHandle = undefined }\n }\n\n renderBrandingZone() {\n return html``\n }\n\n onTapSave() {\n this.dispatchEvent(new CustomEvent('save-model', { bubbles: true, composed: true, detail: { model: this.model } }))\n }\n\n bindShortcutEvent() {\n // TODO: Global Hotkey에 대한 정의를 edit-toolbar에서 가져올 수 있도록 수정해야 함.\n const GLOBAL_HOTKEYS = ['Digit1', 'Digit2', 'F10', 'F11', 'KeyD', 'KeyP', 'KeyS']\n\n this.shortcutHandler = (e: KeyboardEvent) => {\n const target = e.composedPath()[0] as HTMLElement\n var tagName = target.tagName\n var isInput = target.isContentEditable || tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA'\n var isGlobalHotkey = GLOBAL_HOTKEYS.includes(e.code)\n\n if (!isGlobalHotkey && isInput) return\n if (!this.editToolbar.onShortcut(e)) this.onShortcut(e)\n }\n\n document.addEventListener('keydown', this.shortcutHandler)\n }\n\n unbindShortcutEvent() {\n if (this.shortcutHandler) {\n document.removeEventListener('keydown', this.shortcutHandler)\n delete this.shortcutHandler\n }\n }\n\n undoable(): boolean {\n return !!this.scene?.undoable()\n }\n\n redoable(): boolean {\n return !!this.scene?.redoable()\n }\n\n preserve(): void {\n this.scene?.preserve()\n }\n\n hasUnpreservedChanges(): boolean {\n return !!this.scene?.hasUnpreservedChanges()\n }\n\n onContextMenu() {}\n}\n"]}
1
+ {"version":3,"file":"ox-board-modeller.js","sourceRoot":"","sources":["../../src/ox-board-modeller.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/fab/fab.js'\nimport '@hatiolab/things-scene'\nimport './modeller/scene-viewer/ox-scene-handler.js'\nimport './modeller/scene-viewer/ox-scene-layer.js'\nimport './modeller/scene-viewer/ox-scene-property.js'\nimport './modeller/scene-viewer/ox-scene-viewer.js'\nimport './ox-board-viewer.js'\nimport '@operato/input/ox-input-code.js'\n\nimport { saveAs } from 'file-saver'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { LoadTracker, LoadingOverlay, MODE_EDIT, Scene, SCENE_MODE, SceneMode } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { OxPopup } from '@operato/popup'\nimport { openPopup } from '@operato/layout'\nimport { i18next } from '@operato/i18n'\nimport { isMacOS, togglefullscreen } from '@operato/utils'\n\nimport { ComponentToolbar } from './modeller/component-toolbar/component-toolbar.js'\nimport { EditToolbar } from './modeller/edit-toolbar.js'\nimport { SelectionToolbar } from './modeller/selection-toolbar.js'\nimport { PropertySidebar } from './modeller/property-sidebar.js'\nimport { ComponentGroup, ComponentTemplate } from './types.js'\nimport OxSceneViewer from './modeller/scene-viewer/ox-scene-viewer.js'\n\nconst MACOS = isMacOS()\n\nconst ICON_HTOOLBAR = new URL('../../icons/icon-htoolbar.png', import.meta.url).href\nconst ICON_FULLSCREEN = new URL('../../icons/icon-fullscreen.png', import.meta.url).href\nconst ICON_COLLAPSE = new URL('../../icons/icon-collapse.png', import.meta.url).href\nconst ICON_COLLAPSE_ACTIVE = new URL('../../icons/icon-collapse-active.png', import.meta.url).href\n\nvar Registry: ComponentGroup[] = []\n\n@customElement('ox-board-modeller')\nexport class BoardModeller extends ScopedElementsMixin(LitElement) {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n height: 100%;\n overflow: hidden;\n }\n\n edit-toolbar {\n flex: 45px;\n max-height: 45px;\n }\n\n div[content] {\n flex: 1;\n max-height: calc(100% - 45px);\n\n display: flex;\n flex-direction: row;\n }\n\n component-toolbar {\n max-height: 100%;\n }\n\n property-sidebar {\n overflow: hidden;\n }\n\n #scene-wrap {\n position: relative;\n\n flex: 1;\n display: flex;\n flex-direction: row;\n }\n\n ox-scene-viewer {\n flex: 1;\n width: 100%;\n height: 100%;\n }\n\n md-fab {\n position: absolute;\n right: 15px;\n bottom: 15px;\n z-index: 1000;\n }\n\n ox-popup {\n width: 90%;\n height: 90%;\n left: 50%;\n top: 50%;\n transform: translateX(-50%) translateY(-50%);\n background: var(--md-sys-color-on-secondary-container, black);\n\n display: flex;\n justify-content: center;\n flex-direction: column;\n }\n\n ox-board-viewer {\n width: 98%;\n height: 98%;\n margin: auto;\n padding: 0;\n }\n `\n ]\n\n /**\n * Registers a group, or replaces what a group of that name holds. A group filled from a server -- the figures of\n * the active type map (ADR-0114 결정 10) -- registers again when its list changes; this used to assign to a local\n * variable and change nothing.\n */\n static registerGroup(group: ComponentGroup) {\n const found = Registry.find(inRegisterGroup => inRegisterGroup.name == group.name)\n\n if (found) {\n Object.assign(found, group)\n } else {\n Registry.push(group)\n }\n }\n\n static registerTemplate(templates: ComponentTemplate[]): void {\n templates &&\n templates.forEach(template => {\n var groups: string[] = typeof template.group == 'string' ? [template.group] : template.group\n\n Registry.filter(group => groups.includes(group.name)).forEach(group => {\n if (!group.templates.find(inGroupTemplate => inGroupTemplate.type == template.type)) {\n group.templates.push(template)\n }\n })\n })\n }\n\n static get groups(): ComponentGroup[] {\n return Registry\n }\n\n static getGroup(name: string) {\n return Registry.find(group => group.name === name)\n }\n\n @property({ type: String }) boardName: string = ''\n @property({ type: Object }) model: any = null\n @property({ type: String }) baseUrl: string = ''\n @property({ type: Array }) selected: any[] = []\n @property({ type: Number }) mode: SceneMode = SCENE_MODE.EDIT\n @property({ type: Object }) provider: any = null\n @property({ type: Boolean }) hideProperty: boolean = false\n /* Selection verbs float next to the selection (SelectionToolbar) and the top bar keeps only\n * the board verbs. Set false to get the old one-row-of-everything toolbar back. */\n @property({ type: Boolean }) contextualToolbar: boolean = true\n /* Where the contextual bar lives when it is on: floating by the selection, or docked at the\n * top of the canvas. */\n @property({ type: String }) contextualToolbarPlacement: 'floating' | 'docked' = 'floating'\n @property({ type: String }) overlay: string = ''\n @property({ type: Object }) scene?: Scene\n @property({ type: Object }) loadTracker?: LoadTracker\n @property({ type: Array }) componentGroupList: any[] = []\n @property({ type: Array }) fonts: any[] = []\n @property({ type: Array }) propertyEditor: any[] = []\n\n @query('edit-toolbar') private editToolbar!: EditToolbar\n @query('ox-scene-viewer') private viewer!: OxSceneViewer\n\n private group: string = ''\n private shortcutHandler?: (e: KeyboardEvent) => void\n private _loadingOverlay?: LoadingOverlay\n\n constructor() {\n super()\n\n document.addEventListener('get-all-scene-component-ids', (e: Event) => {\n var { component, callback } = (e as CustomEvent).detail\n\n if (!this.scene) return\n\n var ids\n if (component) {\n ids = this.scene.findAll(component).map((c: any) => c.model.id)\n } else {\n // @ts-ignore\n ids = this.scene.ids.map(({ key }) => key)\n }\n\n ids = ids.filter(Boolean).sort()\n callback(ids)\n })\n\n this.style.setProperty('--url-icon-htoolbar', `url(${ICON_HTOOLBAR})`)\n this.style.setProperty('--url-icon-fullscreen', `url(${ICON_FULLSCREEN})`)\n this.style.setProperty('--url-icon-collapse', `url(${ICON_COLLAPSE})`)\n this.style.setProperty('--url-icon-collapse-active', `url(${ICON_COLLAPSE_ACTIVE})`)\n }\n\n static get scopedElements() {\n return {\n 'edit-toolbar': EditToolbar,\n 'selection-toolbar': SelectionToolbar,\n 'property-sidebar': PropertySidebar,\n 'component-toolbar': ComponentToolbar\n }\n }\n\n render() {\n return html`\n <edit-toolbar\n .scene=${this.scene}\n .selected=${this.selected}\n .compact=${this.contextualToolbar}\n @hide-property-changed=${(e: CustomEvent) => (this.hideProperty = e.detail.value)}\n @open-preview=${() => this.preview()}\n @open-data-binding=${() => this.openDataBinding()}\n @download-model=${() => this.downloadModel()}\n @edit-model=${() => this.editModel()}\n @modeller-fullscreen=${() => togglefullscreen(this)}\n >\n ${this.renderBrandingZone()}\n </edit-toolbar>\n\n <div content>\n <component-toolbar\n .scene=${this.scene}\n .mode=${this.mode}\n @mode-changed=${(e: CustomEvent) => {\n this.mode = e.detail.value\n }}\n .componentGroupList=${this.componentGroupList}\n .group=${this.group}\n >\n </component-toolbar>\n\n <div id=\"scene-wrap\">\n <ox-scene-viewer\n id=\"scene\"\n .scene=${this.scene}\n .loadTracker=${this.loadTracker}\n @scene-changed=${(e: CustomEvent) => {\n this.scene = e.detail.value\n }}\n .model=${this.model}\n .selected=${this.selected}\n @selected-changed=${(e: CustomEvent) => {\n this.selected = e.detail.value\n }}\n .mode=${this.mode}\n @mode-changed=${(e: CustomEvent) => {\n this.mode = e.detail.value\n }}\n fit=\"ratio\"\n .baseUrl=${this.baseUrl}\n @contextmenu=${() => this.onContextMenu()}\n .provider=${this.provider}\n name=\"modeller\"\n >\n <ox-scene-layer type=\"snap-guide-layer\"></ox-scene-layer>\n <ox-scene-layer type=\"selection-layer\"></ox-scene-layer>\n <ox-scene-layer type=\"modeling-layer\"></ox-scene-layer>\n <ox-scene-layer type=\"add-layer\"> </ox-scene-layer>\n <ox-scene-layer type=\"shift-layer\">\n <ox-scene-property name=\"text\" value=\"${this.overlay}\"></ox-scene-property>\n <ox-scene-property name=\"alpha\" value=\"0.3\"></ox-scene-property>\n <ox-scene-property name=\"fontFamily\" value=\"arial\"></ox-scene-property>\n <ox-scene-property name=\"fontSize\" value=\"30\" type=\"number\"></ox-scene-property>\n <ox-scene-property name=\"fontColor\" value=\"navy\"></ox-scene-property>\n <ox-scene-property name=\"textBaseline\" value=\"top\"></ox-scene-property>\n <ox-scene-property name=\"textAlign\" value=\"left\"></ox-scene-property>\n <ox-scene-property name=\"paddingTop\" value=\"50\" type=\"number\"></ox-scene-property>\n <ox-scene-property name=\"paddingLeft\" value=\"50\" type=\"number\"></ox-scene-property>\n </ox-scene-layer>\n <ox-scene-handler type=\"text-editor\"></ox-scene-handler>\n <ox-scene-handler type=\"move-handler\"></ox-scene-handler>\n <ox-scene-handler type=\"paste-handler\"></ox-scene-handler>\n </ox-scene-viewer>\n\n ${this.contextualToolbar\n ? html`<selection-toolbar\n .scene=${this.scene}\n .selected=${this.selected}\n .placement=${this.contextualToolbarPlacement}\n ></selection-toolbar>`\n : ''}\n\n <md-fab @click=${() => this.onTapSave()} title=\"save\">\n <md-icon slot=\"icon\">save</md-icon>\n </md-fab>\n </div>\n\n <property-sidebar\n .scene=${this.scene}\n .selected=${this.selected}\n .heading=${this.boardName}\n .collapsed=${this.hideProperty}\n .fonts=${this.fonts}\n .propertyEditor=${this.propertyEditor}\n >\n </property-sidebar>\n </div>\n `\n }\n\n connectedCallback(): void {\n super.connectedCallback()\n this.bindShortcutEvent()\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback()\n this.unbindShortcutEvent()\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('loadTracker') && this.loadTracker) {\n if (!this._loadingOverlay) {\n this._loadingOverlay = new LoadingOverlay()\n }\n this._loadingOverlay.attach(this.renderRoot as HTMLElement, this.loadTracker)\n }\n\n if (changes.has('scene') && this.scene) {\n this.scene.mode = MODE_EDIT\n ;(this.scene as any).onDataBindingToggle = () => this.openDataBinding()\n }\n }\n\n close() {\n this.model = null\n this.requestUpdate()\n }\n\n onShortcut(e: KeyboardEvent) {\n if (MACOS) var ctrlKey = e.metaKey\n else var ctrlKey = e.ctrlKey\n\n switch (e.code) {\n case 'KeyS':\n if (ctrlKey) {\n this.onTapSave()\n e.preventDefault()\n }\n break\n }\n }\n\n preview() {\n const board = {\n id: 'preview',\n model: this.scene?.model ? JSON.parse(JSON.stringify(this.scene.model)) : null\n }\n\n OxPopup.open({\n template: html` <ox-board-viewer style=\"flex: 1;\" .provider=${this.provider} .board=${board}></ox-board-viewer> `,\n style: 'width: 80vw; height: 80vh;',\n backdrop: true,\n preventCloseOnBlur: true\n })\n\n requestAnimationFrame(() => {\n dispatchEvent(new Event('resize'))\n })\n }\n\n private _dataBindingPopup?: any\n\n openDataBinding() {\n // 토글: 이미 열려있으면 닫기\n if (this._dataBindingPopup) {\n this._dataBindingPopup.close()\n this._dataBindingPopup = null\n return\n }\n\n if (!this.scene) return\n\n const selected = this.scene.selected?.[0]\n if (!selected) return\n\n import('@operato/property-panel/data-binding-popup.js')\n\n const PROPS = [\n '',\n 'text',\n 'fillStyle',\n 'strokeStyle',\n 'fontColor',\n 'value',\n 'data',\n 'source',\n 'hidden',\n 'started',\n 'play',\n 'ref',\n 'action',\n 'options',\n 'rotate',\n 'dimension',\n 'location',\n 'accessor',\n 'appendum',\n 'tag',\n 'tap',\n '(action)'\n ].map(p => ({ name: p, label: p }))\n\n const template = html`\n <data-binding-popup\n .mappings=${[...(selected.model.mappings || [])]}\n .properties=${PROPS}\n .selected=${selected}\n ></data-binding-popup>\n `\n\n // document 레벨에서 mappings-change 이벤트 수신 (openPopup 컨텍스트에서 Lit 이벤트 바인딩 불가)\n const onMappingsChange = (e: Event) => {\n const detail = (e as CustomEvent).detail\n if (detail?.mappings) {\n selected.set('mappings', detail.mappings)\n }\n }\n document.addEventListener('mappings-change', onMappingsChange)\n\n this._dataBindingPopup = openPopup(template, {\n backdrop: true,\n size: 'large',\n title: `${i18next.t('label.data-spread')} — ${selected.get('id') || selected.get('type')}`\n })\n\n // 팝업이 외부에서 닫힐 때 참조 정리\n this._dataBindingPopup?.addEventListener?.('closed', () => {\n document.removeEventListener('mappings-change', onMappingsChange)\n this._dataBindingPopup = null\n })\n }\n\n downloadModel() {\n if (!this.scene) return\n\n var model = JSON.stringify(this.model, null, 2)\n var filename = (this.boardName || 'NONAME') + '-' + Date.now() + '.json'\n saveAs(new Blob([model], { type: 'application/octet-stream' }), filename)\n }\n\n private _modelEditorHandle?: any\n\n editModel() {\n if (this._modelEditorHandle && !this._modelEditorHandle.closed) {\n this._modelEditorHandle.close()\n this._modelEditorHandle = undefined\n return\n }\n\n if (!this.scene) return\n\n const modelJson = JSON.stringify(this.scene.model, null, 2)\n let currentValue = modelJson\n\n const handle = this._modelEditorHandle = openPopup(html`\n <div style=\"display:flex;flex-direction:column;height:100%;\">\n <ox-input-code\n .value=${modelJson}\n language=\"json\"\n show-line-numbers\n style=\"flex:1;overflow:auto;\"\n @change=${(e: CustomEvent) => { currentValue = e.detail }}\n ></ox-input-code>\n <div style=\"display:flex;justify-content:flex-end;gap:8px;padding:8px;background:var(--md-sys-color-surface-container, #f0f0f0);\">\n <button @click=${() => {\n try {\n const model = JSON.parse(currentValue)\n this.scene!.model = model\n this.requestUpdate()\n handle.close()\n } catch (err) {\n alert('Invalid JSON: ' + (err as Error).message)\n }\n }} style=\"padding:4px 16px;cursor:pointer;\">Apply</button>\n </div>\n </div>\n `, {\n backdrop: true,\n title: 'Edit Board Model',\n size: 'large'\n })\n handle.onclosed = () => { this._modelEditorHandle = undefined }\n }\n\n renderBrandingZone() {\n return html``\n }\n\n onTapSave() {\n this.dispatchEvent(new CustomEvent('save-model', { bubbles: true, composed: true, detail: { model: this.model } }))\n }\n\n bindShortcutEvent() {\n // TODO: Global Hotkey에 대한 정의를 edit-toolbar에서 가져올 수 있도록 수정해야 함.\n const GLOBAL_HOTKEYS = ['Digit1', 'Digit2', 'F10', 'F11', 'KeyD', 'KeyP', 'KeyS']\n\n this.shortcutHandler = (e: KeyboardEvent) => {\n const target = e.composedPath()[0] as HTMLElement\n var tagName = target.tagName\n var isInput = target.isContentEditable || tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA'\n var isGlobalHotkey = GLOBAL_HOTKEYS.includes(e.code)\n\n if (!isGlobalHotkey && isInput) return\n if (!this.editToolbar.onShortcut(e)) this.onShortcut(e)\n }\n\n document.addEventListener('keydown', this.shortcutHandler)\n }\n\n unbindShortcutEvent() {\n if (this.shortcutHandler) {\n document.removeEventListener('keydown', this.shortcutHandler)\n delete this.shortcutHandler\n }\n }\n\n undoable(): boolean {\n return !!this.scene?.undoable()\n }\n\n redoable(): boolean {\n return !!this.scene?.redoable()\n }\n\n preserve(): void {\n this.scene?.preserve()\n }\n\n hasUnpreservedChanges(): boolean {\n return !!this.scene?.hasUnpreservedChanges()\n }\n\n onContextMenu() {}\n}\n"]}
@@ -3,14 +3,17 @@
3
3
  */
4
4
  import { create, resolveUnknownTypes } from '@hatiolab/things-scene';
5
5
  export async function createResolvedScene(options, stillWanted) {
6
- const { unresolved, failed } = await resolveUnknownTypes(options.model);
6
+ var _a;
7
+ const resolution = await resolveUnknownTypes(options.model);
8
+ const { unresolved, failed } = resolution;
9
+ /* The reason a resolver gave for each type it refused (ADR-0114 A3); older scenes report none. */
10
+ const refused = (_a = resolution.refused) !== null && _a !== void 0 ? _a : [];
7
11
  if (failed.length > 0 || unresolved.length > 0) {
8
12
  const asked = new Set(failed.flatMap(({ types }) => types));
13
+ const said = new Map(refused.map(({ type, message }) => [type, message]));
9
14
  const reasons = [
10
15
  ...failed.map(({ types, error }) => `${types.join(', ')}: ${error instanceof Error ? error.message : String(error)}`),
11
- ...(unresolved.some(type => !asked.has(type))
12
- ? [`${unresolved.filter(type => !asked.has(type)).join(', ')}: 발행된 것이 없다`]
13
- : [])
16
+ ...unresolved.filter(type => !asked.has(type)).map(type => { var _a; return `${type}: ${(_a = said.get(type)) !== null && _a !== void 0 ? _a : '해석되지 않았다'}`; })
14
17
  ];
15
18
  console.warn(`[board] 그리지 못한 type — ${reasons.join(' | ')}`);
16
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resolved-scene.js","sourceRoot":"","sources":["../../src/resolved-scene.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAiCpE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA2B,EAC3B,WAAyB;IAEzB,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAEvE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAG;YACd,GAAG,MAAM,CAAC,GAAG,CACX,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACvG;YACD,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC3C,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;gBAC1E,CAAC,CAAC,EAAE,CAAC;SACR,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC9D,CAAC;IAED,IAAI,WAAW,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QAClC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;AACxB,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { create, resolveUnknownTypes } from '@hatiolab/things-scene'\nimport type { SceneCreateOptions } from '@hatiolab/things-scene'\n\n/*\n * The one place this package turns a model into a scene.\n *\n * ── Why it is one place ─────────────────────────────────────────────────────\n * `create()` is synchronous and compiles what is registered at that moment, so the types a model\n * names and nobody has registered have to be fetched first (`figure-provider.ts` fetches them).\n * Written at each scene site, that \"first\" is six lines that drift apart, and the seventh site\n * forgets it. So every site in this package calls this function instead, and a test counts that\n * nobody else imports `create` (test/scene-create-single-door.test.ts).\n *\n * ── It costs nothing when there is nothing to resolve ───────────────────────\n * `resolveUnknownTypes` collects the model's unregistered types first and only wakes a resolver if\n * there are any. A board of plain scene components asks no server anything — every board-opening\n * screen goes through here, so that has to stay true.\n *\n * ── A scene opens even when the figures do not ──────────────────────────────\n * Resolution never throws: a resolver that rejects is reported in `failed`, and a type nobody\n * published stays in `unresolved`. Both draw as stand-ins and are saved back untouched (ADR-0063\n * 결정 1). They are not the same fact, so the warning says which happened to which type — silence\n * would leave \"the server said no\" looking exactly like \"there is no such figure\".\n */\n\n/**\n * Tells whether the caller still wants this scene after the await.\n *\n * The wait makes the caller re-entrant: an element can be detached, or handed a new model, while\n * the types are being fetched. Without this, the late scene overwrites the current one.\n */\nexport type StillWanted = () => boolean\n\nexport async function createResolvedScene(\n options: SceneCreateOptions,\n stillWanted?: StillWanted\n): Promise<ReturnType<typeof create> | null> {\n const { unresolved, failed } = await resolveUnknownTypes(options.model)\n\n if (failed.length > 0 || unresolved.length > 0) {\n const asked = new Set(failed.flatMap(({ types }) => types))\n const reasons = [\n ...failed.map(\n ({ types, error }) => `${types.join(', ')}: ${error instanceof Error ? error.message : String(error)}`\n ),\n ...(unresolved.some(type => !asked.has(type))\n ? [`${unresolved.filter(type => !asked.has(type)).join(', ')}: 발행된 것이 없다`]\n : [])\n ]\n console.warn(`[board] 그리지 못한 type — ${reasons.join(' | ')}`)\n }\n\n if (stillWanted && !stillWanted()) {\n return null\n }\n\n return create(options)\n}\n"]}
1
+ {"version":3,"file":"resolved-scene.js","sourceRoot":"","sources":["../../src/resolved-scene.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAiCpE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA2B,EAC3B,WAAyB;;IAEzB,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3D,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;IACzC,kGAAkG;IAClG,MAAM,OAAO,GAAwC,MAAC,UAAkB,CAAC,OAAO,mCAAI,EAAE,CAAA;IAEtF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,OAAO,GAAG;YACd,GAAG,MAAM,CAAC,GAAG,CACX,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACvG;YACD,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,WAAC,OAAA,GAAG,IAAI,KAAK,MAAA,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mCAAI,UAAU,EAAE,CAAA,EAAA,CAAC;SACvG,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC9D,CAAC;IAED,IAAI,WAAW,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QAClC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;AACxB,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { create, resolveUnknownTypes } from '@hatiolab/things-scene'\nimport type { SceneCreateOptions } from '@hatiolab/things-scene'\n\n/*\n * The one place this package turns a model into a scene.\n *\n * ── Why it is one place ─────────────────────────────────────────────────────\n * `create()` is synchronous and compiles what is registered at that moment, so the types a model\n * names and nobody has registered have to be fetched first (`figure-provider.ts` fetches them).\n * Written at each scene site, that \"first\" is six lines that drift apart, and the seventh site\n * forgets it. So every site in this package calls this function instead, and a test counts that\n * nobody else imports `create` (test/scene-create-single-door.test.ts).\n *\n * ── It costs nothing when there is nothing to resolve ───────────────────────\n * `resolveUnknownTypes` collects the model's unregistered types first and only wakes a resolver if\n * there are any. A board of plain scene components asks no server anything — every board-opening\n * screen goes through here, so that has to stay true.\n *\n * ── A scene opens even when the figures do not ──────────────────────────────\n * Resolution never throws: a resolver that rejects is reported in `failed`, and a type nobody\n * published stays in `unresolved`. Both draw as stand-ins and are saved back untouched (ADR-0063\n * 결정 1). They are not the same fact, so the warning says which happened to which type — silence\n * would leave \"the server said no\" looking exactly like \"there is no such figure\".\n */\n\n/**\n * Tells whether the caller still wants this scene after the await.\n *\n * The wait makes the caller re-entrant: an element can be detached, or handed a new model, while\n * the types are being fetched. Without this, the late scene overwrites the current one.\n */\nexport type StillWanted = () => boolean\n\nexport async function createResolvedScene(\n options: SceneCreateOptions,\n stillWanted?: StillWanted\n): Promise<ReturnType<typeof create> | null> {\n const resolution = await resolveUnknownTypes(options.model)\n const { unresolved, failed } = resolution\n /* The reason a resolver gave for each type it refused (ADR-0114 A3); older scenes report none. */\n const refused: { type: string; message: string }[] = (resolution as any).refused ?? []\n\n if (failed.length > 0 || unresolved.length > 0) {\n const asked = new Set(failed.flatMap(({ types }) => types))\n const said = new Map(refused.map(({ type, message }) => [type, message]))\n const reasons = [\n ...failed.map(\n ({ types, error }) => `${types.join(', ')}: ${error instanceof Error ? error.message : String(error)}`\n ),\n ...unresolved.filter(type => !asked.has(type)).map(type => `${type}: ${said.get(type) ?? '해석되지 않았다'}`)\n ]\n console.warn(`[board] 그리지 못한 type — ${reasons.join(' | ')}`)\n }\n\n if (stillWanted && !stillWanted()) {\n return null\n }\n\n return create(options)\n}\n"]}
@@ -5,6 +5,10 @@ export interface PalletItem {
5
5
  icon: HTMLImageElement;
6
6
  group: string | string[];
7
7
  model: Model;
8
+ /** Why it cannot be placed here. A template with a reason is shown dimmed and does nothing when picked. */
9
+ unavailableReason?: string;
10
+ /** The short mark shown on an unavailable template, such as "format unsupported". */
11
+ unavailableLabel?: string;
8
12
  }
9
13
  export interface Pallet {
10
14
  name: string;
@@ -16,6 +20,10 @@ export type ComponentTemplate = {
16
20
  group: 'line' | 'shape' | 'textAndMedia' | 'chartAndGauge' | 'table' | 'container' | 'dataSource' | 'IoT' | '3D' | 'warehouse' | 'form' | 'etc' | string;
17
21
  icon: any;
18
22
  model: Model;
23
+ /** Why it cannot be placed here. A template with a reason is shown dimmed and does nothing when picked. */
24
+ unavailableReason?: string;
25
+ /** The short mark shown on an unavailable template, such as "format unsupported". */
26
+ unavailableLabel?: string;
19
27
  };
20
28
  export type ComponentGroup = {
21
29
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Model } from '@hatiolab/things-scene'\n\nexport interface PalletItem {\n type: string\n description: string\n icon: HTMLImageElement\n group: string | string[]\n model: Model\n}\n\nexport interface Pallet {\n name: string\n templates: PalletItem[]\n}\n\nexport type ComponentTemplate = {\n type: string\n description: string\n group:\n | 'line'\n | 'shape'\n | 'textAndMedia'\n | 'chartAndGauge'\n | 'table'\n | 'container'\n | 'dataSource'\n | 'IoT'\n | '3D'\n | 'warehouse'\n | 'form'\n | 'etc'\n | string\n icon: any\n model: Model\n}\n\nexport type ComponentGroup = {\n name: string\n description: string\n icon: string\n /* A Material Symbols glyph name for the palette rail; the rail has a default per known group. */\n symbol?: string\n templates: ComponentTemplate[]\n}\n\nexport type Board = {\n id?: string\n name?: string\n description?: string\n model?: any\n groupId?: string\n thumbnail?: string\n}\n\nexport type BoardGroup = {\n id?: string\n name?: string\n description?: string\n}\n\nexport type PlayGroup = {\n id?: string\n name?: string\n description?: string\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Model } from '@hatiolab/things-scene'\n\nexport interface PalletItem {\n type: string\n description: string\n icon: HTMLImageElement\n group: string | string[]\n model: Model\n /** Why it cannot be placed here. A template with a reason is shown dimmed and does nothing when picked. */\n unavailableReason?: string\n /** The short mark shown on an unavailable template, such as \"format unsupported\". */\n unavailableLabel?: string\n}\n\nexport interface Pallet {\n name: string\n templates: PalletItem[]\n}\n\nexport type ComponentTemplate = {\n type: string\n description: string\n group:\n | 'line'\n | 'shape'\n | 'textAndMedia'\n | 'chartAndGauge'\n | 'table'\n | 'container'\n | 'dataSource'\n | 'IoT'\n | '3D'\n | 'warehouse'\n | 'form'\n | 'etc'\n | string\n icon: any\n model: Model\n /** Why it cannot be placed here. A template with a reason is shown dimmed and does nothing when picked. */\n unavailableReason?: string\n /** The short mark shown on an unavailable template, such as \"format unsupported\". */\n unavailableLabel?: string\n}\n\nexport type ComponentGroup = {\n name: string\n description: string\n icon: string\n /* A Material Symbols glyph name for the palette rail; the rail has a default per known group. */\n symbol?: string\n templates: ComponentTemplate[]\n}\n\nexport type Board = {\n id?: string\n name?: string\n description?: string\n model?: any\n groupId?: string\n thumbnail?: string\n}\n\nexport type BoardGroup = {\n id?: string\n name?: string\n description?: string\n}\n\nexport type PlayGroup = {\n id?: string\n name?: string\n description?: string\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import { expect, fixture, html } from '@open-wc/testing';
2
+ import { ComponentMenu } from '../src/modeller/component-toolbar/component-menu.js';
3
+ /**
4
+ * A tray template that cannot be placed here (ADR-0114 P7): shown dimmed with its mark, its reason on hover, and
5
+ * nothing happens when it is picked -- no add mode, no image drag.
6
+ */
7
+ customElements.get('test-component-menu') || customElements.define('test-component-menu', class extends ComponentMenu {
8
+ });
9
+ const group = {
10
+ name: 'figure',
11
+ templates: [
12
+ { type: 'hatiolab.com/ok', description: 'OK figure', icon: '', group: 'figure', model: { type: 'hatiolab.com/ok' } },
13
+ {
14
+ type: 'hatiolab.com/future',
15
+ description: 'Future figure',
16
+ icon: '',
17
+ group: 'figure',
18
+ model: { type: 'hatiolab.com/future' },
19
+ unavailableReason: 'this server cannot read figure-asset-9',
20
+ unavailableLabel: 'format unsupported'
21
+ }
22
+ ]
23
+ };
24
+ async function menuWith(added) {
25
+ const scene = { rootContainer: { trigger: () => { } }, startAddMode: (model) => added.push(model) };
26
+ const menu = (await fixture(html `<test-component-menu .groups=${[group]} .scene=${scene}></test-component-menu>`));
27
+ menu.group = 'figure';
28
+ await menu.updateComplete;
29
+ return menu;
30
+ }
31
+ const itemOf = (menu, type) => menu.renderRoot.querySelector(`[data-type="${type}"]`);
32
+ describe('트레이 — 놓을 수 없는 템플릿', () => {
33
+ it('흐리게 · 표 · 사유를 가진다, 아이콘은 끌리지 않는다', async () => {
34
+ const menu = await menuWith([]);
35
+ const item = itemOf(menu, 'hatiolab.com/future');
36
+ expect(item.hasAttribute('unavailable')).to.equal(true);
37
+ expect(item.getAttribute('aria-disabled')).to.equal('true');
38
+ expect(item.getAttribute('title')).to.equal('this server cannot read figure-asset-9');
39
+ expect(item.querySelector('[mark]').textContent).to.equal('format unsupported');
40
+ expect(item.querySelector('[reason]').textContent).to.equal('this server cannot read figure-asset-9');
41
+ expect(item.querySelector('img').getAttribute('draggable')).to.equal('false');
42
+ expect(getComputedStyle(item).opacity).to.equal('0.5');
43
+ });
44
+ it('★ 고르면 아무 일도 없다 — 놓을 수 있는 것은 추가 모드에 들어간다', async () => {
45
+ const added = [];
46
+ const menu = await menuWith(added);
47
+ itemOf(menu, 'hatiolab.com/future').click();
48
+ expect(added).to.deep.equal([]);
49
+ menu.group = 'figure';
50
+ await menu.updateComplete;
51
+ itemOf(menu, 'hatiolab.com/ok').click();
52
+ expect(added).to.deep.equal([{ type: 'hatiolab.com/ok' }]);
53
+ });
54
+ it('놓을 수 있는 템플릿에는 표 · 사유가 없다', async () => {
55
+ const menu = await menuWith([]);
56
+ const item = itemOf(menu, 'hatiolab.com/ok');
57
+ expect(item.hasAttribute('unavailable')).to.equal(false);
58
+ expect(item.querySelector('[mark]')).to.equal(null);
59
+ });
60
+ });
61
+ //# sourceMappingURL=component-menu.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-menu.test.js","sourceRoot":"","sources":["../../test/component-menu.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,qDAAqD,CAAA;AAEnF;;;GAGG;AACH,cAAc,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,qBAAqB,EAAE,KAAM,SAAQ,aAAa;CAAG,CAAC,CAAA;AAEzH,MAAM,KAAK,GAAG;IACZ,IAAI,EAAE,QAAQ;IACd,SAAS,EAAE;QACT,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE;QACpH;YACE,IAAI,EAAE,qBAAqB;YAC3B,WAAW,EAAE,eAAe;YAC5B,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,KAAK,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE;YACtC,iBAAiB,EAAE,wCAAwC;YAC3D,gBAAgB,EAAE,oBAAoB;SACvC;KACF;CACF,CAAA;AAED,KAAK,UAAU,QAAQ,CAAC,KAAgB;IACtC,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAA;IAC3G,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,CAAA,gCAAgC,CAAC,KAAK,CAAC,WAAW,KAAc,yBAAyB,CAAC,CAAkB,CAAA;IAC5I,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAA;IACrB,MAAM,IAAI,CAAC,cAAc,CAAA;IACzB,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,IAAmB,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,eAAe,IAAI,IAAI,CAAgB,CAAA;AAE3H,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAA;QAChD,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACvD,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAC3D,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAA;QACrF,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;QAChF,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAA;QACtG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAE,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC9E,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,KAAK,GAAc,EAAE,CAAA;QAC3B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;QAElC,MAAM,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC,KAAK,EAAE,CAAA;QAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAE/B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAA;QACrB,MAAM,IAAI,CAAC,cAAc,CAAA;QACzB,MAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,KAAK,EAAE,CAAA;QACvC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAA;QAC5C,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACxD,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect, fixture, html } from '@open-wc/testing'\n\nimport { ComponentMenu } from '../src/modeller/component-toolbar/component-menu.js'\n\n/**\n * A tray template that cannot be placed here (ADR-0114 P7): shown dimmed with its mark, its reason on hover, and\n * nothing happens when it is picked -- no add mode, no image drag.\n */\ncustomElements.get('test-component-menu') || customElements.define('test-component-menu', class extends ComponentMenu {})\n\nconst group = {\n name: 'figure',\n templates: [\n { type: 'hatiolab.com/ok', description: 'OK figure', icon: '', group: 'figure', model: { type: 'hatiolab.com/ok' } },\n {\n type: 'hatiolab.com/future',\n description: 'Future figure',\n icon: '',\n group: 'figure',\n model: { type: 'hatiolab.com/future' },\n unavailableReason: 'this server cannot read figure-asset-9',\n unavailableLabel: 'format unsupported'\n }\n ]\n}\n\nasync function menuWith(added: unknown[]) {\n const scene = { rootContainer: { trigger: () => {} }, startAddMode: (model: unknown) => added.push(model) }\n const menu = (await fixture(html`<test-component-menu .groups=${[group]} .scene=${scene as never}></test-component-menu>`)) as ComponentMenu\n menu.group = 'figure'\n await menu.updateComplete\n return menu\n}\n\nconst itemOf = (menu: ComponentMenu, type: string) => menu.renderRoot.querySelector(`[data-type=\"${type}\"]`) as HTMLElement\n\ndescribe('트레이 — 놓을 수 없는 템플릿', () => {\n it('흐리게 · 표 · 사유를 가진다, 아이콘은 끌리지 않는다', async () => {\n const menu = await menuWith([])\n const item = itemOf(menu, 'hatiolab.com/future')\n expect(item.hasAttribute('unavailable')).to.equal(true)\n expect(item.getAttribute('aria-disabled')).to.equal('true')\n expect(item.getAttribute('title')).to.equal('this server cannot read figure-asset-9')\n expect(item.querySelector('[mark]')!.textContent).to.equal('format unsupported')\n expect(item.querySelector('[reason]')!.textContent).to.equal('this server cannot read figure-asset-9')\n expect(item.querySelector('img')!.getAttribute('draggable')).to.equal('false')\n expect(getComputedStyle(item).opacity).to.equal('0.5')\n })\n\n it('★ 고르면 아무 일도 없다 — 놓을 수 있는 것은 추가 모드에 들어간다', async () => {\n const added: unknown[] = []\n const menu = await menuWith(added)\n\n itemOf(menu, 'hatiolab.com/future').click()\n expect(added).to.deep.equal([])\n\n menu.group = 'figure'\n await menu.updateComplete\n itemOf(menu, 'hatiolab.com/ok').click()\n expect(added).to.deep.equal([{ type: 'hatiolab.com/ok' }])\n })\n\n it('놓을 수 있는 템플릿에는 표 · 사유가 없다', async () => {\n const menu = await menuWith([])\n const item = itemOf(menu, 'hatiolab.com/ok')\n expect(item.hasAttribute('unavailable')).to.equal(false)\n expect(item.querySelector('[mark]')).to.equal(null)\n })\n})\n"]}
@@ -1,8 +1,8 @@
1
1
  import { expect } from '@open-wc/testing';
2
2
  import { Component, hasFigure, registerTypeResolver, resetFigures, resolveUnknownTypes } from '@hatiolab/things-scene';
3
- import { createFigureResolver } from '../src/figure-provider.js';
3
+ import { createFigureResolver, FIGURE_TYPE_MAP_CHANGED, figureMapReleaseOfPage, resetFigureMapPage, setFigureMapChoice } from '../src/figure-provider.js';
4
4
  /**
5
- * The path a published figure takes to a board (ADR-0063 결정 2).
5
+ * The path a figure takes to a board (ADR-0063 결정 2, ADR-0114): one batch question by full name.
6
6
  *
7
7
  * things-scene holds the seat and knows nothing about figures; this package fills it. What is
8
8
  * checked here is the part that belongs to the board: which names are asked about, what happens to
@@ -29,11 +29,17 @@ const figureAssetOf = (type) => ({
29
29
  { id: 'a0', unit: 'deg', value: 0 }
30
30
  ],
31
31
  nodes: [
32
- { id: 'body.shape', op: 'box-shape@1', args: ['w', 'w', 'w'], outputs: { shape: 'body.s' }, params: { frame: 'body.local' } },
32
+ {
33
+ id: 'body.shape',
34
+ op: 'extrude@1',
35
+ args: ['zero', 'w', 'w', 'w'],
36
+ outputs: { shape: 'body.s' },
37
+ params: { frame: 'body.local', axis: 'y', section: 'rectangle' }
38
+ },
33
39
  {
34
40
  id: 'body.pose',
35
41
  op: 'rigid@1',
36
- args: ['zero', 'half', 'zero', 'a0', 'a0', 'a0'],
42
+ args: ['zero', 'zero', 'zero', 'a0', 'a0', 'a0'],
37
43
  outputs: { pose: 'body.p' },
38
44
  params: { from: 'body.local', to: 'asset' }
39
45
  },
@@ -51,138 +57,141 @@ const figureAssetOf = (type) => ({
51
57
  placement: 'floor'
52
58
  }
53
59
  });
54
- const figurePayloadOf = (type) => ({ type, asset: figureAssetOf(type) });
55
- /** Records what was asked for, and answers from a table. */
56
- function fetcherOf(published, failing = []) {
60
+ /** A server that answers from a table, from one map release, and records each question. */
61
+ function serverOf(published, release = { version: 1, revision: 1 }, refusals = {}) {
57
62
  const asked = [];
63
+ const state = { release };
58
64
  return {
59
65
  asked,
60
- fetch: async (type) => {
61
- var _a;
62
- asked.push(type);
63
- if (failing.includes(type)) {
64
- throw new Error(`no route to the door (${type})`);
65
- }
66
- return ((_a = published[type]) !== null && _a !== void 0 ? _a : null);
66
+ state,
67
+ fetch: async (types, map) => {
68
+ asked.push({ types: [...types], map });
69
+ const items = types.filter(type => published[type]).map(type => ({ type, ref: `${type}@1`, asset: published[type] }));
70
+ const refused = types
71
+ .filter(type => !published[type])
72
+ .map(type => { var _a; return ({ type, code: 'figure-not-in-type-map', message: (_a = refusals[type]) !== null && _a !== void 0 ? _a : `${type} is not in the type map` }); });
73
+ return { release: state.release, items, refused };
67
74
  }
68
75
  };
69
76
  }
70
- describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () => {
77
+ const name = (label) => `hatiolab.com/${label}-${Math.random().toString(36).slice(2, 8)}`;
78
+ describe('figure 공급자 — 보드가 Figure 를 정식 이름으로 한 번에 묻는다', () => {
71
79
  afterEach(() => {
72
80
  resetFigures();
81
+ resetFigureMapPage();
73
82
  });
74
- it('대문자 이름만 서버에 묻는다 — 씬의 기본 type 과 오타는 문을 지나지 않는다', async () => {
75
- const { asked, fetch } = fetcherOf({ EQ_MIXER: figurePayloadOf('EQ_MIXER') });
76
- await createFigureResolver(fetch)(['EQ_MIXER', 'rect', 'Conveyor', 'text', 'VEH_AGV_01']);
77
- expect(asked).to.deep.equal(['EQ_MIXER', 'VEH_AGV_01']);
83
+ it('등록되지 않은 type 을 대소문자와 관계없이 한 번에 묻는다 — 이미 등록된 것은 묻지 않는다', async () => {
84
+ const mixer = name('eq-mixer');
85
+ const { asked, fetch } = serverOf({ [mixer]: figureAssetOf(mixer) });
86
+ await createFigureResolver(fetch)([mixer, 'rect', 'Conveyor', 'text', 'VEH_AGV_01']);
87
+ expect(asked).to.deep.equal([{ types: [mixer, 'Conveyor', 'VEH_AGV_01'], map: 'ACTIVE' }]);
78
88
  });
79
- it('이미 등록된 type 은 묻지 않는다 — 그리고 있는 컴포넌트를 figure 가 덮지 않는다', async () => {
80
- const { asked, fetch } = fetcherOf({ EQ_TAKEN: figurePayloadOf('EQ_TAKEN') });
81
- /* Somebody else already draws this name — a plugin, an app's own component. */
82
- Component.register('EQ_TAKEN', class Taken extends Component {
89
+ it('이미 등록된 이름은 묻지 않고, figure 가 그 컴포넌트를 덮지 않는다', async () => {
90
+ const taken = name('taken');
91
+ const { asked, fetch } = serverOf({ [taken]: figureAssetOf(taken) });
92
+ Component.register(taken, class Taken extends Component {
83
93
  });
84
- await createFigureResolver(fetch)(['EQ_TAKEN']);
94
+ await createFigureResolver(fetch)([taken]);
85
95
  expect(asked).to.deep.equal([]);
86
- expect(hasFigure('EQ_TAKEN')).to.equal(false);
96
+ expect(hasFigure(taken)).to.equal(false);
87
97
  });
88
- it('받은 자산을 등록한다 — 도면은 type 만 적으면 된다', async () => {
89
- const { fetch } = fetcherOf({ EQ_REGISTERED: figurePayloadOf('EQ_REGISTERED') });
90
- await createFigureResolver(fetch)(['EQ_REGISTERED']);
91
- expect(hasFigure('EQ_REGISTERED')).to.equal(true);
92
- /* The component type is registered with it — the model writes `type` and nothing else. */
93
- expect(Component.register('EQ_REGISTERED')).to.not.equal(undefined);
98
+ it('받은 자산을 물은 이름으로 등록한다', async () => {
99
+ const conveyor = name('conveyor');
100
+ const { fetch } = serverOf({ [conveyor]: figureAssetOf(conveyor) });
101
+ await createFigureResolver(fetch)([conveyor]);
102
+ expect(hasFigure(conveyor)).to.equal(true);
103
+ expect(Component.register(conveyor)).to.not.equal(undefined);
94
104
  });
95
- it('자산은 씬의 문으로 등록한다 — 보드는 그것을 읽지 않고 씬에 넘긴다', async () => {
96
- const { fetch } = fetcherOf({ EQ: figurePayloadOf('EQ') });
97
- await createFigureResolver(fetch)(['EQ']);
98
- expect(hasFigure('EQ')).to.equal(true);
99
- /* 도면은 type 하나만 적으면 그려진다. */
100
- expect(Component.register('EQ')).to.not.equal(undefined);
105
+ it('★ 그리지 못한 이름은 서버가 준 이유를 그대로 돌려준다 — 읽을 수 없는 자산도 그 이름만 이유를 받는다', async () => {
106
+ const good = name('good');
107
+ const broken = name('broken');
108
+ const missing = name('missing');
109
+ const brokenAsset = figureAssetOf(broken);
110
+ brokenAsset.appearance = [];
111
+ const { fetch } = serverOf({ [good]: figureAssetOf(good), [broken]: brokenAsset }, { version: 1, revision: 1 }, { [missing]: '타입 맵에 없습니다' });
112
+ const answer = await createFigureResolver(fetch)([good, broken, missing]);
113
+ expect(hasFigure(good)).to.equal(true);
114
+ expect(hasFigure(broken)).to.equal(false);
115
+ expect(answer.refused.map(r => r.type)).to.deep.equal([missing, broken]);
116
+ expect(answer.refused[0].message).to.equal('타입 맵에 없습니다');
101
117
  });
102
- it('자산이 없는 답은 그 type 만 실패로 남는다 — 옛 청사진을 그리지 않는다', async () => {
103
- const { fetch } = fetcherOf({ EQ_NEW: figurePayloadOf('EQ_NEW'), EQ_OLD: { version: 1, type: 'EQ_OLD', groups: [] } });
118
+ it('물을 수 없으면 거절한다 — 씬은 실패로 모으고 보드는 열린다', async () => {
119
+ const fetch = async () => {
120
+ throw new Error('no route to the door');
121
+ };
104
122
  let message = '';
105
123
  try {
106
- await createFigureResolver(fetch)(['EQ_NEW', 'EQ_OLD']);
124
+ await createFigureResolver(fetch)([name('x')]);
107
125
  }
108
126
  catch (error) {
109
127
  message = error instanceof Error ? error.message : String(error);
110
128
  }
111
- expect(message).to.contain('not a figure asset: EQ_OLD');
112
- expect(hasFigure('EQ_NEW')).to.equal(true);
113
- expect(hasFigure('EQ_OLD')).to.equal(false);
129
+ expect(message).to.contain('no route to the door');
114
130
  });
115
- it('읽을 수 없는 자산은 그 type 만 실패로 남는다', async () => {
116
- const broken = figurePayloadOf('EQ_ASSET_BROKEN');
117
- broken.asset.appearance = [];
118
- const { fetch } = fetcherOf({ EQ_BESIDE: figurePayloadOf('EQ_BESIDE'), EQ_ASSET_BROKEN: broken });
119
- let message = '';
131
+ it('★ 페이지는 처음 받은 맵 릴리스를 기억하고, 후보의 revision 이 바뀐 답은 등록하지 않는다', async () => {
132
+ const first = name('first');
133
+ const later = name('later');
134
+ const server = serverOf({ [first]: figureAssetOf(first), [later]: figureAssetOf(later) }, { version: 2, revision: 3 });
135
+ const resolver = createFigureResolver(server.fetch);
136
+ setFigureMapChoice('CANDIDATE');
137
+ await resolver([first]);
138
+ expect(figureMapReleaseOfPage()).to.deep.equal({ map: 'CANDIDATE', version: 2, revision: 3 });
139
+ let changed = null;
140
+ const listen = (e) => (changed = e.detail);
141
+ window.addEventListener(FIGURE_TYPE_MAP_CHANGED, listen);
120
142
  try {
121
- await createFigureResolver(fetch)(['EQ_BESIDE', 'EQ_ASSET_BROKEN']);
143
+ server.state.release = { version: 2, revision: 4 };
144
+ const answer = await resolver([later]);
145
+ expect(hasFigure(later)).to.equal(false);
146
+ expect(answer.refused.map(r => r.type)).to.deep.equal([later]);
147
+ expect(changed).to.deep.equal({ was: { map: 'CANDIDATE', version: 2, revision: 3 }, now: { map: 'CANDIDATE', version: 2, revision: 4 } });
148
+ expect(figureMapReleaseOfPage()).to.deep.equal({ map: 'CANDIDATE', version: 2, revision: 3 });
122
149
  }
123
- catch (error) {
124
- message = error instanceof Error ? error.message : String(error);
150
+ finally {
151
+ window.removeEventListener(FIGURE_TYPE_MAP_CHANGED, listen);
125
152
  }
126
- expect(message).to.contain('EQ_ASSET_BROKEN');
127
- expect(hasFigure('EQ_BESIDE')).to.equal(true);
128
- expect(hasFigure('EQ_ASSET_BROKEN')).to.equal(false);
129
153
  });
130
- it('발행된 것이 없으면 조용히 자리표시로 남는다 — 거절이 아니다', async () => {
131
- const { fetch } = fetcherOf({});
132
- let rejected = false;
133
- try {
134
- await createFigureResolver(fetch)(['EQ_NOT_PUBLISHED']);
135
- }
136
- catch (_a) {
137
- rejected = true;
138
- }
139
- expect(rejected).to.equal(false);
140
- expect(hasFigure('EQ_NOT_PUBLISHED')).to.equal(false);
154
+ it('★ 활성 맵과 후보 맵의 등록을 한 페이지에서 섞지 않는다', async () => {
155
+ const active = name('active');
156
+ const preview = name('preview');
157
+ const server = serverOf({ [active]: figureAssetOf(active), [preview]: figureAssetOf(preview) }, { version: 1, revision: 1 });
158
+ const resolver = createFigureResolver(server.fetch);
159
+ await resolver([active]);
160
+ expect(figureMapReleaseOfPage()).to.deep.equal({ map: 'ACTIVE', version: 1, revision: 1 });
161
+ setFigureMapChoice('CANDIDATE');
162
+ const answer = await resolver([preview]);
163
+ expect(server.asked.map(a => a.map)).to.deep.equal(['ACTIVE', 'CANDIDATE']);
164
+ expect(hasFigure(preview)).to.equal(false);
165
+ expect(answer.refused.map(r => r.type)).to.deep.equal([preview]);
141
166
  });
142
- it('물을 수 없으면 거절한다. 그때도 답을 받은 것은 등록된다', async () => {
143
- const { fetch } = fetcherOf({ EQ_BESIDE_BROKEN: figurePayloadOf('EQ_BESIDE_BROKEN') }, ['EQ_BROKEN']);
144
- let message = '';
145
- try {
146
- await createFigureResolver(fetch)(['EQ_BESIDE_BROKEN', 'EQ_BROKEN']);
147
- }
148
- catch (error) {
149
- message = error instanceof Error ? error.message : String(error);
150
- }
151
- expect(message).to.contain('EQ_BROKEN');
152
- expect(message).to.not.contain('EQ_BESIDE_BROKEN');
153
- expect(hasFigure('EQ_BESIDE_BROKEN')).to.equal(true);
154
- });
155
- it('읽을 수 없는 자산은 그 type 만 실패로 남는다 — 다른 type 을 막지 않는다', async () => {
156
- const { fetch } = fetcherOf({
157
- EQ_BESIDE_MALFORMED: figurePayloadOf('EQ_BESIDE_MALFORMED'),
158
- EQ_MALFORMED: { type: 'EQ_MALFORMED', asset: { version: 'figure-asset-1' } }
159
- });
160
- let message = '';
161
- try {
162
- await createFigureResolver(fetch)(['EQ_BESIDE_MALFORMED', 'EQ_MALFORMED']);
163
- }
164
- catch (error) {
165
- message = error instanceof Error ? error.message : String(error);
166
- }
167
- expect(message).to.contain('EQ_MALFORMED');
168
- expect(hasFigure('EQ_BESIDE_MALFORMED')).to.equal(true);
169
- expect(hasFigure('EQ_MALFORMED')).to.equal(false);
167
+ it('맵 릴리스가 없는 서버(저작 서버의 최신 정책)는 기억하지 않는다', async () => {
168
+ const a = name('a');
169
+ const b = name('b');
170
+ const server = serverOf({ [a]: figureAssetOf(a), [b]: figureAssetOf(b) }, null);
171
+ const resolver = createFigureResolver(server.fetch);
172
+ await resolver([a]);
173
+ await resolver([b]);
174
+ expect(figureMapReleaseOfPage()).to.equal(null);
175
+ expect(hasFigure(a)).to.equal(true);
176
+ expect(hasFigure(b)).to.equal(true);
170
177
  });
171
- it('씬의 자리에 앉아 동작한다 — 모델의 모르는 type 이 해석 뒤에 남지 않는다', async () => {
172
- const { fetch } = fetcherOf({ EQ_ON_A_BOARD: figurePayloadOf('EQ_ON_A_BOARD') });
178
+ it('씬의 자리에 앉아 동작한다 — 받은 것은 그려지고 나머지는 자리표시로 남는다', async () => {
179
+ const onBoard = name('on-board');
180
+ const never = name('never');
181
+ const { fetch } = serverOf({ [onBoard]: figureAssetOf(onBoard) });
173
182
  const takeBack = registerTypeResolver(createFigureResolver(fetch));
174
183
  try {
175
184
  const model = {
176
185
  type: 'container',
177
186
  components: [
178
- { type: 'EQ_ON_A_BOARD', left: 0, top: 0, width: 100, height: 100 },
179
- { type: 'EQ_NEVER_PUBLISHED', left: 0, top: 0, width: 100, height: 100 }
187
+ { type: onBoard, left: 0, top: 0, width: 100, height: 100 },
188
+ { type: never, left: 0, top: 0, width: 100, height: 100 }
180
189
  ]
181
190
  };
182
191
  const resolution = await resolveUnknownTypes(model);
183
- expect(resolution.unresolved).to.deep.equal(['EQ_NEVER_PUBLISHED']);
192
+ expect(resolution.unresolved).to.deep.equal([never]);
184
193
  expect(resolution.failed).to.deep.equal([]);
185
- expect(hasFigure('EQ_ON_A_BOARD')).to.equal(true);
194
+ expect(hasFigure(onBoard)).to.equal(true);
186
195
  }
187
196
  finally {
188
197
  takeBack();