Skip to content

mica-ui: data access settings page (/settings/data-access) #4615

Open

Description

@ymarcon

Follows #4613: the Settings › Data access page of the mica-ui app, reachable from the Settings page when isDataAccessEnabled. Reference: the Angular admin page #/admin/data-access-config (tabs: application form, preliminary, feasibility, amendment, end user agreement, notifications, other settings, permissions). Each of the five forms is edited with QJsonFormBuilder, as the entity forms are, and the texts of a form are stored with it (translations) rather than in the Mica bundle.

Branch feat/mica-ui-data-access-settings, merged into mica-ui.

Findings

  • The five forms (/config/data-access-form, -preliminary-form, -feasibility-form, -amendment-form, -agreement-form) have a draft / published revision lifecycle: GET ?revision=draft|latest, PUT saves the draft (revision 0), PUT /_publish creates the next revision. The Angular page enables Publish when the draft lastUpdateDate differs from the latest one. There is no mandatory part (no definition-mandatory.json): the builder edits the whole form.
  • The domain classes extend EntityConfig, so they already carry translations, but the five DTOs (DataAccess*FormDto) do not, and MicaConfigDtos does not map it. AbstractDataAccessEntityFormService.validateForm requires the definition to be a JSON array: a JSON Forms UI schema (object) is rejected.
  • Where the forms are rendered or read on the server:
    • the portal pages (DataAccessMainFormController and the four others) build a SchemaFormConfig that resolves the t() tokens with the Mica bundle only: the texts stored with the form are ignored. EntityConfigKeyTranslationService.translateSchemaForm (CSV export, diffs) already looks them up first (FormTranslations).
    • the portal renderer (mica-webapp/src/main/vue/data-access-form/DataAccessForm.vue) converts the ASF pair at render time (convertAsf(schema, definition[])): a JSON Forms pair (object definition) is not handled.
    • the Word export (DataAccessEntityExporter.traverseDefinitionTree) walks the ASF definition (key, items, type: help|tabs): a UI schema (elements, scope, Label, Group...) is not walked.
    • the default forms (config/data-access-*-form/definition.json) are ASF arrays, and the forms already stored by existing deployments are ASF too.
    • the CSV export and the title / summary / end date extraction (titleFieldPath...) read the schema and the model only: unaffected.
  • The default forms hold t(data-access-request.default.*) tokens, some embedded in HTML help blocks (<h2>I - t(...)</h2>). useEntityConfigForm keeps a token whose key is not translated by the form as a literal, resolved by the server at render time: the texts would not be editable in the builder.
  • DataAccessFormDto carries more than the form pair: pdfTemplates (one PDF per language, uploaded through /files/temp and saved as justUploaded attachments), pdfDownloadType (Template | Embedded), titleFieldPath, summaryFieldPath, endDateFieldPath, properties. The amendment DTO has the three field paths too (its withReview / approvedFinal are not edited by the Angular page). A save must round trip these fields.
  • Notifications and other settings are the DataAccessConfigDto (GET/PUT /config/data-access, whole object replaced): the csvExportFormat fields it also holds must be sent back as received.
  • Permissions: /config/data-access-form/permissions is a SubjectAclResource on /data-access-request with the single role READER, a file resource, and two other resources (action-logs, private-comment) granted through the repeated otherResources query parameter. useAcl / AclDialog / AclTable do not handle other resources yet (AclDto.otherResources is typed).
  • The legacy Angular editor (mica-webapp/src/main/webapp/app/access-config) edits the ASF pair as JSON text: it is the reference for the page, and stays as is.

Decisions

  1. Same storage model as the entity forms: the JSON Forms pair with the texts stored in the form translations (by locale, flat keys), the server resolving them before the Mica bundle everywhere the form is rendered.
  2. The texts come from the builder: when a form is loaded whose translations do not cover its t() tokens (legacy form), the texts of these keys are fetched from the resolved bundles (GET /config/i18n/{lang}.json, one per configured language) and seeded into the builder translations; a string that is exactly t(key) keeps key as its translation key, a token embedded in HTML is replaced by its text in each language (the builder then owns that text under its generated key). The first save persists them with the form. A leftover token (a key missing from the bundles) is kept literal and still resolved by the server. The seeding lives in the shared composable, so the entity forms benefit from it too.
  3. One page, one drawer, as SettingsEntityConfigPage: five form panels, Notifications, Other settings, Permissions. Every form panel has Save and Publish (enabled when the draft is newer than the published revision), the unsaved-changes guard on panel switch and route leave.
  4. No backward compatibility on the editing side once the page is in mica-ui: a data access form is saved as a JSON Forms pair only (the form service accepts a UI schema object, not an ASF array), the default forms ship as JSON Forms. The Angular access-config module is left untouched, as a reference. The mica-ui builder page converts a stored ASF form on load (toJsonForms) so that the administrator can save and publish it.
  5. No data migration: the request contents have the same schema whichever dialect captured them. The form definitions of an existing deployment stay in the ASF dialect in two places: the published revision until the form is published again from the mica-ui page (the page flags such a form and asks for it), and the revisions that submitted requests were pinned to on submission (DataAccessEntityResource.submit, unpinned on reopen only), for good. The ASF dialect is kept as a read-only rendering path so that such a request is still shown and exported with the exact form it was submitted with: the portal renderer keeps convertAsf for an array definition (and renders an object definition directly), the Word export keeps its ASF walk beside the new UI schema walk, and the t() tokens of those revisions keep resolving through the Mica bundle.

Plan

1. Server (mica-core, mica-web-model, mica-rest, mica-webapp)

  • Mica.proto: optional translations on the five DataAccess*FormDto; MicaConfigDtos asDto / fromDto map it; Mica.ts regenerated / updated
  • AbstractDataAccessEntityFormService.validateForm: the definition is a UI schema (JSON object); the translations, when present, are a JSON object (as EntityConfigService.validateTranslations, shared helper). A stored ASF form is still served by GET (the builder converts it) but can no longer be saved as is
  • default forms: definition.json of the five config/data-access-*-form/ folders replaced by uischema.json generated with toJsonForms (as the uischema-mandatory.json files were), t() tokens kept; createDefault*Form() read it
  • SchemaFormConfig: takes the form (EntityConfig) and translates with FormTranslations.translator(form, lang, bundle); the five portal controllers pass the form; data-access-form-scripts.ftl default definition becomes {}
  • DataAccessEntityExporter: a UI schema (object) is adapted to the definition tree the exporter walks (UischemaDefinition: Control → keyed item, Label → help, labelled Group / Category → titled section), option labels read from the schema oneOf as well as the ASF titleMap; the ASF traversal kept for an array (pinned revisions)
  • portal renderer DataAccessForm.vue / types.ts / main.ts: definition: unknown; an object is rendered by QJsonForm as is, an array goes through convertAsf (read-only rendering of pinned ASF revisions); bundle rebuilt (mica-webapp/src/main/vue)
  • UPGRADE.md: the data access forms are to be published once from the new page for the portal to use the JSON Forms dialect (existing requests keep rendering with their pinned revision)
  • tests: FormValidationTest, DataAccessFormServicesTest (defaults are JSON Forms pairs, object accepted, array rejected, invalid translations), SchemaFormConfigTest (stored texts first, then the bundle), UischemaDefinitionTest, DataAccessEntityExporterTest (UI schema, ASF, oneOf / titleMap labels; the file was JUnit 4 and never ran in mica-core, now JUnit 5)
  • verified against the local Mica: an ASF draft served by GET, saved back as a UI schema with translations, an array or invalid translations rejected (400), published (revision bumped), the portal page rendering the UI schema with the stored texts in en and fr, the Word export using them; a request redirected to an ASF preliminary revision still renders through the read-only path

2. mica-ui: generic configuration form composable and builder

  • useEntityConfigForm split into a generic useConfigForm(source) where the source gives the resource path, the load query (revision=draft for the data access forms), the extra DTO fields to carry over on save, and an optional publish; useEntityConfigForm and the new useDataAccessConfigForm(kind) are thin wrappers; prepareForm / parseTranslations shared
  • translation seeding from GET /config/i18n/{lang}.json per configured language (decision 2), the bundles cached in formsStore; a whole t(key) keeps key with the bundle texts, an embedded token becomes a text of the builder through setText (own key, resolved per language); vitest coverage: whole-token keys, embedded tokens, missing keys, form already translated (no bundle fetched)
  • EntityFormBuilder.vue becomes ConfigFormBuilder.vue: the composable state as prop, Save / Cancel, optional Publish (published date and canPublish from the source), confirmLeave exposed; SettingsEntityConfigPage updated
  • latest revision date: GET ?revision=latest after load / save / publish, to drive the Publish button and show the published date

3. mica-ui: data access page, routes and form panels

  • route settings/data-access → SettingsDataAccessPage.vue; Settings page entry (Content column, shown when isDataAccessEnabled), breadcrumbs
  • drawer items: Application form, Preliminary form, Feasibility form, Amendment form, End user agreement form, Notifications, Other settings, Permissions (a form whose feature is disabled in the settings is still editable, as in Angular, with a caption saying it is disabled); the last three panels are filled by steps 4 to 6
  • five form panels with ConfigFormBuilder (/config/data-access-form, -preliminary-form, -feasibility-form, -amendment-form, -agreement-form); a legacy form (array definition, converted on load) shows a banner asking to save and publish it, and is reported dirty so that Save is enabled
  • application form panel, below the builder: Properties (titleFieldPath, summaryFieldPath, endDateFieldPath) and PDF download (pdfDownloadType radio; for Template, one PDF file input per configured language, uploaded through useTempFiles, the stored template shown by name and size and removable; there is no endpoint to download a stored template, so none is offered); saved with the form
  • amendment form panel: Properties (titleFieldPath, summaryFieldPath, endDateFieldPath), saved with the form

4. mica-ui: notifications panel

  • DataAccessNotificationsPanel.vue on a working copy of DataAccessConfigDto (GET /config/data-access), three tabs as Angular: Events (created, submitted, reviewed, reopened, conditionally approved, rejected, approved, commented, attachment: toggle + subject input enabled with the toggle, placeholder [${organization}] ${title}), Reports (final / intermediate report toggles and subjects, nbOfDaysBeforeReport), Collaborators (invitation subject, collaborator accepted toggle and subject, enabled when collaborators are enabled)
  • Save (PUT /config/data-access with the whole DTO), Cancel (reload), dirty guard (useConfirmLeave, shared with the form builder); useDataAccessConfig composable shared with the other settings panel (one loaded copy, saved from either panel)

5. mica-ui: other settings panel

  • General: permissions (daoCanEdit), collaborators (collaboratorsEnabled, collaboratorInvitationDays), other forms (preliminaryEnabled, mergePreliminaryContentEnabled, feasibilityEnabled, amendmentsEnabled, agreementEnabled, agreementOpenedPolicy select ALWAYS / PRELIMINARY_APPROVED / MAIN_APPROVED), variables (variablesEnabled, preliminaryVariablesEnabled, feasibilityVariablesEnabled, amendmentVariablesEnabled), with the same enabling dependencies as Angular
  • ID generation: idPrefix (pattern [a-zA-Z0-9_-]+), idLength, randomId, allowIdWithLeadingZeros
  • Workflow: withReview, withConditionalApproval, approvedFinal, rejectedFinal
  • Predefined action names: predefinedActions as a list of keys (chips input), help text naming the data-access-request.action-log.config.label. translation prefix (the translations editor is not in mica-ui yet: plain text, no link)
  • Save / Cancel, dirty guard, layout in two columns as the general settings page (ConfigToggle / ConfigInput reused or generalized to a message-key prefix)

6. mica-ui: permissions panel

  • useAcl: optional otherResources in AclInput, sent as repeated otherResources query parameters on save; AclEndpoints.otherResources lists the ones offered
  • AclDialog: a checkbox per offered other resource (labels: "Apply the same permission to associated action logs", "Give access to the private comments section"); AclTable: the granted other resources shown with the role
  • panel: ConfigAclPanel extended (file option, other resources), on /config/data-access-form/permissions, role READER only, admin only
  • server: the Shiro annotations moved off the permissions() locator of DataAccessFormResource (and its class) onto its methods, the sub-resource checking the permission itself: the annotated locator failed the unauthenticated CORS preflight of the dev server
  • vitest: useAcl other resources parameters

7. i18n (en / fr)

  • settings.data_access / settings.data_access_caption; config.data_access.* keys ported from the Angular bundle (data-access-config.* of mica-webapp/src/main/resources/i18n/{en,fr}.json): panel titles and infos (the form infos reworded for the builder, no angular-schema-form link), properties, PDF download, notifications, settings, ID generation, workflow, action names, permissions, save / publish messages

8. Verification

  • vitest, lint, vue-tsc, prettier; mica-core tests; portal bundle build
  • against the local Mica (rebuilt web-model, core, rest, webapp): an ASF form is flagged, converted, saved and published from mica-ui and round trips with its translations; a request pinned to an ASF revision still renders and exports with that revision; a fresh Mica gets the JSON Forms defaults; _publish bumps the revision; the portal page /data-access-form/{id} renders the JSON Forms form with the stored texts in each language; Word export of a request; notifications / settings / permissions saved and re-read; PDF template upload
  • headless screenshots of every panel

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions