Repository navigation
Fixes #36713: Guide first run from empty states to the New class panel - #36723
Conversation
First unit of #35983. The enum carries the Any or All reviewer rule that later commits put on the ontology, freeze into the review target, and turn into the review task's approval threshold.
…and CSV Make the preview request's format optional, add CSV and the uploaded file name, and add the preview response that wraps the change set with the detected format, the source label, and per-kind counts.
…ionship types Decision record for the native relation picker: registry types become native object properties matched by exact predicate IRI, inverses stay reciprocal on write, and the create option is gated on the relationshipType permission.
Adds the fields to the concept and property schemas, the create requests, the release payload allowlist, and the RDF catalog vocabulary. Adds the DEPRECATED change type, the REPLACED_BY reference role, and the concept-grouped rows of the working diff. Regenerates the TypeScript types.
The request, the summary, and the detection response now reference one format definition with its own Java type, NativeOntologyImportFormat. A reference to the request's property made jsonschema2pojo generate a second enum per schema. The preview response wraps a summary and the change set; the summary carries the detected format, the source label, and eight counts. The RDF reader returns a NativeOntologyDocument: the source's definitions sorted by IRI and axiom signature, plus the ontology header when the source declares exactly one. Axiom signatures move with it.
The IT states the contract before the implementation: setting, creating with, repointing, clearing, deleting and restoring an object property's inverse keeps both sides reciprocal; a one-directional import normalizes on apply and is reused by exact IRI; the release export carries owl:inverseOf both ways.
Concepts and properties now carry deprecation and replacement, and
concepts carry abstract and a definition source:
- A replacement must name another definition of the same kind in the
same ontology. It is indexed as a REPLACED_BY reference, so deleting
a replacement target is refused like any other dangling reference.
- An enumeration needs at least two allowed values. One-value
enumerations stored before this rule stay editable until their values
change.
- Release projection writes om:abstract, dct:source, owl:deprecated,
and dct:isReplacedBy, and native import reads them back.
- Release and working diffs classify a member whose deprecated flag
turned true as DEPRECATED.
- GET /ontologies/{id}/working/diff?groupBy=concept returns the working
changes grouped by the concept they define, with parent labels and a
property count, paged by group under its own revision-bound cursor.
…sion IndependentOntologyClassModelIT covers the field round trips, the enumeration minimum and its legacy carve-out, replacedBy integrity, the DEPRECATED diff row, and grouped diff paging with the 412 cursor rule. NativeOntologyMemoryIT adds a class-create change set and its rollback. Existing ITs that stored one-value enumerations now use two values.
Adds the fields to the concept and property schemas, the create requests, the release payload allowlist, and the RDF catalog vocabulary. Adds the DEPRECATED change type, the REPLACED_BY reference role, and the concept-grouped rows of the working diff. Regenerates the TypeScript types.
Concepts and properties now carry deprecation and replacement, and
concepts carry abstract and a definition source:
- A replacement must name another definition of the same kind in the
same ontology. It is indexed as a REPLACED_BY reference, so deleting
a replacement target is refused like any other dangling reference.
- An enumeration needs at least two allowed values. One-value
enumerations stored before this rule stay editable until their values
change.
- Release projection writes om:abstract, dct:source, owl:deprecated,
and dct:isReplacedBy, and native import reads them back.
- Release and working diffs classify a member whose deprecated flag
turned true as DEPRECATED.
- GET /ontologies/{id}/working/diff?groupBy=concept returns the working
changes grouped by the concept they define, with parent labels and a
property count, paged by group under its own revision-bound cursor.
…sion IndependentOntologyClassModelIT covers the field round trips, the enumeration minimum and its legacy carve-out, replacedBy integrity, the DEPRECATED diff row, and grouped diff paging with the 412 cursor rule. NativeOntologyMemoryIT adds a class-create change set and its rollback. Existing ITs that stored one-value enumerations now use two values.
…d per-operation revisions
…tatus and release change summary
…tatus and release change summary
OntologyWorkingState runs registered finalizers at the outermost mutation's exit, before validation. OntologyPropertyRepository registers one that settles inverse links over the affected neighbourhood: the side that states a link decides it, the latest statement wins, and a partner no longer pointed back at is released. Partners are written through the updater so they version, index and validate like any edit. The RDF importer reads owl:inverseOf as symmetric, so a one-directional file describes both sides and a re-import changes nothing. IndependentOntologyAxiomIT drops its indirect inverse variant, which relied on one-sided inverse chains.
An ontology carries an approvalRule, AnyReviewer by default or
AllReviewers. prepareReview freezes the rule into the task's review
target and leaves the requester's and the author's own user entries out
of the assignees. The rule reaches the workflow as the start variable
approvalMode=allAssignees, which CreateTask turns into the task's
approvalThreshold, so the shared counters stay unchanged.
Each counted vote is recorded on the task in reviewVotes with its
comment; the deciding vote is recorded in the decision transaction with
any voter whose record was lost. Reviewers and the approval rule are
locked with 409 while a release of the ontology is in review.
GET /v1/ontologyReleases/{id}/review and
GET /v1/ontologies/reviews?view=assigned|created|pending read a review
from the task's recorded votes.
Amends ADR:2026-10-14-ontology-reviews-bind-workflow-tasks-to-revisions
as v13.
Only an ontology review reconciles the deciding vote, so recording counted votes on any other multi-approval task would always leave its last vote out and add version bumps to glossary approvals. The waiting branch now records a vote only for an ontology review. OntologyReleaseReviewReaderTest reads reviews through the reader with literal tasks and votes. OntologyReleaseRepository.page and offset are static so the cursor math has a test with literal rows.
A restore relinks or drops its inverse through the reciprocity finalizer, which writes the same row a second time inside one mutation. Validation kept the first row per id, so it still saw the dangling inverse and refused the restore. OntologyWorkingState now folds a mutation's changes to one per definition before finalizers and validation see them. A restored property whose partner was hard-deleted meanwhile drops the link before its updater runs, so the restore response matches the stored row, and IndependentOntologyInverseIT covers it on both profiles.
The native relation picker lists the relationship-type registry in two groups, Core and Custom, with each type's inverse beside it, plus the ontology's own object properties that no registry predicate backs. Picking a type writes the missing property pair with the registry predicates as IRIs, linked through inverse, then the restriction axiom. An admin can create a custom type with its inverse from the picker; the dialog writes both registry types and links them before instantiating. The concept inspector labels incoming relations with the inverse. The Playwright spec covers the groups, Part Of, a custom type, and a steward who sees the types but no create option.
…RDF ontology The release inherits its reviewers from the ontology, and the entity updater drops inherited references from a reviewer list, so the task's REVIEWS rows vanished on the workflow's first stage update. OntologyReview.eligibleReviewers now returns plain copies. A counted vote whose record loses every optimistic-locking retry answers 200 with a warning, because the vote already counted in Flowable and the decision records it. openmetadata.ttl declares om:approvalRule, which the ontology projection writes. The ITs unwrap the SDK's wrapped 409 and fetch the task with its reviewers.
The panel detects the format on the server, shows counts from a dry run, and imports into the chosen ontology or a new one through the library installation flow. Documents the native CSV and amends the working-draft import decision.
…anges count, drop restating comments
The decision record said a refusal leaves nothing written. An apply-stage refusal, such as a contended lease, comes after the create, so the refused change set stays behind unapplied and the rebuild creates a second one. Nothing is applied, which is what makes the rebuild safe. The record now says so, and says that Retry creates the change set again under the same name when the lookup confirms it is absent. The builder test now asserts the concept operation id and one axiom name as literal UUID v5 values of 'attempt:<key>' in the URL namespace, so a change to the identity derivation fails the Guard.
Takes PR9's decision-record wording fix.
Retry looks the change set up by id or by name before it applies. When that read fails, resolveDraft leaves the unknown flag set, so the panel stays locked. The record now names that case beside the failed re-read on apply.
FeaturesPlaceholder accepts an action on a feature and renders that feature's title as the button that runs it, so an onboarding state can offer several ways to start. Features without an action render as before. The no-ontologies state now renders its three options through FeaturesPlaceholder, and the no-concepts card renders through NoDataPlaceholder. Both take the shared brand icon tiles in place of the hand-built Card, FeaturedIcon and gray tiles, per ADR:2026-10-21-empty-states-render-through-the-placeholder-wrappers.
The create dialog gives a new ontology the IRI <baseUri>/onto/<prefix> and the namespace <iri>#, with a prefix derived from the name. Imports and the RDF projection read these values, so the format, its source of truth and what the server checks are now a decision record, cited from ontologyIris.
The first-run options passed their test ids through an object spread to get past the action type. The action type now accepts data-testid.
The placeholder is absolutely positioned and centred, so options taller than the viewport spilled past both edges of an overflow-hidden page. The host now scrolls, and the placeholder flows inside it, centred when it fits. The icon colour test also inspects the glyph element, so a grey class on the icon itself fails it.
The placeholder now sits in a centred core Card at the old 340px width, so the copy no longer runs through the canvas dot grid. The overlay still lets pointer events through, and only the card takes them. The test names what it proves: the shared empty placeholder renders inside the card. The wrapper guard itself is a lint rule, not a DOM assertion.
…mment The record now says iri and namespace must parse as a URI and that the server has no uniqueness check on namespace, so the duplicate refusal is client-only. It no longer claims other code reads the onto/ shape, and the comment above ontologyIris keeps only the record citation.
The wrapper now maps an optional per-feature action to a title button, which the record said it never would. Add a v3 revision and a dated amendment, and leave the Decision text unchanged.
The organize-imports and ESLint pass in CI inserts this blank line.
Takes the decision record's last wording fix from PR9's final head, which main now holds as #36721.
main's tree equals the class authoring head merged in the parent commit, so this merge records the squash and keeps the first-run tree as it is.
… its scroll host The placeholder kept flex-shrink 1 and min-h-full replaced its automatic minimum, so it shrank to the host height and its centred content spilled above the scroll origin. Use flex-1 with h-auto so it grows past the host and stays centred when it fits. Put the no-concepts placeholder in Card.Content so the card supplies the padding.
At 720x450 the headline must sit at or below the scroll host top and Create from scratch must scroll into view.
…ding A relative iri also gets 400, iriHash covers iri and not namespace, and the context no longer says the server stores whatever it is sent. The v3 amendment follows the v2 heading and lead-line style.
Without tw:h-auto the shell keeps its own h-full, shrinks to the scroll host and clips the headline again, so the scroll host test now asserts it.
Code Review ✅ Approved 2 closed / 2 findings🟡 Medium risk · The new empty-state flow creates ontologies with generated namespaces and imports into them; a mistaken IRI could leave persistent ontology identity confusing. Adds a first-run empty state to Ontology Studio with Install from library, Import a file and Create from scratch options, plus a create dialog that derives the namespace prefix and previews the IRI live. Both empty states now render through the shared placeholder wrappers, and the IRI scheme ✅ 2 closed✅ Quality: First-run empty states skip the EmptyPlaceholder wrappers ADR
✅ Quality: New ontology IRI scheme
|
| Compact |
|
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source
|
| Count | Rule |
|---|---|
| 1 | openmetadata-imports/review-sequential-api-calls |
All findings
| Location | Rule | Message | |
|---|---|---|---|
| 🟡 | src/components/governance/ontology/OntologyGraphView/OntologyGraphView.tsx:561:9 |
openmetadata-imports/review-sequential-api-calls |
Review these sequential API requests. If they are independent, start them together with Promise.all/Promise.allSettled; keep sequencing only when data-dependent |
Fix locally (fast - only checks files changed in this branch):
make ui-checkstyle-changed
|
Takes #36726, which changes only backend repositories and their tests.
main's tree equals the first-run head this branch already holds, merged with #36726 in the parent commit, so this merge records the squash and keeps the Data mode tree as it is.



The stack targets release 2.1.0.
PR1 #35990, PR2 #35994, PR3 #35997, PR4 #35995, PR5 #36183, PR6 #36187, PR7 #36188, PR8 #36190, PR9 #36721, PR10 #35991, PR12 #35996 and PR15 #35989 are merged.
This PR targets
main. PR13 #36724 builds on this branch, and PR14 #36725 builds on PR13. PR16 is not published yet.Current assessment for
4f9d666e3cf, recorded 2026-10-30.Verdict. PASS. The independent review of the second fix round passed at
1c77b6fe174.4f9d666e3cfadds the one assertion that review proposed, which pins the placeholder's auto height. The assertion passes at this head and fails whentw:h-autois removed.What moved since the last assessment. gitar-bot's review raised two findings, and both are fixed.
OntologyEmptyStateusesFeaturesPlaceholder, and the no-concepts card putsNoDataPlaceholderinside an elevatedCard.FeaturesPlaceholdergained an optional per-featureaction, which renders the feature title as a coreButton. No other caller passes it, so the other 13 pages render as before. The record gains a v3 amendment for the action.Two independent reviews of those fixes found that the first-run screen had lost its scroll container, so a short viewport clipped the options. The screen now scrolls from the top. On a model of the page's layout in Chromium, the headline sits 32px below the top of the scroll area at 720x450 and at 320x568, where it was above the top before.
PR9 landed as
bcd1cb2332a.c5b877b4256merges PR9's final head, which changes one line of PR9's decision record.9f5a102b677then mergesmainand keeps PR11's tree, becausemain's tree equals PR9's final head. PR11's stable patch-id is3b0fc5f5381againstmainand against PR9's final head.The reviews declared these minor issues, which do not block.
canEditonly on Save, not on the settings rows. The rewritten AI create case also droppedmain's required-field check.NoDataPlaceholderfrom a direct use of coreEmptyPlaceholder, so no unit test can catch a page that skips the wrapper. Ano-restricted-importsrule would, in a separate PR.Card's own surface classes, so a core restyle of that variant would fail it.Test evidence. The gates ran at
1c77b6fe174. Jest passes 1,773 tests in 175 suites, covering every Studio suite, the placeholder wrappers and the test files of the otherFeaturesPlaceholdercallers. Two suites failed once under CPU load and passed when rerun alone. ESLint, Prettier and organize-imports leave no change on PR11's 45 UI files. The i18n check passes for 21 locales, the Playwright impact map is up to date, the Playwright project compiles, and the import guard is clean. TypeScript reports onlymain's error atIngestionWorkflowForm.tsx(413,9). The decision record check is clean.CI. This head was pushed on 2026-10-30, and CI is running. With
mainas the base, GitHub linksFixes #36713, so Validate PR Metadata andmaven-collate-cican pass.Still owed. None of these has run yet. Run each IT on
-Pmysql-elasticsearchand then-Ppostgres-opensearch, and confirm aTests run:line.OntologyFirstRun.spec.ts, including the new short-viewport case, andOntologyNativeStudio.spec.tsagainst a live stack built from this head, then the specs that the impact map routesOntologyExplorerPage.tsxto. They drive classic mode. No Playwright spec drives first run in AI mode.IndependentOntologyAuthorizationIT,OntologyConceptResourceITandOntologyChangeSetIT, for the class-creation rights where PR9's Add concept meets PR11's no-concepts card. PR11 changes no Java.AI mode.
main's AI-mode restyle #36433 gates new screens on AI mode. Paths are underopenmetadata-ui/src/main/resources/ui/src/. The three first-run options and theNo ontologies yetheading incomponents/governance/ontology/OntologyEmptyState/OntologyEmptyState.tsxrender only in the classic branch. AI mode keepsmain's feature placeholder, whose New ontology action now opens PR11's create dialog. AI mode reaches the Library from the header and the empty-catalog import from the header's import and export menu. A user who cannot create sees disabled options with a reason in classic mode. In AI mode, that user sees no create entry and no reason. The create dialog, the hand-off to Edit with the New class panel open, the import dialog, the no-concepts card, the hidden Publish and the settings-only form sit in code that both modes share.Not verified yet. This PR is verified only when its unit, live and performance boxes in the plan are all checked. The operator lands the stack.
Describe your changes
Fixes #36713
A Studio with no ontologies now shows a first-run empty state in place of the canvas. It reads
No ontologies yet, says in one sentence what an ontology is, and offers three options.While the catalog is empty or the first list loads, the top bar hides the mode switch and Publish and keeps Library, Import/export and Tasks. Installing or importing leaves the empty state without a reload. A user who cannot create ontologies sees the options disabled.
The create dialog keeps Create disabled until the name has text. It derives the namespace prefix from the first eight lowercase letters of the name, falls back to
onto, and keeps the prefix editable. It previews the IRI live as<baseUri>/onto/<prefix>#, withbaseUriread from the server's RDF status. The dialog refuses a prefix that is not IRI safe or whose namespace a visible ontology already uses. It keeps Create disabled and says why while the ontology list is unknown, and it cannot create without the base URI. A new ontology starts at the schema default layerL3, owned by the current user. After Create, the picker selects the new ontology, the page switches to Edit, the New class panel opens, and a toast names the ontology.Both empty states render through the shared placeholder wrappers.
FeaturesPlaceholderfeatures take an optionalaction, which the first-run options use.An ontology with zero classes shows the card
This ontology has no conceptswith Add concept. The card and the sub-tab Add concept both open the New class panel.OntologyCreateFormnow edits settings only, since creation moved to the dialog.This is PR11 of the sixteen-part Ontology Studio program for release 2.1.0.
Type of change
High-level design
Of the 48 changed files, 45 are UI files. The others are two decision records and the generated Playwright impact map. PR11 adds no endpoint.
OntologyExplorerPagedecides the first-run state from the ontology list. In classic mode it rendersOntologyEmptyStatewhen the list is empty.OntologyEmptyStaterenders throughFeaturesPlaceholderinside a scroll host, and each option is a feature with anaction. In both modes it passes no modes to the header while the catalog is empty or the first list loads.OntologyCreateDialogis built on the coreModal. It builds its request throughnewOntologyRequestinOntologyCreateForm.utils.ts, which joins the server's base URI, theonto/segment and the prefix. Theonto/segment keeps user namespaces apart from thehttps://open-metadata.org/ontology/vocabulary. The IRI record states the shape and what the server checks. The server checks only that the IRI and the namespace are absolute, and it does not refuse a duplicate namespace, so that refusal is the client's.After a create, the page holds a pending first class for the new ontology. It opens the New class panel once the URL, the loaded selection and Edit mode all name that ontology. The page clears the pending first class after the URL has reached the new ontology and then moved off it. That rule handles a stale reload of the previous ontology and browser Back. The empty-catalog import reuses the library installation flow that the import decision record describes for import into a new ontology. PR11 adds the IRI record and a v3 amendment to the empty-state record.
Tests
Use cases covered
The tests cover these cases.
ontofallback, an edited prefix, a prefix already in use, an unknown ontology list and a missing base URI.actionrenders as a button, and a feature without one renders as before.Unit tests
New suites cover
OntologyEmptyState,OntologyCreateDialogandOntologyEmptyCard, andEmptyPlaceholderVariantsgains a case for the featureaction. The explorer page, its integration suite,OntologyImportExportMenu,OntologyCreateFormandOntologyStudioWorkspacegain or change cases. The slow-transition regression test passed 5 of 5 repeat runs in review. See Test evidence above for the gate counts at this head.Backend and ingestion integration tests
Not applicable. PR11 changes no backend or ingestion code. The ITs behind the rights it shares with PR9 are listed under Still owed.
Playwright and UI recording
playwright/e2e/Features/OntologyFirstRun.spec.tsruns each of the three options from an empty catalog. A new case sets a 720x450 viewport and checks that the headline sits inside the scroll area and that Create from scratch scrolls into view.OntologyNativeStudio.spec.tsnow expects Edit with the New class panel open after create. Neither has run against a stack built from this head. The UI recording and review screenshots are not made yet.Performance
Not measured yet. The plan's lane times Studio load on an empty catalog against trunk, and the time from Create to the open panel.
Checklist
Fixes <issue-number>: <short explanation>.Fixes #36713above.