sanity-plugin-taxonomy-manager 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/LICENSE +21 -0
- package/README.md +91 -0
- package/_local/POC images/README.md +7 -0
- package/_local/POC images/Screen Recording 2022-03-15 at 5.40.31 PM.mov +0 -0
- package/_local/POC images/config.dist.json +3 -0
- package/_local/POC images/sanity-taxonomy-manager-poc-demo.gif +0 -0
- package/_local/POC images/taxo-mgr-1.png +0 -0
- package/_local/POC images/taxo-mgr-2.png +0 -0
- package/_local/POC images/taxo-mgr-3.png +0 -0
- package/_local/POC images/taxo-mgr-4.png +0 -0
- package/_local/POC images/taxo-mgr-5.png +0 -0
- package/_local/POC images/taxo-mgr-6.png +0 -0
- package/lib/components/prefLabel.js +89 -0
- package/lib/components/prefLabel.js.map +1 -0
- package/lib/objects/baseIri.js +28 -0
- package/lib/objects/baseIri.js.map +1 -0
- package/lib/skosConcept.js +251 -0
- package/lib/skosConcept.js.map +1 -0
- package/lib/skosConceptScheme.js +49 -0
- package/lib/skosConceptScheme.js.map +1 -0
- package/lib/skosTaxonomySettings.js +40 -0
- package/lib/skosTaxonomySettings.js.map +1 -0
- package/package.json +60 -0
- package/sanity.json +24 -0
- package/src/components/prefLabel.js +70 -0
- package/src/objects/baseIri.js +22 -0
- package/src/skosConcept.js +242 -0
- package/src/skosConceptScheme.js +41 -0
- package/src/skosTaxonomySettings.js +38 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format of this document is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [TODO]
|
|
8
|
+
- Initial development release.
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2022-03-17
|
|
11
|
+
### Added
|
|
12
|
+
- Update README with installation, basic use instructions, and development warning
|
|
13
|
+
- Add changelog
|
|
14
|
+
- Migrate SKOS Taxonomy Management schemas from local development branch to (this) plugin repository
|
|
15
|
+
|
|
16
|
+
<!---
|
|
17
|
+
## Change Log Principles
|
|
18
|
+
- Changelogs are for humans, not machines.
|
|
19
|
+
- There should be an entry for every single version.
|
|
20
|
+
- The same types of changes should be grouped.
|
|
21
|
+
- Versions and sections should be linkable.
|
|
22
|
+
- The latest version comes first.
|
|
23
|
+
- The release date of each version is displayed.
|
|
24
|
+
- Mention whether you follow Semantic Versioning.
|
|
25
|
+
|
|
26
|
+
## Tags
|
|
27
|
+
### Added
|
|
28
|
+
- for new features.
|
|
29
|
+
### Changed
|
|
30
|
+
- for changes in existing functionality.
|
|
31
|
+
### Deprecated
|
|
32
|
+
- for soon-to-be removed features.
|
|
33
|
+
### Removed
|
|
34
|
+
- for now removed features.
|
|
35
|
+
### Fixed
|
|
36
|
+
- for any bug fixes.
|
|
37
|
+
### Security
|
|
38
|
+
- in case of vulnerabilities.
|
|
39
|
+
|
|
40
|
+
### Unreleased
|
|
41
|
+
- Keep at the top to track upcoming changes.
|
|
42
|
+
- People can see what changes they might expect in upcoming releases
|
|
43
|
+
- At release time, you can move the Unreleased section changes into a new release version section.
|
|
44
|
+
--->
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Andy Fitzgerald
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Sanity Plugin Taxonomy Manager
|
|
2
|
+
|
|
3
|
+
#### WARNING: This plugin is still in development. Please do not use it in production until this warning is removed.
|
|
4
|
+
|
|
5
|
+
Create and manage [SKOS](https://www.w3.org/TR/skos-primer/) compliant taxonomies, thesauri, and classification schemes in Sanity Studio.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Adds three document types to your Sanity schema which are used to generate SKOS compliant concepts and concept schemes: `skosConcept`, `skosConceptScheme`, and `skosTaxonomySettings`
|
|
12
|
+
- Pre-populates [base URI](https://www.w3.org/TR/skos-primer/#secconcept) and [concept scheme](https://www.w3.org/TR/skos-primer/#secscheme) values for new concepts
|
|
13
|
+
- Validates [disjunction between Broader and Related relationships](https://www.w3.org/TR/skos-reference/#L2422)
|
|
14
|
+
- Validates [disjunction between Preferred and Alternate/Hidden labels](https://www.w3.org/TR/skos-reference/#L1567)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Install using the [Sanity CLI](https://www.sanity.io/docs/cli).
|
|
19
|
+
|
|
20
|
+
#### NOTE: This plugin is still in development. Please do not use it in production until this warning is removed.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
$ sanity install taxonomy-manager
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
1. Create the Taxonomy Settings doc and set your taxonomy bases IRI.
|
|
29
|
+
2. Create a [Concept Scheme](https://www.w3.org/TR/skos-reference/#schemes) to group related concepts (optional)
|
|
30
|
+
3. Create and describe Concepts.
|
|
31
|
+
- All fields *except* PrefLabel are optional, and are to be used as best fits the needs of your information modeling task.
|
|
32
|
+
- All Concept fields map to elements of the machine readable data model described in the [W3C SKOS Recommendation](https://www.w3.org/TR/skos-reference/).
|
|
33
|
+
4. Tag resources with concepts and then integrate into search indexing, navigation, and semantic web services.
|
|
34
|
+
- 👉 Examples to come!
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
You can use [Structure Builder](https://www.sanity.io/docs/structure-builder-reference) to create a separate area for your taxonomy tools.
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import {RiNodeTree} from 'react-icons/ri'
|
|
42
|
+
import {AiFillTags,AiOutlineTags} from 'react-icons/ai'
|
|
43
|
+
|
|
44
|
+
const hiddenDocTypes = (listItem) =>
|
|
45
|
+
!['skosTaxonomySettings', 'skosConcept', 'skosConceptScheme'].includes(
|
|
46
|
+
listItem.getId()
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
export default () =>
|
|
50
|
+
// ... other structure builder items
|
|
51
|
+
S.divider(),
|
|
52
|
+
S.listItem()
|
|
53
|
+
.title('Concepts')
|
|
54
|
+
.icon(AiFillTags)
|
|
55
|
+
.child(
|
|
56
|
+
S.documentList()
|
|
57
|
+
.title('Concepts')
|
|
58
|
+
.filter('_type == "skosConcept"')
|
|
59
|
+
),
|
|
60
|
+
S.listItem()
|
|
61
|
+
.title('Taxonomy Schemes')
|
|
62
|
+
.icon(RiNodeTree)
|
|
63
|
+
.child(
|
|
64
|
+
S.documentList()
|
|
65
|
+
.title('Taxonomy Schemes')
|
|
66
|
+
.filter('_type == "skosConceptScheme"')
|
|
67
|
+
),
|
|
68
|
+
S.listItem()
|
|
69
|
+
.title('Taxonomy Settings')
|
|
70
|
+
.icon(RiSettings4Line)
|
|
71
|
+
.child(
|
|
72
|
+
S.document()
|
|
73
|
+
.schemaType('skosTaxonomySettings')
|
|
74
|
+
.documentId('skosTaxonomySettings')
|
|
75
|
+
),
|
|
76
|
+
S.divider(),
|
|
77
|
+
// ... other structure builder items
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## [SKOS Overview](https://www.w3.org/TR/skos-reference/)
|
|
81
|
+
|
|
82
|
+
> The Simple Knowledge Organization System (SKOS) is a common data model for sharing and linking knowledge organization systems via the Web.
|
|
83
|
+
>
|
|
84
|
+
>Many knowledge organization systems, such as thesauri, taxonomies, classification schemes and subject heading systems, share a similar structure, and are used in similar applications. SKOS captures much of this similarity and makes it explicit, to enable data and technology sharing across diverse applications.
|
|
85
|
+
>
|
|
86
|
+
>The SKOS data model provides a standard, low-cost migration path for porting existing knowledge organization systems to the Semantic Web. SKOS also provides a lightweight, intuitive language for developing and sharing new knowledge organization systems. It may be used on its own, or in combination with formal knowledge representation languages such as the Web Ontology language (OWL).
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT © Andy Fitzgerald
|
|
91
|
+
See LICENSE
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
## Config File
|
|
2
|
+
|
|
3
|
+
`config.dist.json` is where the plugin config object lives.
|
|
4
|
+
- It is installed in the Sanity /config folder when the plugin is installed.
|
|
5
|
+
- This is where use accessible plugin config options should go.
|
|
6
|
+
- If/when I want to use this, move it back into the plugin root directory.
|
|
7
|
+
- Be sure to add config instructions to the README file.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
|
|
10
|
+
var _components = require("@sanity/base/components");
|
|
11
|
+
|
|
12
|
+
var _ui = require("@sanity/ui");
|
|
13
|
+
|
|
14
|
+
var _PatchEvent = _interopRequireWildcard(require("@sanity/form-builder/PatchEvent"));
|
|
15
|
+
|
|
16
|
+
var _autoId = require("@reach/auto-id");
|
|
17
|
+
|
|
18
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
|
+
|
|
20
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
21
|
+
|
|
22
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* PrefLabel input component for SKOS Concept
|
|
26
|
+
* This component creates a Concept IRI preview to help taxonomy managers avoid errors in minting URIs.
|
|
27
|
+
*/
|
|
28
|
+
// hook to generate unique IDs
|
|
29
|
+
var PrefLabel = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
|
|
30
|
+
var type = props.type,
|
|
31
|
+
value = props.value,
|
|
32
|
+
readOnly = props.readOnly,
|
|
33
|
+
placeholder = props.placeholder,
|
|
34
|
+
markers = props.markers,
|
|
35
|
+
presence = props.presence,
|
|
36
|
+
compareValue = props.compareValue,
|
|
37
|
+
onFocus = props.onFocus,
|
|
38
|
+
onBlur = props.onBlur,
|
|
39
|
+
onChange = props.onChange,
|
|
40
|
+
parent = props.parent; // Creates a unique ID for input
|
|
41
|
+
|
|
42
|
+
var inputId = (0, _autoId.useId)(); // Creates a change handler for patching data
|
|
43
|
+
|
|
44
|
+
var handleChange = _react.default.useCallback( // useCallback will help with performance
|
|
45
|
+
event => {
|
|
46
|
+
var inputValue = event.currentTarget.value; // get current value
|
|
47
|
+
// if the value exists, set the data, if not, unset the data
|
|
48
|
+
|
|
49
|
+
onChange(_PatchEvent.default.from(inputValue ? (0, _PatchEvent.set)(inputValue) : (0, _PatchEvent.unset)()));
|
|
50
|
+
}, [onChange]);
|
|
51
|
+
|
|
52
|
+
return /*#__PURE__*/_react.default.createElement(_ui.Stack, {
|
|
53
|
+
space: 1
|
|
54
|
+
}, /*#__PURE__*/_react.default.createElement(_components.FormField, {
|
|
55
|
+
description: type.description,
|
|
56
|
+
title: type.title,
|
|
57
|
+
__unstable_markers: markers // Handles all markers including validation
|
|
58
|
+
,
|
|
59
|
+
__unstable_presence: presence // Handles presence avatars
|
|
60
|
+
,
|
|
61
|
+
compareValue: compareValue // Handles "edited" status
|
|
62
|
+
,
|
|
63
|
+
inputId: inputId // Allows the label to connect to the input field
|
|
64
|
+
|
|
65
|
+
}, /*#__PURE__*/_react.default.createElement(_ui.TextInput, {
|
|
66
|
+
id: inputId // A unique ID for this input
|
|
67
|
+
,
|
|
68
|
+
onChange: handleChange // A function to call when the input value changes
|
|
69
|
+
,
|
|
70
|
+
value: value // Current field value
|
|
71
|
+
,
|
|
72
|
+
readOnly: readOnly // If "readOnly" is defined make this field read only
|
|
73
|
+
,
|
|
74
|
+
placeholder: placeholder // If placeholder is defined, display placeholder text
|
|
75
|
+
,
|
|
76
|
+
onFocus: onFocus // Handles focus events
|
|
77
|
+
,
|
|
78
|
+
onBlur: onBlur // Handles blur events
|
|
79
|
+
,
|
|
80
|
+
ref: ref
|
|
81
|
+
})), /*#__PURE__*/_react.default.createElement(_ui.Text, {
|
|
82
|
+
muted: true,
|
|
83
|
+
size: 1
|
|
84
|
+
}, /*#__PURE__*/_react.default.createElement("strong", null, "Concept IRI: "), parent.conceptIriBase ? parent.conceptIriBase.iriValue : '[base URI not defined] ', value === null || value === void 0 ? void 0 : value.replaceAll(' ', '')));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
var _default = PrefLabel;
|
|
88
|
+
exports.default = _default;
|
|
89
|
+
//# sourceMappingURL=prefLabel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/prefLabel.js"],"names":["PrefLabel","React","forwardRef","props","ref","type","value","readOnly","placeholder","markers","presence","compareValue","onFocus","onBlur","onChange","parent","inputId","handleChange","useCallback","event","inputValue","currentTarget","PatchEvent","from","description","title","conceptIriBase","iriValue","replaceAll"],"mappings":";;;;;;;AAIA;;AACA;;AACA;;AACA;;AACA;;;;;;;;AARA;AACA;AACA;AACA;AAKqC;AAErC,IAAMA,SAAS,gBAAGC,eAAMC,UAAN,CAAiB,CAACC,KAAD,EAAQC,GAAR,KAAgB;AACjD,MACEC,IADF,GAYIF,KAZJ,CACEE,IADF;AAAA,MAEEC,KAFF,GAYIH,KAZJ,CAEEG,KAFF;AAAA,MAGEC,QAHF,GAYIJ,KAZJ,CAGEI,QAHF;AAAA,MAIEC,WAJF,GAYIL,KAZJ,CAIEK,WAJF;AAAA,MAKEC,OALF,GAYIN,KAZJ,CAKEM,OALF;AAAA,MAMEC,QANF,GAYIP,KAZJ,CAMEO,QANF;AAAA,MAOEC,YAPF,GAYIR,KAZJ,CAOEQ,YAPF;AAAA,MAQEC,OARF,GAYIT,KAZJ,CAQES,OARF;AAAA,MASEC,MATF,GAYIV,KAZJ,CASEU,MATF;AAAA,MAUEC,QAVF,GAYIX,KAZJ,CAUEW,QAVF;AAAA,MAWEC,MAXF,GAYIZ,KAZJ,CAWEY,MAXF,CADiD,CAejD;;AACA,MAAMC,OAAO,GAAG,oBAAhB,CAhBiD,CAkBjD;;AACA,MAAMC,YAAY,GAAGhB,eAAMiB,WAAN,EACnB;AACCC,EAAAA,KAAD,IAAW;AACT,QAAMC,UAAU,GAAGD,KAAK,CAACE,aAAN,CAAoBf,KAAvC,CADS,CACoC;AAC7C;;AACAQ,IAAAA,QAAQ,CAACQ,oBAAWC,IAAX,CAAgBH,UAAU,GAAG,qBAAIA,UAAJ,CAAH,GAAqB,wBAA/C,CAAD,CAAR;AACD,GANkB,EAOnB,CAACN,QAAD,CAPmB,CAArB;;AAUA,sBACE,6BAAC,SAAD;AAAO,IAAA,KAAK,EAAE;AAAd,kBACE,6BAAC,qBAAD;AACE,IAAA,WAAW,EAAET,IAAI,CAACmB,WADpB;AAEE,IAAA,KAAK,EAAEnB,IAAI,CAACoB,KAFd;AAGE,IAAA,kBAAkB,EAAEhB,OAHtB,CAG+B;AAH/B;AAIE,IAAA,mBAAmB,EAAEC,QAJvB,CAIiC;AAJjC;AAKE,IAAA,YAAY,EAAEC,YALhB,CAK8B;AAL9B;AAME,IAAA,OAAO,EAAEK,OANX,CAMoB;;AANpB,kBAQE,6BAAC,aAAD;AACE,IAAA,EAAE,EAAEA,OADN,CACe;AADf;AAEE,IAAA,QAAQ,EAAEC,YAFZ,CAE0B;AAF1B;AAGE,IAAA,KAAK,EAAEX,KAHT,CAGgB;AAHhB;AAIE,IAAA,QAAQ,EAAEC,QAJZ,CAIsB;AAJtB;AAKE,IAAA,WAAW,EAAEC,WALf,CAK4B;AAL5B;AAME,IAAA,OAAO,EAAEI,OANX,CAMoB;AANpB;AAOE,IAAA,MAAM,EAAEC,MAPV,CAOkB;AAPlB;AAQE,IAAA,GAAG,EAAET;AARP,IARF,CADF,eAoBE,6BAAC,QAAD;AAAM,IAAA,KAAK,MAAX;AAAY,IAAA,IAAI,EAAE;AAAlB,kBACE,6DADF,EAEGW,MAAM,CAACW,cAAP,GAAwBX,MAAM,CAACW,cAAP,CAAsBC,QAA9C,GAAyD,yBAF5D,EAGGrB,KAHH,aAGGA,KAHH,uBAGGA,KAAK,CAAEsB,UAAP,CAAkB,GAAlB,EAAuB,EAAvB,CAHH,CApBF,CADF;AA4BD,CAzDiB,CAAlB;;eA2De5B,S","sourcesContent":["/**\n * PrefLabel input component for SKOS Concept\n * This component creates a Concept IRI preview to help taxonomy managers avoid errors in minting URIs.\n */\nimport React from 'react'\nimport {FormField} from '@sanity/base/components'\nimport {TextInput, Stack, Text} from '@sanity/ui'\nimport PatchEvent, {set, unset} from '@sanity/form-builder/PatchEvent'\nimport {useId} from '@reach/auto-id' // hook to generate unique IDs\n\nconst PrefLabel = React.forwardRef((props, ref) => {\n const {\n type, // Schema information\n value, // Current field value\n readOnly, // Boolean if field is not editable\n placeholder, // Placeholder text from the schema\n markers, // Markers including validation rules\n presence, // Presence information for collaborative avatars\n compareValue, // Value to check for \"edited\" functionality\n onFocus, // Method to handle focus state\n onBlur, // Method to handle blur state\n onChange, // Method to handle patch events\n parent,\n } = props\n\n // Creates a unique ID for input\n const inputId = useId()\n\n // Creates a change handler for patching data\n const handleChange = React.useCallback(\n // useCallback will help with performance\n (event) => {\n const inputValue = event.currentTarget.value // get current value\n // if the value exists, set the data, if not, unset the data\n onChange(PatchEvent.from(inputValue ? set(inputValue) : unset()))\n },\n [onChange]\n )\n\n return (\n <Stack space={1}>\n <FormField\n description={type.description}\n title={type.title}\n __unstable_markers={markers} // Handles all markers including validation\n __unstable_presence={presence} // Handles presence avatars\n compareValue={compareValue} // Handles \"edited\" status\n inputId={inputId} // Allows the label to connect to the input field\n >\n <TextInput\n id={inputId} // A unique ID for this input\n onChange={handleChange} // A function to call when the input value changes\n value={value} // Current field value\n readOnly={readOnly} // If \"readOnly\" is defined make this field read only\n placeholder={placeholder} // If placeholder is defined, display placeholder text\n onFocus={onFocus} // Handles focus events\n onBlur={onBlur} // Handles blur events\n ref={ref}\n />\n </FormField>\n <Text muted size={1}>\n <strong>Concept IRI: </strong>\n {parent.conceptIriBase ? parent.conceptIriBase.iriValue : '[base URI not defined] '}\n {value?.replaceAll(' ', '')}\n </Text>\n </Stack>\n )\n})\n\nexport default PrefLabel\n"],"file":"prefLabel.js"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Base Internationalized Resource Identifier object for Sanity Taxonomy Manager
|
|
10
|
+
* This field is created as an object in order to present it as collapsed in the Sanity Studio UI.
|
|
11
|
+
*/
|
|
12
|
+
var _default = {
|
|
13
|
+
name: 'baseIri',
|
|
14
|
+
title: 'Base IRI',
|
|
15
|
+
type: 'object',
|
|
16
|
+
fields: [{
|
|
17
|
+
name: 'iriValue',
|
|
18
|
+
title: 'IRI Value',
|
|
19
|
+
type: 'url',
|
|
20
|
+
description: 'The W3C encourages the use of HTTP URIs when minting concept URIs since they are resolvable to representations that can be accessed using standard Web technologies.'
|
|
21
|
+
}],
|
|
22
|
+
options: {
|
|
23
|
+
collapsible: true,
|
|
24
|
+
collapsed: true
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
exports.default = _default;
|
|
28
|
+
//# sourceMappingURL=baseIri.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/objects/baseIri.js"],"names":["name","title","type","fields","description","options","collapsible","collapsed"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;eACe;AACbA,EAAAA,IAAI,EAAE,SADO;AAEbC,EAAAA,KAAK,EAAE,UAFM;AAGbC,EAAAA,IAAI,EAAE,QAHO;AAIbC,EAAAA,MAAM,EAAE,CACN;AACEH,IAAAA,IAAI,EAAE,UADR;AAEEC,IAAAA,KAAK,EAAE,WAFT;AAGEC,IAAAA,IAAI,EAAE,KAHR;AAIEE,IAAAA,WAAW,EACT;AALJ,GADM,CAJK;AAabC,EAAAA,OAAO,EAAE;AACPC,IAAAA,WAAW,EAAE,IADN;AAEPC,IAAAA,SAAS,EAAE;AAFJ;AAbI,C","sourcesContent":["/**\n * Base Internationalized Resource Identifier object for Sanity Taxonomy Manager\n * This field is created as an object in order to present it as collapsed in the Sanity Studio UI.\n */\nexport default {\n name: 'baseIri',\n title: 'Base IRI',\n type: 'object',\n fields: [\n {\n name: 'iriValue',\n title: 'IRI Value',\n type: 'url',\n description:\n 'The W3C encourages the use of HTTP URIs when minting concept URIs since they are resolvable to representations that can be accessed using standard Web technologies.',\n },\n ],\n options: {\n collapsible: true,\n collapsed: true,\n },\n}\n"],"file":"baseIri.js"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _client = _interopRequireDefault(require("part:@sanity/base/client"));
|
|
9
|
+
|
|
10
|
+
var _ai = require("react-icons/ai");
|
|
11
|
+
|
|
12
|
+
var _prefLabel = _interopRequireDefault(require("./components/prefLabel"));
|
|
13
|
+
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
|
|
16
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
17
|
+
|
|
18
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
19
|
+
|
|
20
|
+
var client = _client.default.withConfig({
|
|
21
|
+
apiVersion: '2021-03-25'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
var _default = {
|
|
25
|
+
name: 'skosConcept',
|
|
26
|
+
title: 'Concepts',
|
|
27
|
+
type: 'document',
|
|
28
|
+
icon: _ai.AiFillTags,
|
|
29
|
+
initialValue: function () {
|
|
30
|
+
var _initialValue = _asyncToGenerator(function* () {
|
|
31
|
+
var _yield$client$fetch;
|
|
32
|
+
|
|
33
|
+
var iriBase = yield client.fetch("\n *[_id == 'skosTaxonomySettings']{\n 'iriValue': baseIri,\n }[0]\n ");
|
|
34
|
+
var conceptIriBase = iriBase !== null && iriBase !== void 0 && iriBase.iriValue ? iriBase : undefined;
|
|
35
|
+
var scheme = (_yield$client$fetch = yield client.fetch("\n *[_type == 'skosConceptScheme']{\n '_type': 'reference',\n '_ref': _id\n }[0]\n ")) !== null && _yield$client$fetch !== void 0 ? _yield$client$fetch : undefined;
|
|
36
|
+
return {
|
|
37
|
+
conceptIriBase: conceptIriBase,
|
|
38
|
+
scheme: scheme,
|
|
39
|
+
topConcept: false
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
function initialValue() {
|
|
44
|
+
return _initialValue.apply(this, arguments);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return initialValue;
|
|
48
|
+
}(),
|
|
49
|
+
validation: Rule => Rule.custom(fields => {
|
|
50
|
+
if (fields.altLabel && fields.hiddenLabel && fields.altLabel.filter(label => fields.hiddenLabel.includes(label)).length > 0 || fields.altLabel && fields.altLabel.includes(fields.prefLabel) || fields.hiddenLabel && fields.hiddenLabel.includes(fields.prefLabel)) return 'Preferred Label, Alternate Labels, and Hidden Labels must all be unique. Please remove any labels duplicated across label types.';
|
|
51
|
+
return true;
|
|
52
|
+
}),
|
|
53
|
+
groups: [{
|
|
54
|
+
name: 'relationship',
|
|
55
|
+
title: 'Relationships'
|
|
56
|
+
}, {
|
|
57
|
+
name: 'label',
|
|
58
|
+
title: 'Labels'
|
|
59
|
+
}, {
|
|
60
|
+
name: 'note',
|
|
61
|
+
title: 'Documentation'
|
|
62
|
+
}],
|
|
63
|
+
fields: [{
|
|
64
|
+
name: 'prefLabel',
|
|
65
|
+
title: 'Preferred Label',
|
|
66
|
+
group: ['label', 'relationship'],
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'The preferred lexical label for this concept. This label is also used to unambiguously represent this concept via the concept IRI.',
|
|
69
|
+
validation: Rule => Rule.required().error('Concepts must have a preferred label'),
|
|
70
|
+
inputComponent: _prefLabel.default
|
|
71
|
+
}, {
|
|
72
|
+
name: 'conceptIriBase',
|
|
73
|
+
title: 'Edit the base IRI',
|
|
74
|
+
type: 'baseIri'
|
|
75
|
+
}, {
|
|
76
|
+
name: 'altLabel',
|
|
77
|
+
title: 'Alternate Label(s)',
|
|
78
|
+
group: 'label',
|
|
79
|
+
type: 'array',
|
|
80
|
+
description: 'Alternative labels can be used to assign synonyms, near-synonyms, abbreviations, and acronyms to a concept. Preferred, alternative, and hidden label sets must not overlap.',
|
|
81
|
+
of: [{
|
|
82
|
+
type: 'string'
|
|
83
|
+
}],
|
|
84
|
+
validation: Rule => Rule.unique()
|
|
85
|
+
}, {
|
|
86
|
+
name: 'hiddenLabel',
|
|
87
|
+
title: 'Hidden Label(s)',
|
|
88
|
+
group: 'label',
|
|
89
|
+
type: 'array',
|
|
90
|
+
description: 'Hidden labels are for character strings that need to be accessible to applications performing text-based indexing and search operations, but not visible otherwise. Hidden labels may for instance be used to include misspelled variants of other lexical labels. Preferred, alternative, and hidden label sets must not overlap.',
|
|
91
|
+
of: [{
|
|
92
|
+
type: 'string'
|
|
93
|
+
}],
|
|
94
|
+
validation: Rule => Rule.unique()
|
|
95
|
+
}, {
|
|
96
|
+
name: 'topConcept',
|
|
97
|
+
title: 'Top Concept',
|
|
98
|
+
group: 'relationship',
|
|
99
|
+
type: 'boolean',
|
|
100
|
+
description: 'Top concepts provide an efficient entry point to broader/narrower concept hierarchies and/or top level facets. By convention, resources can be a Top Concept, or have Broader relationships, but not both.',
|
|
101
|
+
hidden: _ref2 => {
|
|
102
|
+
var document = _ref2.document;
|
|
103
|
+
return document.broader ? document.broader.length > 0 : false;
|
|
104
|
+
}
|
|
105
|
+
}, {
|
|
106
|
+
name: 'broader',
|
|
107
|
+
title: 'Broader Concept(s)',
|
|
108
|
+
hidden: _ref3 => {
|
|
109
|
+
var document = _ref3.document;
|
|
110
|
+
return document.topConcept;
|
|
111
|
+
},
|
|
112
|
+
description: 'Broader relationships create a hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.',
|
|
113
|
+
group: 'relationship',
|
|
114
|
+
type: 'array',
|
|
115
|
+
of: [{
|
|
116
|
+
type: 'reference',
|
|
117
|
+
to: {
|
|
118
|
+
type: 'skosConcept'
|
|
119
|
+
},
|
|
120
|
+
options: {
|
|
121
|
+
filter: _ref4 => {
|
|
122
|
+
var document = _ref4.document;
|
|
123
|
+
return {
|
|
124
|
+
filter: '!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',
|
|
125
|
+
params: {
|
|
126
|
+
self: document._id.replace('drafts.', ''),
|
|
127
|
+
broader: document.broader ? document.broader.map(_ref5 => {
|
|
128
|
+
var _ref = _ref5._ref;
|
|
129
|
+
return _ref;
|
|
130
|
+
}) : [],
|
|
131
|
+
related: document.related ? document.related.map(_ref6 => {
|
|
132
|
+
var _ref = _ref6._ref;
|
|
133
|
+
return _ref;
|
|
134
|
+
}) : []
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}]
|
|
140
|
+
}, {
|
|
141
|
+
name: 'related',
|
|
142
|
+
title: 'Related Concept(s)',
|
|
143
|
+
description: 'Associative links between concepts indicate that the two are inherently "related", but that one is not in any way more general than the other. Broader and Associated relationships are mutually exclusive.',
|
|
144
|
+
group: 'relationship',
|
|
145
|
+
type: 'array',
|
|
146
|
+
of: [{
|
|
147
|
+
type: 'reference',
|
|
148
|
+
to: [{
|
|
149
|
+
type: 'skosConcept'
|
|
150
|
+
}],
|
|
151
|
+
options: {
|
|
152
|
+
filter: _ref7 => {
|
|
153
|
+
var document = _ref7.document;
|
|
154
|
+
return {
|
|
155
|
+
filter: '!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',
|
|
156
|
+
params: {
|
|
157
|
+
self: document._id.replace('drafts.', ''),
|
|
158
|
+
broader: document.broader ? document.broader.map(_ref8 => {
|
|
159
|
+
var _ref = _ref8._ref;
|
|
160
|
+
return _ref;
|
|
161
|
+
}) : [],
|
|
162
|
+
related: document.related ? document.related.map(_ref9 => {
|
|
163
|
+
var _ref = _ref9._ref;
|
|
164
|
+
return _ref;
|
|
165
|
+
}) : []
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}]
|
|
171
|
+
}, {
|
|
172
|
+
name: 'scheme',
|
|
173
|
+
title: 'Concept Scheme(s)',
|
|
174
|
+
group: 'relationship',
|
|
175
|
+
type: 'reference',
|
|
176
|
+
description: 'Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets.',
|
|
177
|
+
to: [{
|
|
178
|
+
type: 'skosConceptScheme'
|
|
179
|
+
}],
|
|
180
|
+
options: {
|
|
181
|
+
disableNew: true
|
|
182
|
+
}
|
|
183
|
+
}, {
|
|
184
|
+
name: 'scopeNote',
|
|
185
|
+
title: 'Scope Note',
|
|
186
|
+
type: 'text',
|
|
187
|
+
description: 'A brief statement on the intended meaning of this concept, especially as an indication of how the use of the concept is limited in indexing practice',
|
|
188
|
+
rows: 3,
|
|
189
|
+
group: 'note'
|
|
190
|
+
}, {
|
|
191
|
+
name: 'definition',
|
|
192
|
+
title: 'Definition',
|
|
193
|
+
type: 'text',
|
|
194
|
+
description: 'A complete explanation of the intended meaning of the concept',
|
|
195
|
+
rows: 3,
|
|
196
|
+
group: 'note'
|
|
197
|
+
}, {
|
|
198
|
+
name: 'example',
|
|
199
|
+
title: 'Examples',
|
|
200
|
+
type: 'text',
|
|
201
|
+
description: 'An example of the use of the concept.',
|
|
202
|
+
rows: 3,
|
|
203
|
+
group: 'note'
|
|
204
|
+
}],
|
|
205
|
+
orderings: [{
|
|
206
|
+
title: 'Top Concepts',
|
|
207
|
+
name: 'topConcept',
|
|
208
|
+
by: [{
|
|
209
|
+
field: 'topConcept',
|
|
210
|
+
direction: 'desc'
|
|
211
|
+
}, {
|
|
212
|
+
field: 'prefLabel',
|
|
213
|
+
direction: 'asc'
|
|
214
|
+
}]
|
|
215
|
+
}, {
|
|
216
|
+
title: 'Preferred Label',
|
|
217
|
+
name: 'prefLabel',
|
|
218
|
+
by: [{
|
|
219
|
+
field: 'prefLabel',
|
|
220
|
+
direction: 'asc'
|
|
221
|
+
}]
|
|
222
|
+
}],
|
|
223
|
+
preview: {
|
|
224
|
+
select: {
|
|
225
|
+
title: 'prefLabel',
|
|
226
|
+
topConcept: 'topConcept',
|
|
227
|
+
broader: 'broader.0.prefLabel',
|
|
228
|
+
broaderPlusOne: 'broader.0.broader.0.prefLabel',
|
|
229
|
+
broaderPlusTwo: 'broader.0.broader.0.broader.0.prefLabel'
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
prepare(_ref10) {
|
|
233
|
+
var title = _ref10.title,
|
|
234
|
+
topConcept = _ref10.topConcept,
|
|
235
|
+
broader = _ref10.broader,
|
|
236
|
+
broaderPlusOne = _ref10.broaderPlusOne,
|
|
237
|
+
broaderPlusTwo = _ref10.broaderPlusTwo;
|
|
238
|
+
var conceptBroader = [broaderPlusOne, broader].filter(Boolean);
|
|
239
|
+
var broaderPath = conceptBroader.length > 0 ? "".concat(conceptBroader.join(' ▷ '), " \u25B6\uFE0E ").concat(title) : '';
|
|
240
|
+
var hierarchy = broaderPlusTwo ? "... ".concat(broaderPath) : broaderPath;
|
|
241
|
+
return {
|
|
242
|
+
title: title,
|
|
243
|
+
subtitle: topConcept ? 'Top Concept' : hierarchy,
|
|
244
|
+
media: topConcept ? _ai.AiOutlineTag : _ai.AiFillTag
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
exports.default = _default;
|
|
251
|
+
//# sourceMappingURL=skosConcept.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/skosConcept.js"],"names":["client","sanityClient","withConfig","apiVersion","name","title","type","icon","AiFillTags","initialValue","iriBase","fetch","conceptIriBase","iriValue","undefined","scheme","topConcept","validation","Rule","custom","fields","altLabel","hiddenLabel","filter","label","includes","length","prefLabel","groups","group","description","required","error","inputComponent","PrefLabel","of","unique","hidden","document","broader","to","options","params","self","_id","replace","map","_ref","related","disableNew","rows","orderings","by","field","direction","preview","select","broaderPlusOne","broaderPlusTwo","prepare","conceptBroader","Boolean","broaderPath","join","hierarchy","subtitle","media","AiOutlineTag","AiFillTag"],"mappings":"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","sourcesContent":["/**\n * Sanity document scheme for SKOS Taxonomy Concepts\n * @todo PrefLabel: add document level validation that prevents the creation of two concepts with the same PrefLabel\n * @todo Hierarchy, Broader, & Associated: enforce disjointedness between Associated and BroaderTransitive (integrity constraint); prohibit cycles in hierarchical relations (best practice)\n * @todo Lexical labels: add child level validation so that offending labels are shown directly when a duplicate is entered. Then consider removing document level validation. cf. https://www.sanity.io/docs/validation#9e69d5db6f72\n * @todo Scheme initial value: Configure \"default\" option in Concept Scheme; configure initialValue to default to that selection.\n * @todo Abstract broader and related concept filter into reusable function. Need more clarity on what syntax \"filter:\" needs\n */\nimport sanityClient from 'part:@sanity/base/client'\nconst client = sanityClient.withConfig({apiVersion: '2021-03-25'})\nimport {AiFillTag, AiOutlineTag, AiFillTags} from 'react-icons/ai'\nimport PrefLabel from './components/prefLabel'\n\nexport default {\n name: 'skosConcept',\n title: 'Concepts',\n type: 'document',\n icon: AiFillTags,\n initialValue: async () => {\n const iriBase = await client.fetch(`\n *[_id == 'skosTaxonomySettings']{\n 'iriValue': baseIri,\n }[0]\n `)\n const conceptIriBase = iriBase?.iriValue ? iriBase : undefined\n const scheme =\n (await client.fetch(`\n *[_type == 'skosConceptScheme']{\n '_type': 'reference',\n '_ref': _id\n }[0]\n `)) ?? undefined\n return {\n conceptIriBase: conceptIriBase,\n scheme: scheme,\n topConcept: false,\n }\n },\n validation: (Rule) =>\n Rule.custom((fields) => {\n if (\n (fields.altLabel &&\n fields.hiddenLabel &&\n fields.altLabel.filter((label) => fields.hiddenLabel.includes(label)).length > 0) ||\n (fields.altLabel && fields.altLabel.includes(fields.prefLabel)) ||\n (fields.hiddenLabel && fields.hiddenLabel.includes(fields.prefLabel))\n )\n return 'Preferred Label, Alternate Labels, and Hidden Labels must all be unique. Please remove any labels duplicated across label types.'\n return true\n }),\n groups: [\n {\n name: 'relationship',\n title: 'Relationships',\n },\n {\n name: 'label',\n title: 'Labels',\n },\n {\n name: 'note',\n title: 'Documentation',\n },\n ],\n fields: [\n {\n name: 'prefLabel',\n title: 'Preferred Label',\n group: ['label', 'relationship'],\n type: 'string',\n description:\n 'The preferred lexical label for this concept. This label is also used to unambiguously represent this concept via the concept IRI.',\n validation: (Rule) => Rule.required().error('Concepts must have a preferred label'),\n inputComponent: PrefLabel,\n },\n {\n name: 'conceptIriBase',\n title: 'Edit the base IRI',\n type: 'baseIri',\n },\n {\n name: 'altLabel',\n title: 'Alternate Label(s)',\n group: 'label',\n type: 'array',\n description:\n 'Alternative labels can be used to assign synonyms, near-synonyms, abbreviations, and acronyms to a concept. Preferred, alternative, and hidden label sets must not overlap.',\n of: [{type: 'string'}],\n validation: (Rule) => Rule.unique(),\n },\n {\n name: 'hiddenLabel',\n title: 'Hidden Label(s)',\n group: 'label',\n type: 'array',\n description:\n 'Hidden labels are for character strings that need to be accessible to applications performing text-based indexing and search operations, but not visible otherwise. Hidden labels may for instance be used to include misspelled variants of other lexical labels. Preferred, alternative, and hidden label sets must not overlap.',\n of: [{type: 'string'}],\n validation: (Rule) => Rule.unique(),\n },\n {\n name: 'topConcept',\n title: 'Top Concept',\n group: 'relationship',\n type: 'boolean',\n description:\n 'Top concepts provide an efficient entry point to broader/narrower concept hierarchies and/or top level facets. By convention, resources can be a Top Concept, or have Broader relationships, but not both.',\n hidden: ({document}) => (document.broader ? document.broader.length > 0 : false),\n },\n {\n name: 'broader',\n title: 'Broader Concept(s)',\n hidden: ({document}) => document.topConcept,\n description:\n 'Broader relationships create a hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.',\n group: 'relationship',\n type: 'array',\n of: [\n {\n type: 'reference',\n to: {type: 'skosConcept'},\n options: {\n filter: ({document}) => {\n return {\n filter:\n '!(_id in $broader || _id in $related || _id in path(\"drafts.**\") || _id == $self)',\n params: {\n self: document._id.replace('drafts.', ''),\n broader: document.broader ? document.broader.map(({_ref}) => _ref) : [],\n related: document.related ? document.related.map(({_ref}) => _ref) : [],\n },\n }\n },\n },\n },\n ],\n },\n {\n name: 'related',\n title: 'Related Concept(s)',\n description:\n 'Associative links between concepts indicate that the two are inherently \"related\", but that one is not in any way more general than the other. Broader and Associated relationships are mutually exclusive.',\n group: 'relationship',\n type: 'array',\n of: [\n {\n type: 'reference',\n to: [{type: 'skosConcept'}],\n options: {\n filter: ({document}) => {\n return {\n filter:\n '!(_id in $broader || _id in $related || _id in path(\"drafts.**\") || _id == $self)',\n params: {\n self: document._id.replace('drafts.', ''),\n broader: document.broader ? document.broader.map(({_ref}) => _ref) : [],\n related: document.related ? document.related.map(({_ref}) => _ref) : [],\n },\n }\n },\n },\n },\n ],\n },\n {\n name: 'scheme',\n title: 'Concept Scheme(s)',\n group: 'relationship',\n type: 'reference',\n description:\n 'Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets.',\n to: [\n {\n type: 'skosConceptScheme',\n },\n ],\n options: {\n disableNew: true,\n },\n },\n {\n name: 'scopeNote',\n title: 'Scope Note',\n type: 'text',\n description:\n 'A brief statement on the intended meaning of this concept, especially as an indication of how the use of the concept is limited in indexing practice',\n rows: 3,\n group: 'note',\n },\n {\n name: 'definition',\n title: 'Definition',\n type: 'text',\n description: 'A complete explanation of the intended meaning of the concept',\n rows: 3,\n group: 'note',\n },\n {\n name: 'example',\n title: 'Examples',\n type: 'text',\n description: 'An example of the use of the concept.',\n rows: 3,\n group: 'note',\n },\n ],\n orderings: [\n {\n title: 'Top Concepts',\n name: 'topConcept',\n by: [\n {field: 'topConcept', direction: 'desc'},\n {field: 'prefLabel', direction: 'asc'},\n ],\n },\n {\n title: 'Preferred Label',\n name: 'prefLabel',\n by: [{field: 'prefLabel', direction: 'asc'}],\n },\n ],\n preview: {\n select: {\n title: 'prefLabel',\n topConcept: 'topConcept',\n broader: 'broader.0.prefLabel',\n broaderPlusOne: 'broader.0.broader.0.prefLabel',\n broaderPlusTwo: 'broader.0.broader.0.broader.0.prefLabel',\n },\n prepare({title, topConcept, broader, broaderPlusOne, broaderPlusTwo}) {\n const conceptBroader = [broaderPlusOne, broader].filter(Boolean)\n const broaderPath =\n conceptBroader.length > 0 ? `${conceptBroader.join(' ▷ ')} ▶︎ ${title}` : ''\n const hierarchy = broaderPlusTwo ? `... ${broaderPath}` : broaderPath\n return {\n title: title,\n subtitle: topConcept ? 'Top Concept' : hierarchy,\n media: topConcept ? AiOutlineTag : AiFillTag,\n }\n },\n },\n}\n"],"file":"skosConcept.js"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _ri = require("react-icons/ri");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Sanity document scheme for SKOS Concept Schemes
|
|
12
|
+
* @todo Afford setting a "default" scheme which is used as an initial value for new concepts. When no default is set, concepts are created without any scheme.
|
|
13
|
+
* @todo Add administrative metadata: author, date, last revised, etc.
|
|
14
|
+
* @todo Consider adding informational lists to this view (via custom input component): number of terms, list of terms, links. Perhaps eventually a navigable tree view.
|
|
15
|
+
*/
|
|
16
|
+
var _default = {
|
|
17
|
+
name: 'skosConceptScheme',
|
|
18
|
+
title: 'Taxonomy Schemes',
|
|
19
|
+
type: 'document',
|
|
20
|
+
icon: _ri.RiNodeTree,
|
|
21
|
+
fields: [{
|
|
22
|
+
name: 'title',
|
|
23
|
+
title: 'Taxonomy Identifier',
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets. Concepts may belong on many (or no) concept schemes, and you may create as many (or few) concept schemes as you like.'
|
|
26
|
+
}, {
|
|
27
|
+
name: 'description',
|
|
28
|
+
title: 'Description',
|
|
29
|
+
type: 'text',
|
|
30
|
+
rows: 3,
|
|
31
|
+
description: 'Describe the intended use of this scheme.'
|
|
32
|
+
}],
|
|
33
|
+
preview: {
|
|
34
|
+
select: {
|
|
35
|
+
title: 'title'
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
prepare(_ref) {
|
|
39
|
+
var title = _ref.title;
|
|
40
|
+
return {
|
|
41
|
+
title: title,
|
|
42
|
+
media: _ri.RiNodeTree
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
exports.default = _default;
|
|
49
|
+
//# sourceMappingURL=skosConceptScheme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/skosConceptScheme.js"],"names":["name","title","type","icon","RiNodeTree","fields","description","rows","preview","select","prepare","media"],"mappings":";;;;;;;AAMA;;AANA;AACA;AACA;AACA;AACA;AACA;eAGe;AACbA,EAAAA,IAAI,EAAE,mBADO;AAEbC,EAAAA,KAAK,EAAE,kBAFM;AAGbC,EAAAA,IAAI,EAAE,UAHO;AAIbC,EAAAA,IAAI,EAAEC,cAJO;AAKbC,EAAAA,MAAM,EAAE,CACN;AACEL,IAAAA,IAAI,EAAE,OADR;AAEEC,IAAAA,KAAK,EAAE,qBAFT;AAGEC,IAAAA,IAAI,EAAE,QAHR;AAIEI,IAAAA,WAAW,EACT;AALJ,GADM,EAQN;AACEN,IAAAA,IAAI,EAAE,aADR;AAEEC,IAAAA,KAAK,EAAE,aAFT;AAGEC,IAAAA,IAAI,EAAE,MAHR;AAIEK,IAAAA,IAAI,EAAE,CAJR;AAKED,IAAAA,WAAW,EAAE;AALf,GARM,CALK;AAqBbE,EAAAA,OAAO,EAAE;AACPC,IAAAA,MAAM,EAAE;AACNR,MAAAA,KAAK,EAAE;AADD,KADD;;AAIPS,IAAAA,OAAO,OAAU;AAAA,UAART,KAAQ,QAARA,KAAQ;AACf,aAAO;AACLA,QAAAA,KAAK,EAAEA,KADF;AAELU,QAAAA,KAAK,EAAEP;AAFF,OAAP;AAID;;AATM;AArBI,C","sourcesContent":["/**\n * Sanity document scheme for SKOS Concept Schemes\n * @todo Afford setting a \"default\" scheme which is used as an initial value for new concepts. When no default is set, concepts are created without any scheme.\n * @todo Add administrative metadata: author, date, last revised, etc.\n * @todo Consider adding informational lists to this view (via custom input component): number of terms, list of terms, links. Perhaps eventually a navigable tree view.\n */\nimport {RiNodeTree} from 'react-icons/ri'\n\nexport default {\n name: 'skosConceptScheme',\n title: 'Taxonomy Schemes',\n type: 'document',\n icon: RiNodeTree,\n fields: [\n {\n name: 'title',\n title: 'Taxonomy Identifier',\n type: 'string',\n description:\n 'Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets. Concepts may belong on many (or no) concept schemes, and you may create as many (or few) concept schemes as you like.',\n },\n {\n name: 'description',\n title: 'Description',\n type: 'text',\n rows: 3,\n description: 'Describe the intended use of this scheme.',\n },\n ],\n preview: {\n select: {\n title: 'title',\n },\n prepare({title}) {\n return {\n title: title,\n media: RiNodeTree,\n }\n },\n },\n}\n"],"file":"skosConceptScheme.js"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _ri = require("react-icons/ri");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Global SKOS taxonomy settings
|
|
12
|
+
* @todo BaseIri validation: figure out why the validation warning message shows up twice when there's no value.
|
|
13
|
+
* @todo Deal with Settings values when the Settings doc may not have been created from structure builder (with a 'skosTaxonomySettings' ID)
|
|
14
|
+
* @todo Add IRI pattern selector (or instructions): hash or slash; default to slash
|
|
15
|
+
* @todo Add IRI format selector: PrefLabel or UUID (perhaps from Sanity _id); default to PrefLabel
|
|
16
|
+
* @todo Consider adding an array (or list) here of Concept Schemes. These were originally envisioned as being accessed here, but are in their own top level grouping for now to support editing. They do need to be distinct, addressable entities, so they need to remain documents.
|
|
17
|
+
*/
|
|
18
|
+
var _default = {
|
|
19
|
+
name: 'skosTaxonomySettings',
|
|
20
|
+
title: 'Taxonomy Settings',
|
|
21
|
+
type: 'document',
|
|
22
|
+
icon: _ri.RiSettings4Line,
|
|
23
|
+
// Once you've created your settings doc, uncomment this line to disable the creation of additional copies:
|
|
24
|
+
// __experimental_actions: [/*'create',*/ 'update', /*'delete',*/ 'publish'],
|
|
25
|
+
fields: [{
|
|
26
|
+
name: 'title',
|
|
27
|
+
title: 'Taxonomy Name',
|
|
28
|
+
type: 'string',
|
|
29
|
+
hidden: true,
|
|
30
|
+
initialValue: 'Taxonomy Settings'
|
|
31
|
+
}, {
|
|
32
|
+
name: 'baseIri',
|
|
33
|
+
title: 'Base IRI',
|
|
34
|
+
type: 'url',
|
|
35
|
+
description: 'The base IRI (Internationalised Resource Identifier) is used to specify the fully qualified name of taxonomy elements. The W3C encourages the use of HTTP URIs when minting concept URIs since they are resolvable to representations that can be accessed using standard Web technologies. The "base IRI" entered here is used as the default base for new concepts.',
|
|
36
|
+
validation: Rule => Rule.required().warning('Entering a Base IRI is highly recommended in order to ensure taxonomy integrity and interoperability.')
|
|
37
|
+
}]
|
|
38
|
+
};
|
|
39
|
+
exports.default = _default;
|
|
40
|
+
//# sourceMappingURL=skosTaxonomySettings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/skosTaxonomySettings.js"],"names":["name","title","type","icon","RiSettings4Line","fields","hidden","initialValue","description","validation","Rule","required","warning"],"mappings":";;;;;;;AAQA;;AARA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;eAGe;AACbA,EAAAA,IAAI,EAAE,sBADO;AAEbC,EAAAA,KAAK,EAAE,mBAFM;AAGbC,EAAAA,IAAI,EAAE,UAHO;AAIbC,EAAAA,IAAI,EAAEC,mBAJO;AAKb;AACA;AACAC,EAAAA,MAAM,EAAE,CACN;AACEL,IAAAA,IAAI,EAAE,OADR;AAEEC,IAAAA,KAAK,EAAE,eAFT;AAGEC,IAAAA,IAAI,EAAE,QAHR;AAIEI,IAAAA,MAAM,EAAE,IAJV;AAKEC,IAAAA,YAAY,EAAE;AALhB,GADM,EAQN;AACEP,IAAAA,IAAI,EAAE,SADR;AAEEC,IAAAA,KAAK,EAAE,UAFT;AAGEC,IAAAA,IAAI,EAAE,KAHR;AAIEM,IAAAA,WAAW,EACT,uWALJ;AAMEC,IAAAA,UAAU,EAAGC,IAAD,IACVA,IAAI,CAACC,QAAL,GAAgBC,OAAhB,CACE,uGADF;AAPJ,GARM;AAPK,C","sourcesContent":["/**\n * Global SKOS taxonomy settings\n * @todo BaseIri validation: figure out why the validation warning message shows up twice when there's no value.\n * @todo Deal with Settings values when the Settings doc may not have been created from structure builder (with a 'skosTaxonomySettings' ID)\n * @todo Add IRI pattern selector (or instructions): hash or slash; default to slash\n * @todo Add IRI format selector: PrefLabel or UUID (perhaps from Sanity _id); default to PrefLabel\n * @todo Consider adding an array (or list) here of Concept Schemes. These were originally envisioned as being accessed here, but are in their own top level grouping for now to support editing. They do need to be distinct, addressable entities, so they need to remain documents. \n */\nimport {RiSettings4Line} from 'react-icons/ri'\n\nexport default {\n name: 'skosTaxonomySettings',\n title: 'Taxonomy Settings',\n type: 'document',\n icon: RiSettings4Line,\n // Once you've created your settings doc, uncomment this line to disable the creation of additional copies:\n // __experimental_actions: [/*'create',*/ 'update', /*'delete',*/ 'publish'],\n fields: [\n {\n name: 'title',\n title: 'Taxonomy Name',\n type: 'string',\n hidden: true,\n initialValue: 'Taxonomy Settings',\n },\n {\n name: 'baseIri',\n title: 'Base IRI',\n type: 'url',\n description:\n 'The base IRI (Internationalised Resource Identifier) is used to specify the fully qualified name of taxonomy elements. The W3C encourages the use of HTTP URIs when minting concept URIs since they are resolvable to representations that can be accessed using standard Web technologies. The \"base IRI\" entered here is used as the default base for new concepts.',\n validation: (Rule) =>\n Rule.required().warning(\n 'Entering a Base IRI is highly recommended in order to ensure taxonomy integrity and interoperability.'\n ),\n },\n ],\n}\n"],"file":"skosTaxonomySettings.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sanity-plugin-taxonomy-manager",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Create and manage SKOS compliant taxonomies, thesauri, and classification schemes in Sanity Studio.",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"lint": "eslint .",
|
|
7
|
+
"build": "sanipack build",
|
|
8
|
+
"watch": "sanipack build --watch",
|
|
9
|
+
"prepublishOnly": "sanipack build && sanipack verify"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+ssh://git@github.com/andybywire/sanity-plugin-taxonomy-manager.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"sanity",
|
|
17
|
+
"sanity-plugin"
|
|
18
|
+
],
|
|
19
|
+
"author": "Andy Fitzgerald",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@reach/auto-id": "^0.16.0",
|
|
23
|
+
"@sanity/base": "^2.28.2",
|
|
24
|
+
"@sanity/form-builder": "^2.29.1",
|
|
25
|
+
"@sanity/ui": "^0.37.5",
|
|
26
|
+
"react-icons": "^4.3.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"eslint": "^7.32.0",
|
|
30
|
+
"eslint-config-prettier": "^8.5.0",
|
|
31
|
+
"eslint-config-sanity": "^5.1.0",
|
|
32
|
+
"eslint-plugin-react": "^7.29.4",
|
|
33
|
+
"prettier": "^2.5.1",
|
|
34
|
+
"sanipack": "^2.1.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": "^17.0.0"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/andybywire/sanity-plugin-taxonomy-manager/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/andybywire/sanity-plugin-taxonomy-manager#readme",
|
|
43
|
+
"prettier": {
|
|
44
|
+
"semi": false,
|
|
45
|
+
"printWidth": 100,
|
|
46
|
+
"bracketSpacing": false,
|
|
47
|
+
"singleQuote": true
|
|
48
|
+
},
|
|
49
|
+
"eslintConfig": {
|
|
50
|
+
"parser": "sanipack/babel/eslint-parser",
|
|
51
|
+
"extends": [
|
|
52
|
+
"sanity",
|
|
53
|
+
"sanity/react",
|
|
54
|
+
"prettier"
|
|
55
|
+
],
|
|
56
|
+
"ignorePatterns": [
|
|
57
|
+
"lib/**/"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
package/sanity.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"paths": {
|
|
3
|
+
"source": "./src",
|
|
4
|
+
"compiled": "./lib"
|
|
5
|
+
},
|
|
6
|
+
"parts": [
|
|
7
|
+
{
|
|
8
|
+
"implements": "part:@sanity/base/schema-type",
|
|
9
|
+
"path": "skosTaxonomySettings.js"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"implements": "part:@sanity/base/schema-type",
|
|
13
|
+
"path": "skosConceptScheme.js"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"implements": "part:@sanity/base/schema-type",
|
|
17
|
+
"path": "skosConcept.js"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"implements": "part:@sanity/base/schema-type",
|
|
21
|
+
"path": "objects/baseIri.js"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrefLabel input component for SKOS Concept
|
|
3
|
+
* This component creates a Concept IRI preview to help taxonomy managers avoid errors in minting URIs.
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import {FormField} from '@sanity/base/components'
|
|
7
|
+
import {TextInput, Stack, Text} from '@sanity/ui'
|
|
8
|
+
import PatchEvent, {set, unset} from '@sanity/form-builder/PatchEvent'
|
|
9
|
+
import {useId} from '@reach/auto-id' // hook to generate unique IDs
|
|
10
|
+
|
|
11
|
+
const PrefLabel = React.forwardRef((props, ref) => {
|
|
12
|
+
const {
|
|
13
|
+
type, // Schema information
|
|
14
|
+
value, // Current field value
|
|
15
|
+
readOnly, // Boolean if field is not editable
|
|
16
|
+
placeholder, // Placeholder text from the schema
|
|
17
|
+
markers, // Markers including validation rules
|
|
18
|
+
presence, // Presence information for collaborative avatars
|
|
19
|
+
compareValue, // Value to check for "edited" functionality
|
|
20
|
+
onFocus, // Method to handle focus state
|
|
21
|
+
onBlur, // Method to handle blur state
|
|
22
|
+
onChange, // Method to handle patch events
|
|
23
|
+
parent,
|
|
24
|
+
} = props
|
|
25
|
+
|
|
26
|
+
// Creates a unique ID for input
|
|
27
|
+
const inputId = useId()
|
|
28
|
+
|
|
29
|
+
// Creates a change handler for patching data
|
|
30
|
+
const handleChange = React.useCallback(
|
|
31
|
+
// useCallback will help with performance
|
|
32
|
+
(event) => {
|
|
33
|
+
const inputValue = event.currentTarget.value // get current value
|
|
34
|
+
// if the value exists, set the data, if not, unset the data
|
|
35
|
+
onChange(PatchEvent.from(inputValue ? set(inputValue) : unset()))
|
|
36
|
+
},
|
|
37
|
+
[onChange]
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Stack space={1}>
|
|
42
|
+
<FormField
|
|
43
|
+
description={type.description}
|
|
44
|
+
title={type.title}
|
|
45
|
+
__unstable_markers={markers} // Handles all markers including validation
|
|
46
|
+
__unstable_presence={presence} // Handles presence avatars
|
|
47
|
+
compareValue={compareValue} // Handles "edited" status
|
|
48
|
+
inputId={inputId} // Allows the label to connect to the input field
|
|
49
|
+
>
|
|
50
|
+
<TextInput
|
|
51
|
+
id={inputId} // A unique ID for this input
|
|
52
|
+
onChange={handleChange} // A function to call when the input value changes
|
|
53
|
+
value={value} // Current field value
|
|
54
|
+
readOnly={readOnly} // If "readOnly" is defined make this field read only
|
|
55
|
+
placeholder={placeholder} // If placeholder is defined, display placeholder text
|
|
56
|
+
onFocus={onFocus} // Handles focus events
|
|
57
|
+
onBlur={onBlur} // Handles blur events
|
|
58
|
+
ref={ref}
|
|
59
|
+
/>
|
|
60
|
+
</FormField>
|
|
61
|
+
<Text muted size={1}>
|
|
62
|
+
<strong>Concept IRI: </strong>
|
|
63
|
+
{parent.conceptIriBase ? parent.conceptIriBase.iriValue : '[base URI not defined] '}
|
|
64
|
+
{value?.replaceAll(' ', '')}
|
|
65
|
+
</Text>
|
|
66
|
+
</Stack>
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
export default PrefLabel
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Internationalized Resource Identifier object for Sanity Taxonomy Manager
|
|
3
|
+
* This field is created as an object in order to present it as collapsed in the Sanity Studio UI.
|
|
4
|
+
*/
|
|
5
|
+
export default {
|
|
6
|
+
name: 'baseIri',
|
|
7
|
+
title: 'Base IRI',
|
|
8
|
+
type: 'object',
|
|
9
|
+
fields: [
|
|
10
|
+
{
|
|
11
|
+
name: 'iriValue',
|
|
12
|
+
title: 'IRI Value',
|
|
13
|
+
type: 'url',
|
|
14
|
+
description:
|
|
15
|
+
'The W3C encourages the use of HTTP URIs when minting concept URIs since they are resolvable to representations that can be accessed using standard Web technologies.',
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
options: {
|
|
19
|
+
collapsible: true,
|
|
20
|
+
collapsed: true,
|
|
21
|
+
},
|
|
22
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanity document scheme for SKOS Taxonomy Concepts
|
|
3
|
+
* @todo PrefLabel: add document level validation that prevents the creation of two concepts with the same PrefLabel
|
|
4
|
+
* @todo Hierarchy, Broader, & Associated: enforce disjointedness between Associated and BroaderTransitive (integrity constraint); prohibit cycles in hierarchical relations (best practice)
|
|
5
|
+
* @todo Lexical labels: add child level validation so that offending labels are shown directly when a duplicate is entered. Then consider removing document level validation. cf. https://www.sanity.io/docs/validation#9e69d5db6f72
|
|
6
|
+
* @todo Scheme initial value: Configure "default" option in Concept Scheme; configure initialValue to default to that selection.
|
|
7
|
+
* @todo Abstract broader and related concept filter into reusable function. Need more clarity on what syntax "filter:" needs
|
|
8
|
+
*/
|
|
9
|
+
import sanityClient from 'part:@sanity/base/client'
|
|
10
|
+
const client = sanityClient.withConfig({apiVersion: '2021-03-25'})
|
|
11
|
+
import {AiFillTag, AiOutlineTag, AiFillTags} from 'react-icons/ai'
|
|
12
|
+
import PrefLabel from './components/prefLabel'
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
name: 'skosConcept',
|
|
16
|
+
title: 'Concepts',
|
|
17
|
+
type: 'document',
|
|
18
|
+
icon: AiFillTags,
|
|
19
|
+
initialValue: async () => {
|
|
20
|
+
const iriBase = await client.fetch(`
|
|
21
|
+
*[_id == 'skosTaxonomySettings']{
|
|
22
|
+
'iriValue': baseIri,
|
|
23
|
+
}[0]
|
|
24
|
+
`)
|
|
25
|
+
const conceptIriBase = iriBase?.iriValue ? iriBase : undefined
|
|
26
|
+
const scheme =
|
|
27
|
+
(await client.fetch(`
|
|
28
|
+
*[_type == 'skosConceptScheme']{
|
|
29
|
+
'_type': 'reference',
|
|
30
|
+
'_ref': _id
|
|
31
|
+
}[0]
|
|
32
|
+
`)) ?? undefined
|
|
33
|
+
return {
|
|
34
|
+
conceptIriBase: conceptIriBase,
|
|
35
|
+
scheme: scheme,
|
|
36
|
+
topConcept: false,
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
validation: (Rule) =>
|
|
40
|
+
Rule.custom((fields) => {
|
|
41
|
+
if (
|
|
42
|
+
(fields.altLabel &&
|
|
43
|
+
fields.hiddenLabel &&
|
|
44
|
+
fields.altLabel.filter((label) => fields.hiddenLabel.includes(label)).length > 0) ||
|
|
45
|
+
(fields.altLabel && fields.altLabel.includes(fields.prefLabel)) ||
|
|
46
|
+
(fields.hiddenLabel && fields.hiddenLabel.includes(fields.prefLabel))
|
|
47
|
+
)
|
|
48
|
+
return 'Preferred Label, Alternate Labels, and Hidden Labels must all be unique. Please remove any labels duplicated across label types.'
|
|
49
|
+
return true
|
|
50
|
+
}),
|
|
51
|
+
groups: [
|
|
52
|
+
{
|
|
53
|
+
name: 'relationship',
|
|
54
|
+
title: 'Relationships',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'label',
|
|
58
|
+
title: 'Labels',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'note',
|
|
62
|
+
title: 'Documentation',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
fields: [
|
|
66
|
+
{
|
|
67
|
+
name: 'prefLabel',
|
|
68
|
+
title: 'Preferred Label',
|
|
69
|
+
group: ['label', 'relationship'],
|
|
70
|
+
type: 'string',
|
|
71
|
+
description:
|
|
72
|
+
'The preferred lexical label for this concept. This label is also used to unambiguously represent this concept via the concept IRI.',
|
|
73
|
+
validation: (Rule) => Rule.required().error('Concepts must have a preferred label'),
|
|
74
|
+
inputComponent: PrefLabel,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'conceptIriBase',
|
|
78
|
+
title: 'Edit the base IRI',
|
|
79
|
+
type: 'baseIri',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'altLabel',
|
|
83
|
+
title: 'Alternate Label(s)',
|
|
84
|
+
group: 'label',
|
|
85
|
+
type: 'array',
|
|
86
|
+
description:
|
|
87
|
+
'Alternative labels can be used to assign synonyms, near-synonyms, abbreviations, and acronyms to a concept. Preferred, alternative, and hidden label sets must not overlap.',
|
|
88
|
+
of: [{type: 'string'}],
|
|
89
|
+
validation: (Rule) => Rule.unique(),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'hiddenLabel',
|
|
93
|
+
title: 'Hidden Label(s)',
|
|
94
|
+
group: 'label',
|
|
95
|
+
type: 'array',
|
|
96
|
+
description:
|
|
97
|
+
'Hidden labels are for character strings that need to be accessible to applications performing text-based indexing and search operations, but not visible otherwise. Hidden labels may for instance be used to include misspelled variants of other lexical labels. Preferred, alternative, and hidden label sets must not overlap.',
|
|
98
|
+
of: [{type: 'string'}],
|
|
99
|
+
validation: (Rule) => Rule.unique(),
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'topConcept',
|
|
103
|
+
title: 'Top Concept',
|
|
104
|
+
group: 'relationship',
|
|
105
|
+
type: 'boolean',
|
|
106
|
+
description:
|
|
107
|
+
'Top concepts provide an efficient entry point to broader/narrower concept hierarchies and/or top level facets. By convention, resources can be a Top Concept, or have Broader relationships, but not both.',
|
|
108
|
+
hidden: ({document}) => (document.broader ? document.broader.length > 0 : false),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'broader',
|
|
112
|
+
title: 'Broader Concept(s)',
|
|
113
|
+
hidden: ({document}) => document.topConcept,
|
|
114
|
+
description:
|
|
115
|
+
'Broader relationships create a hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.',
|
|
116
|
+
group: 'relationship',
|
|
117
|
+
type: 'array',
|
|
118
|
+
of: [
|
|
119
|
+
{
|
|
120
|
+
type: 'reference',
|
|
121
|
+
to: {type: 'skosConcept'},
|
|
122
|
+
options: {
|
|
123
|
+
filter: ({document}) => {
|
|
124
|
+
return {
|
|
125
|
+
filter:
|
|
126
|
+
'!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',
|
|
127
|
+
params: {
|
|
128
|
+
self: document._id.replace('drafts.', ''),
|
|
129
|
+
broader: document.broader ? document.broader.map(({_ref}) => _ref) : [],
|
|
130
|
+
related: document.related ? document.related.map(({_ref}) => _ref) : [],
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'related',
|
|
140
|
+
title: 'Related Concept(s)',
|
|
141
|
+
description:
|
|
142
|
+
'Associative links between concepts indicate that the two are inherently "related", but that one is not in any way more general than the other. Broader and Associated relationships are mutually exclusive.',
|
|
143
|
+
group: 'relationship',
|
|
144
|
+
type: 'array',
|
|
145
|
+
of: [
|
|
146
|
+
{
|
|
147
|
+
type: 'reference',
|
|
148
|
+
to: [{type: 'skosConcept'}],
|
|
149
|
+
options: {
|
|
150
|
+
filter: ({document}) => {
|
|
151
|
+
return {
|
|
152
|
+
filter:
|
|
153
|
+
'!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',
|
|
154
|
+
params: {
|
|
155
|
+
self: document._id.replace('drafts.', ''),
|
|
156
|
+
broader: document.broader ? document.broader.map(({_ref}) => _ref) : [],
|
|
157
|
+
related: document.related ? document.related.map(({_ref}) => _ref) : [],
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: 'scheme',
|
|
167
|
+
title: 'Concept Scheme(s)',
|
|
168
|
+
group: 'relationship',
|
|
169
|
+
type: 'reference',
|
|
170
|
+
description:
|
|
171
|
+
'Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets.',
|
|
172
|
+
to: [
|
|
173
|
+
{
|
|
174
|
+
type: 'skosConceptScheme',
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
options: {
|
|
178
|
+
disableNew: true,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: 'scopeNote',
|
|
183
|
+
title: 'Scope Note',
|
|
184
|
+
type: 'text',
|
|
185
|
+
description:
|
|
186
|
+
'A brief statement on the intended meaning of this concept, especially as an indication of how the use of the concept is limited in indexing practice',
|
|
187
|
+
rows: 3,
|
|
188
|
+
group: 'note',
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'definition',
|
|
192
|
+
title: 'Definition',
|
|
193
|
+
type: 'text',
|
|
194
|
+
description: 'A complete explanation of the intended meaning of the concept',
|
|
195
|
+
rows: 3,
|
|
196
|
+
group: 'note',
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'example',
|
|
200
|
+
title: 'Examples',
|
|
201
|
+
type: 'text',
|
|
202
|
+
description: 'An example of the use of the concept.',
|
|
203
|
+
rows: 3,
|
|
204
|
+
group: 'note',
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
orderings: [
|
|
208
|
+
{
|
|
209
|
+
title: 'Top Concepts',
|
|
210
|
+
name: 'topConcept',
|
|
211
|
+
by: [
|
|
212
|
+
{field: 'topConcept', direction: 'desc'},
|
|
213
|
+
{field: 'prefLabel', direction: 'asc'},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
title: 'Preferred Label',
|
|
218
|
+
name: 'prefLabel',
|
|
219
|
+
by: [{field: 'prefLabel', direction: 'asc'}],
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
preview: {
|
|
223
|
+
select: {
|
|
224
|
+
title: 'prefLabel',
|
|
225
|
+
topConcept: 'topConcept',
|
|
226
|
+
broader: 'broader.0.prefLabel',
|
|
227
|
+
broaderPlusOne: 'broader.0.broader.0.prefLabel',
|
|
228
|
+
broaderPlusTwo: 'broader.0.broader.0.broader.0.prefLabel',
|
|
229
|
+
},
|
|
230
|
+
prepare({title, topConcept, broader, broaderPlusOne, broaderPlusTwo}) {
|
|
231
|
+
const conceptBroader = [broaderPlusOne, broader].filter(Boolean)
|
|
232
|
+
const broaderPath =
|
|
233
|
+
conceptBroader.length > 0 ? `${conceptBroader.join(' ▷ ')} ▶︎ ${title}` : ''
|
|
234
|
+
const hierarchy = broaderPlusTwo ? `... ${broaderPath}` : broaderPath
|
|
235
|
+
return {
|
|
236
|
+
title: title,
|
|
237
|
+
subtitle: topConcept ? 'Top Concept' : hierarchy,
|
|
238
|
+
media: topConcept ? AiOutlineTag : AiFillTag,
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanity document scheme for SKOS Concept Schemes
|
|
3
|
+
* @todo Afford setting a "default" scheme which is used as an initial value for new concepts. When no default is set, concepts are created without any scheme.
|
|
4
|
+
* @todo Add administrative metadata: author, date, last revised, etc.
|
|
5
|
+
* @todo Consider adding informational lists to this view (via custom input component): number of terms, list of terms, links. Perhaps eventually a navigable tree view.
|
|
6
|
+
*/
|
|
7
|
+
import {RiNodeTree} from 'react-icons/ri'
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
name: 'skosConceptScheme',
|
|
11
|
+
title: 'Taxonomy Schemes',
|
|
12
|
+
type: 'document',
|
|
13
|
+
icon: RiNodeTree,
|
|
14
|
+
fields: [
|
|
15
|
+
{
|
|
16
|
+
name: 'title',
|
|
17
|
+
title: 'Taxonomy Identifier',
|
|
18
|
+
type: 'string',
|
|
19
|
+
description:
|
|
20
|
+
'Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets. Concepts may belong on many (or no) concept schemes, and you may create as many (or few) concept schemes as you like.',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'description',
|
|
24
|
+
title: 'Description',
|
|
25
|
+
type: 'text',
|
|
26
|
+
rows: 3,
|
|
27
|
+
description: 'Describe the intended use of this scheme.',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
preview: {
|
|
31
|
+
select: {
|
|
32
|
+
title: 'title',
|
|
33
|
+
},
|
|
34
|
+
prepare({title}) {
|
|
35
|
+
return {
|
|
36
|
+
title: title,
|
|
37
|
+
media: RiNodeTree,
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global SKOS taxonomy settings
|
|
3
|
+
* @todo BaseIri validation: figure out why the validation warning message shows up twice when there's no value.
|
|
4
|
+
* @todo Deal with Settings values when the Settings doc may not have been created from structure builder (with a 'skosTaxonomySettings' ID)
|
|
5
|
+
* @todo Add IRI pattern selector (or instructions): hash or slash; default to slash
|
|
6
|
+
* @todo Add IRI format selector: PrefLabel or UUID (perhaps from Sanity _id); default to PrefLabel
|
|
7
|
+
* @todo Consider adding an array (or list) here of Concept Schemes. These were originally envisioned as being accessed here, but are in their own top level grouping for now to support editing. They do need to be distinct, addressable entities, so they need to remain documents.
|
|
8
|
+
*/
|
|
9
|
+
import {RiSettings4Line} from 'react-icons/ri'
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
name: 'skosTaxonomySettings',
|
|
13
|
+
title: 'Taxonomy Settings',
|
|
14
|
+
type: 'document',
|
|
15
|
+
icon: RiSettings4Line,
|
|
16
|
+
// Once you've created your settings doc, uncomment this line to disable the creation of additional copies:
|
|
17
|
+
// __experimental_actions: [/*'create',*/ 'update', /*'delete',*/ 'publish'],
|
|
18
|
+
fields: [
|
|
19
|
+
{
|
|
20
|
+
name: 'title',
|
|
21
|
+
title: 'Taxonomy Name',
|
|
22
|
+
type: 'string',
|
|
23
|
+
hidden: true,
|
|
24
|
+
initialValue: 'Taxonomy Settings',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'baseIri',
|
|
28
|
+
title: 'Base IRI',
|
|
29
|
+
type: 'url',
|
|
30
|
+
description:
|
|
31
|
+
'The base IRI (Internationalised Resource Identifier) is used to specify the fully qualified name of taxonomy elements. The W3C encourages the use of HTTP URIs when minting concept URIs since they are resolvable to representations that can be accessed using standard Web technologies. The "base IRI" entered here is used as the default base for new concepts.',
|
|
32
|
+
validation: (Rule) =>
|
|
33
|
+
Rule.required().warning(
|
|
34
|
+
'Entering a Base IRI is highly recommended in order to ensure taxonomy integrity and interoperability.'
|
|
35
|
+
),
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
}
|