Skip to content

Commit 213e921

Browse files
JeroenDeDauwclaude
authored andcommitted
Add Special:Mappings special page listing ontology Mappings
Adds a `Special:Mappings` page that lists and manages the ontology Mapping pages (the `Mapping:` namespace), mirroring `Special:Schemas` and `Special:Layouts`. There is no tracking issue; this description is the spec. - **`Special:Mappings`** (mount div `ext-neowiki-mappings`), registered in `extension.json` and `i18n/_Aliases.php`. - **`GET /neowiki/v0/mappings`**: paginated (`limit`/`offset`) list returning `{mappings: [{name, schemas}], totalRows}`, where `schemas` is the names of the Mapping's mapped Schemas, sorted alphabetically server-side. - **`MappingsPage.vue`**: a Codex table with a **Name** column (linking to `Mapping:<name>`) and a **Mapped schemas** column listing each mapped Schema (linked to its `Schema:` page) followed by the count, e.g. `Artist, Artwork, City, Person (4)`; a Mapping with no mapped Schemas shows `None`. Pagination and an empty state. - **Create / Edit / Delete**: - A **Create** button (gated on `neowiki-mapping-edit`) opens a name-only dialog that creates `Mapping:<name>` with an empty mapping skeleton and opens the new page for editing. Pressing Enter in the name field submits. The reserved name `native` is rejected inline (the backend also rejects a `Mapping:Native` save, so this is a fast inline check rather than the sole guard). - Per-row **Edit** (gated on `neowiki-mapping-edit`; opens the page's raw-JSON edit view) and **Delete** (gated on the core `delete` right; confirmation dialog). - **"All mappings" sidebar link** on Mapping-namespace pages (`t-neowiki-mappings`), parallel to the Schema/Layout links. - **Messages** in `i18n/en.json` + `i18n/qqq.json` (the frontend ones also registered in the ResourceLoader module). - **Discovery links**: the Developers Browse list, the RDF-and-ontology-mappings demo page, `Main_Page`'s RDF bullet, `docs/api/rest-api.md`, and a one-line mention in `docs/rdf/ontology-mapping.md`. - **The API returns Schema names, not a count.** The mapped-schemas cell shows which Schemas a Mapping covers; the count is the array length. Sorting is done server-side so the view carries no ordering logic. - **In-handler pagination.** `MappingNameLookup` exposes only `getMappingNames()` (no SQL limit/offset/count) and is shared with the RDF projection path, so the handler slices the (one-page-per-ontology, small) name list and counts it for `totalRows`. Endpoint behaviour matches the Schema/Layout summaries APIs. - **Edit navigates; Create seeds and navigates.** Mapping pages are raw JSON with no editor UI, so Edit opens the standard `action=edit` view, and Create writes an empty skeleton and lands on the new page for the user to fill in. - **Create uses `mw.Api` `action=edit` with `createonly`.** This is atomic and surfaces a "page exists" error as an inline name-taken message; a plain create-or-update save would overwrite an existing mapping. - **Delete is gated on the core `delete` right** (which alone authorizes page deletion), unlike the Schema/Layout pages which gate delete on their entity-edit right; the same sibling inconsistency is tracked in #1114. `make cs`, `make phpunit`, and the TypeScript gates (vitest, build, lint) pass. Verified live on the dev wiki: the endpoint returns the EDM mapping's four sorted Schema names; the page renders them as comma-separated links with the count, and a zero-Schema mapping as `None`; creating a mapping (via the button or Enter) writes a `NeoWikiMapping` skeleton page and lands on it; `native` is rejected inline; Edit opens the JSON edit view; and the actions column is right-aligned. Delete gating checked with both a non-sysop user (Create and Edit shown, Delete hidden) and a sysop (all three shown, delete succeeds). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 606a960 commit 213e921

27 files changed

Lines changed: 1372 additions & 6 deletions

DemoData/Page/Developers.wikitext

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ NeoWiki exposes a programmable surface: a graph database, parser functions, a Lu
44

55
* [[Special:Schemas]]: all schemas
66
* [[Special:Layouts]]: all layouts
7+
* [[Special:Mappings]]: all ontology mappings
78
* [[Special:NeoJson|Special:NeoJson/&lt;subject id&gt;]]: view any subject as JSON
89
910
== Query the graph ==

DemoData/Page/Main_Page.wikitext

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This is a public demo of NeoWiki, an early-stage MediaWiki extension. Explore th
1212
* Structured data, queried in a page: [[Museum collection]] runs live graph queries over linked museums, artworks, and exhibitions.
1313
* Several Subjects on one page: open the Data tab on [{{fullurl:Rijksmuseum|action=subjects}} Rijksmuseum] to see the museum and its yearly visitor records as separate Subjects.
1414
* Every Subject is shaped by a [[Special:Schemas|Schema]], and [[Special:Layouts|Layouts]] control how Subjects are displayed.
15-
* Every Subject's data as RDF: [[RDF and ontology mappings]] shows native and EDM projections of the demo content.
15+
* Every Subject's data as RDF: [[RDF and ontology mappings]] shows native and EDM projections of the demo content, the latter defined by [[Special:Mappings|Mappings]].
1616
1717
'''Trying it hands-on'''
1818

DemoData/Page/RDF_and_ontology_mappings.wikitext

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Each export is produced on demand from the page's current data and downloads as
77

88
== The Mapping page ==
99

10-
Each Mapping page targets one ontology, named by the page title, and holds an entry for every mapped Schema. This wiki ships one:
10+
Each Mapping page targets one ontology, named by the page title, and holds an entry for every mapped Schema. [[Special:Mappings]] lists them all; this wiki ships one:
1111

1212
* [[Mapping:EDM]] — the Person, City, Artwork and Artist Schemas, all mapped to EDM
1313

docs/api/rest-api.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ A Layout defines how a Subject is displayed.
8383
| `GET /neowiki/v0/layouts` | List Layouts. Paginated with `limit` and `offset`. |
8484
| `GET /neowiki/v0/layout/{layoutName}` | Fetch a Layout by name. |
8585

86+
### Mappings
87+
88+
An ontology Mapping projects native Schemas to a target ontology. For the format and concepts, see
89+
[Ontology Mapping](../rdf/ontology-mapping.md).
90+
91+
| Endpoint | Description |
92+
|---|---|
93+
| `GET /neowiki/v0/mappings` | List ontology Mappings, each with the names of its mapped Schemas. Paginated with `limit` and `offset`. |
94+
8695
### Query
8796

8897
| Endpoint | Description |

docs/rdf/ontology-mapping.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ with native and mapped output side by side and the current gaps.
2424

2525
A Mapping is a page in the **`Mapping:` namespace** with content model `NeoWikiMapping` (JSON), gated by the
2626
`neowiki-mapping-edit` right. There is **one Mapping page per target ontology**, and the page title is the
27-
projection name you pass to the export surfaces: the page `Mapping:EDM` defines the `EDM` projection.
27+
projection name you pass to the export surfaces: the page `Mapping:EDM` defines the `EDM` projection. The
28+
`Special:Mappings` page lists every Mapping on the wiki.
2829

2930
A single page holds an entry for **every mapped Schema** — map a Schema to an ontology by adding an entry to
3031
that ontology's page, not by creating a page. A Schema maps to several ontologies through one entry on each

extension.json

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@
153153
"SpecialPages": {
154154
"NeoJson": "ProfessionalWiki\\NeoWiki\\EntryPoints\\SpecialPages\\SpecialNeoJson",
155155
"Schemas": "ProfessionalWiki\\NeoWiki\\EntryPoints\\SpecialPages\\SpecialSchemas",
156-
"Layouts": "ProfessionalWiki\\NeoWiki\\EntryPoints\\SpecialPages\\SpecialLayouts"
156+
"Layouts": "ProfessionalWiki\\NeoWiki\\EntryPoints\\SpecialPages\\SpecialLayouts",
157+
"Mappings": "ProfessionalWiki\\NeoWiki\\EntryPoints\\SpecialPages\\SpecialMappings"
157158
},
158159

159160
"Actions": {
@@ -294,6 +295,11 @@
294295
"method": [ "GET" ],
295296
"factory": "ProfessionalWiki\\NeoWiki\\NeoWikiExtension::newGetSchemaSummariesApi"
296297
},
298+
{
299+
"path": "/neowiki/v0/mappings",
300+
"method": [ "GET" ],
301+
"factory": "ProfessionalWiki\\NeoWiki\\NeoWikiExtension::newGetMappingSummariesApi"
302+
},
297303
{
298304
"path": "/neowiki/v0/subject-ids",
299305
"method": [ "POST" ],
@@ -549,6 +555,30 @@
549555
"neowiki-layouts-column-type",
550556
"neowiki-layouts-column-description",
551557
"neowiki-layouts-empty",
558+
"neowiki-special-mappings",
559+
"neowiki-mappings-column-name",
560+
"neowiki-mappings-column-schemas",
561+
"neowiki-mappings-schema-count",
562+
"neowiki-mappings-schemas-none",
563+
"neowiki-mappings-empty",
564+
"neowiki-mapping-creator-button",
565+
"neowiki-mapping-creator-title",
566+
"neowiki-mapping-creator-name-field",
567+
"neowiki-mapping-creator-name-placeholder",
568+
"neowiki-mapping-creator-name-required",
569+
"neowiki-mapping-creator-name-reserved",
570+
"neowiki-mapping-creator-name-taken",
571+
"neowiki-mapping-creator-save",
572+
"neowiki-mapping-creator-error",
573+
"neowiki-mapping-creator-summary-default",
574+
"neowiki-edit-mapping",
575+
"neowiki-mapping-delete",
576+
"neowiki-mapping-delete-confirm-title",
577+
"neowiki-mapping-delete-confirm-message",
578+
"neowiki-mapping-delete-confirm-delete",
579+
"neowiki-mapping-delete-summary-default",
580+
"neowiki-mapping-delete-success",
581+
"neowiki-mapping-delete-error",
552582
"neowiki-layout-creator-title",
553583
"neowiki-layout-creator-button",
554584
"neowiki-layout-creator-name-field",

i18n/_Aliases.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
'NeoJson' => [ 'NeoJson' ],
77
'Schemas' => [ 'Schemas' ],
88
'Layouts' => [ 'Layouts' ],
9+
'Mappings' => [ 'Mappings' ],
910
];

i18n/en.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,32 @@
250250
"neowiki-layouts-column-description": "Description",
251251
"neowiki-layouts-empty": "No layouts have been created yet.",
252252

253+
"neowiki-special-mappings": "Ontology mappings",
254+
"neowiki-mappings-column-name": "Name",
255+
"neowiki-mappings-column-schemas": "Mapped schemas",
256+
"neowiki-mappings-schema-count": "($1)",
257+
"neowiki-mappings-schemas-none": "None",
258+
"neowiki-mappings-empty": "No mappings have been created yet.",
259+
"neowiki-mapping-sidebar-all-mappings": "All mappings",
260+
"neowiki-mapping-creator-button": "Create",
261+
"neowiki-mapping-creator-title": "Create mapping",
262+
"neowiki-mapping-creator-name-field": "Mapping name",
263+
"neowiki-mapping-creator-name-placeholder": "Enter a name for the mapping",
264+
"neowiki-mapping-creator-name-required": "Please enter a mapping name.",
265+
"neowiki-mapping-creator-name-reserved": "\"native\" is a reserved name and cannot be used.",
266+
"neowiki-mapping-creator-name-taken": "A mapping with this name already exists.",
267+
"neowiki-mapping-creator-save": "Create mapping",
268+
"neowiki-mapping-creator-error": "Failed to create $1 mapping.",
269+
"neowiki-mapping-creator-summary-default": "Create mapping via NeoWiki UI",
270+
"neowiki-edit-mapping": "Edit mapping",
271+
"neowiki-mapping-delete": "Delete mapping",
272+
"neowiki-mapping-delete-confirm-title": "Delete mapping?",
273+
"neowiki-mapping-delete-confirm-message": "The mapping $1 will be permanently deleted.",
274+
"neowiki-mapping-delete-confirm-delete": "Delete",
275+
"neowiki-mapping-delete-summary-default": "Delete mapping via NeoWiki UI",
276+
"neowiki-mapping-delete-success": "Deleted $1 mapping",
277+
"neowiki-mapping-delete-error": "Failed to delete $1 mapping.",
278+
253279
"neowiki-layout-creator-title": "Create layout",
254280
"neowiki-layout-creator-button": "Create",
255281
"neowiki-layout-creator-name-field": "Layout name",

i18n/qqq.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,32 @@
148148
"neowiki-layouts-column-description": "Column header for layout description in the layouts list table on [[Special:Layouts]].",
149149
"neowiki-layouts-empty": "Message shown when no layouts exist yet on [[Special:Layouts]].",
150150

151+
"neowiki-special-mappings": "Title and description of the [[Special:Mappings]] page, which lists the ontology mapping pages.",
152+
"neowiki-mappings-column-name": "Column header for mapping name in the mappings list table on [[Special:Mappings]].",
153+
"neowiki-mappings-column-schemas": "Column header for the mapped schemas in the mappings list table on [[Special:Mappings]]. The cell lists the mapped Schema names followed by their count.",
154+
"neowiki-mappings-schema-count": "Parenthesized count of mapped schemas, shown after the list of Schema names in a row of the mappings list table on [[Special:Mappings]]. $1 is the number of mapped schemas.",
155+
"neowiki-mappings-schemas-none": "Placeholder shown in the mapped-schemas cell of a row on [[Special:Mappings]] when the Mapping has no mapped Schemas.",
156+
"neowiki-mappings-empty": "Message shown when no mappings exist yet on [[Special:Mappings]].",
157+
"neowiki-mapping-sidebar-all-mappings": "Label for the link in the NeoWiki section of the sidebar on Mapping pages that navigates to [[Special:Mappings]].",
158+
"neowiki-mapping-creator-button": "Label for the button that opens the mapping creation dialog on [[Special:Mappings]].",
159+
"neowiki-mapping-creator-title": "Title of the dialog for creating a new ontology mapping.",
160+
"neowiki-mapping-creator-name-field": "Label for the mapping name field in the mapping creation dialog.",
161+
"neowiki-mapping-creator-name-placeholder": "Placeholder text for the mapping name field in the mapping creation dialog.",
162+
"neowiki-mapping-creator-name-required": "Inline validation error shown when the mapping name field is left empty.",
163+
"neowiki-mapping-creator-name-reserved": "Inline validation error shown when the entered mapping name is the reserved projection name \"native\".",
164+
"neowiki-mapping-creator-name-taken": "Inline validation error shown when a mapping with the entered name already exists.",
165+
"neowiki-mapping-creator-save": "Label for the save button in the mapping creation dialog.",
166+
"neowiki-mapping-creator-error": "Error notification title shown when creating a mapping fails. $1 is the mapping name.",
167+
"neowiki-mapping-creator-summary-default": "Default edit summary used when creating a mapping via the UI.",
168+
"neowiki-edit-mapping": "Aria label for the edit button on a Mapping row in the mappings list.",
169+
"neowiki-mapping-delete": "Aria label for the delete button on a Mapping row in the mappings list.",
170+
"neowiki-mapping-delete-confirm-title": "Title of the confirmation dialog shown when deleting a mapping.",
171+
"neowiki-mapping-delete-confirm-message": "Message in the delete confirmation dialog. $1 is the mapping name.",
172+
"neowiki-mapping-delete-confirm-delete": "Label for the delete button in the mapping deletion dialog.",
173+
"neowiki-mapping-delete-summary-default": "Default deletion reason used when deleting a mapping via the UI.",
174+
"neowiki-mapping-delete-success": "Success notification shown after deleting a mapping. $1 is the mapping name.",
175+
"neowiki-mapping-delete-error": "Error notification title shown when deleting a mapping fails. $1 is the mapping name.",
176+
151177
"neowiki-layout-creator-title": "Title of the dialog for creating a new layout.",
152178
"neowiki-layout-creator-button": "Label for the button that opens the layout creation dialog on [[Special:Layouts]].",
153179
"neowiki-layout-creator-name-field": "Label for the layout name input field in the layout creation dialog.",

resources/ext.neowiki/src/NeoWikiExtension.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import { LayoutSerializer } from '@/persistence/LayoutSerializer.ts';
3333
import { LayoutDeserializer } from '@/persistence/LayoutDeserializer.ts';
3434
import { LayoutPermissionHints } from '@/application/LayoutPermissionHints.ts';
3535
import { RightsBasedLayoutPermissionHints } from '@/persistence/RightsBasedLayoutPermissionHints.ts';
36+
import { MappingPermissionHints } from '@/application/MappingPermissionHints.ts';
37+
import { RightsBasedMappingPermissionHints } from '@/persistence/RightsBasedMappingPermissionHints.ts';
3638
import { CsrfSendingHttpClient } from '@/infrastructure/HttpClient/CsrfSendingHttpClient.ts';
3739
import { SchemaSerializer } from '@/persistence/SchemaSerializer.ts';
3840
import { SchemaDeserializer } from '@/persistence/SchemaDeserializer.ts';
@@ -228,6 +230,12 @@ export class NeoWikiExtension {
228230
);
229231
}
230232

233+
public newMappingPermissionHints(): MappingPermissionHints {
234+
return new RightsBasedMappingPermissionHints(
235+
this.getUserObjectBasedRightsFetcher(),
236+
);
237+
}
238+
231239
public newHttpClient(): HttpClient {
232240
return new CsrfSendingHttpClient(
233241
new ProductionHttpClient(),

0 commit comments

Comments
 (0)