@operato/board 10.29.8 → 10.29.9
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/CHANGELOG.md +19 -0
- package/coverage/lcov-report/index.html +25 -25
- package/coverage/lcov.info +211 -153
- package/dist/src/figure-provider.d.ts +52 -16
- package/dist/src/figure-provider.js +70 -65
- package/dist/src/figure-provider.js.map +1 -1
- package/dist/src/modeller/component-toolbar/component-menu.js +3 -1
- package/dist/src/modeller/component-toolbar/component-menu.js.map +1 -1
- package/dist/src/ox-board-modeller.d.ts +5 -0
- package/dist/src/ox-board-modeller.js +7 -5
- package/dist/src/ox-board-modeller.js.map +1 -1
- package/dist/src/resolved-scene.js +7 -4
- package/dist/src/resolved-scene.js.map +1 -1
- package/dist/test/figure-provider.test.js +100 -97
- package/dist/test/figure-provider.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/test/figure-provider.test.ts +115 -105
- package/translations/en.json +2 -1
- package/translations/ja.json +2 -1
- package/translations/ko.json +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@operato/board",
|
|
3
|
-
"version": "10.29.
|
|
3
|
+
"version": "10.29.9",
|
|
4
4
|
"description": "Webcomponent for board following open-wc recommendations",
|
|
5
5
|
"author": "heartyoh",
|
|
6
6
|
"type": "module",
|
|
@@ -120,18 +120,18 @@
|
|
|
120
120
|
"dependencies": {
|
|
121
121
|
"@material/web": "^2.0.0",
|
|
122
122
|
"@open-wc/scoped-elements": "^2.1.3",
|
|
123
|
-
"@operato/app": "^10.29.
|
|
124
|
-
"@operato/data-grist": "^10.29.
|
|
125
|
-
"@operato/font": "^10.29.
|
|
123
|
+
"@operato/app": "^10.29.9",
|
|
124
|
+
"@operato/data-grist": "^10.29.9",
|
|
125
|
+
"@operato/font": "^10.29.9",
|
|
126
126
|
"@operato/graphql": "^10.29.5",
|
|
127
127
|
"@operato/i18n": "^10.29.1",
|
|
128
|
-
"@operato/input": "^10.29.
|
|
129
|
-
"@operato/layout": "^10.29.
|
|
130
|
-
"@operato/markdown": "^10.29.
|
|
131
|
-
"@operato/popup": "^10.29.
|
|
132
|
-
"@operato/property-editor": "^10.29.
|
|
133
|
-
"@operato/property-panel": "^10.29.
|
|
134
|
-
"@operato/styles": "^10.29.
|
|
128
|
+
"@operato/input": "^10.29.9",
|
|
129
|
+
"@operato/layout": "^10.29.9",
|
|
130
|
+
"@operato/markdown": "^10.29.9",
|
|
131
|
+
"@operato/popup": "^10.29.9",
|
|
132
|
+
"@operato/property-editor": "^10.29.9",
|
|
133
|
+
"@operato/property-panel": "^10.29.9",
|
|
134
|
+
"@operato/styles": "^10.29.9",
|
|
135
135
|
"@operato/utils": "^10.29.1",
|
|
136
136
|
"@types/file-saver": "^2.0.4",
|
|
137
137
|
"@types/sortablejs": "^1.10.7",
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"devDependencies": {
|
|
145
145
|
"@custom-elements-manifest/analyzer": "^0.10.0",
|
|
146
146
|
"@hatiolab/prettier-config": "^1.0.0",
|
|
147
|
-
"@hatiolab/things-scene": "^10.1.
|
|
147
|
+
"@hatiolab/things-scene": "^10.1.74",
|
|
148
148
|
"@open-wc/eslint-config": "^12.0.3",
|
|
149
149
|
"@open-wc/testing": "^4.0.0",
|
|
150
150
|
"@rollup/plugin-image": "^3.0.3",
|
|
@@ -180,5 +180,5 @@
|
|
|
180
180
|
"prettier --write"
|
|
181
181
|
]
|
|
182
182
|
},
|
|
183
|
-
"gitHead": "
|
|
183
|
+
"gitHead": "24e4809ab0168eef48792291f72b11f75d8179ad"
|
|
184
184
|
}
|
|
@@ -2,10 +2,17 @@ import { expect } from '@open-wc/testing'
|
|
|
2
2
|
|
|
3
3
|
import { Component, hasFigure, registerTypeResolver, resetFigures, resolveUnknownTypes } from '@hatiolab/things-scene'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createFigureResolver,
|
|
7
|
+
FIGURE_TYPE_MAP_CHANGED,
|
|
8
|
+
figureMapReleaseOfPage,
|
|
9
|
+
resetFigureMapPage,
|
|
10
|
+
setFigureMapChoice,
|
|
11
|
+
type FigureBlueprintsAnswer
|
|
12
|
+
} from '../src/figure-provider.js'
|
|
6
13
|
|
|
7
14
|
/**
|
|
8
|
-
* The path a
|
|
15
|
+
* The path a figure takes to a board (ADR-0063 결정 2, ADR-0114): one batch question by full name.
|
|
9
16
|
*
|
|
10
17
|
* things-scene holds the seat and knows nothing about figures; this package fills it. What is
|
|
11
18
|
* checked here is the part that belongs to the board: which names are asked about, what happens to
|
|
@@ -56,166 +63,169 @@ const figureAssetOf = (type: string) => ({
|
|
|
56
63
|
}
|
|
57
64
|
})
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
/** A server that answers from a table, from one map release, and records each question. */
|
|
67
|
+
function serverOf(
|
|
68
|
+
published: Record<string, unknown>,
|
|
69
|
+
release: { version: number; revision: number } | null = { version: 1, revision: 1 },
|
|
70
|
+
refusals: Record<string, string> = {}
|
|
71
|
+
) {
|
|
72
|
+
const asked: { types: string[]; map: string }[] = []
|
|
73
|
+
const state = { release }
|
|
65
74
|
return {
|
|
66
75
|
asked,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
state,
|
|
77
|
+
fetch: async (types: readonly string[], map: string): Promise<FigureBlueprintsAnswer> => {
|
|
78
|
+
asked.push({ types: [...types], map })
|
|
79
|
+
const items = types.filter(type => published[type]).map(type => ({ type, ref: `${type}@1`, asset: published[type] }))
|
|
80
|
+
const refused = types
|
|
81
|
+
.filter(type => !published[type])
|
|
82
|
+
.map(type => ({ type, code: 'figure-not-in-type-map', message: refusals[type] ?? `${type} is not in the type map` }))
|
|
83
|
+
return { release: state.release, items, refused }
|
|
73
84
|
}
|
|
74
85
|
}
|
|
75
86
|
}
|
|
76
87
|
|
|
77
|
-
|
|
88
|
+
const name = (label: string) => `hatiolab.com/${label}-${Math.random().toString(36).slice(2, 8)}`
|
|
89
|
+
|
|
90
|
+
describe('figure 공급자 — 보드가 Figure 를 정식 이름으로 한 번에 묻는다', () => {
|
|
78
91
|
afterEach(() => {
|
|
79
92
|
resetFigures()
|
|
93
|
+
resetFigureMapPage()
|
|
80
94
|
})
|
|
81
95
|
|
|
82
|
-
it('
|
|
83
|
-
const
|
|
96
|
+
it('등록되지 않은 type 을 대소문자와 관계없이 한 번에 묻는다 — 이미 등록된 것은 묻지 않는다', async () => {
|
|
97
|
+
const mixer = name('eq-mixer')
|
|
98
|
+
const { asked, fetch } = serverOf({ [mixer]: figureAssetOf(mixer) })
|
|
84
99
|
|
|
85
|
-
await createFigureResolver(fetch)([
|
|
100
|
+
await createFigureResolver(fetch)([mixer, 'rect', 'Conveyor', 'text', 'VEH_AGV_01'])
|
|
86
101
|
|
|
87
|
-
expect(asked).to.deep.equal(['
|
|
102
|
+
expect(asked).to.deep.equal([{ types: [mixer, 'Conveyor', 'VEH_AGV_01'], map: 'ACTIVE' }])
|
|
88
103
|
})
|
|
89
104
|
|
|
90
|
-
it('이미 등록된
|
|
91
|
-
const
|
|
105
|
+
it('이미 등록된 이름은 묻지 않고, figure 가 그 컴포넌트를 덮지 않는다', async () => {
|
|
106
|
+
const taken = name('taken')
|
|
107
|
+
const { asked, fetch } = serverOf({ [taken]: figureAssetOf(taken) })
|
|
108
|
+
Component.register(taken, class Taken extends Component {} as never)
|
|
92
109
|
|
|
93
|
-
|
|
94
|
-
Component.register('EQ_TAKEN', class Taken extends Component {} as never)
|
|
95
|
-
|
|
96
|
-
await createFigureResolver(fetch)(['EQ_TAKEN'])
|
|
110
|
+
await createFigureResolver(fetch)([taken])
|
|
97
111
|
|
|
98
112
|
expect(asked).to.deep.equal([])
|
|
99
|
-
expect(hasFigure(
|
|
113
|
+
expect(hasFigure(taken)).to.equal(false)
|
|
100
114
|
})
|
|
101
115
|
|
|
102
|
-
it('받은 자산을
|
|
103
|
-
const
|
|
116
|
+
it('받은 자산을 물은 이름으로 등록한다', async () => {
|
|
117
|
+
const conveyor = name('conveyor')
|
|
118
|
+
const { fetch } = serverOf({ [conveyor]: figureAssetOf(conveyor) })
|
|
104
119
|
|
|
105
|
-
await createFigureResolver(fetch)([
|
|
120
|
+
await createFigureResolver(fetch)([conveyor])
|
|
106
121
|
|
|
107
|
-
expect(hasFigure(
|
|
108
|
-
|
|
109
|
-
expect(Component.register('EQ_REGISTERED')).to.not.equal(undefined)
|
|
122
|
+
expect(hasFigure(conveyor)).to.equal(true)
|
|
123
|
+
expect(Component.register(conveyor)).to.not.equal(undefined)
|
|
110
124
|
})
|
|
111
125
|
|
|
112
|
-
it('
|
|
113
|
-
const
|
|
126
|
+
it('★ 그리지 못한 이름은 서버가 준 이유를 그대로 돌려준다 — 읽을 수 없는 자산도 그 이름만 이유를 받는다', async () => {
|
|
127
|
+
const good = name('good')
|
|
128
|
+
const broken = name('broken')
|
|
129
|
+
const missing = name('missing')
|
|
130
|
+
const brokenAsset = figureAssetOf(broken)
|
|
131
|
+
brokenAsset.appearance = []
|
|
132
|
+
const { fetch } = serverOf({ [good]: figureAssetOf(good), [broken]: brokenAsset }, { version: 1, revision: 1 }, { [missing]: '타입 맵에 없습니다' })
|
|
114
133
|
|
|
115
|
-
await createFigureResolver(fetch)([
|
|
134
|
+
const answer = await createFigureResolver(fetch)([good, broken, missing])
|
|
116
135
|
|
|
117
|
-
expect(hasFigure(
|
|
118
|
-
|
|
119
|
-
expect(
|
|
136
|
+
expect(hasFigure(good)).to.equal(true)
|
|
137
|
+
expect(hasFigure(broken)).to.equal(false)
|
|
138
|
+
expect(answer!.refused.map(r => r.type)).to.deep.equal([missing, broken])
|
|
139
|
+
expect(answer!.refused[0].message).to.equal('타입 맵에 없습니다')
|
|
120
140
|
})
|
|
121
141
|
|
|
122
|
-
it('
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
let message = ''
|
|
126
|
-
try {
|
|
127
|
-
await createFigureResolver(fetch)(['EQ_NEW', 'EQ_OLD'])
|
|
128
|
-
} catch (error) {
|
|
129
|
-
message = error instanceof Error ? error.message : String(error)
|
|
142
|
+
it('물을 수 없으면 거절한다 — 씬은 실패로 모으고 보드는 열린다', async () => {
|
|
143
|
+
const fetch = async () => {
|
|
144
|
+
throw new Error('no route to the door')
|
|
130
145
|
}
|
|
131
|
-
|
|
132
|
-
expect(message).to.contain('not a figure asset: EQ_OLD')
|
|
133
|
-
expect(hasFigure('EQ_NEW')).to.equal(true)
|
|
134
|
-
expect(hasFigure('EQ_OLD')).to.equal(false)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
it('읽을 수 없는 자산은 그 type 만 실패로 남는다', async () => {
|
|
138
|
-
const broken = figurePayloadOf('EQ_ASSET_BROKEN')
|
|
139
|
-
broken.asset.appearance = []
|
|
140
|
-
const { fetch } = fetcherOf({ EQ_BESIDE: figurePayloadOf('EQ_BESIDE'), EQ_ASSET_BROKEN: broken })
|
|
141
|
-
|
|
142
146
|
let message = ''
|
|
143
147
|
try {
|
|
144
|
-
await createFigureResolver(fetch)(['
|
|
148
|
+
await createFigureResolver(fetch as never)([name('x')])
|
|
145
149
|
} catch (error) {
|
|
146
150
|
message = error instanceof Error ? error.message : String(error)
|
|
147
151
|
}
|
|
148
|
-
|
|
149
|
-
expect(message).to.contain('EQ_ASSET_BROKEN')
|
|
150
|
-
expect(hasFigure('EQ_BESIDE')).to.equal(true)
|
|
151
|
-
expect(hasFigure('EQ_ASSET_BROKEN')).to.equal(false)
|
|
152
|
+
expect(message).to.contain('no route to the door')
|
|
152
153
|
})
|
|
153
154
|
|
|
154
|
-
it('
|
|
155
|
-
const
|
|
155
|
+
it('★ 페이지는 처음 받은 맵 릴리스를 기억하고, 후보의 revision 이 바뀐 답은 등록하지 않는다', async () => {
|
|
156
|
+
const first = name('first')
|
|
157
|
+
const later = name('later')
|
|
158
|
+
const server = serverOf({ [first]: figureAssetOf(first), [later]: figureAssetOf(later) }, { version: 2, revision: 3 })
|
|
159
|
+
const resolver = createFigureResolver(server.fetch)
|
|
160
|
+
setFigureMapChoice('CANDIDATE')
|
|
161
|
+
|
|
162
|
+
await resolver([first])
|
|
163
|
+
expect(figureMapReleaseOfPage()).to.deep.equal({ map: 'CANDIDATE', version: 2, revision: 3 })
|
|
156
164
|
|
|
157
|
-
let
|
|
165
|
+
let changed: any = null
|
|
166
|
+
const listen = (e: Event) => (changed = (e as CustomEvent).detail)
|
|
167
|
+
window.addEventListener(FIGURE_TYPE_MAP_CHANGED, listen)
|
|
158
168
|
try {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
169
|
+
server.state.release = { version: 2, revision: 4 }
|
|
170
|
+
const answer = await resolver([later])
|
|
171
|
+
expect(hasFigure(later)).to.equal(false)
|
|
172
|
+
expect(answer!.refused.map(r => r.type)).to.deep.equal([later])
|
|
173
|
+
expect(changed).to.deep.equal({ was: { map: 'CANDIDATE', version: 2, revision: 3 }, now: { map: 'CANDIDATE', version: 2, revision: 4 } })
|
|
174
|
+
expect(figureMapReleaseOfPage()).to.deep.equal({ map: 'CANDIDATE', version: 2, revision: 3 })
|
|
175
|
+
} finally {
|
|
176
|
+
window.removeEventListener(FIGURE_TYPE_MAP_CHANGED, listen)
|
|
162
177
|
}
|
|
163
|
-
|
|
164
|
-
expect(rejected).to.equal(false)
|
|
165
|
-
expect(hasFigure('EQ_NOT_PUBLISHED')).to.equal(false)
|
|
166
178
|
})
|
|
167
179
|
|
|
168
|
-
it('
|
|
169
|
-
const
|
|
180
|
+
it('★ 활성 맵과 후보 맵의 등록을 한 페이지에서 섞지 않는다', async () => {
|
|
181
|
+
const active = name('active')
|
|
182
|
+
const preview = name('preview')
|
|
183
|
+
const server = serverOf({ [active]: figureAssetOf(active), [preview]: figureAssetOf(preview) }, { version: 1, revision: 1 })
|
|
184
|
+
const resolver = createFigureResolver(server.fetch)
|
|
170
185
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
186
|
+
await resolver([active])
|
|
187
|
+
expect(figureMapReleaseOfPage()).to.deep.equal({ map: 'ACTIVE', version: 1, revision: 1 })
|
|
188
|
+
|
|
189
|
+
setFigureMapChoice('CANDIDATE')
|
|
190
|
+
const answer = await resolver([preview])
|
|
177
191
|
|
|
178
|
-
expect(
|
|
179
|
-
expect(
|
|
180
|
-
expect(
|
|
192
|
+
expect(server.asked.map(a => a.map)).to.deep.equal(['ACTIVE', 'CANDIDATE'])
|
|
193
|
+
expect(hasFigure(preview)).to.equal(false)
|
|
194
|
+
expect(answer!.refused.map(r => r.type)).to.deep.equal([preview])
|
|
181
195
|
})
|
|
182
196
|
|
|
183
|
-
it('
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
197
|
+
it('맵 릴리스가 없는 서버(저작 서버의 최신 정책)는 기억하지 않는다', async () => {
|
|
198
|
+
const a = name('a')
|
|
199
|
+
const b = name('b')
|
|
200
|
+
const server = serverOf({ [a]: figureAssetOf(a), [b]: figureAssetOf(b) }, null)
|
|
201
|
+
const resolver = createFigureResolver(server.fetch)
|
|
188
202
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
await createFigureResolver(fetch)(['EQ_BESIDE_MALFORMED', 'EQ_MALFORMED'])
|
|
192
|
-
} catch (error) {
|
|
193
|
-
message = error instanceof Error ? error.message : String(error)
|
|
194
|
-
}
|
|
203
|
+
await resolver([a])
|
|
204
|
+
await resolver([b])
|
|
195
205
|
|
|
196
|
-
expect(
|
|
197
|
-
expect(hasFigure(
|
|
198
|
-
expect(hasFigure(
|
|
206
|
+
expect(figureMapReleaseOfPage()).to.equal(null)
|
|
207
|
+
expect(hasFigure(a)).to.equal(true)
|
|
208
|
+
expect(hasFigure(b)).to.equal(true)
|
|
199
209
|
})
|
|
200
210
|
|
|
201
|
-
it('씬의 자리에 앉아 동작한다 —
|
|
202
|
-
const
|
|
203
|
-
const
|
|
211
|
+
it('씬의 자리에 앉아 동작한다 — 받은 것은 그려지고 나머지는 자리표시로 남는다', async () => {
|
|
212
|
+
const onBoard = name('on-board')
|
|
213
|
+
const never = name('never')
|
|
214
|
+
const { fetch } = serverOf({ [onBoard]: figureAssetOf(onBoard) })
|
|
215
|
+
const takeBack = registerTypeResolver(createFigureResolver(fetch) as never)
|
|
204
216
|
|
|
205
217
|
try {
|
|
206
218
|
const model = {
|
|
207
219
|
type: 'container',
|
|
208
220
|
components: [
|
|
209
|
-
{ type:
|
|
210
|
-
{ type:
|
|
221
|
+
{ type: onBoard, left: 0, top: 0, width: 100, height: 100 },
|
|
222
|
+
{ type: never, left: 0, top: 0, width: 100, height: 100 }
|
|
211
223
|
]
|
|
212
224
|
}
|
|
213
|
-
|
|
214
225
|
const resolution = await resolveUnknownTypes(model)
|
|
215
|
-
|
|
216
|
-
expect(resolution.unresolved).to.deep.equal(['EQ_NEVER_PUBLISHED'])
|
|
226
|
+
expect(resolution.unresolved).to.deep.equal([never])
|
|
217
227
|
expect(resolution.failed).to.deep.equal([])
|
|
218
|
-
expect(hasFigure(
|
|
228
|
+
expect(hasFigure(onBoard)).to.equal(true)
|
|
219
229
|
} finally {
|
|
220
230
|
takeBack()
|
|
221
231
|
}
|
package/translations/en.json
CHANGED
|
@@ -36,5 +36,6 @@
|
|
|
36
36
|
"label.list": "list",
|
|
37
37
|
"label.visibility-domain": "public in group",
|
|
38
38
|
"label.visibility-private": "private",
|
|
39
|
-
"label.visibility-public": "public"
|
|
39
|
+
"label.visibility-public": "public",
|
|
40
|
+
"text.figure-type-map-changed": "the type map changed. reopen to draw it."
|
|
40
41
|
}
|
package/translations/ja.json
CHANGED
package/translations/ko.json
CHANGED