@operato/app 10.8.1 → 10.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/src/grist-editor/ox-grist-editor-code.d.ts +1 -0
  3. package/dist/src/grist-editor/ox-grist-editor-code.js +2 -0
  4. package/dist/src/grist-editor/ox-grist-editor-code.js.map +1 -1
  5. package/dist/src/grist-editor/ox-grist-editor-json.d.ts +1 -0
  6. package/dist/src/grist-editor/ox-grist-editor-json.js +2 -0
  7. package/dist/src/grist-editor/ox-grist-editor-json.js.map +1 -1
  8. package/dist/src/grist-editor/ox-grist-editor-privilege.d.ts +1 -0
  9. package/dist/src/grist-editor/ox-grist-editor-privilege.js +2 -0
  10. package/dist/src/grist-editor/ox-grist-editor-privilege.js.map +1 -1
  11. package/dist/src/grist-editor/ox-grist-editor-resource-code.d.ts +1 -0
  12. package/dist/src/grist-editor/ox-grist-editor-resource-code.js +2 -0
  13. package/dist/src/grist-editor/ox-grist-editor-resource-code.js.map +1 -1
  14. package/dist/src/grist-editor/ox-grist-editor-resource-id.d.ts +1 -0
  15. package/dist/src/grist-editor/ox-grist-editor-resource-id.js +2 -0
  16. package/dist/src/grist-editor/ox-grist-editor-resource-id.js.map +1 -1
  17. package/dist/src/grist-editor/ox-grist-editor-resource-object-legacy.d.ts +1 -0
  18. package/dist/src/grist-editor/ox-grist-editor-resource-object-legacy.js +2 -0
  19. package/dist/src/grist-editor/ox-grist-editor-resource-object-legacy.js.map +1 -1
  20. package/dist/src/grist-editor/ox-grist-editor-resource-object.d.ts +1 -0
  21. package/dist/src/grist-editor/ox-grist-editor-resource-object.js +2 -0
  22. package/dist/src/grist-editor/ox-grist-editor-resource-object.js.map +1 -1
  23. package/dist/src/relation/ox-relation-view.d.ts +88 -0
  24. package/dist/src/relation/ox-relation-view.js +262 -0
  25. package/dist/src/relation/ox-relation-view.js.map +1 -0
  26. package/dist/src/relation/relation-groups.d.ts +33 -0
  27. package/dist/src/relation/relation-groups.js +87 -0
  28. package/dist/src/relation/relation-groups.js.map +1 -0
  29. package/dist/src/selector/ox-selector-resource-object-legacy.js +13 -1
  30. package/dist/src/selector/ox-selector-resource-object-legacy.js.map +1 -1
  31. package/dist/src/selector/ox-selector-resource-object.d.ts +40 -2
  32. package/dist/src/selector/ox-selector-resource-object.js +180 -16
  33. package/dist/src/selector/ox-selector-resource-object.js.map +1 -1
  34. package/dist/test/selector-confirm-keeps-value.test.d.ts +1 -0
  35. package/dist/test/selector-confirm-keeps-value.test.js +108 -0
  36. package/dist/test/selector-confirm-keeps-value.test.js.map +1 -0
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +61 -53
  39. package/test/selector-confirm-keeps-value.test.ts +127 -0
  40. package/translations/en.json +18 -0
  41. package/translations/es.json +20 -0
  42. package/translations/ja.json +20 -0
  43. package/translations/ko.json +18 -0
  44. package/translations/zh.json +18 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@operato/app",
3
3
  "description": "WebApplication production supporting components following open-wc recommendations",
4
4
  "author": "heartyoh",
5
- "version": "10.8.1",
5
+ "version": "10.9.0",
6
6
  "type": "module",
7
7
  "main": "dist/src/index.js",
8
8
  "module": "dist/src/index.js",
@@ -31,37 +31,51 @@
31
31
  "./filters-form/filter-resource-code.js": "./dist/src/filters-form/filter-resource-code.js",
32
32
  "./filters-form/filter-resource-object.js": "./dist/src/filters-form/filter-resource-object.js",
33
33
  "./filter-renderer.js": "./dist/src/filter-renderer/index.js",
34
- "./filters-form.js": "./dist/src/filters-form/index.js"
34
+ "./filters-form.js": "./dist/src/filters-form/index.js",
35
+ "./relation/ox-relation-view.js": "./dist/src/relation/ox-relation-view.js",
36
+ "./relation/relation-groups.js": "./dist/src/relation/relation-groups.js"
35
37
  },
36
38
  "typesVersions": {
37
39
  "*": {
38
- "input.js": [
39
- "dist/src/input/index.d.ts"
40
+ "filter-renderer.js": [
41
+ "dist/src/filter-renderer/index.d.ts"
40
42
  ],
41
- "input/ox-input-graphql.js": [
42
- "dist/src/input/ox-input-graphql.d.ts"
43
+ "filters-form.js": [
44
+ "dist/src/filters-form/index.d.ts"
43
45
  ],
44
- "selector/ox-selector-resource-id.js": [
45
- "dist/src/selector/ox-selector-resource-id.d.ts"
46
+ "filters-form/filter-resource-code.js": [
47
+ "./dist/src/filters-form/filter-resource-code.d.ts"
46
48
  ],
47
- "selector/ox-selector-resource-object.js": [
48
- "dist/src/selector/ox-selector-resource-object.d.ts"
49
+ "filters-form/filter-resource-object.js": [
50
+ "./dist/src/filters-form/filter-resource-object.d.ts"
49
51
  ],
50
- "property-editor.js": [
51
- "dist/src/property-editor/index.d.ts"
52
+ "grist-editor.js": [
53
+ "dist/src/grist-editor/index.d.ts"
52
54
  ],
53
- "property-editor/ox-property-editor-graphql.js": [
54
- "dist/src/property-editor/ox-property-editor-graphql.d.ts"
55
+ "grist-editor/ox-grist-editor-code.js": [
56
+ "dist/src/grist-editor/ox-grist-editor-code.d.ts"
55
57
  ],
56
- "property-editor/ox-property-editor-resource-object.js": [
57
- "dist/src/property-editor/ox-property-editor-resource-object.d.ts"
58
+ "grist-editor/ox-grist-editor-json.js": [
59
+ "dist/src/grist-editor/ox-grist-editor-json.d.ts"
58
60
  ],
59
- "grist-editor.js": [
60
- "dist/src/grist-editor/index.d.ts"
61
+ "grist-editor/ox-grist-editor-privilege.js": [
62
+ "dist/src/grist-editor/ox-grist-editor-privilege.d.ts"
63
+ ],
64
+ "grist-editor/ox-grist-editor-resource-code.js": [
65
+ "dist/src/grist-editor/ox-grist-editor-resource-code.d.ts"
61
66
  ],
62
67
  "grist-editor/ox-grist-editor-resource-id.js": [
63
68
  "dist/src/grist-editor/ox-grist-editor-resource-id.d.ts"
64
69
  ],
70
+ "grist-editor/ox-grist-editor-resource-object-legacy.js": [
71
+ "dist/src/grist-editor/ox-grist-editor-resource-object-legacy.d.ts"
72
+ ],
73
+ "grist-editor/ox-grist-editor-resource-object.js": [
74
+ "dist/src/grist-editor/ox-grist-editor-resource-object.d.ts"
75
+ ],
76
+ "grist-editor/ox-grist-renderer-crontab.js": [
77
+ "dist/src/grist-editor/ox-grist-renderer-crontab.d.ts"
78
+ ],
65
79
  "grist-editor/ox-grist-renderer-resource-code.js": [
66
80
  "dist/src/grist-editor/ox-grist-renderer-resource-code.d.ts"
67
81
  ],
@@ -71,38 +85,32 @@
71
85
  "grist-editor/ox-grist-renderer-resource-object.js": [
72
86
  "dist/src/grist-editor/ox-grist-renderer-resource-object.d.ts"
73
87
  ],
74
- "grist-editor/ox-grist-renderer-crontab.js": [
75
- "dist/src/grist-editor/ox-grist-renderer-crontab.d.ts"
76
- ],
77
- "grist-editor/ox-grist-editor-json.js": [
78
- "dist/src/grist-editor/ox-grist-editor-json.d.ts"
79
- ],
80
- "grist-editor/ox-grist-editor-code.js": [
81
- "dist/src/grist-editor/ox-grist-editor-code.d.ts"
88
+ "input.js": [
89
+ "dist/src/input/index.d.ts"
82
90
  ],
83
- "grist-editor/ox-grist-editor-privilege.js": [
84
- "dist/src/grist-editor/ox-grist-editor-privilege.d.ts"
91
+ "input/ox-input-graphql.js": [
92
+ "dist/src/input/ox-input-graphql.d.ts"
85
93
  ],
86
- "grist-editor/ox-grist-editor-resource-object.js": [
87
- "dist/src/grist-editor/ox-grist-editor-resource-object.d.ts"
94
+ "property-editor.js": [
95
+ "dist/src/property-editor/index.d.ts"
88
96
  ],
89
- "grist-editor/ox-grist-editor-resource-object-legacy.js": [
90
- "dist/src/grist-editor/ox-grist-editor-resource-object-legacy.d.ts"
97
+ "property-editor/ox-property-editor-graphql.js": [
98
+ "dist/src/property-editor/ox-property-editor-graphql.d.ts"
91
99
  ],
92
- "grist-editor/ox-grist-editor-resource-code.js": [
93
- "dist/src/grist-editor/ox-grist-editor-resource-code.d.ts"
100
+ "property-editor/ox-property-editor-resource-object.js": [
101
+ "dist/src/property-editor/ox-property-editor-resource-object.d.ts"
94
102
  ],
95
- "filters-form/filter-resource-code.js": [
96
- "./dist/src/filters-form/filter-resource-code.d.ts"
103
+ "relation/ox-relation-view.js": [
104
+ "dist/src/relation/ox-relation-view.d.ts"
97
105
  ],
98
- "filters-form/filter-resource-object.js": [
99
- "./dist/src/filters-form/filter-resource-object.d.ts"
106
+ "relation/relation-groups.js": [
107
+ "dist/src/relation/relation-groups.d.ts"
100
108
  ],
101
- "filters-form.js": [
102
- "dist/src/filters-form/index.d.ts"
109
+ "selector/ox-selector-resource-id.js": [
110
+ "dist/src/selector/ox-selector-resource-id.d.ts"
103
111
  ],
104
- "filter-renderer.js": [
105
- "dist/src/filter-renderer/index.d.ts"
112
+ "selector/ox-selector-resource-object.js": [
113
+ "dist/src/selector/ox-selector-resource-object.d.ts"
106
114
  ]
107
115
  }
108
116
  },
@@ -140,18 +148,18 @@
140
148
  "@graphql-tools/delegate": "^10.0.1",
141
149
  "@graphql-tools/wrap": "^10.0.0",
142
150
  "@material/web": "^2.0.0",
143
- "@operato/attachment": "^10.8.1",
144
- "@operato/data-grist": "^10.8.1",
145
- "@operato/font": "^10.8.1",
146
- "@operato/form": "^10.8.1",
151
+ "@operato/attachment": "^10.9.0",
152
+ "@operato/data-grist": "^10.9.0",
153
+ "@operato/font": "^10.9.0",
154
+ "@operato/form": "^10.9.0",
147
155
  "@operato/graphql": "^10.7.0",
148
156
  "@operato/i18n": "^10.0.0",
149
- "@operato/input": "^10.8.1",
150
- "@operato/layout": "^10.8.1",
151
- "@operato/property-editor": "^10.8.1",
152
- "@operato/property-panel": "^10.8.1",
153
- "@operato/shell": "^10.8.1",
154
- "@operato/styles": "^10.8.1",
157
+ "@operato/input": "^10.9.0",
158
+ "@operato/layout": "^10.9.0",
159
+ "@operato/property-editor": "^10.9.0",
160
+ "@operato/property-panel": "^10.9.0",
161
+ "@operato/shell": "^10.9.0",
162
+ "@operato/styles": "^10.9.0",
155
163
  "@operato/utils": "^10.7.0",
156
164
  "cm6-graphql": "^0.0.14",
157
165
  "codemirror": "^6.0.1",
@@ -193,5 +201,5 @@
193
201
  "prettier --write"
194
202
  ]
195
203
  },
196
- "gitHead": "fab8f4d2205af38c407507213746ccca0210efa5"
204
+ "gitHead": "5282356a0fbf7601a1bd023cf65ba5dc60986337"
197
205
  }
@@ -0,0 +1,127 @@
1
+ import { expect } from '@open-wc/testing'
2
+
3
+ /**
4
+ * 참조 팝업의 **확인이 값을 지우지 않는다.**
5
+ *
6
+ * ## 무엇을 지키나
7
+ *
8
+ * `ox-selector-resource-object` 의 확인은 「이 고른 것으로 한다」다. 고른 것이 없으면 확인할 것이
9
+ * 없으므로 닫기와 같아야 한다. **값을 지우는 길은 「지정 안 함」 하나다.**
10
+ *
11
+ * ## 왜 이 시험이 있나 (2026-09-05)
12
+ *
13
+ * 전에는 `confirmCallback(this.selected)` 를 조건 없이 불렀다. 고른 것이 없으면 `selected` 가
14
+ * undefined 이고, 그것은 `onEmpty` 가 넘기는 것과 **똑같다** — 확인이 「지정 안 함」과 같은 일을
15
+ * 했다. 값을 지우는 단추가 둘이었고 그중 하나가 주 동작(채운 단추)이었다.
16
+ *
17
+ * 고른 표시는 목록을 받아올 때 그 쪽에서 값을 찾으면 켜진다. 그래서 목록이 한 쪽에 다 들어가는
18
+ * 표에서는 안 드러났고, 여러 쪽이면 값이 2쪽에 있을 때 빈 채였다.
19
+ *
20
+ * ```
21
+ * [재봤음] 제조법 · 만드는 품목 · 총 106건 · value=MT10097283 은 1쪽에 없다
22
+ * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다
23
+ * ```
24
+ *
25
+ * ## 왜 부품을 세우지 않고 원문을 보나
26
+ *
27
+ * 이 부품은 `@operato/graphql` 의 클라이언트를 모듈 적재 시점에 끌어온다. 시험 안에서 그것을 세우면
28
+ * 서버가 필요하고, 그 무거움이 이 한 줄의 규칙을 지키는 값보다 크다.
29
+ *
30
+ * 대신 **그 규칙이 코드에 남아 있는지**를 본다. 조건 없이 부르는 모양으로 되돌아가면 빨갛게 난다.
31
+ * 부품을 세우는 시험은 그래프가 가벼워지면 그때 더한다.
32
+ */
33
+ /**
34
+ * `onConfirm` 의 본문만 떼어 낸다.
35
+ *
36
+ * 처음에 `indexOf('fetchHandler')` 를 끝 경계로 썼다가 빈 문자열이 나왔다 — 그 낱말은 render 의
37
+ * 템플릿(`.fetchHandler=…`)에 **먼저** 나온다. 메서드 선언을 경계로 삼는다.
38
+ */
39
+ function onConfirmBody(source: string): string {
40
+ const start = source.indexOf(' onConfirm() {')
41
+ if (start < 0) return ''
42
+ const rest = source.slice(start)
43
+ const end = rest.indexOf('\n }')
44
+ return end < 0 ? rest : rest.slice(0, end + 4)
45
+ }
46
+
47
+ describe('참조 선택기 · 확인은 값을 지우지 않는다', () => {
48
+ let source: string
49
+
50
+ before(async () => {
51
+ const response = await fetch('/src/selector/ox-selector-resource-object.ts')
52
+ expect(response.ok, '원문을 읽을 수 있어야 한다').to.be.true
53
+ source = await response.text()
54
+ })
55
+
56
+ it('확인은 고른 것이 없으면 콜백을 부르지 않는다', () => {
57
+ const body = onConfirmBody(source)
58
+
59
+ expect(body, 'onConfirm 을 찾아야 한다').to.include('onConfirm')
60
+
61
+ /*
62
+ * 고른 것이 없을 때 빠져나가는 길이 있어야 한다.
63
+ *
64
+ * 조건 안에 다른 절이 더 붙어도 통과시킨다 — 여럿 고르기가 들어오면서 빈 배열도 함께 봐야
65
+ * 했다. 지키려는 것은 「!selected 를 보고 닫고 끝낸다」이지 조건의 글자 수가 아니다.
66
+ */
67
+ expect(body.replace(/\s+/g, ' '), '고른 것이 없으면 닫고 끝낸다').to.match(
68
+ /if\s*\([^)]*!\s*selected[^{]*\)\s*\{\s*closePopup\(this\)\s*;?\s*return/
69
+ )
70
+ })
71
+
72
+ it('확인이 넘기는 것은 고른 것 하나다 — this.selected 를 조건 없이 넘기지 않는다', () => {
73
+ const body = onConfirmBody(source).replace(/\s+/g, ' ')
74
+
75
+ /*
76
+ * 되돌아간 모양을 직접 막는다. 주석 안에 같은 글자가 있어도 걸리지 않도록 앞의 주석을 걷는다.
77
+ */
78
+ const code = body.replace(/\/\*[\s\S]*?\*\//g, '')
79
+
80
+ expect(code, '조건 없이 this.selected 를 넘기는 모양으로 돌아가면 안 된다').to.not.include(
81
+ 'confirmCallback(this.selected)'
82
+ )
83
+ })
84
+
85
+ it('값을 지우는 길은 지정 안 함 하나다', () => {
86
+ const empty = source.slice(source.indexOf('onEmpty()'), source.indexOf('onCancel()')).replace(/\s+/g, ' ')
87
+
88
+ /* 인자 없이 부르는 것이 「지우기」의 뜻이다. */
89
+ expect(empty, '지정 안 함은 빈 값을 넘긴다').to.include('confirmCallback()')
90
+ })
91
+
92
+ /**
93
+ * 그리스트에 **빈 data 를 넘기지 않는다.**
94
+ *
95
+ * data-grist 는 data 가 설정되면 reset() 한다. 이 부품은 fetchHandler 로 목록을 채우면서
96
+ * `.data` 로 늘 ZERO_DATA 를 함께 넘기고 있었다. 그래서 이 부품이 다시 그려지는 순간 빈 값이
97
+ * 내려가 목록이 통째로 사라졌다.
98
+ *
99
+ * ```
100
+ * [재봤음] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건
101
+ * ```
102
+ *
103
+ * 첫 렌더 뒤로 다시 그릴 일이 없어서 여태 안 드러났다. 바닥 단추를 고른 상태에 묶으면서
104
+ * 드러났고, 그것을 되돌리는 대신 이 바인딩을 걷었다.
105
+ */
106
+ it('ox-grist 에 .data 를 넘기지 않는다', () => {
107
+ const template = source.slice(source.indexOf('<ox-grist'), source.indexOf('</ox-grist>'))
108
+
109
+ expect(template, 'ox-grist 를 찾아야 한다').to.include('.fetchHandler=')
110
+ expect(template.replace(/<!--[\s\S]*?-->/g, ''), '.data 를 다시 넘기면 목록이 사라진다').to.not.include(
111
+ '.data='
112
+ )
113
+ })
114
+
115
+ /**
116
+ * **여럿 고르기에서 빈 배열도 막는다.**
117
+ *
118
+ * multiple 을 켜면 `selected` 가 배열이다. 아무것도 안 고른 상태는 undefined 가 아니라 `[]` 이고,
119
+ * 그것은 truthy 다 — `!selected` 만으로는 빠져나가지 못하고 빈 배열이 그대로 넘어간다. 받는 쪽이
120
+ * 그것을 「전부 지워라」로 읽으면 하나만 고르기 때와 같은 데이터 손실이 난다.
121
+ */
122
+ it('여럿 고르기에서 빈 배열을 넘기지 않는다', () => {
123
+ const body = onConfirmBody(source).replace(/\s+/g, ' ')
124
+
125
+ expect(body, '빈 배열도 걸러야 한다').to.match(/Array\.isArray\(selected\)\s*&&\s*selected\.length\s*===?\s*0/)
126
+ })
127
+ })
@@ -1,4 +1,22 @@
1
1
  {
2
+ "ops.rel.area": "sits in",
3
+ "ops.rel.asset": "carried on",
4
+ "ops.rel.at": "performed at",
5
+ "ops.rel.by": "performed by",
6
+ "ops.rel.class": "belongs to class",
7
+ "ops.rel.crew": "crew",
8
+ "ops.rel.from": "from place",
9
+ "ops.rel.home": "based at",
10
+ "ops.rel.input": "consumes",
11
+ "ops.rel.item": "item",
12
+ "ops.rel.operation": "operation",
13
+ "ops.rel.order": "order",
14
+ "ops.rel.output": "produces",
15
+ "ops.rel.parent": "packed in",
16
+ "ops.rel.route": "follows route",
17
+ "ops.rel.step": "includes step",
18
+ "ops.rel.test": "verified by test",
19
+ "ops.rel.type": "is of type",
2
20
  "title.edit code": "edit code",
3
21
  "title.edit json": "edit json"
4
22
  }
@@ -0,0 +1,20 @@
1
+ {
2
+ "ops.rel.area": "ubicado en",
3
+ "ops.rel.asset": "transportado en",
4
+ "ops.rel.at": "se realiza en",
5
+ "ops.rel.by": "realizado por",
6
+ "ops.rel.class": "pertenece a la clase",
7
+ "ops.rel.crew": "personal",
8
+ "ops.rel.from": "lugar de origen",
9
+ "ops.rel.home": "con base en",
10
+ "ops.rel.input": "consume",
11
+ "ops.rel.item": "artículo",
12
+ "ops.rel.operation": "operación",
13
+ "ops.rel.order": "pedido",
14
+ "ops.rel.output": "produce",
15
+ "ops.rel.parent": "empaquetado en",
16
+ "ops.rel.route": "sigue la ruta",
17
+ "ops.rel.step": "incluye el paso",
18
+ "ops.rel.test": "verified by test",
19
+ "ops.rel.type": "es del tipo"
20
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "ops.rel.area": "所属エリア",
3
+ "ops.rel.asset": "積載資産",
4
+ "ops.rel.at": "実施場所",
5
+ "ops.rel.by": "実施資源",
6
+ "ops.rel.class": "所属クラス",
7
+ "ops.rel.crew": "投入人員",
8
+ "ops.rel.from": "出発の場所",
9
+ "ops.rel.home": "基準場所",
10
+ "ops.rel.input": "投入",
11
+ "ops.rel.item": "扱う品目",
12
+ "ops.rel.operation": "実行工程",
13
+ "ops.rel.order": "所属オーダー",
14
+ "ops.rel.output": "産出",
15
+ "ops.rel.parent": "梱包単位",
16
+ "ops.rel.route": "従うルート",
17
+ "ops.rel.step": "含む工程",
18
+ "ops.rel.test": "verified by test",
19
+ "ops.rel.type": "タイプ"
20
+ }
@@ -1,4 +1,22 @@
1
1
  {
2
+ "ops.rel.area": "속한 구역",
3
+ "ops.rel.asset": "실린 자산",
4
+ "ops.rel.at": "수행 로케이션",
5
+ "ops.rel.by": "수행 자원",
6
+ "ops.rel.class": "속한 등급",
7
+ "ops.rel.crew": "투입 인원",
8
+ "ops.rel.from": "출발 로케이션",
9
+ "ops.rel.home": "기준 로케이션",
10
+ "ops.rel.input": "투입",
11
+ "ops.rel.item": "다루는 품목",
12
+ "ops.rel.operation": "수행 공정",
13
+ "ops.rel.order": "속한 오더",
14
+ "ops.rel.output": "산출",
15
+ "ops.rel.parent": "담긴 물류단위",
16
+ "ops.rel.route": "따르는 라우트",
17
+ "ops.rel.step": "포함 공정",
18
+ "ops.rel.test": "검증한 시험",
19
+ "ops.rel.type": "타입",
2
20
  "title.edit code": "코드 편집",
3
21
  "title.edit json": "JSON 편집"
4
22
  }
@@ -1,4 +1,22 @@
1
1
  {
2
+ "ops.rel.area": "所属区域",
3
+ "ops.rel.asset": "承载资产",
4
+ "ops.rel.at": "执行位置",
5
+ "ops.rel.by": "执行资源",
6
+ "ops.rel.class": "所属等级",
7
+ "ops.rel.crew": "投入人员",
8
+ "ops.rel.from": "起始位置",
9
+ "ops.rel.home": "基准位置",
10
+ "ops.rel.input": "投入",
11
+ "ops.rel.item": "处理品目",
12
+ "ops.rel.operation": "执行工序",
13
+ "ops.rel.order": "所属工单",
14
+ "ops.rel.output": "产出",
15
+ "ops.rel.parent": "包装单元",
16
+ "ops.rel.route": "所遵路线",
17
+ "ops.rel.step": "包含工序",
18
+ "ops.rel.test": "verified by test",
19
+ "ops.rel.type": "类型",
2
20
  "title.edit code": "代码编辑",
3
21
  "title.edit json": "JSON编辑"
4
22
  }