diff --git a/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts b/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts index 9e30c111e0..3a64318005 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts @@ -6,6 +6,7 @@ import GEOCAT_CH_DATASET from '../fixtures/geocat-ch.iso19139.dataset.xml' // @ts-ignore import GEOCAT_CH_SERVICE from '../fixtures/geocat-ch.iso19139.service.xml' import { + getUpdateFrequencyFromCustomPeriod, readContacts, readDistributions, readOnlineResources, @@ -91,6 +92,18 @@ describe('read parts', () => { }) }) }) + describe('getUpdateFrequencyFromCustomPeriod', () => { + it('keeps a partial weekly period', () => { + expect(getUpdateFrequencyFromCustomPeriod('P0Y0M2D')).toEqual({ + updatedTimes: 3, + per: 'week', + }) + expect(getUpdateFrequencyFromCustomPeriod('P0Y0M3D')).toEqual({ + updatedTimes: 2, + per: 'week', + }) + }) + }) }) describe('dataset record', () => { diff --git a/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts b/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts index 674feff624..dfb1cc3590 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts @@ -434,7 +434,7 @@ export function getUpdateFrequencyFromCustomPeriod( } else if (days <= 7) { return { per: 'week', - updatedTimes: Math.round(7 / days), + updatedTimes: Math.round(7 / days - 0.0001), // this is to make sure that 'every 2 days' = '3 times per week' } } else if (days) { return { diff --git a/libs/api/metadata-converter/src/lib/iso19139/write-parts.spec.ts b/libs/api/metadata-converter/src/lib/iso19139/write-parts.spec.ts index 12b4cd1009..1169c595b6 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/write-parts.spec.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/write-parts.spec.ts @@ -5,7 +5,11 @@ import { parseXmlString, xmlToString, } from '../xml-utils' -import { writeDistributions, writeKeywords } from './write-parts' +import { + getISODuration, + writeDistributions, + writeKeywords, +} from './write-parts' import { GENERIC_DATASET_RECORD } from '../fixtures/generic.records' import { DatasetRecord } from '@geonetwork-ui/common/domain/model/record' @@ -512,4 +516,21 @@ describe('write parts', () => { `) }) }) + + describe('getISODuration', () => { + it('keeps a partial weekly period', () => { + expect( + getISODuration({ + updatedTimes: 3, + per: 'week', + }) + ).toEqual('P0Y0M2D') + expect( + getISODuration({ + updatedTimes: 2, + per: 'week', + }) + ).toEqual('P0Y0M3D') + }) + }) }) diff --git a/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts b/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts index 21b54ca1c0..b29dc6b599 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts @@ -24,10 +24,8 @@ import { findChildOrCreate, findChildrenElement, findNestedChildOrCreate, - findNestedElement, findNestedElements, readAttribute, - readText, removeAllChildren, removeChildren, removeChildrenByName, @@ -36,7 +34,6 @@ import { } from '../xml-utils' import { ChainableFunction, - combine, fallback, filterArray, getAtIndex, @@ -220,7 +217,7 @@ export function getISODuration(updateFrequency: UpdateFrequencyCustom): string { else duration.hours = Math.round(24 / updateFrequency.updatedTimes) break case 'week': - duration.days = Math.round(7 / updateFrequency.updatedTimes) + duration.days = Math.round(7 / updateFrequency.updatedTimes - 0.0001) // this is to make sure that '2 times per week' = 'every 3 days' break case 'month': if (updateFrequency.updatedTimes <= 1) duration.months = 1 diff --git a/libs/feature/editor/src/lib/+state/editor.selectors.spec.ts b/libs/feature/editor/src/lib/+state/editor.selectors.spec.ts index 2b5363ad47..847ac23f37 100644 --- a/libs/feature/editor/src/lib/+state/editor.selectors.spec.ts +++ b/libs/feature/editor/src/lib/+state/editor.selectors.spec.ts @@ -71,6 +71,10 @@ describe('Editor Selectors', () => { config: DEFAULT_FIELDS[5], value: DATASET_RECORDS[0].resourceUpdated, }, + { + config: DEFAULT_FIELDS[6], + value: DATASET_RECORDS[0].updateFrequency, + }, ]) }) }) diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.css b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html new file mode 100644 index 0000000000..bea8e2d5aa --- /dev/null +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html @@ -0,0 +1,14 @@ + + + diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.spec.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.spec.ts new file mode 100644 index 0000000000..b862ada4b4 --- /dev/null +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.spec.ts @@ -0,0 +1,63 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing' + +import { FormFieldUpdateFrequencyComponent } from './form-field-update-frequency.component' +import { TranslateModule } from '@ngx-translate/core' +import { FormControl } from '@angular/forms' + +describe('FormFieldUpdateFrequencyComponent', () => { + let component: FormFieldUpdateFrequencyComponent + let fixture: ComponentFixture + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormFieldUpdateFrequencyComponent, TranslateModule.forRoot()], + }).compileComponents() + + fixture = TestBed.createComponent(FormFieldUpdateFrequencyComponent) + component = fixture.componentInstance + const control = new FormControl() + control.setValue({ + updatedTimes: 3, + per: 'week', + }) + component.control = control + fixture.detectChanges() + }) + + it('should create', () => { + expect(component).toBeTruthy() + }) + + it('should parse the updatedTimes and per values', () => { + component.onSelectFrequencyValue('day.1') + expect(component.control.value).toEqual({ + updatedTimes: 1, + per: 'day', + }) + }) + + it('should be recognized as planned', () => { + expect(component.planned).toBeTruthy() + }) + + it('should add the custom frequency to the dropdown choices', () => { + expect(component.choices).toContainEqual({ + value: 'week.3', + label: 'domain.record.updateFrequency.week', + }) + }) + + describe('Switch to not planned', () => { + beforeEach(async () => { + component.onPlannedToggled() + }) + + it('should set the value as notPlanned', () => { + expect(component.control.value).toBe('notPlanned') + }) + + it('should be recognized as not planned', () => { + expect(component.planned).toBeFalsy() + }) + }) +}) diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts new file mode 100644 index 0000000000..81e045279f --- /dev/null +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts @@ -0,0 +1,143 @@ +import { + ChangeDetectionStrategy, + Component, + Input, + OnInit, +} from '@angular/core' +import { FormControl } from '@angular/forms' +import { marker } from '@biesbjerg/ngx-translate-extract-marker' +import { + CheckToggleComponent, + DropdownSelectorComponent, +} from '@geonetwork-ui/ui/inputs' +import { TranslateModule, TranslateService } from '@ngx-translate/core' + +@Component({ + selector: 'gn-ui-form-field-update-frequency', + templateUrl: './form-field-update-frequency.component.html', + styleUrls: ['./form-field-update-frequency.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [CheckToggleComponent, DropdownSelectorComponent, TranslateModule], +}) +export class FormFieldUpdateFrequencyComponent implements OnInit { + @Input() control: FormControl + + get planned() { + return this.control.value !== 'notPlanned' + } + + constructor(private translateService: TranslateService) {} + + ngOnInit() { + const updatedTimes = this.control.value?.updatedTimes + const per = this.control.value?.per + if (updatedTimes && updatedTimes !== 1 && updatedTimes !== 2) { + this.choices = [ + { + value: `${per}.${updatedTimes}`, + label: this.translateService.instant( + `domain.record.updateFrequency.${per}`, + { + count: updatedTimes, + } + ), + }, + ...this.choices, + ] + } + } + + onPlannedToggled() { + if (this.planned) { + this.control.setValue('notPlanned') + } else { + this.control.setValue({ updatedTimes: 1, per: 'day' }) + } + } + + get selectedFrequency() { + const { updatedTimes, per } = this.control.value + return `${per}.${updatedTimes}` + } + + onSelectFrequencyValue(value: unknown) { + const split = (value as string).split('.') + this.control.setValue({ updatedTimes: Number(split[1]), per: split[0] }) + } + + choices = [ + { + value: 'day.1', + label: this.translateService.instant( + 'domain.record.updateFrequency.day', + { + count: 1, + } + ), + }, + { + value: 'day.2', + label: this.translateService.instant( + 'domain.record.updateFrequency.day', + { + count: 2, + } + ), + }, + { + value: 'week.1', + label: this.translateService.instant( + 'domain.record.updateFrequency.week', + { + count: 1, + } + ), + }, + { + value: 'week.2', + label: this.translateService.instant( + 'domain.record.updateFrequency.week', + { + count: 2, + } + ), + }, + { + value: 'month.1', + label: this.translateService.instant( + 'domain.record.updateFrequency.month', + { + count: 1, + } + ), + }, + { + value: 'month.2', + label: this.translateService.instant( + 'domain.record.updateFrequency.month', + { + count: 2, + } + ), + }, + { + value: 'year.1', + label: this.translateService.instant( + 'domain.record.updateFrequency.year', + { + count: 1, + } + ), + }, + { + value: 'year.2', + label: this.translateService.instant( + 'domain.record.updateFrequency.year', + { + count: 2, + } + ), + }, + ] +} diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html index e4047c7e3d..861a3e0bbc 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html @@ -56,6 +56,11 @@ [control]="formControl" > + + + { let component: FormFieldComponent @@ -48,6 +50,51 @@ describe('FormFieldComponent', () => { expect(formField).toBeTruthy() }) }) + describe('license field', () => { + let formField + beforeEach(() => { + component.model = 'licenses' + component.value = 'cc-by' + fixture.detectChanges() + formField = fixture.debugElement.query( + By.directive(FormFieldLicenseComponent) + ).componentInstance + }) + it('creates a license form field', () => { + expect(formField).toBeTruthy() + }) + }) + describe('resource updated field', () => { + let formField + beforeEach(() => { + component.model = 'resourceUpdated' + component.value = new Date('2022-12-04T15:12:00') + fixture.detectChanges() + formField = fixture.debugElement.query( + By.directive(FormFieldResourceUpdatedComponent) + ).componentInstance + }) + it('creates a resource updated form field', () => { + expect(formField).toBeTruthy() + }) + }) + describe('update frequency field', () => { + let formField + beforeEach(() => { + component.model = 'updateFrequency' + component.value = { + updatedTimes: 3, + per: 'week', + } + fixture.detectChanges() + formField = fixture.debugElement.query( + By.directive(FormFieldUpdateFrequencyComponent) + ).componentInstance + }) + it('creates an update frequency form field', () => { + expect(formField).toBeTruthy() + }) + }) describe('simple field', () => { let fieldWrapper let formField diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts index 009ab05e70..c60ff1a41b 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts @@ -24,6 +24,7 @@ import { FormFieldSimpleComponent } from './form-field-simple/form-field-simple. import { FormFieldSpatialExtentComponent } from './form-field-spatial-extent/form-field-spatial-extent.component' import { FormFieldTemporalExtentComponent } from './form-field-temporal-extent/form-field-temporal-extent.component' import { FormFieldConfig } from './form-field.model' +import { FormFieldUpdateFrequencyComponent } from './form-field-update-frequency/form-field-update-frequency.component' @Component({ selector: 'gn-ui-form-field', @@ -40,6 +41,7 @@ import { FormFieldConfig } from './form-field.model' FormFieldWrapperComponent, FormFieldLicenseComponent, FormFieldResourceUpdatedComponent, + FormFieldUpdateFrequencyComponent, FormFieldSimpleComponent, FormFieldRichComponent, FormFieldObjectComponent, @@ -130,6 +132,9 @@ export class FormFieldComponent { get isResourceUpdated() { return this.model === 'resourceUpdated' } + get isUpdateFrequency() { + return this.model === 'updateFrequency' + } get withoutWrapper() { return this.model === 'title' || this.model === 'abstract' diff --git a/libs/feature/editor/src/lib/fields.config.ts b/libs/feature/editor/src/lib/fields.config.ts index f5a4082b7c..8c83feb68a 100644 --- a/libs/feature/editor/src/lib/fields.config.ts +++ b/libs/feature/editor/src/lib/fields.config.ts @@ -47,4 +47,11 @@ export const DEFAULT_FIELDS: EditorFieldsConfig = [ type: 'date', }, }, + { + model: 'updateFrequency', + formFieldConfig: { + labelKey: marker('editor.record.form.updateFrequency'), + type: 'text', + }, + }, ] diff --git a/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.spec.ts b/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.spec.ts index 46ecd4aefe..dbad56689d 100644 --- a/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.spec.ts +++ b/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.spec.ts @@ -8,7 +8,7 @@ describe('CheckToggleComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [CheckToggleComponent], + imports: [CheckToggleComponent], }).compileComponents() fixture = TestBed.createComponent(CheckToggleComponent) diff --git a/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.stories.ts b/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.stories.ts new file mode 100644 index 0000000000..4278c5efa7 --- /dev/null +++ b/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.stories.ts @@ -0,0 +1,13 @@ +import { Meta, StoryObj } from '@storybook/angular' +import { CheckToggleComponent } from './check-toggle.component' + +export default { + title: 'Inputs/CheckToggleComponent', + component: CheckToggleComponent, +} as Meta + +export const Primary: StoryObj = { + args: { + label: 'Some label', + }, +} diff --git a/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.ts b/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.ts index dfb4456615..bacf97e057 100644 --- a/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.ts +++ b/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.ts @@ -5,12 +5,15 @@ import { Input, Output, } from '@angular/core' +import { FormsModule } from '@angular/forms' @Component({ selector: 'gn-ui-check-toggle', templateUrl: './check-toggle.component.html', styleUrls: ['./check-toggle.component.css'], changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [FormsModule], }) export class CheckToggleComponent { @Input() title: string diff --git a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html index f0d9855be6..834596982c 100644 --- a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html +++ b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html @@ -18,6 +18,7 @@ cdkOverlayOrigin #overlayOrigin="cdkOverlayOrigin" (keydown)="handleTriggerKeydown($event)" + [disabled]="disabled" >
{{ getChoiceLabel() | translate }} diff --git a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.stories.ts b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.stories.ts index 1ce8402e66..65e2d43d8f 100644 --- a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.stories.ts +++ b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.stories.ts @@ -49,6 +49,7 @@ export const Primary: StoryObj = { ], selected: 'choice1', showTitle: true, + disabled: false, }, argTypes: { selectValue: { diff --git a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts index 296995ffd2..1f4b3979f1 100644 --- a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts +++ b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.ts @@ -48,6 +48,7 @@ export class DropdownSelectorComponent implements OnInit { @Input() maxRows: number @Input() extraBtnClass = '' @Input() minWidth = '' + @Input() disabled: boolean @Output() selectValue = new EventEmitter() @ViewChild('overlayOrigin') overlayOrigin: CdkOverlayOrigin @ViewChild(CdkConnectedOverlay) overlay: CdkConnectedOverlay diff --git a/libs/ui/inputs/src/lib/ui-inputs.module.ts b/libs/ui/inputs/src/lib/ui-inputs.module.ts index f96f975288..db239ac117 100644 --- a/libs/ui/inputs/src/lib/ui-inputs.module.ts +++ b/libs/ui/inputs/src/lib/ui-inputs.module.ts @@ -44,7 +44,6 @@ import { ImageInputComponent } from './image-input/image-input.component' StarToggleComponent, DropdownMultiselectComponent, ViewportIntersectorComponent, - CheckToggleComponent, CopyTextButtonComponent, CheckboxComponent, SearchInputComponent, @@ -73,6 +72,7 @@ import { ImageInputComponent } from './image-input/image-input.component' ImageInputComponent, DropdownSelectorComponent, DateRangePickerComponent, + CheckToggleComponent, ], exports: [ DropdownSelectorComponent, diff --git a/translations/de.json b/translations/de.json index 7e9df0c40f..82e415af95 100644 --- a/translations/de.json +++ b/translations/de.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "", "editor.record.form.license.unknown": "Unbekannt oder nicht vorhanden", "editor.record.form.resourceUpdated": "", + "editor.record.form.updateFrequency": "", + "editor.record.form.updateFrequency.planned": "", "editor.record.loadError.body": "", "editor.record.loadError.closeMessage": "", "editor.record.loadError.title": "", diff --git a/translations/en.json b/translations/en.json index a126cde62b..bd8ab68644 100644 --- a/translations/en.json +++ b/translations/en.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "Open Data Commons PDDL", "editor.record.form.license.unknown": "Unknown or absent", "editor.record.form.resourceUpdated": "Last update date", + "editor.record.form.updateFrequency": "Update frequency", + "editor.record.form.updateFrequency.planned": "The data should be updated regularly.", "editor.record.loadError.body": "The record could not be loaded:", "editor.record.loadError.closeMessage": "Understood", "editor.record.loadError.title": "Error loading record", diff --git a/translations/es.json b/translations/es.json index 26c5e3ccb8..ac3dcc767b 100644 --- a/translations/es.json +++ b/translations/es.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "", "editor.record.form.license.unknown": "", "editor.record.form.resourceUpdated": "", + "editor.record.form.updateFrequency": "", + "editor.record.form.updateFrequency.planned": "", "editor.record.loadError.body": "", "editor.record.loadError.closeMessage": "", "editor.record.loadError.title": "", diff --git a/translations/fr.json b/translations/fr.json index a78c3cfc22..20064052ce 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "", "editor.record.form.license.unknown": "Non-reconnue ou absente", "editor.record.form.resourceUpdated": "Date de dernière révision", + "editor.record.form.updateFrequency": "Fréquence de mise à jour", + "editor.record.form.updateFrequency.planned": "Ces données doivent être mise à jour régulièrement.", "editor.record.loadError.body": "", "editor.record.loadError.closeMessage": "", "editor.record.loadError.title": "", diff --git a/translations/it.json b/translations/it.json index c8aacdc045..fe28b7a321 100644 --- a/translations/it.json +++ b/translations/it.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "", "editor.record.form.license.unknown": "Non riconosciuta o assente", "editor.record.form.resourceUpdated": "", + "editor.record.form.updateFrequency": "", + "editor.record.form.updateFrequency.planned": "", "editor.record.loadError.body": "", "editor.record.loadError.closeMessage": "", "editor.record.loadError.title": "", diff --git a/translations/nl.json b/translations/nl.json index 89616d1e96..7d331e8f6c 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "", "editor.record.form.license.unknown": "", "editor.record.form.resourceUpdated": "", + "editor.record.form.updateFrequency": "", + "editor.record.form.updateFrequency.planned": "", "editor.record.loadError.body": "", "editor.record.loadError.closeMessage": "", "editor.record.loadError.title": "", diff --git a/translations/pt.json b/translations/pt.json index 031e933c7a..6e7c864b38 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "", "editor.record.form.license.unknown": "", "editor.record.form.resourceUpdated": "", + "editor.record.form.updateFrequency": "", + "editor.record.form.updateFrequency.planned": "", "editor.record.loadError.body": "", "editor.record.loadError.closeMessage": "", "editor.record.loadError.title": "", diff --git a/translations/sk.json b/translations/sk.json index 006938fead..c1a0c4d691 100644 --- a/translations/sk.json +++ b/translations/sk.json @@ -156,6 +156,8 @@ "editor.record.form.license.pddl": "", "editor.record.form.license.unknown": "Neznáme alebo chýbajúce", "editor.record.form.resourceUpdated": "", + "editor.record.form.updateFrequency": "", + "editor.record.form.updateFrequency.planned": "", "editor.record.loadError.body": "", "editor.record.loadError.closeMessage": "", "editor.record.loadError.title": "",