From 7c55c2e68efc3a51865ee35d68ce589ad78f3f90 Mon Sep 17 00:00:00 2001
From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com>
Date: Thu, 17 Sep 2026 15:54:57 +0200
Subject: [PATCH 1/5] feat(formatters): support static text and field formats
---
specifyweb/backend/stored_queries/format.py | 7 ++++
.../tests/test_format/test_format_sprintf.py | 36 ++++++++++++++++++-
.../lib/components/Formatters/formatters.ts | 22 ++++++++++++
.../js_src/lib/components/Formatters/spec.ts | 4 +--
4 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/specifyweb/backend/stored_queries/format.py b/specifyweb/backend/stored_queries/format.py
index 1a8970b6238..6837a5af4b7 100644
--- a/specifyweb/backend/stored_queries/format.py
+++ b/specifyweb/backend/stored_queries/format.py
@@ -194,6 +194,13 @@ def make_expr(self,
do_blank_null = True
) -> tuple[
QueryConstruct, blank_nulls, QueryFieldSpec]:
+ if path is None:
+ # A field without a mapped field is static text. The editor uses
+ # ``sep`` for these entries so that the text is retained when
+ # neighbouring fields are null.
+ static_text = fieldNodeAttrib.get('format', fieldNodeAttrib.get('sep', ''))
+ return query, blank_nulls(literal(static_text)), None
+
path = path.split('.')
path = [inspect(orm_table).class_.__name__, *path]
formatter_field_spec = QueryFieldSpec.from_path(path)
diff --git a/specifyweb/backend/stored_queries/tests/test_format/test_format_sprintf.py b/specifyweb/backend/stored_queries/tests/test_format/test_format_sprintf.py
index 918a98c7419..009d07fc0f2 100644
--- a/specifyweb/backend/stored_queries/tests/test_format/test_format_sprintf.py
+++ b/specifyweb/backend/stored_queries/tests/test_format/test_format_sprintf.py
@@ -56,4 +56,38 @@ def test_accession(self, get_app_resource: Mock):
(acc3.id, ', [89]'),
(acc4.id, '')],
results
- )
\ No newline at end of file
+ )
+
+ @patch('specifyweb.backend.stored_queries.format.app_resource.get_app_resource')
+ def test_static_fields_and_postfix(self, get_app_resource: Mock):
+ get_app_resource.return_value = ("""
+
+
+
+
+
+ remarks
+
+
+
+
+
+ """, None, None)
+ Accession.objects.all().delete()
+ accession = Accession.objects.create(
+ division=self.division,
+ remarks="Remarks",
+ accessionnumber="1",
+ )
+ empty = Accession.objects.create(
+ division=self.division,
+ accessionnumber="2",
+ )
+ table, query_fields = make_query_fields_test("Accession", [[]])
+
+ results = self._get_results(table, query_fields)
+ self.assertCountEqual([
+ (accession.id, "[Remarks]!"),
+ (empty.id, "[!"),
+ ], results)
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts b/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
index 6ab299b8406..0c7da61173b 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
@@ -169,6 +169,7 @@ async function formatField(
fieldFormatter,
formatFieldValue = true,
trimZeros = false,
+ format: displayFormat,
}: Formatter['definition']['fields'][number]['fields'][number] & {
readonly formatFieldValue?: boolean;
},
@@ -184,6 +185,14 @@ async function formatField(
const cycleDetector = [...cycleDetection, parentResource];
let formatted: string | undefined = undefined;
+ if (fields === undefined) {
+ // An unmapped field is a static formatter entry. Its separator is the
+ // text to emit, rather than a separator for another value.
+ return {
+ formatted: displayFormat ?? separator ?? '',
+ separator: localized(''),
+ };
+ }
const hasPermission = hasPathPermission(fields ?? [], 'read');
if (hasPermission) {
@@ -229,6 +238,18 @@ async function formatField(
: num.toString();
}
+ if (displayFormat !== undefined) {
+ const substitution = displayFormat.includes('%s')
+ ? '%s'
+ : displayFormat.includes('%d')
+ ? '%d'
+ : undefined;
+ formatted =
+ formatted === undefined || substitution === undefined
+ ? displayFormat
+ : displayFormat.replace(substitution, formatted ?? '');
+ }
+
return {
formatted: formatted?.toString() ?? '',
separator: (formatted ?? '') === '' ? '' : separator,
@@ -301,6 +322,7 @@ const autoGenerateFormatter = (table: SpecifyTable): Formatter => ({
formatter: undefined,
aggregator: undefined,
fieldFormatter: undefined,
+ format: undefined,
trimZeros: false,
})),
},
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts b/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts
index e36777f8025..81d5f3ed5f7 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts
@@ -26,9 +26,6 @@ export const formattersSpec = f.store(() =>
.filter((fieldGroup) => fieldGroup.fields.length > 0)
.map((fieldGroup) => ({
...fieldGroup,
- fields: fieldGroup.fields.filter(
- (field) => field.field !== undefined
- ),
})),
isSingle: definition.fields.length <= 1,
},
@@ -125,6 +122,7 @@ const fieldSpec = (table: SpecifyTable | undefined) =>
),
aggregator: syncers.xmlAttribute('aggregator', 'skip'),
formatter: syncers.xmlAttribute('formatter', 'skip'),
+ format: syncers.xmlAttribute('format', 'skip'),
fieldFormatter: syncers.xmlAttribute('uiFieldFormatter', 'skip'),
field: pipe(syncers.xmlContent, syncers.field(table?.name)),
trimZeros: pipe(
From 67c64f93ade825d086dc5d3fe816c5e070f233cf Mon Sep 17 00:00:00 2001
From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com>
Date: Thu, 17 Sep 2026 15:55:02 +0200
Subject: [PATCH 2/5] feat(formatters): improve field format editor
---
.../lib/components/Formatters/Definitions.tsx | 1 +
.../lib/components/Formatters/Fields.tsx | 77 ++++++++++++++++++-
.../Formatters/__tests__/formatters.test.ts | 35 +++++++++
.../js_src/lib/localization/resources.ts | 22 ++++++
4 files changed, 132 insertions(+), 3 deletions(-)
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/Definitions.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/Definitions.tsx
index ca931387c9d..4ff493272b3 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/Definitions.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/Definitions.tsx
@@ -200,6 +200,7 @@ function ConditionalFormatter({
separator: localized(' '),
aggregator: undefined,
formatter: undefined,
+ format: undefined,
fieldFormatter: undefined,
field: undefined,
trimZeros: false,
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
index acb6b41f016..5eb114cc507 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
@@ -64,8 +64,8 @@ export function Fields({
[&_td]:!items-stretch
${
displayFormatter
- ? 'grid-cols-[min-content_1fr_auto_min-content]'
- : 'grid-cols-[min-content_1fr_min-content]'
+ ? 'grid-cols-[min-content_1fr_auto_auto_min-content]'
+ : 'grid-cols-[min-content_1fr_auto_min-content]'
}
`}
>
@@ -73,7 +73,8 @@ export function Fields({
| {resourcesText.separator()} |
{schemaText.field()} |
- {displayFormatter && {schemaText.customFieldFormat()} | }
+ {resourcesText.displayFormat()} |
+ {displayFormatter && {resourcesText.fieldFormat()} | }
|
@@ -115,6 +116,7 @@ export function Fields({
separator: localized(' '),
aggregator: undefined,
formatter: undefined,
+ format: undefined,
fieldFormatter: undefined,
field: undefined,
trimZeros: false,
@@ -203,6 +205,25 @@ function Field({
+
+ {field.field === undefined ? (
+
+ handleChange({
+ ...field,
+ format: format.length === 0 ? undefined : format,
+ })
+ }
+ />
+ ) : (
+
+ )}
+ |
{displayFormatter && (
@@ -240,6 +261,56 @@ function Field({
);
}
+function FieldFormat({
+ field: [field, handleChange],
+}: {
+ readonly field: GetSet<
+ Formatter['definition']['fields'][number]['fields'][number]
+ >;
+}): JSX.Element {
+ const isReadOnly = React.useContext(ReadOnlyContext);
+ const format = field.format ?? '';
+ const substitution = field.format?.match(/%[sd]/)?.[0] ?? '%s';
+ const [prefix, suffix] = format.includes(substitution)
+ ? format.split(substitution, 2)
+ : [format, ''];
+ const updateFormat = (newPrefix: string, newSuffix: string): void => {
+ const format = `${newPrefix}${substitution}${newSuffix}`;
+ handleChange({ ...field, format: format === '%s' ? undefined : format });
+ };
+
+ return (
+
+ updateFormat(value, suffix)}
+ />
+
+ …
+
+ updateFormat(prefix, value)}
+ />
+
+ );
+}
+
function FieldFormatter({
field: [field, handleChange],
}: {
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts b/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts
index 1cfc1557635..ad0c3e8b8ba 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts
@@ -143,6 +143,41 @@ describe('formatField', () => {
separator: ', ',
});
});
+
+ test('applies a field format and preserves static formatter entries', async () => {
+ const parentResource = new tables.Collector.Resource({ id: collectorId });
+ await expect(
+ formatField(
+ {
+ field: [
+ tables.Collector.strictGetField('agent'),
+ tables.Agent.strictGetField('agentType'),
+ ],
+ formatter: undefined,
+ aggregator: undefined,
+ fieldFormatter: undefined,
+ format: '(%s)',
+ separator: localized(''),
+ trimZeros: false,
+ },
+ parentResource
+ )
+ ).resolves.toEqual({ formatted: '(Person)', separator: '' });
+ await expect(
+ formatField(
+ {
+ field: undefined,
+ formatter: undefined,
+ aggregator: undefined,
+ fieldFormatter: undefined,
+ format: undefined,
+ separator: localized(' / '),
+ trimZeros: false,
+ },
+ parentResource
+ )
+ ).resolves.toEqual({ formatted: ' / ', separator: '' });
+ });
});
const referenceWorkId = 1;
diff --git a/specifyweb/frontend/js_src/lib/localization/resources.ts b/specifyweb/frontend/js_src/lib/localization/resources.ts
index 58e2b7eac4e..cc15eb55cca 100644
--- a/specifyweb/frontend/js_src/lib/localization/resources.ts
+++ b/specifyweb/frontend/js_src/lib/localization/resources.ts
@@ -994,6 +994,28 @@ export const resourcesText = createDictionary({
'hr-hr': 'Prilagodite formate polja',
nb: 'Tilpass feltformater',
},
+ displayFormat: {
+ 'en-us': 'Display Format',
+ 'de-ch': 'Anzeigeformat',
+ 'es-es': 'Formato de visualización',
+ 'fr-fr': "Format d'affichage",
+ 'ru-ru': 'Формат отображения',
+ 'uk-ua': 'Формат відображення',
+ 'pt-br': 'Formato de exibição',
+ 'hr-hr': 'Format prikaza',
+ nb: 'Visningsformat',
+ },
+ fieldFormat: {
+ 'en-us': 'Field Format',
+ 'de-ch': 'Feldformat',
+ 'es-es': 'Formato de campo',
+ 'fr-fr': 'Format de champ',
+ 'ru-ru': 'Формат поля',
+ 'uk-ua': 'Формат поля',
+ 'pt-br': 'Formato do campo',
+ 'hr-hr': 'Format polja',
+ nb: 'Feltformat',
+ },
expandConditionalField: {
'en-us': 'Expand Conditional Field',
'de-ch': 'Bedingtes Feld erweitern',
From 5d3e8b8d7463adc20d4c9e76daf711aead9ff67f Mon Sep 17 00:00:00 2001
From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com>
Date: Thu, 17 Sep 2026 16:11:36 +0200
Subject: [PATCH 3/5] fix: failing test
---
.../frontend/js_src/lib/components/Formatters/Fields.tsx | 5 ++++-
specifyweb/frontend/js_src/lib/components/Formatters/spec.ts | 2 +-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
index 5eb114cc507..14b9e2ab051 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
@@ -276,7 +276,10 @@ function FieldFormat({
: [format, ''];
const updateFormat = (newPrefix: string, newSuffix: string): void => {
const format = `${newPrefix}${substitution}${newSuffix}`;
- handleChange({ ...field, format: format === '%s' ? undefined : format });
+ handleChange({
+ ...field,
+ format: format === '%s' ? undefined : localized(format),
+ });
};
return (
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts b/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts
index 81d5f3ed5f7..5de578d2543 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/spec.ts
@@ -122,7 +122,7 @@ const fieldSpec = (table: SpecifyTable | undefined) =>
),
aggregator: syncers.xmlAttribute('aggregator', 'skip'),
formatter: syncers.xmlAttribute('formatter', 'skip'),
- format: syncers.xmlAttribute('format', 'skip'),
+ format: syncers.xmlAttribute('format', 'skip', false),
fieldFormatter: syncers.xmlAttribute('uiFieldFormatter', 'skip'),
field: pipe(syncers.xmlContent, syncers.field(table?.name)),
trimZeros: pipe(
From d3d1c0a5b415473d7f74ac12b52a4f421770b90f Mon Sep 17 00:00:00 2001
From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com>
Date: Thu, 17 Sep 2026 21:54:57 +0200
Subject: [PATCH 4/5] fix(tests): one more
---
.../__snapshots__/formatters.test.ts.snap | 1 +
.../Formatters/__tests__/formatters.test.ts | 28 ++++++++++++++++++-
.../lib/components/Formatters/formatters.ts | 7 +++--
.../components/Syncer/__tests__/index.test.ts | 1 +
4 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/__snapshots__/formatters.test.ts.snap b/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/__snapshots__/formatters.test.ts.snap
index dea1513e2c1..81a5cf42986 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/__snapshots__/formatters.test.ts.snap
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/__snapshots__/formatters.test.ts.snap
@@ -1536,6 +1536,7 @@ exports[`Formatters are fetched and parsed correctly 1`] = `
"field": [
"[literalField LoanReturnPreparation.quantityResolved]",
],
+ "format": "%d",
"separator": " - ",
"trimZeros": false,
},
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts b/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts
index ad0c3e8b8ba..4f3d28f0393 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/__tests__/formatters.test.ts
@@ -106,6 +106,7 @@ describe('formatField', () => {
formatter: undefined,
aggregator: undefined,
fieldFormatter: undefined,
+ format: undefined,
separator: localized(', '),
trimZeros: false,
},
@@ -132,6 +133,7 @@ describe('formatField', () => {
formatter: undefined,
aggregator: undefined,
fieldFormatter: undefined,
+ format: undefined,
formatFieldValue: false,
separator: localized(', '),
trimZeros: false,
@@ -156,7 +158,7 @@ describe('formatField', () => {
formatter: undefined,
aggregator: undefined,
fieldFormatter: undefined,
- format: '(%s)',
+ format: localized('(%s)'),
separator: localized(''),
trimZeros: false,
},
@@ -178,6 +180,26 @@ describe('formatField', () => {
)
).resolves.toEqual({ formatted: ' / ', separator: '' });
});
+
+ test('omits empty mapped values from substitution formats', async () => {
+ const parentResource = new tables.Agent.Resource({ agentType: undefined });
+ const field = [tables.Agent.strictGetField('agentType')];
+ const base = {
+ field,
+ formatter: undefined,
+ aggregator: undefined,
+ fieldFormatter: undefined,
+ separator: localized(''),
+ trimZeros: false,
+ } as const;
+
+ await expect(
+ formatField({ ...base, format: localized('%s') }, parentResource)
+ ).resolves.toEqual({ formatted: '', separator: '' });
+ await expect(
+ formatField({ ...base, format: localized('%d') }, parentResource)
+ ).resolves.toEqual({ formatted: '', separator: '' });
+ });
});
const referenceWorkId = 1;
@@ -230,6 +252,7 @@ test('Circular formatting is detected and prevented', async () => {
separator: localized(''),
formatter: undefined,
fieldFormatter: undefined,
+ format: undefined,
trimZeros: false,
},
{
@@ -238,6 +261,7 @@ test('Circular formatting is detected and prevented', async () => {
separator: localized(''),
formatter: undefined,
fieldFormatter: undefined,
+ format: undefined,
trimZeros: false,
},
],
@@ -264,6 +288,7 @@ test('Circular formatting is detected and prevented', async () => {
separator: localized(' - '),
formatter: undefined,
fieldFormatter: undefined,
+ format: undefined,
trimZeros: false,
},
{
@@ -272,6 +297,7 @@ test('Circular formatting is detected and prevented', async () => {
separator: localized(' -- '),
formatter: undefined,
fieldFormatter: undefined,
+ format: undefined,
trimZeros: false,
},
],
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts b/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
index 0c7da61173b..45af4066194 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/formatters.ts
@@ -245,9 +245,11 @@ async function formatField(
? '%d'
: undefined;
formatted =
- formatted === undefined || substitution === undefined
+ substitution === undefined
? displayFormat
- : displayFormat.replace(substitution, formatted ?? '');
+ : formatted === undefined || formatted === ''
+ ? undefined
+ : displayFormat.replace(substitution, formatted);
}
return {
@@ -272,6 +274,7 @@ export async function fetchPathAsString(
separator: localized(''),
aggregator: undefined,
fieldFormatter: undefined,
+ format: undefined,
formatFieldValue,
trimZeros: false,
},
diff --git a/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/index.test.ts b/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/index.test.ts
index 359a83b877c..54b8860ad26 100644
--- a/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/index.test.ts
+++ b/specifyweb/frontend/js_src/lib/components/Syncer/__tests__/index.test.ts
@@ -55,6 +55,7 @@ test('Editing Data Object Formatter', () => {
aggregator: undefined,
formatter: undefined,
fieldFormatter: undefined,
+ format: undefined,
field: [getField(tables.Accession, 'accessionAgents')],
trimZeros: false,
},
From 9d4dd3ccb1effe34f82717bbcfdeac337719ae18 Mon Sep 17 00:00:00 2001
From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com>
Date: Fri, 18 Sep 2026 10:20:24 +0200
Subject: [PATCH 5/5] fix(formatters): use proper localization
---
.../js_src/lib/components/Formatters/Fields.tsx | 2 +-
.../frontend/js_src/lib/localization/resources.ts | 11 -----------
specifyweb/frontend/js_src/lib/localization/schema.ts | 11 -----------
3 files changed, 1 insertion(+), 23 deletions(-)
diff --git a/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx b/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
index 14b9e2ab051..02dbd81b841 100644
--- a/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
+++ b/specifyweb/frontend/js_src/lib/components/Formatters/Fields.tsx
@@ -74,7 +74,7 @@ export function Fields({
| {resourcesText.separator()} |
{schemaText.field()} |
{resourcesText.displayFormat()} |
- {displayFormatter && {resourcesText.fieldFormat()} | }
+ {displayFormatter && {schemaText.fieldFormat()} | }
|
diff --git a/specifyweb/frontend/js_src/lib/localization/resources.ts b/specifyweb/frontend/js_src/lib/localization/resources.ts
index cc15eb55cca..491ce86de2f 100644
--- a/specifyweb/frontend/js_src/lib/localization/resources.ts
+++ b/specifyweb/frontend/js_src/lib/localization/resources.ts
@@ -1005,17 +1005,6 @@ export const resourcesText = createDictionary({
'hr-hr': 'Format prikaza',
nb: 'Visningsformat',
},
- fieldFormat: {
- 'en-us': 'Field Format',
- 'de-ch': 'Feldformat',
- 'es-es': 'Formato de campo',
- 'fr-fr': 'Format de champ',
- 'ru-ru': 'Формат поля',
- 'uk-ua': 'Формат поля',
- 'pt-br': 'Formato do campo',
- 'hr-hr': 'Format polja',
- nb: 'Feltformat',
- },
expandConditionalField: {
'en-us': 'Expand Conditional Field',
'de-ch': 'Bedingtes Feld erweitern',
diff --git a/specifyweb/frontend/js_src/lib/localization/schema.ts b/specifyweb/frontend/js_src/lib/localization/schema.ts
index d80d3f6c6aa..befcb585ef9 100644
--- a/specifyweb/frontend/js_src/lib/localization/schema.ts
+++ b/specifyweb/frontend/js_src/lib/localization/schema.ts
@@ -735,15 +735,4 @@ export const schemaText = createDictionary({
'hr-hr': 'Vidljivo',
nb: 'Synlig',
},
- customFieldFormat: {
- 'en-us': 'Custom Field Format',
- 'de-ch': 'Format für benutzerdefinierte Felder',
- 'es-es': 'Formato de campo personalizado',
- 'fr-fr': 'Format de champ personnalisé',
- 'ru-ru': 'Формат пользовательского поля',
- 'uk-ua': 'Формат користувацького поля',
- 'pt-br': 'Formato de campo personalizado',
- 'hr-hr': 'Prilagođeni format polja',
- nb: 'Tilpasset feltformat',
- },
} as const);