@wisemen/nestjs-custom-fields 4.2.1 → 5.0.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 +70 -0
- package/dist/custom-field-rules.d.ts +2 -0
- package/dist/custom-field-type-contract.d.ts +2 -0
- package/dist/custom-field-type-contract.js.map +1 -1
- package/dist/custom-field-types/index.d.ts +1 -0
- package/dist/custom-field-types/index.js +1 -0
- package/dist/custom-field-types/index.js.map +1 -1
- package/dist/custom-field-types/progress/index.d.ts +7 -0
- package/dist/custom-field-types/progress/index.js +8 -0
- package/dist/custom-field-types/progress/index.js.map +1 -0
- package/dist/custom-field-types/progress/progress.color.d.ts +25 -0
- package/dist/custom-field-types/progress/progress.color.js +27 -0
- package/dist/custom-field-types/progress/progress.color.js.map +1 -0
- package/dist/custom-field-types/progress/progress.contract.d.ts +20 -0
- package/dist/custom-field-types/progress/progress.contract.js +2 -0
- package/dist/custom-field-types/progress/progress.contract.js.map +1 -0
- package/dist/custom-field-types/progress/progress.custom-field-definition.factory.unit.test.d.ts +1 -0
- package/dist/custom-field-types/progress/progress.custom-field-definition.factory.unit.test.js +67 -0
- package/dist/custom-field-types/progress/progress.custom-field-definition.factory.unit.test.js.map +1 -0
- package/dist/custom-field-types/progress/progress.custom-field-value.validator.d.ts +6 -0
- package/dist/custom-field-types/progress/progress.custom-field-value.validator.js +34 -0
- package/dist/custom-field-types/progress/progress.custom-field-value.validator.js.map +1 -0
- package/dist/custom-field-types/progress/progress.custom-field-value.validator.unit.test.d.ts +1 -0
- package/dist/custom-field-types/progress/progress.custom-field-value.validator.unit.test.js +91 -0
- package/dist/custom-field-types/progress/progress.custom-field-value.validator.unit.test.js.map +1 -0
- package/dist/custom-field-types/progress/progress.definition-validation.d.ts +7 -0
- package/dist/custom-field-types/progress/progress.definition-validation.js +44 -0
- package/dist/custom-field-types/progress/progress.definition-validation.js.map +1 -0
- package/dist/custom-field-types/progress/progress.dto.d.ts +22 -0
- package/dist/custom-field-types/progress/progress.dto.js +94 -0
- package/dist/custom-field-types/progress/progress.dto.js.map +1 -0
- package/dist/custom-field-types/progress/progress.rules.d.ts +5 -0
- package/dist/custom-field-types/progress/progress.rules.js +2 -0
- package/dist/custom-field-types/progress/progress.rules.js.map +1 -0
- package/dist/custom-field-types/progress/progress.value.d.ts +5 -0
- package/dist/custom-field-types/progress/progress.value.js +2 -0
- package/dist/custom-field-types/progress/progress.value.js.map +1 -0
- package/dist/dto/custom-field-value.dto.d.ts +7 -4
- package/dist/dto/custom-field-value.dto.js +6 -2
- package/dist/dto/custom-field-value.dto.js.map +1 -1
- package/dist/dto/custom-field-value.dto.unit.test.js +43 -1
- package/dist/dto/custom-field-value.dto.unit.test.js.map +1 -1
- package/dist/enum/custom-field-type.enum.d.ts +2 -1
- package/dist/enum/custom-field-type.enum.js +1 -0
- package/dist/enum/custom-field-type.enum.js.map +1 -1
- package/dist/factory/custom-field-definition.factory.js +6 -1
- package/dist/factory/custom-field-definition.factory.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/typeorm/custom-field-value.column.js +2 -0
- package/dist/typeorm/custom-field-value.column.js.map +1 -1
- package/dist/validators/custom-field-value.validator.js +4 -0
- package/dist/validators/custom-field-value.validator.js.map +1 -1
- package/package.json +5 -5
- package/skills/getting-started/SKILL.md +70 -0
package/README.md
CHANGED
|
@@ -162,6 +162,76 @@ you `switch` over `CustomFieldType` or build a `Record<CustomFieldType, ...>`;
|
|
|
162
162
|
those no longer type-check until the new case is added. No database migration is
|
|
163
163
|
needed: `type` is stored as `varchar` and `rules` as `jsonb`.
|
|
164
164
|
|
|
165
|
+
### Progress Fields
|
|
166
|
+
|
|
167
|
+
Use `CustomFieldType.PROGRESS` for a progress bar. The definition's `choices`
|
|
168
|
+
are the bar's segments, and `rules` set a `ProgressCustomFieldColor` for every
|
|
169
|
+
choice and an optional `icon`. The value is `{ total?, segments }`: `segments`
|
|
170
|
+
is a list of `{ key, amount }`, where `key` is a choice value and `amount` is a
|
|
171
|
+
finite number of at least 0. Keys can appear only once. A missing segment
|
|
172
|
+
counts as 0, so `{ segments: [] }` is a valid value.
|
|
173
|
+
|
|
174
|
+
Each segment fills `amount / total` of the bar. Set `total` when it is known,
|
|
175
|
+
such as `100` for a percentage: it must be greater than 0, the amounts can not
|
|
176
|
+
add up to more than it, and the rest of the bar stays empty. Leave `total` out
|
|
177
|
+
when it is not known: the total is then the sum of the amounts and the bar is
|
|
178
|
+
always fully filled.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { ProgressCustomFieldColor } from '@wisemen/nestjs-custom-fields'
|
|
182
|
+
|
|
183
|
+
const tasksField = customFieldDefinition(CustomFieldType.PROGRESS, {
|
|
184
|
+
tenantUuid: null,
|
|
185
|
+
entityType: CustomFieldEntityType.TICKET,
|
|
186
|
+
key: 'tasks',
|
|
187
|
+
label: new LocalizedString([{ locale: 'en', value: 'Tasks' }]),
|
|
188
|
+
description: null,
|
|
189
|
+
isRequired: false,
|
|
190
|
+
choices: [
|
|
191
|
+
{
|
|
192
|
+
value: 'completed',
|
|
193
|
+
order: 1,
|
|
194
|
+
label: new LocalizedString([{ locale: 'en', value: 'Completed' }])
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
value: 'in_progress',
|
|
198
|
+
order: 2,
|
|
199
|
+
label: new LocalizedString([{ locale: 'en', value: 'In progress' }])
|
|
200
|
+
}
|
|
201
|
+
],
|
|
202
|
+
rules: {
|
|
203
|
+
icon: 'tasks',
|
|
204
|
+
colors: {
|
|
205
|
+
completed: ProgressCustomFieldColor.SUCCESS,
|
|
206
|
+
in_progress: ProgressCustomFieldColor.WARNING
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
// 2 completed and 3 in progress, total unknown: 2/5 green, 3/5 yellow
|
|
212
|
+
const value = {
|
|
213
|
+
segments: [
|
|
214
|
+
{ key: 'completed', amount: 2 },
|
|
215
|
+
{ key: 'in_progress', amount: 3 }
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 20% completed: 20/100 green, the rest empty
|
|
220
|
+
const percentage = {
|
|
221
|
+
total: 100,
|
|
222
|
+
segments: [{ key: 'completed', amount: 20 }]
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The icon is an app-defined string, like `entityType`: the package stores it
|
|
227
|
+
as-is. Leave it out to render the bar without an icon; an empty string is
|
|
228
|
+
rejected.
|
|
229
|
+
|
|
230
|
+
When upgrading from 4.x to 5.0.0, handle `CustomFieldType.PROGRESS` wherever
|
|
231
|
+
you `switch` over `CustomFieldType` or build a `Record<CustomFieldType, ...>`;
|
|
232
|
+
those no longer type-check until the new case is added. No database migration is
|
|
233
|
+
needed: `type` is stored as `varchar`, and `choices` and `rules` as `jsonb`.
|
|
234
|
+
|
|
165
235
|
## Step 3: Store Values On The Entity With The Custom Column
|
|
166
236
|
|
|
167
237
|
Resolved custom field values live on your own entity. Use
|
|
@@ -5,6 +5,7 @@ import type { DateCustomFieldRules as DateCustomFieldRulesModel } from '#src/cus
|
|
|
5
5
|
import type { MonetaryCustomFieldRules as MonetaryCustomFieldRulesModel } from '#src/custom-field-types/monetary/monetary.rules.js';
|
|
6
6
|
import type { MultiSelectCustomFieldRules as MultiSelectCustomFieldRulesModel } from '#src/custom-field-types/multi-select/multi-select.rules.js';
|
|
7
7
|
import type { NumberCustomFieldRules as NumberCustomFieldRulesModel } from '#src/custom-field-types/number/number.rules.js';
|
|
8
|
+
import type { ProgressCustomFieldRules as ProgressCustomFieldRulesModel } from '#src/custom-field-types/progress/progress.rules.js';
|
|
8
9
|
import type { ReferenceCustomFieldRules as ReferenceCustomFieldRulesModel } from '#src/custom-field-types/reference/reference.rules.js';
|
|
9
10
|
import type { SelectCustomFieldRules as SelectCustomFieldRulesModel } from '#src/custom-field-types/single-select/single-select.rules.js';
|
|
10
11
|
import type { TextArrayCustomFieldRules as TextArrayCustomFieldRulesModel } from '#src/custom-field-types/text-array/text-array.rules.js';
|
|
@@ -23,6 +24,7 @@ export type SelectCustomFieldRules = SelectCustomFieldRulesModel;
|
|
|
23
24
|
export type MultiSelectCustomFieldRules = MultiSelectCustomFieldRulesModel;
|
|
24
25
|
export type MonetaryCustomFieldRules = MonetaryCustomFieldRulesModel;
|
|
25
26
|
export type ReferenceCustomFieldRules = ReferenceCustomFieldRulesModel;
|
|
27
|
+
export type ProgressCustomFieldRules = ProgressCustomFieldRulesModel;
|
|
26
28
|
export type CustomFieldRulesByType<T extends CustomFieldType> = CustomFieldRulesFor<T>;
|
|
27
29
|
export type CustomFieldRules = {
|
|
28
30
|
[T in CustomFieldType]: CustomFieldRulesByType<T>;
|
|
@@ -3,6 +3,7 @@ import type { DateCustomFieldTypeContract } from '#src/custom-field-types/date/d
|
|
|
3
3
|
import type { MonetaryCustomFieldTypeContract } from '#src/custom-field-types/monetary/monetary.contract.js';
|
|
4
4
|
import type { MultiSelectCustomFieldTypeContract } from '#src/custom-field-types/multi-select/multi-select.contract.js';
|
|
5
5
|
import type { NumberCustomFieldTypeContract } from '#src/custom-field-types/number/number.contract.js';
|
|
6
|
+
import type { ProgressCustomFieldTypeContract } from '#src/custom-field-types/progress/progress.contract.js';
|
|
6
7
|
import type { ReferenceCustomFieldTypeContract } from '#src/custom-field-types/reference/reference.contract.js';
|
|
7
8
|
import type { SingleSelectCustomFieldTypeContract } from '#src/custom-field-types/single-select/single-select.contract.js';
|
|
8
9
|
import type { TextArrayCustomFieldTypeContract } from '#src/custom-field-types/text-array/text-array.contract.js';
|
|
@@ -31,6 +32,7 @@ export type CustomFieldTypeContract = Satisfies<{
|
|
|
31
32
|
[CustomFieldType.MULTI_SELECT]: MultiSelectCustomFieldTypeContract;
|
|
32
33
|
[CustomFieldType.MONETARY]: MonetaryCustomFieldTypeContract;
|
|
33
34
|
[CustomFieldType.REFERENCE]: ReferenceCustomFieldTypeContract;
|
|
35
|
+
[CustomFieldType.PROGRESS]: ProgressCustomFieldTypeContract;
|
|
34
36
|
}, Record<CustomFieldType, CustomFieldTypeContractBase>>;
|
|
35
37
|
export type CustomFieldDomainValueByType<T extends CustomFieldType> = CustomFieldTypeContract[T]['value'];
|
|
36
38
|
export type CustomFieldColumnValueByType<T extends CustomFieldType> = CustomFieldTypeContract[T]['columnValue'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-field-type-contract.js","sourceRoot":"","sources":["../lib/custom-field-type-contract.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"custom-field-type-contract.js","sourceRoot":"","sources":["../lib/custom-field-type-contract.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA"}
|
|
@@ -3,6 +3,7 @@ export * from '#src/custom-field-types/date/index.js';
|
|
|
3
3
|
export * from '#src/custom-field-types/monetary/index.js';
|
|
4
4
|
export * from '#src/custom-field-types/multi-select/index.js';
|
|
5
5
|
export * from '#src/custom-field-types/number/index.js';
|
|
6
|
+
export * from '#src/custom-field-types/progress/index.js';
|
|
6
7
|
export * from '#src/custom-field-types/reference/index.js';
|
|
7
8
|
export * from '#src/custom-field-types/single-select/index.js';
|
|
8
9
|
export * from '#src/custom-field-types/text-array/index.js';
|
|
@@ -3,6 +3,7 @@ export * from '#src/custom-field-types/date/index.js';
|
|
|
3
3
|
export * from '#src/custom-field-types/monetary/index.js';
|
|
4
4
|
export * from '#src/custom-field-types/multi-select/index.js';
|
|
5
5
|
export * from '#src/custom-field-types/number/index.js';
|
|
6
|
+
export * from '#src/custom-field-types/progress/index.js';
|
|
6
7
|
export * from '#src/custom-field-types/reference/index.js';
|
|
7
8
|
export * from '#src/custom-field-types/single-select/index.js';
|
|
8
9
|
export * from '#src/custom-field-types/text-array/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/custom-field-types/index.ts"],"names":[],"mappings":"AAAA,cAAc,0CAA0C,CAAA;AACxD,cAAc,uCAAuC,CAAA;AACrD,cAAc,2CAA2C,CAAA;AACzD,cAAc,+CAA+C,CAAA;AAC7D,cAAc,yCAAyC,CAAA;AACvD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,gDAAgD,CAAA;AAC9D,cAAc,6CAA6C,CAAA;AAC3D,cAAc,uCAAuC,CAAA;AACrD,cAAc,4CAA4C,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/custom-field-types/index.ts"],"names":[],"mappings":"AAAA,cAAc,0CAA0C,CAAA;AACxD,cAAc,uCAAuC,CAAA;AACrD,cAAc,2CAA2C,CAAA;AACzD,cAAc,+CAA+C,CAAA;AAC7D,cAAc,yCAAyC,CAAA;AACvD,cAAc,2CAA2C,CAAA;AACzD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,gDAAgD,CAAA;AAC9D,cAAc,6CAA6C,CAAA;AAC3D,cAAc,uCAAuC,CAAA;AACrD,cAAc,4CAA4C,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from '#src/custom-field-types/progress/progress.color.js';
|
|
2
|
+
export * from '#src/custom-field-types/progress/progress.contract.js';
|
|
3
|
+
export * from '#src/custom-field-types/progress/progress.definition-validation.js';
|
|
4
|
+
export * from '#src/custom-field-types/progress/progress.dto.js';
|
|
5
|
+
export * from '#src/custom-field-types/progress/progress.rules.js';
|
|
6
|
+
export * from '#src/custom-field-types/progress/progress.custom-field-value.validator.js';
|
|
7
|
+
export * from '#src/custom-field-types/progress/progress.value.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from '#src/custom-field-types/progress/progress.color.js';
|
|
2
|
+
export * from '#src/custom-field-types/progress/progress.contract.js';
|
|
3
|
+
export * from '#src/custom-field-types/progress/progress.definition-validation.js';
|
|
4
|
+
export * from '#src/custom-field-types/progress/progress.dto.js';
|
|
5
|
+
export * from '#src/custom-field-types/progress/progress.rules.js';
|
|
6
|
+
export * from '#src/custom-field-types/progress/progress.custom-field-value.validator.js';
|
|
7
|
+
export * from '#src/custom-field-types/progress/progress.value.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/custom-field-types/progress/index.ts"],"names":[],"mappings":"AAAA,cAAc,oDAAoD,CAAA;AAClE,cAAc,uDAAuD,CAAA;AACrE,cAAc,oEAAoE,CAAA;AAClF,cAAc,kDAAkD,CAAA;AAChE,cAAc,oDAAoD,CAAA;AAClE,cAAc,2EAA2E,CAAA;AACzF,cAAc,oDAAoD,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare enum ProgressCustomFieldColor {
|
|
2
|
+
MOSS = "moss",
|
|
3
|
+
GREEN_LIGHT = "green-light",
|
|
4
|
+
GREEN = "green",
|
|
5
|
+
TEAL = "teal",
|
|
6
|
+
CYAN = "cyan",
|
|
7
|
+
BLUE_LIGHT = "blue-light",
|
|
8
|
+
BLUE = "blue",
|
|
9
|
+
BLUE_DARK = "blue-dark",
|
|
10
|
+
INDIGO = "indigo",
|
|
11
|
+
VIOLET = "violet",
|
|
12
|
+
PURPLE = "purple",
|
|
13
|
+
FUCHSIA = "fuchsia",
|
|
14
|
+
PINK = "pink",
|
|
15
|
+
ROSE = "rose",
|
|
16
|
+
ORANGE_DARK = "orange-dark",
|
|
17
|
+
ORANGE = "orange",
|
|
18
|
+
YELLOW = "yellow",
|
|
19
|
+
ERROR = "error",
|
|
20
|
+
WARNING = "warning",
|
|
21
|
+
SUCCESS = "success",
|
|
22
|
+
INFO = "info",
|
|
23
|
+
BRAND = "brand",
|
|
24
|
+
NEUTRAL = "neutral"
|
|
25
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export var ProgressCustomFieldColor;
|
|
2
|
+
(function (ProgressCustomFieldColor) {
|
|
3
|
+
ProgressCustomFieldColor["MOSS"] = "moss";
|
|
4
|
+
ProgressCustomFieldColor["GREEN_LIGHT"] = "green-light";
|
|
5
|
+
ProgressCustomFieldColor["GREEN"] = "green";
|
|
6
|
+
ProgressCustomFieldColor["TEAL"] = "teal";
|
|
7
|
+
ProgressCustomFieldColor["CYAN"] = "cyan";
|
|
8
|
+
ProgressCustomFieldColor["BLUE_LIGHT"] = "blue-light";
|
|
9
|
+
ProgressCustomFieldColor["BLUE"] = "blue";
|
|
10
|
+
ProgressCustomFieldColor["BLUE_DARK"] = "blue-dark";
|
|
11
|
+
ProgressCustomFieldColor["INDIGO"] = "indigo";
|
|
12
|
+
ProgressCustomFieldColor["VIOLET"] = "violet";
|
|
13
|
+
ProgressCustomFieldColor["PURPLE"] = "purple";
|
|
14
|
+
ProgressCustomFieldColor["FUCHSIA"] = "fuchsia";
|
|
15
|
+
ProgressCustomFieldColor["PINK"] = "pink";
|
|
16
|
+
ProgressCustomFieldColor["ROSE"] = "rose";
|
|
17
|
+
ProgressCustomFieldColor["ORANGE_DARK"] = "orange-dark";
|
|
18
|
+
ProgressCustomFieldColor["ORANGE"] = "orange";
|
|
19
|
+
ProgressCustomFieldColor["YELLOW"] = "yellow";
|
|
20
|
+
ProgressCustomFieldColor["ERROR"] = "error";
|
|
21
|
+
ProgressCustomFieldColor["WARNING"] = "warning";
|
|
22
|
+
ProgressCustomFieldColor["SUCCESS"] = "success";
|
|
23
|
+
ProgressCustomFieldColor["INFO"] = "info";
|
|
24
|
+
ProgressCustomFieldColor["BRAND"] = "brand";
|
|
25
|
+
ProgressCustomFieldColor["NEUTRAL"] = "neutral";
|
|
26
|
+
})(ProgressCustomFieldColor || (ProgressCustomFieldColor = {}));
|
|
27
|
+
//# sourceMappingURL=progress.color.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.color.js","sourceRoot":"","sources":["../../../lib/custom-field-types/progress/progress.color.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,wBAwBX;AAxBD,WAAY,wBAAwB;IAClC,yCAAa,CAAA;IACb,uDAA2B,CAAA;IAC3B,2CAAe,CAAA;IACf,yCAAa,CAAA;IACb,yCAAa,CAAA;IACb,qDAAyB,CAAA;IACzB,yCAAa,CAAA;IACb,mDAAuB,CAAA;IACvB,6CAAiB,CAAA;IACjB,6CAAiB,CAAA;IACjB,6CAAiB,CAAA;IACjB,+CAAmB,CAAA;IACnB,yCAAa,CAAA;IACb,yCAAa,CAAA;IACb,uDAA2B,CAAA;IAC3B,6CAAiB,CAAA;IACjB,6CAAiB,CAAA;IACjB,2CAAe,CAAA;IACf,+CAAmB,CAAA;IACnB,+CAAmB,CAAA;IACnB,yCAAa,CAAA;IACb,2CAAe,CAAA;IACf,+CAAmB,CAAA;AACrB,CAAC,EAxBW,wBAAwB,KAAxB,wBAAwB,QAwBnC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DefineContract } from '#src/custom-field-type-contract.js';
|
|
2
|
+
import type { ProgressCustomFieldColor } from '#src/custom-field-types/progress/progress.color.js';
|
|
3
|
+
export interface ProgressCustomFieldSegment {
|
|
4
|
+
key: string;
|
|
5
|
+
amount: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ProgressCustomFieldData {
|
|
8
|
+
total?: number;
|
|
9
|
+
segments: ProgressCustomFieldSegment[];
|
|
10
|
+
}
|
|
11
|
+
export type ProgressCustomFieldTypeContract = DefineContract<{
|
|
12
|
+
value: ProgressCustomFieldData;
|
|
13
|
+
columnValue: ProgressCustomFieldData;
|
|
14
|
+
rules: {
|
|
15
|
+
icon?: string;
|
|
16
|
+
colors: Record<string, ProgressCustomFieldColor>;
|
|
17
|
+
};
|
|
18
|
+
rulesMode: 'required';
|
|
19
|
+
choicesMode: 'required';
|
|
20
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.contract.js","sourceRoot":"","sources":["../../../lib/custom-field-types/progress/progress.contract.ts"],"names":[],"mappings":""}
|
package/dist/custom-field-types/progress/progress.custom-field-definition.factory.unit.test.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/custom-field-types/progress/progress.custom-field-definition.factory.unit.test.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import { expect } from 'expect';
|
|
3
|
+
import { LocalizedString } from '@wisemen/localized-string';
|
|
4
|
+
import { CustomFieldDefinitionError } from '#src/errors/custom-field-definition.error.js';
|
|
5
|
+
import { CustomFieldType } from '#src/enum/custom-field-type.enum.js';
|
|
6
|
+
import { customFieldDefinition } from '#src/factory/custom-field-definition.factory.js';
|
|
7
|
+
import { ProgressCustomFieldColor } from '#src/custom-field-types/progress/progress.color.js';
|
|
8
|
+
const choices = [
|
|
9
|
+
{ value: 'completed', order: 1, label: new LocalizedString([{ locale: 'en', value: 'Completed' }]) },
|
|
10
|
+
{ value: 'in_progress', order: 2, label: new LocalizedString([{ locale: 'en', value: 'In progress' }]) }
|
|
11
|
+
];
|
|
12
|
+
const rules = {
|
|
13
|
+
icon: 'tasks',
|
|
14
|
+
colors: {
|
|
15
|
+
completed: ProgressCustomFieldColor.SUCCESS,
|
|
16
|
+
in_progress: ProgressCustomFieldColor.WARNING
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function progressDefinition(overrides = {}) {
|
|
20
|
+
return customFieldDefinition(CustomFieldType.PROGRESS, {
|
|
21
|
+
tenantUuid: null,
|
|
22
|
+
entityType: 'project',
|
|
23
|
+
key: 'tasks',
|
|
24
|
+
label: new LocalizedString([{ locale: 'en', value: 'Tasks' }]),
|
|
25
|
+
description: null,
|
|
26
|
+
isRequired: false,
|
|
27
|
+
choices: overrides.choices ?? choices,
|
|
28
|
+
rules: overrides.rules ?? rules
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
describe('progress customFieldDefinition', () => {
|
|
32
|
+
it('creates a progress custom field definition', () => {
|
|
33
|
+
const definition = progressDefinition();
|
|
34
|
+
expect(definition.type).toBe(CustomFieldType.PROGRESS);
|
|
35
|
+
expect(definition.choices).toEqual(choices);
|
|
36
|
+
expect(definition.rules).toEqual({ type: CustomFieldType.PROGRESS, ...rules });
|
|
37
|
+
});
|
|
38
|
+
it('creates a progress custom field definition without an icon', () => {
|
|
39
|
+
const definition = progressDefinition({ rules: { colors: rules.colors } });
|
|
40
|
+
expect(definition.rules).toEqual({ type: CustomFieldType.PROGRESS, colors: rules.colors });
|
|
41
|
+
});
|
|
42
|
+
it('rejects a progress field without choices', () => {
|
|
43
|
+
expect(() => progressDefinition({ choices: [], rules: { icon: 'tasks', colors: {} } }))
|
|
44
|
+
.toThrow(new CustomFieldDefinitionError('Progress custom field must define at least one choice'));
|
|
45
|
+
});
|
|
46
|
+
it('rejects a progress field with duplicate choice values', () => {
|
|
47
|
+
expect(() => progressDefinition({ choices: [choices[0], { ...choices[1], value: 'completed' }] }))
|
|
48
|
+
.toThrow(new CustomFieldDefinitionError('Custom field choice value must be unique'));
|
|
49
|
+
});
|
|
50
|
+
it('rejects a progress field with an empty icon', () => {
|
|
51
|
+
expect(() => progressDefinition({ rules: { ...rules, icon: ' ' } }))
|
|
52
|
+
.toThrow(new CustomFieldDefinitionError('Progress custom field icon can not be empty'));
|
|
53
|
+
});
|
|
54
|
+
it('rejects a progress field without a color for every choice', () => {
|
|
55
|
+
expect(() => progressDefinition({ rules: { ...rules, colors: { completed: ProgressCustomFieldColor.SUCCESS } } }))
|
|
56
|
+
.toThrow(new CustomFieldDefinitionError('Progress custom field must define a color for every choice'));
|
|
57
|
+
});
|
|
58
|
+
it('rejects a progress field with a color for an unknown choice', () => {
|
|
59
|
+
expect(() => progressDefinition({ rules: { ...rules, colors: { ...rules.colors, blocked: ProgressCustomFieldColor.ERROR } } }))
|
|
60
|
+
.toThrow(new CustomFieldDefinitionError('Progress custom field colors can only be defined for choices'));
|
|
61
|
+
});
|
|
62
|
+
it('rejects a progress field with an unsupported color', () => {
|
|
63
|
+
expect(() => progressDefinition({ rules: { ...rules, colors: { ...rules.colors, completed: 'lime' } } }))
|
|
64
|
+
.toThrow(new CustomFieldDefinitionError('Progress custom field color must be a supported color'));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=progress.custom-field-definition.factory.unit.test.js.map
|
package/dist/custom-field-types/progress/progress.custom-field-definition.factory.unit.test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.custom-field-definition.factory.unit.test.js","sourceRoot":"","sources":["../../../lib/custom-field-types/progress/progress.custom-field-definition.factory.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CustomFieldDefinitionFieldsByType } from '#src/custom-field-definition.js';
|
|
2
|
+
import type { CustomFieldType } from '#src/enum/custom-field-type.enum.js';
|
|
3
|
+
import type { ProgressCustomFieldData } from '#src/custom-field-types/progress/progress.contract.js';
|
|
4
|
+
type ProgressCustomFieldDefinition = CustomFieldDefinitionFieldsByType<CustomFieldType.PROGRESS>;
|
|
5
|
+
export declare function validateProgressCustomFieldValue(definition: ProgressCustomFieldDefinition, value: ProgressCustomFieldData): void;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CustomFieldValueValidationError } from '#src/validators/custom-field-value-validation.error.js';
|
|
2
|
+
export function validateProgressCustomFieldValue(definition, value) {
|
|
3
|
+
if (definition.choices === null) {
|
|
4
|
+
throw new CustomFieldValueValidationError('Progress custom field definition must define choices');
|
|
5
|
+
}
|
|
6
|
+
const seenKeys = new Set();
|
|
7
|
+
let sum = 0;
|
|
8
|
+
for (const segment of value.segments) {
|
|
9
|
+
if (!definition.choices.some(choice => choice.value === segment.key)) {
|
|
10
|
+
throw new CustomFieldValueValidationError('Progress custom field value keys must be defined choices');
|
|
11
|
+
}
|
|
12
|
+
if (seenKeys.has(segment.key)) {
|
|
13
|
+
throw new CustomFieldValueValidationError('Progress custom field value can not contain duplicate keys');
|
|
14
|
+
}
|
|
15
|
+
if (!Number.isFinite(segment.amount)) {
|
|
16
|
+
throw new CustomFieldValueValidationError('Progress custom field value amount must be a finite number');
|
|
17
|
+
}
|
|
18
|
+
if (segment.amount < 0) {
|
|
19
|
+
throw new CustomFieldValueValidationError('Progress custom field value amount can not be negative');
|
|
20
|
+
}
|
|
21
|
+
seenKeys.add(segment.key);
|
|
22
|
+
sum += segment.amount;
|
|
23
|
+
}
|
|
24
|
+
if (value.total === undefined) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!Number.isFinite(value.total) || value.total <= 0) {
|
|
28
|
+
throw new CustomFieldValueValidationError('Progress custom field value total must be a finite number greater than zero');
|
|
29
|
+
}
|
|
30
|
+
if (sum > value.total) {
|
|
31
|
+
throw new CustomFieldValueValidationError('Progress custom field value amounts can not exceed the total');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=progress.custom-field-value.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.custom-field-value.validator.js","sourceRoot":"","sources":["../../../lib/custom-field-types/progress/progress.custom-field-value.validator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,wDAAwD,CAAA;AAMxG,MAAM,UAAU,gCAAgC,CAC9C,UAAyC,EACzC,KAA8B;IAE9B,IAAI,UAAU,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAChC,MAAM,IAAI,+BAA+B,CAAC,sDAAsD,CAAC,CAAA;IACnG,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAClC,IAAI,GAAG,GAAG,CAAC,CAAA;IAEX,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,+BAA+B,CAAC,0DAA0D,CAAC,CAAA;QACvG,CAAC;QAED,IAAI,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,+BAA+B,CAAC,4DAA4D,CAAC,CAAA;QACzG,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,+BAA+B,CAAC,4DAA4D,CAAC,CAAA;QACzG,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,+BAA+B,CAAC,wDAAwD,CAAC,CAAA;QACrG,CAAC;QAED,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACzB,GAAG,IAAI,OAAO,CAAC,MAAM,CAAA;IACvB,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAM;IACR,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,+BAA+B,CAAC,6EAA6E,CAAC,CAAA;IAC1H,CAAC;IAED,IAAI,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,+BAA+B,CAAC,8DAA8D,CAAC,CAAA;IAC3G,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import { expect } from 'expect';
|
|
3
|
+
import { LocalizedString } from '@wisemen/localized-string';
|
|
4
|
+
import { customFieldDefinition } from '#src/factory/custom-field-definition.factory.js';
|
|
5
|
+
import { CustomFieldType } from '#src/enum/custom-field-type.enum.js';
|
|
6
|
+
import { validateCustomFieldValue } from '#src/validators/custom-field-value.validator.js';
|
|
7
|
+
import { CustomFieldValueValidationError } from '#src/validators/custom-field-value-validation.error.js';
|
|
8
|
+
import { ProgressCustomFieldColor } from '#src/custom-field-types/progress/progress.color.js';
|
|
9
|
+
const definition = customFieldDefinition(CustomFieldType.PROGRESS, {
|
|
10
|
+
tenantUuid: null,
|
|
11
|
+
entityType: 'project',
|
|
12
|
+
key: 'tasks',
|
|
13
|
+
label: new LocalizedString([{ locale: 'en', value: 'Tasks' }]),
|
|
14
|
+
description: null,
|
|
15
|
+
isRequired: false,
|
|
16
|
+
choices: [
|
|
17
|
+
{ value: 'completed', order: 1, label: new LocalizedString([{ locale: 'en', value: 'Completed' }]) },
|
|
18
|
+
{ value: 'in_progress', order: 2, label: new LocalizedString([{ locale: 'en', value: 'In progress' }]) }
|
|
19
|
+
],
|
|
20
|
+
rules: {
|
|
21
|
+
icon: 'tasks',
|
|
22
|
+
colors: {
|
|
23
|
+
completed: ProgressCustomFieldColor.SUCCESS,
|
|
24
|
+
in_progress: ProgressCustomFieldColor.WARNING
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
function validate(value) {
|
|
29
|
+
validateCustomFieldValue(definition, {
|
|
30
|
+
definitionUuid: definition.uuid,
|
|
31
|
+
type: CustomFieldType.PROGRESS,
|
|
32
|
+
value
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
describe('progress validateCustomFieldValue', () => {
|
|
36
|
+
it('accepts amounts for defined choices', () => {
|
|
37
|
+
expect(() => validate({
|
|
38
|
+
segments: [
|
|
39
|
+
{ key: 'completed', amount: 2 },
|
|
40
|
+
{ key: 'in_progress', amount: 3 }
|
|
41
|
+
]
|
|
42
|
+
})).not.toThrow();
|
|
43
|
+
});
|
|
44
|
+
it('accepts a decimal amount', () => {
|
|
45
|
+
expect(() => validate({ segments: [{ key: 'completed', amount: 0.42 }] })).not.toThrow();
|
|
46
|
+
});
|
|
47
|
+
it('accepts an empty value', () => {
|
|
48
|
+
expect(() => validate({ segments: [] })).not.toThrow();
|
|
49
|
+
});
|
|
50
|
+
it('rejects a key that is not a defined choice', () => {
|
|
51
|
+
expect(() => validate({ segments: [{ key: 'blocked', amount: 1 }] }))
|
|
52
|
+
.toThrow(new CustomFieldValueValidationError('Progress custom field value keys must be defined choices'));
|
|
53
|
+
});
|
|
54
|
+
it('rejects duplicate keys', () => {
|
|
55
|
+
expect(() => validate({
|
|
56
|
+
segments: [
|
|
57
|
+
{ key: 'completed', amount: 1 },
|
|
58
|
+
{ key: 'completed', amount: 2 }
|
|
59
|
+
]
|
|
60
|
+
})).toThrow(new CustomFieldValueValidationError('Progress custom field value can not contain duplicate keys'));
|
|
61
|
+
});
|
|
62
|
+
it('rejects a negative amount', () => {
|
|
63
|
+
expect(() => validate({ segments: [{ key: 'completed', amount: -1 }] }))
|
|
64
|
+
.toThrow(new CustomFieldValueValidationError('Progress custom field value amount can not be negative'));
|
|
65
|
+
});
|
|
66
|
+
it('rejects a non-finite amount', () => {
|
|
67
|
+
expect(() => validate({ segments: [{ key: 'completed', amount: Number.POSITIVE_INFINITY }] }))
|
|
68
|
+
.toThrow(new CustomFieldValueValidationError('Progress custom field value amount must be a finite number'));
|
|
69
|
+
});
|
|
70
|
+
it('accepts amounts below the total', () => {
|
|
71
|
+
expect(() => validate({ total: 100, segments: [{ key: 'completed', amount: 20 }] })).not.toThrow();
|
|
72
|
+
});
|
|
73
|
+
it('rejects amounts that exceed the total', () => {
|
|
74
|
+
expect(() => validate({
|
|
75
|
+
total: 4,
|
|
76
|
+
segments: [
|
|
77
|
+
{ key: 'completed', amount: 2 },
|
|
78
|
+
{ key: 'in_progress', amount: 3 }
|
|
79
|
+
]
|
|
80
|
+
})).toThrow(new CustomFieldValueValidationError('Progress custom field value amounts can not exceed the total'));
|
|
81
|
+
});
|
|
82
|
+
it('rejects a total of zero', () => {
|
|
83
|
+
expect(() => validate({ total: 0, segments: [] }))
|
|
84
|
+
.toThrow(new CustomFieldValueValidationError('Progress custom field value total must be a finite number greater than zero'));
|
|
85
|
+
});
|
|
86
|
+
it('rejects a non-finite total', () => {
|
|
87
|
+
expect(() => validate({ total: Number.POSITIVE_INFINITY, segments: [] }))
|
|
88
|
+
.toThrow(new CustomFieldValueValidationError('Progress custom field value total must be a finite number greater than zero'));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=progress.custom-field-value.validator.unit.test.js.map
|
package/dist/custom-field-types/progress/progress.custom-field-value.validator.unit.test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.custom-field-value.validator.unit.test.js","sourceRoot":"","sources":["../../../lib/custom-field-types/progress/progress.custom-field-value.validator.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedCustomFieldDefinitionFields } from '#src/custom-field-definition.js';
|
|
2
|
+
import type { CustomFieldType } from '#src/enum/custom-field-type.enum.js';
|
|
3
|
+
type ProgressCustomFieldDefinition = Extract<ResolvedCustomFieldDefinitionFields, {
|
|
4
|
+
type: CustomFieldType.PROGRESS;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function validateProgressCustomFieldDefinition(definition: ProgressCustomFieldDefinition): void;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { CustomFieldDefinitionError } from '#src/errors/custom-field-definition.error.js';
|
|
2
|
+
import { ProgressCustomFieldColor } from '#src/custom-field-types/progress/progress.color.js';
|
|
3
|
+
export function validateProgressCustomFieldDefinition(definition) {
|
|
4
|
+
validateProgressChoices(definition.choices);
|
|
5
|
+
const rules = definition.rules;
|
|
6
|
+
if (rules === null) {
|
|
7
|
+
throw new CustomFieldDefinitionError('Progress custom field rules are required');
|
|
8
|
+
}
|
|
9
|
+
if (rules.icon !== undefined && rules.icon.trim() === '') {
|
|
10
|
+
throw new CustomFieldDefinitionError('Progress custom field icon can not be empty');
|
|
11
|
+
}
|
|
12
|
+
const choiceValues = new Set(definition.choices.map(choice => choice.value));
|
|
13
|
+
for (const [key, color] of Object.entries(rules.colors)) {
|
|
14
|
+
if (!choiceValues.has(key)) {
|
|
15
|
+
throw new CustomFieldDefinitionError('Progress custom field colors can only be defined for choices');
|
|
16
|
+
}
|
|
17
|
+
if (!Object.values(ProgressCustomFieldColor).includes(color)) {
|
|
18
|
+
throw new CustomFieldDefinitionError('Progress custom field color must be a supported color');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
for (const choice of definition.choices) {
|
|
22
|
+
if (rules.colors[choice.value] === undefined) {
|
|
23
|
+
throw new CustomFieldDefinitionError('Progress custom field must define a color for every choice');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function validateProgressChoices(choices) {
|
|
28
|
+
if (choices.length === 0) {
|
|
29
|
+
throw new CustomFieldDefinitionError('Progress custom field must define at least one choice');
|
|
30
|
+
}
|
|
31
|
+
const choiceValues = new Set();
|
|
32
|
+
const choiceOrders = new Set();
|
|
33
|
+
for (const choice of choices) {
|
|
34
|
+
if (choiceValues.has(choice.value)) {
|
|
35
|
+
throw new CustomFieldDefinitionError('Custom field choice value must be unique');
|
|
36
|
+
}
|
|
37
|
+
if (choiceOrders.has(choice.order)) {
|
|
38
|
+
throw new CustomFieldDefinitionError('Custom field choice order must be unique');
|
|
39
|
+
}
|
|
40
|
+
choiceValues.add(choice.value);
|
|
41
|
+
choiceOrders.add(choice.order);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=progress.definition-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.definition-validation.js","sourceRoot":"","sources":["../../../lib/custom-field-types/progress/progress.definition-validation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8CAA8C,CAAA;AAEzF,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAA;AAI7F,MAAM,UAAU,qCAAqC,CAAC,UAAyC;IAC7F,uBAAuB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;IAE3C,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAA;IAE9B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,0BAA0B,CAAC,0CAA0C,CAAC,CAAA;IAClF,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACzD,MAAM,IAAI,0BAA0B,CAAC,6CAA6C,CAAC,CAAA;IACrF,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;IAE5E,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,0BAA0B,CAAC,8DAA8D,CAAC,CAAA;QACtG,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,0BAA0B,CAAC,uDAAuD,CAAC,CAAA;QAC/F,CAAC;IACH,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,EAAE,CAAC;YAC7C,MAAM,IAAI,0BAA0B,CAAC,4DAA4D,CAAC,CAAA;QACpG,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,OAA4B;IAC3D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,0BAA0B,CAAC,uDAAuD,CAAC,CAAA;IAC/F,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAA;IACtC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAA;IAEtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,0BAA0B,CAAC,0CAA0C,CAAC,CAAA;QAClF,CAAC;QAED,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,0BAA0B,CAAC,0CAA0C,CAAC,CAAA;QAClF,CAAC;QAED,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC9B,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BaseCustomFieldValueDto } from '#src/dto/base-custom-field-value.dto.js';
|
|
2
|
+
import { CustomFieldType } from '#src/enum/custom-field-type.enum.js';
|
|
3
|
+
import type { ProgressCustomFieldData, ProgressCustomFieldSegment } from '#src/custom-field-types/progress/progress.contract.js';
|
|
4
|
+
import type { ProgressCustomFieldValue } from '#src/custom-field-types/progress/progress.value.js';
|
|
5
|
+
export declare class ProgressCustomFieldSegmentDto {
|
|
6
|
+
key: string;
|
|
7
|
+
amount: number;
|
|
8
|
+
parse(): ProgressCustomFieldSegment;
|
|
9
|
+
static from(segment: ProgressCustomFieldSegment): ProgressCustomFieldSegmentDto;
|
|
10
|
+
}
|
|
11
|
+
export declare class ProgressCustomFieldDataDto {
|
|
12
|
+
total?: number;
|
|
13
|
+
segments: ProgressCustomFieldSegmentDto[];
|
|
14
|
+
parse(): ProgressCustomFieldData;
|
|
15
|
+
static from(data: ProgressCustomFieldData): ProgressCustomFieldDataDto;
|
|
16
|
+
}
|
|
17
|
+
export declare class ProgressCustomFieldValueDto extends BaseCustomFieldValueDto {
|
|
18
|
+
type: CustomFieldType.PROGRESS;
|
|
19
|
+
value: ProgressCustomFieldDataDto;
|
|
20
|
+
parse(): ProgressCustomFieldValue;
|
|
21
|
+
static from(customFieldValue: ProgressCustomFieldValue): ProgressCustomFieldValueDto;
|
|
22
|
+
}
|