@gisce/ooui 2.40.0-alpha.3 → 2.40.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.
- package/README.md +0 -2
- package/dist/WidgetFactory.d.ts.map +1 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/ooui.es.js +1056 -1245
- package/dist/ooui.es.js.map +1 -1
- package/package.json +1 -1
- package/src/WidgetFactory.ts +0 -4
- package/src/index.ts +0 -4
- package/dist/Icon.d.ts +0 -24
- package/dist/Icon.d.ts.map +0 -1
- package/dist/Kanban.d.ts +0 -80
- package/dist/Kanban.d.ts.map +0 -1
- package/src/Icon.ts +0 -59
- package/src/Kanban.ts +0 -285
- package/src/spec/Icon.spec.ts +0 -93
- package/src/spec/Kanban.spec.ts +0 -364
package/src/spec/Kanban.spec.ts
DELETED
|
@@ -1,364 +0,0 @@
|
|
|
1
|
-
import { it, expect, describe } from "vitest";
|
|
2
|
-
import Kanban from "../Kanban";
|
|
3
|
-
import Field from "../Field";
|
|
4
|
-
import Button from "../Button";
|
|
5
|
-
|
|
6
|
-
const XML_VIEW_KANBAN = `<?xml version="1.0"?>
|
|
7
|
-
<kanban string="Tasks" column_field="state" drag="1" sort="1" set_max_cards="1" colors="blue:state=='draft';green:state=='done'">
|
|
8
|
-
<field name="name"/>
|
|
9
|
-
<field name="user_id" widget="avatar"/>
|
|
10
|
-
<field name="planned_hours" sum="Total hours" widget="float_time"/>
|
|
11
|
-
<field name="state"/>
|
|
12
|
-
<button name="do_open" type="object" string="Start" states="draft"/>
|
|
13
|
-
<button name="do_done" type="object" string="Complete" states="open,pending"/>
|
|
14
|
-
</kanban>
|
|
15
|
-
`;
|
|
16
|
-
|
|
17
|
-
const XML_VIEW_KANBAN_MINIMAL = `<?xml version="1.0"?>
|
|
18
|
-
<kanban column_field="status">
|
|
19
|
-
<field name="name"/>
|
|
20
|
-
</kanban>
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
|
-
const XML_VIEW_KANBAN_NO_DRAG_SORT = `<?xml version="1.0"?>
|
|
24
|
-
<kanban column_field="state" drag="0" sort="0">
|
|
25
|
-
<field name="name"/>
|
|
26
|
-
<field name="priority"/>
|
|
27
|
-
</kanban>
|
|
28
|
-
`;
|
|
29
|
-
|
|
30
|
-
const FIELDS = {
|
|
31
|
-
name: {
|
|
32
|
-
required: true,
|
|
33
|
-
size: 128,
|
|
34
|
-
string: "Task Summary",
|
|
35
|
-
type: "char",
|
|
36
|
-
views: {},
|
|
37
|
-
},
|
|
38
|
-
user_id: {
|
|
39
|
-
context: "",
|
|
40
|
-
domain: [],
|
|
41
|
-
relation: "res.users",
|
|
42
|
-
size: 64,
|
|
43
|
-
string: "Assigned to",
|
|
44
|
-
type: "many2one",
|
|
45
|
-
views: {},
|
|
46
|
-
widget: "avatar",
|
|
47
|
-
},
|
|
48
|
-
planned_hours: {
|
|
49
|
-
help: "Estimated time to complete the task",
|
|
50
|
-
string: "Planned Hours",
|
|
51
|
-
type: "float",
|
|
52
|
-
views: {},
|
|
53
|
-
widget: "float_time",
|
|
54
|
-
},
|
|
55
|
-
state: {
|
|
56
|
-
required: true,
|
|
57
|
-
readonly: true,
|
|
58
|
-
selection: [
|
|
59
|
-
["draft", "Draft"],
|
|
60
|
-
["open", "In Progress"],
|
|
61
|
-
["pending", "Pending"],
|
|
62
|
-
["cancelled", "Cancelled"],
|
|
63
|
-
["done", "Done"],
|
|
64
|
-
],
|
|
65
|
-
string: "State",
|
|
66
|
-
type: "selection",
|
|
67
|
-
views: {},
|
|
68
|
-
},
|
|
69
|
-
status: {
|
|
70
|
-
selection: [
|
|
71
|
-
["new", "New"],
|
|
72
|
-
["active", "Active"],
|
|
73
|
-
["completed", "Completed"],
|
|
74
|
-
],
|
|
75
|
-
string: "Status",
|
|
76
|
-
type: "selection",
|
|
77
|
-
views: {},
|
|
78
|
-
},
|
|
79
|
-
priority: {
|
|
80
|
-
selection: [
|
|
81
|
-
["0", "Low"],
|
|
82
|
-
["1", "Normal"],
|
|
83
|
-
["2", "High"],
|
|
84
|
-
],
|
|
85
|
-
string: "Priority",
|
|
86
|
-
type: "selection",
|
|
87
|
-
views: {},
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
describe("A Kanban", () => {
|
|
92
|
-
it("should parse xml with all attributes", () => {
|
|
93
|
-
const tree = new Kanban(FIELDS);
|
|
94
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
95
|
-
|
|
96
|
-
expect(tree.type).toBe("kanban");
|
|
97
|
-
expect(tree.string).toBe("Tasks");
|
|
98
|
-
expect(tree.column_field).toBe("state");
|
|
99
|
-
expect(tree.drag).toBe(true);
|
|
100
|
-
expect(tree.sort).toBe(true);
|
|
101
|
-
expect(tree.set_max_cards).toBe(true);
|
|
102
|
-
expect(tree.colors).toBe("blue:state=='draft';green:state=='done'");
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("should parse minimal kanban xml", () => {
|
|
106
|
-
const tree = new Kanban(FIELDS);
|
|
107
|
-
tree.parse(XML_VIEW_KANBAN_MINIMAL);
|
|
108
|
-
|
|
109
|
-
expect(tree.type).toBe("kanban");
|
|
110
|
-
expect(tree.string).toBe(null);
|
|
111
|
-
expect(tree.column_field).toBe("status");
|
|
112
|
-
expect(tree.drag).toBe(true); // Default value
|
|
113
|
-
expect(tree.sort).toBe(true); // Default value
|
|
114
|
-
expect(tree.set_max_cards).toBe(false); // Default value
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("should parse drag and sort as false", () => {
|
|
118
|
-
const tree = new Kanban(FIELDS);
|
|
119
|
-
tree.parse(XML_VIEW_KANBAN_NO_DRAG_SORT);
|
|
120
|
-
|
|
121
|
-
expect(tree.drag).toBe(false);
|
|
122
|
-
expect(tree.sort).toBe(false);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it("should throw error if column_field is missing", () => {
|
|
126
|
-
const tree = new Kanban(FIELDS);
|
|
127
|
-
const invalidXml = `<?xml version="1.0"?>
|
|
128
|
-
<kanban string="Invalid">
|
|
129
|
-
<field name="name"/>
|
|
130
|
-
</kanban>
|
|
131
|
-
`;
|
|
132
|
-
|
|
133
|
-
expect(() => tree.parse(invalidXml)).toThrow(
|
|
134
|
-
"Kanban view must have a column_field attribute",
|
|
135
|
-
);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("should parse fields correctly", () => {
|
|
139
|
-
const tree = new Kanban(FIELDS);
|
|
140
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
141
|
-
|
|
142
|
-
expect(tree.card_fields).toHaveLength(4);
|
|
143
|
-
expect(tree.card_fields[0].id).toBe("name");
|
|
144
|
-
expect(tree.card_fields[1].id).toBe("user_id");
|
|
145
|
-
expect(tree.card_fields[2].id).toBe("planned_hours");
|
|
146
|
-
expect(tree.card_fields[3].id).toBe("state");
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("should parse field with sum aggregation", () => {
|
|
150
|
-
const tree = new Kanban(FIELDS);
|
|
151
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
152
|
-
|
|
153
|
-
const hoursField = tree.card_fields.find((f) => f.id === "planned_hours");
|
|
154
|
-
expect(hoursField).toBeDefined();
|
|
155
|
-
expect((hoursField as any).sum).toBe("Total hours");
|
|
156
|
-
|
|
157
|
-
expect(tree.aggregations).toHaveProperty("planned_hours");
|
|
158
|
-
expect(tree.aggregations.planned_hours).toBe("Total hours");
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it("should preserve field widget attribute", () => {
|
|
162
|
-
const tree = new Kanban(FIELDS);
|
|
163
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
164
|
-
|
|
165
|
-
const avatarField = tree.card_fields.find((f) => f.id === "user_id");
|
|
166
|
-
expect(avatarField).toBeDefined();
|
|
167
|
-
expect((avatarField as any).raw_props?.widget).toBe("avatar");
|
|
168
|
-
|
|
169
|
-
const hoursField = tree.card_fields.find((f) => f.id === "planned_hours");
|
|
170
|
-
expect(hoursField).toBeDefined();
|
|
171
|
-
expect((hoursField as any).raw_props?.widget).toBe("float_time");
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it("should parse buttons correctly", () => {
|
|
175
|
-
const tree = new Kanban(FIELDS);
|
|
176
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
177
|
-
|
|
178
|
-
expect(tree.buttons).toHaveLength(2);
|
|
179
|
-
|
|
180
|
-
const startButton = tree.buttons[0];
|
|
181
|
-
expect(startButton.id).toBe("do_open");
|
|
182
|
-
expect(startButton.buttonType).toBe("object");
|
|
183
|
-
expect(startButton.caption).toBe("Start");
|
|
184
|
-
expect((startButton as any).states).toBe("draft");
|
|
185
|
-
|
|
186
|
-
const completeButton = tree.buttons[1];
|
|
187
|
-
expect(completeButton.id).toBe("do_done");
|
|
188
|
-
expect(completeButton.buttonType).toBe("object");
|
|
189
|
-
expect(completeButton.caption).toBe("Complete");
|
|
190
|
-
expect((completeButton as any).states).toBe("open,pending");
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it("should handle button without states attribute", () => {
|
|
194
|
-
const xmlWithButton = `<?xml version="1.0"?>
|
|
195
|
-
<kanban column_field="state">
|
|
196
|
-
<field name="name"/>
|
|
197
|
-
<button name="action_test" type="object" string="Test"/>
|
|
198
|
-
</kanban>
|
|
199
|
-
`;
|
|
200
|
-
const tree = new Kanban(FIELDS);
|
|
201
|
-
tree.parse(xmlWithButton);
|
|
202
|
-
|
|
203
|
-
expect(tree.buttons).toHaveLength(1);
|
|
204
|
-
const button = tree.buttons[0];
|
|
205
|
-
expect(button.id).toBe("action_test");
|
|
206
|
-
expect((button as any).states).toBeUndefined();
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("should merge field attributes correctly", () => {
|
|
210
|
-
const tree = new Kanban(FIELDS);
|
|
211
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
212
|
-
|
|
213
|
-
const nameField = tree.card_fields.find((f) => f.id === "name");
|
|
214
|
-
expect(nameField).toBeDefined();
|
|
215
|
-
expect(nameField?.type).toBe("char");
|
|
216
|
-
expect((nameField as any).required).toBe(true);
|
|
217
|
-
expect((nameField as any).size).toBe(128);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it("should handle context for fields", () => {
|
|
221
|
-
const xmlWithContext = `<?xml version="1.0"?>
|
|
222
|
-
<kanban column_field="state">
|
|
223
|
-
<field name="user_id" context="{'show_all': True}"/>
|
|
224
|
-
</kanban>
|
|
225
|
-
`;
|
|
226
|
-
const tree = new Kanban(FIELDS);
|
|
227
|
-
tree.parse(xmlWithContext);
|
|
228
|
-
|
|
229
|
-
expect(tree.contextForFields).toHaveProperty("user_id");
|
|
230
|
-
expect(tree.contextForFields.user_id).toBeDefined();
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it("should throw error for non-existent field", () => {
|
|
234
|
-
const xmlWithInvalidField = `<?xml version="1.0"?>
|
|
235
|
-
<kanban column_field="state">
|
|
236
|
-
<field name="nonexistent_field"/>
|
|
237
|
-
</kanban>
|
|
238
|
-
`;
|
|
239
|
-
const tree = new Kanban(FIELDS);
|
|
240
|
-
|
|
241
|
-
expect(() => tree.parse(xmlWithInvalidField)).toThrow(
|
|
242
|
-
"Field nonexistent_field doesn't exist in fields definition",
|
|
243
|
-
);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it("should find field by id", () => {
|
|
247
|
-
const tree = new Kanban(FIELDS);
|
|
248
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
249
|
-
|
|
250
|
-
const nameField = tree.findById("name");
|
|
251
|
-
expect(nameField).toBeDefined();
|
|
252
|
-
expect(nameField?.id).toBe("name");
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it("should find button by id", () => {
|
|
256
|
-
const tree = new Kanban(FIELDS);
|
|
257
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
258
|
-
|
|
259
|
-
const button = tree.findById("do_open");
|
|
260
|
-
expect(button).toBeDefined();
|
|
261
|
-
expect(button?.id).toBe("do_open");
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it("should return null for non-existent id", () => {
|
|
265
|
-
const tree = new Kanban(FIELDS);
|
|
266
|
-
tree.parse(XML_VIEW_KANBAN);
|
|
267
|
-
|
|
268
|
-
const result = tree.findById("nonexistent");
|
|
269
|
-
expect(result).toBeNull();
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it("should handle empty kanban (only column_field)", () => {
|
|
273
|
-
const emptyXml = `<?xml version="1.0"?>
|
|
274
|
-
<kanban column_field="state"></kanban>
|
|
275
|
-
`;
|
|
276
|
-
const tree = new Kanban(FIELDS);
|
|
277
|
-
tree.parse(emptyXml);
|
|
278
|
-
|
|
279
|
-
expect(tree.card_fields).toHaveLength(0);
|
|
280
|
-
expect(tree.buttons).toHaveLength(0);
|
|
281
|
-
expect(tree.column_field).toBe("state");
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("should handle HTML entities in string attribute", () => {
|
|
285
|
-
const xmlWithEntities = `<?xml version="1.0"?>
|
|
286
|
-
<kanban string="Tasks & Projects" column_field="state">
|
|
287
|
-
<field name="name"/>
|
|
288
|
-
</kanban>
|
|
289
|
-
`;
|
|
290
|
-
const tree = new Kanban(FIELDS);
|
|
291
|
-
tree.parse(xmlWithEntities);
|
|
292
|
-
|
|
293
|
-
expect(tree.string).toBe("Tasks & Projects");
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it("should handle HTML entities in colors attribute", () => {
|
|
297
|
-
const xmlWithEntities = `<?xml version="1.0"?>
|
|
298
|
-
<kanban column_field="state" colors="red:priority>1;blue:priority<1">
|
|
299
|
-
<field name="name"/>
|
|
300
|
-
<field name="priority"/>
|
|
301
|
-
</kanban>
|
|
302
|
-
`;
|
|
303
|
-
const tree = new Kanban(FIELDS);
|
|
304
|
-
tree.parse(xmlWithEntities);
|
|
305
|
-
|
|
306
|
-
expect(tree.colors).toBe("red:priority>1;blue:priority<1");
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it("should skip invisible fields", () => {
|
|
310
|
-
const xmlWithInvisible = `<?xml version="1.0"?>
|
|
311
|
-
<kanban column_field="state">
|
|
312
|
-
<field name="name"/>
|
|
313
|
-
<field name="priority" invisible="1"/>
|
|
314
|
-
</kanban>
|
|
315
|
-
`;
|
|
316
|
-
const tree = new Kanban(FIELDS);
|
|
317
|
-
tree.parse(xmlWithInvisible);
|
|
318
|
-
|
|
319
|
-
expect(tree.card_fields).toHaveLength(1);
|
|
320
|
-
expect(tree.card_fields[0].id).toBe("name");
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it("should handle buttons without name (skip them)", () => {
|
|
324
|
-
const xmlWithUnnamedButton = `<?xml version="1.0"?>
|
|
325
|
-
<kanban column_field="state">
|
|
326
|
-
<field name="name"/>
|
|
327
|
-
<button type="object" string="Test"/>
|
|
328
|
-
</kanban>
|
|
329
|
-
`;
|
|
330
|
-
const tree = new Kanban(FIELDS);
|
|
331
|
-
tree.parse(xmlWithUnnamedButton);
|
|
332
|
-
|
|
333
|
-
expect(tree.buttons).toHaveLength(0);
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it("should handle fields without name (skip them)", () => {
|
|
337
|
-
const xmlWithUnnamedField = `<?xml version="1.0"?>
|
|
338
|
-
<kanban column_field="state">
|
|
339
|
-
<field name="name"/>
|
|
340
|
-
<field widget="custom"/>
|
|
341
|
-
</kanban>
|
|
342
|
-
`;
|
|
343
|
-
const tree = new Kanban(FIELDS);
|
|
344
|
-
tree.parse(xmlWithUnnamedField);
|
|
345
|
-
|
|
346
|
-
expect(tree.card_fields).toHaveLength(1);
|
|
347
|
-
expect(tree.card_fields[0].id).toBe("name");
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("should store multiple aggregations", () => {
|
|
351
|
-
const xmlWithMultipleAggs = `<?xml version="1.0"?>
|
|
352
|
-
<kanban column_field="state">
|
|
353
|
-
<field name="planned_hours" sum="Total Planned"/>
|
|
354
|
-
<field name="priority" sum="Total Priority"/>
|
|
355
|
-
</kanban>
|
|
356
|
-
`;
|
|
357
|
-
const tree = new Kanban(FIELDS);
|
|
358
|
-
tree.parse(xmlWithMultipleAggs);
|
|
359
|
-
|
|
360
|
-
expect(Object.keys(tree.aggregations)).toHaveLength(2);
|
|
361
|
-
expect(tree.aggregations.planned_hours).toBe("Total Planned");
|
|
362
|
-
expect(tree.aggregations.priority).toBe("Total Priority");
|
|
363
|
-
});
|
|
364
|
-
});
|