@webitel/api-services 26.8.42 → 26.8.44
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/package.json +1 -1
- package/src/api/clients/cases/_internals/types.ts +11 -0
- package/src/api/clients/cases/cases.ts +54 -5
- package/src/api/clients//321/201ontacts/_internals/__tests__/stringifyContactExtensionFilters.spec.ts +80 -0
- package/src/api/clients//321/201ontacts/_internals/stringifyContactExtensionFilters.ts +88 -0
- package/src/api/clients//321/201ontacts/contacts.ts +27 -14
- package/src/api/transformers/translateError/__tests__/translateError.spec.ts +38 -0
- package/src/api/transformers/translateError/translateError.transformer.ts +17 -5
- package/src/locale/en/en.ts +8 -0
- package/src/locale/es/es.ts +8 -0
- package/src/locale/kz/kz.ts +8 -0
- package/src/locale/pl/pl.ts +8 -0
- package/src/locale/ro/ro.ts +8 -0
- package/src/locale/ru/ru.ts +8 -0
- package/src/locale/uk/uk.ts +8 -0
- package/src/locale/uz/uz.ts +8 -0
- package/src/locale/vi/vi.ts +8 -0
- package/types/.tsbuildinfo +1 -1
- package/types/api/clients/cases/_internals/types.d.ts +9 -0
- package/types/api/clients/cases/cases.d.ts +4 -2
- package/types/api/clients//321/201ontacts/_internals/stringifyContactExtensionFilters.d.ts +3 -0
- package/types/api/transformers/translateError/translateError.transformer.d.ts +6 -4
- package/types/locale/en/en.d.ts +7 -0
- package/types/locale/es/es.d.ts +7 -0
- package/types/locale/index.d.ts +63 -0
- package/types/locale/kz/kz.d.ts +7 -0
- package/types/locale/pl/pl.d.ts +7 -0
- package/types/locale/ro/ro.d.ts +7 -0
- package/types/locale/ru/ru.d.ts +7 -0
- package/types/locale/uk/uk.d.ts +7 -0
- package/types/locale/uz/uz.d.ts +7 -0
- package/types/locale/vi/vi.d.ts +7 -0
package/package.json
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LocateCaseNeighborDirection } from '@webitel/api-services/gen/models';
|
|
2
|
+
import type { ApiParams, GetItemParams } from '../../_shared/types';
|
|
3
|
+
|
|
4
|
+
export interface GetCaseParams extends GetItemParams {
|
|
5
|
+
listParams?: ApiParams;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface GetCaseNeighborParams extends GetItemParams {
|
|
9
|
+
direction: LocateCaseNeighborDirection;
|
|
10
|
+
listParams: ApiParams;
|
|
11
|
+
}
|
|
@@ -21,10 +21,10 @@ import type {
|
|
|
21
21
|
ApiId,
|
|
22
22
|
ApiParams,
|
|
23
23
|
DeleteItemParams,
|
|
24
|
-
GetItemParams,
|
|
25
24
|
} from '../_shared/types';
|
|
26
25
|
import { FTSServiceAPI } from './_internals/ftsService';
|
|
27
26
|
import { stringifyCaseFilters } from './_internals/stringifyCaseFilters';
|
|
27
|
+
import type { GetCaseNeighborParams, GetCaseParams } from './_internals/types';
|
|
28
28
|
|
|
29
29
|
const casesService = getCases();
|
|
30
30
|
|
|
@@ -174,11 +174,36 @@ const caseFieldsToSend = [
|
|
|
174
174
|
'custom',
|
|
175
175
|
];
|
|
176
176
|
|
|
177
|
-
const
|
|
177
|
+
const caseNeighborFields = [
|
|
178
|
+
'has_prev',
|
|
179
|
+
'has_next',
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
const getCaseListContext = ({ sort, ...filters }: ApiParams) => ({
|
|
183
|
+
q: filters.search,
|
|
184
|
+
sort,
|
|
185
|
+
filters: stringifyCaseFilters(filters),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const getLocateCaseParams = (listParams?: ApiParams) =>
|
|
189
|
+
listParams
|
|
190
|
+
? {
|
|
191
|
+
...getCaseListContext(listParams),
|
|
192
|
+
fields: [
|
|
193
|
+
...caseFieldsToSend,
|
|
194
|
+
...caseNeighborFields,
|
|
195
|
+
],
|
|
196
|
+
}
|
|
197
|
+
: {
|
|
198
|
+
fields: caseFieldsToSend,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const getCase = async ({ itemId: id, listParams }: GetCaseParams) => {
|
|
178
202
|
try {
|
|
179
|
-
const response = await casesService.locateCase(
|
|
180
|
-
|
|
181
|
-
|
|
203
|
+
const response = await casesService.locateCase(
|
|
204
|
+
String(id),
|
|
205
|
+
getLocateCaseParams(listParams),
|
|
206
|
+
);
|
|
182
207
|
return applyTransform(response.data, [
|
|
183
208
|
snakeToCamel([
|
|
184
209
|
'custom',
|
|
@@ -193,6 +218,29 @@ const getCase = async ({ itemId: id }: GetItemParams) => {
|
|
|
193
218
|
}
|
|
194
219
|
};
|
|
195
220
|
|
|
221
|
+
const getCaseNeighbor = async ({
|
|
222
|
+
itemId: id,
|
|
223
|
+
direction,
|
|
224
|
+
listParams,
|
|
225
|
+
}: GetCaseNeighborParams) => {
|
|
226
|
+
try {
|
|
227
|
+
const response = await casesService.locateCaseNeighbor(String(id), {
|
|
228
|
+
...getCaseListContext(listParams),
|
|
229
|
+
direction,
|
|
230
|
+
fields: [
|
|
231
|
+
'id',
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
return applyTransform(response.data, [
|
|
235
|
+
snakeToCamel(),
|
|
236
|
+
]);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
throw applyTransform(err, [
|
|
239
|
+
notify,
|
|
240
|
+
]);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
196
244
|
const deleteCase = async ({ id }: DeleteItemParams) => {
|
|
197
245
|
try {
|
|
198
246
|
const response = await casesService.deleteCase(String(id));
|
|
@@ -364,6 +412,7 @@ export const CasesAPI = {
|
|
|
364
412
|
getList: getCasesList,
|
|
365
413
|
getLookup: getCasesLookup,
|
|
366
414
|
get: getCase,
|
|
415
|
+
getNeighbor: getCaseNeighbor,
|
|
367
416
|
delete: deleteCase,
|
|
368
417
|
update: updateCase,
|
|
369
418
|
add: addCase,
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type { DataField } from '../../../../../gen/_models';
|
|
4
|
+
import { stringifyContactExtensionFilters } from '../stringifyContactExtensionFilters';
|
|
5
|
+
|
|
6
|
+
const fields: DataField[] = [
|
|
7
|
+
{
|
|
8
|
+
id: 'tee',
|
|
9
|
+
kind: 'string',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: 'test',
|
|
13
|
+
kind: 'int32',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'my_bool',
|
|
17
|
+
kind: 'bool',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'ca',
|
|
21
|
+
kind: 'datetime',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'my_priority',
|
|
25
|
+
kind: 'lookup',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'tags',
|
|
29
|
+
kind: 'list',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
describe('stringifyContactExtensionFilters', () => {
|
|
34
|
+
it('builds a CEL expression by field kind', () => {
|
|
35
|
+
expect(
|
|
36
|
+
stringifyContactExtensionFilters(
|
|
37
|
+
{
|
|
38
|
+
tee: '123',
|
|
39
|
+
test: 42,
|
|
40
|
+
my_bool: false,
|
|
41
|
+
ca: {
|
|
42
|
+
from: 1700000000000,
|
|
43
|
+
},
|
|
44
|
+
my_priority: '1',
|
|
45
|
+
tags: [
|
|
46
|
+
'1',
|
|
47
|
+
'2',
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
fields,
|
|
51
|
+
),
|
|
52
|
+
).toBe(
|
|
53
|
+
'tee == "123" && test == 42 && my_bool == false && ca >= 1700000000000 && my_priority.id == "1" && (tags.exists(x, x.id == "1") || tags.exists(x, x.id == "2"))',
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('skips a list filter with no selected items', () => {
|
|
58
|
+
expect(
|
|
59
|
+
stringifyContactExtensionFilters(
|
|
60
|
+
{
|
|
61
|
+
tee: '123',
|
|
62
|
+
tags: [],
|
|
63
|
+
},
|
|
64
|
+
fields,
|
|
65
|
+
),
|
|
66
|
+
).toBe('tee == "123"');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('returns undefined when no extension filter is applied', () => {
|
|
70
|
+
expect(
|
|
71
|
+
stringifyContactExtensionFilters(
|
|
72
|
+
{
|
|
73
|
+
page: 1,
|
|
74
|
+
tee: null,
|
|
75
|
+
},
|
|
76
|
+
fields,
|
|
77
|
+
),
|
|
78
|
+
).toBeUndefined();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { DataField } from '../../../../gen/_models';
|
|
2
|
+
import { TypeKind } from '../../../../gen/_models/typeKind';
|
|
3
|
+
import {
|
|
4
|
+
type DatetimeRangeValue,
|
|
5
|
+
type NormalizeDatetimeValueParam,
|
|
6
|
+
normalizeDatetimeRange,
|
|
7
|
+
} from '../../../../scripts';
|
|
8
|
+
import type { ApiParams } from '../../_shared/types';
|
|
9
|
+
|
|
10
|
+
type ScalarFilterValue = string | number | boolean;
|
|
11
|
+
|
|
12
|
+
type LookupFilterValue =
|
|
13
|
+
| string
|
|
14
|
+
| number
|
|
15
|
+
| {
|
|
16
|
+
id: string | number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type DatetimeFilterValue = NormalizeDatetimeValueParam | DatetimeRangeValue;
|
|
20
|
+
|
|
21
|
+
type ExtensionFilterValue =
|
|
22
|
+
| ScalarFilterValue
|
|
23
|
+
| LookupFilterValue
|
|
24
|
+
| LookupFilterValue[]
|
|
25
|
+
| DatetimeFilterValue;
|
|
26
|
+
|
|
27
|
+
const quote = (value: ScalarFilterValue) => JSON.stringify(String(value));
|
|
28
|
+
|
|
29
|
+
const lookupId = (value: LookupFilterValue) =>
|
|
30
|
+
typeof value === 'object' ? value.id : value;
|
|
31
|
+
|
|
32
|
+
const toListCondition = (
|
|
33
|
+
id: string,
|
|
34
|
+
value: LookupFilterValue | LookupFilterValue[],
|
|
35
|
+
) => {
|
|
36
|
+
const items = [
|
|
37
|
+
value,
|
|
38
|
+
].flat();
|
|
39
|
+
if (!items.length) return '';
|
|
40
|
+
|
|
41
|
+
const conditions = items.map(
|
|
42
|
+
(item) => `${id}.exists(x, x.id == ${quote(lookupId(item))})`,
|
|
43
|
+
);
|
|
44
|
+
return `(${conditions.join(' || ')})`;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const toDatetimeCondition = (id: string, value: DatetimeFilterValue) => {
|
|
48
|
+
const { from, to } = normalizeDatetimeRange(value) ?? {};
|
|
49
|
+
return [
|
|
50
|
+
from && `${id} >= ${from}`,
|
|
51
|
+
to && `${id} <= ${to}`,
|
|
52
|
+
]
|
|
53
|
+
.filter(Boolean)
|
|
54
|
+
.join(' && ');
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const toCondition = (
|
|
58
|
+
id: string,
|
|
59
|
+
kind: DataField['kind'],
|
|
60
|
+
value: ExtensionFilterValue,
|
|
61
|
+
) => {
|
|
62
|
+
switch (kind) {
|
|
63
|
+
case TypeKind.String:
|
|
64
|
+
case TypeKind.Richtext:
|
|
65
|
+
return `${id} == ${quote(value as ScalarFilterValue)}`;
|
|
66
|
+
case TypeKind.Lookup:
|
|
67
|
+
return `${id}.id == ${quote(lookupId(value as LookupFilterValue))}`;
|
|
68
|
+
case TypeKind.List:
|
|
69
|
+
return toListCondition(
|
|
70
|
+
id,
|
|
71
|
+
value as LookupFilterValue | LookupFilterValue[],
|
|
72
|
+
);
|
|
73
|
+
case TypeKind.Datetime:
|
|
74
|
+
return toDatetimeCondition(id, value as DatetimeFilterValue);
|
|
75
|
+
default:
|
|
76
|
+
return `${id} == ${value}`;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const stringifyContactExtensionFilters = (
|
|
81
|
+
params: ApiParams,
|
|
82
|
+
extensionFields: DataField[] = [],
|
|
83
|
+
) =>
|
|
84
|
+
extensionFields
|
|
85
|
+
.filter(({ id = '' }) => params[id] != null)
|
|
86
|
+
.map(({ id = '', kind }) => toCondition(id, kind, params[id]))
|
|
87
|
+
.filter(Boolean)
|
|
88
|
+
.join(' && ') || undefined;
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
notify,
|
|
13
13
|
sanitizeToWire,
|
|
14
14
|
snakeToCamel,
|
|
15
|
+
translateError,
|
|
15
16
|
} from '../../transformers';
|
|
16
17
|
import { generatePermissionsApi } from '../_shared/generatePermissionsApi';
|
|
17
18
|
import type {
|
|
@@ -20,6 +21,7 @@ import type {
|
|
|
20
21
|
DeleteItemParams,
|
|
21
22
|
GetItemParams,
|
|
22
23
|
} from '../_shared/types';
|
|
24
|
+
import { stringifyContactExtensionFilters } from './_internals/stringifyContactExtensionFilters';
|
|
23
25
|
import { ContactsSearchMode } from './enums/ContactsSearchMode';
|
|
24
26
|
|
|
25
27
|
const baseUrl = '/contacts';
|
|
@@ -118,20 +120,30 @@ const getList = async (params: ApiParams) => {
|
|
|
118
120
|
]);
|
|
119
121
|
|
|
120
122
|
try {
|
|
121
|
-
const response = await getContacts().searchContacts(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
const response = await getContacts().searchContacts(
|
|
124
|
+
{
|
|
125
|
+
...searchParams,
|
|
126
|
+
sort: searchParams.sort
|
|
127
|
+
? [
|
|
128
|
+
searchParams.sort,
|
|
129
|
+
]
|
|
130
|
+
: [
|
|
131
|
+
'+name',
|
|
132
|
+
],
|
|
133
|
+
fields: [
|
|
134
|
+
'mode',
|
|
135
|
+
...(searchParams.fields || []),
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
params: {
|
|
140
|
+
filters: stringifyContactExtensionFilters(
|
|
141
|
+
params,
|
|
142
|
+
params.extensionFields,
|
|
143
|
+
),
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
);
|
|
135
147
|
|
|
136
148
|
const { items, next } = applyTransform(
|
|
137
149
|
{
|
|
@@ -152,6 +164,7 @@ const getList = async (params: ApiParams) => {
|
|
|
152
164
|
};
|
|
153
165
|
} catch (err) {
|
|
154
166
|
throw applyTransform(err, [
|
|
167
|
+
translateError,
|
|
155
168
|
notify,
|
|
156
169
|
]);
|
|
157
170
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { createI18n } from 'vue-i18n';
|
|
3
|
+
|
|
4
|
+
import { config, setConfig } from '../../../../config/config';
|
|
5
|
+
import translateError from '../translateError.transformer';
|
|
6
|
+
|
|
7
|
+
const reservedFieldError = () => ({
|
|
8
|
+
response: {
|
|
9
|
+
data: {
|
|
10
|
+
id: 'contacts.search.filters.reserved_field',
|
|
11
|
+
detail:
|
|
12
|
+
"contacts: field 'list' has a reserved name and cannot be used in filters; rename it",
|
|
13
|
+
} as {
|
|
14
|
+
id: string;
|
|
15
|
+
detail: string;
|
|
16
|
+
translation?: string;
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('translateError', () => {
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
config.i18n = null;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('translates contacts reserved field error with the field code', () => {
|
|
27
|
+
setConfig({
|
|
28
|
+
i18n: createI18n({
|
|
29
|
+
legacy: false,
|
|
30
|
+
locale: 'uk',
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(translateError(reservedFieldError()).response.data.translation).toBe(
|
|
35
|
+
'Поле "list" має зарезервоване ім\'я. Перейменуйте його в розділі Персоналізація, щоб увімкнути фільтрацію',
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -9,15 +9,27 @@ const BACKEND_ERRORS_PREFIX = 'backendErrors';
|
|
|
9
9
|
// Converts snake_case error IDs from backend to camelCase keys
|
|
10
10
|
// Looks up translations in api-services locale files under 'backendErrors' prefix
|
|
11
11
|
// Adds the translated message to err.response.data.translation for use by notify transformer
|
|
12
|
+
interface TranslatableErrorData {
|
|
13
|
+
id?: string;
|
|
14
|
+
detail?: string;
|
|
15
|
+
translation?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
interface TranslatableError {
|
|
13
19
|
response?: {
|
|
14
|
-
data?:
|
|
15
|
-
id?: string;
|
|
16
|
-
translation?: string;
|
|
17
|
-
};
|
|
20
|
+
data?: TranslatableErrorData;
|
|
18
21
|
};
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
const errorTranslationParams: Record<
|
|
25
|
+
string,
|
|
26
|
+
(data: TranslatableErrorData) => Record<string, unknown>
|
|
27
|
+
> = {
|
|
28
|
+
'contacts.search.filters.reserved_field': ({ detail }) => ({
|
|
29
|
+
field: detail?.match(/'([^']+)'/)?.[1],
|
|
30
|
+
}),
|
|
31
|
+
};
|
|
32
|
+
|
|
21
33
|
const translateError = <T extends TranslatableError>(err: T): T => {
|
|
22
34
|
const errorId = err?.response?.data?.id;
|
|
23
35
|
if (!errorId) return err;
|
|
@@ -33,7 +45,7 @@ const translateError = <T extends TranslatableError>(err: T): T => {
|
|
|
33
45
|
// unify, so narrow to the composition-API Composer we run with.
|
|
34
46
|
const translation = (i18n.global as Composer).t(
|
|
35
47
|
fullKey,
|
|
36
|
-
{},
|
|
48
|
+
errorTranslationParams[errorId]?.(err.response?.data ?? {}) ?? {},
|
|
37
49
|
{
|
|
38
50
|
missingWarn: false,
|
|
39
51
|
fallbackWarn: false,
|
package/src/locale/en/en.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'"{field}" is a reserved name. Rename the field in Personalization to enable filtering',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/es/es.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'"{field}" es un nombre reservado. Cambie el nombre del campo en Personalización para habilitar el filtrado',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/kz/kz.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'"{field}" — резервтелген атау. Сүзгілеуді қосу үшін өрісті Жекелендіру бөлімінде қайта атаңыз',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/pl/pl.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'"{field}" to zarezerwowana nazwa. Zmień nazwę pola w sekcji Personalizacja, aby włączyć filtrowanie',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/ro/ro.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'"{field}" este un nume rezervat. Redenumiți câmpul în Personalizare pentru a activa filtrarea',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/ru/ru.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'Поле "{field}" имеет зарезервированное имя. Переименуйте его в разделе Персонализация, чтобы включить фильтрацию',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/uk/uk.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'Поле "{field}" має зарезервоване ім\'я. Перейменуйте його в розділі Персоналізація, щоб увімкнути фільтрацію',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/uz/uz.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'"{field}" zaxiralangan nom. Filtrlashni yoqish uchun maydonni Shaxsiylashtirish bo\'limida qayta nomlang',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|
package/src/locale/vi/vi.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { MessageContext } from 'vue-i18n';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
backendErrors: {
|
|
5
|
+
contacts: {
|
|
6
|
+
search: {
|
|
7
|
+
filters: {
|
|
8
|
+
reservedField:
|
|
9
|
+
'"{field}" là tên dành riêng. Hãy đổi tên trường trong mục Cá nhân hóa để bật lọc',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
5
13
|
app: {
|
|
6
14
|
auditForm: {
|
|
7
15
|
isValid: {
|