sanity-plugin-taxonomy-manager 2.0.0-beta.0 → 2.0.1
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/README.md +47 -47
- package/lib/index.esm.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
- package/src/components/Hierarchy.tsx +13 -20
- package/src/components/TreeView.tsx +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Sanity
|
|
1
|
+
# Sanity Taxonomy Manager Plugin
|
|
2
2
|

|
|
3
3
|

|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ Taxonomies are crucial tools for organization and interoperability between and a
|
|
|
11
11
|
|
|
12
12
|
The Taxonomy Manager document schema is based on the [World Wide Web Consortium](https://www.w3.org/) (W3C) [Simple Knowledge Organization Scheme](https://www.w3.org/TR/skos-reference/) (SKOS) recommendation. Concept and concept scheme editor tools include standard SKOS properties, hints for creating consistent concepts and vocabularies, and validation functions for preventing consistency errors.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
<img src="https://user-images.githubusercontent.com/3710835/212743871-14760a60-0689-4cc3-a13e-55dd7a4ef19a.png" width="700">
|
|
15
15
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
@@ -32,23 +32,25 @@ $ npm i sanity-plugin-taxonomy-manager
|
|
|
32
32
|
Add the plugin to your project configuration to make the skosConcept and skosConceptScheme document types available in your studio.
|
|
33
33
|
|
|
34
34
|
```js
|
|
35
|
-
// sanity.config.
|
|
35
|
+
// sanity.config.js
|
|
36
36
|
|
|
37
|
-
import {
|
|
38
|
-
|
|
39
|
-
import {
|
|
37
|
+
import {defineConfig} from 'sanity'
|
|
38
|
+
import {deskTool} from 'sanity/desk'
|
|
39
|
+
import {structure} from "./deskStructure"
|
|
40
|
+
import {taxonomyManager} from 'sanity-plugin-taxonomy-manager'
|
|
41
|
+
import {schemaTypes} from './schemas'
|
|
40
42
|
|
|
41
43
|
export default defineConfig({
|
|
42
44
|
name: 'default',
|
|
43
|
-
title: '
|
|
44
|
-
projectId: '
|
|
45
|
+
title: 'Sanity Studio',
|
|
46
|
+
projectId: 'project-id',
|
|
45
47
|
dataset: 'production',
|
|
46
48
|
plugins: [
|
|
47
|
-
// Include the taxonomy manager plugin
|
|
48
|
-
taxonomyManager(),
|
|
49
49
|
deskTool({
|
|
50
|
-
structure
|
|
51
|
-
})
|
|
50
|
+
structure
|
|
51
|
+
}),
|
|
52
|
+
// Include the taxonomy manager plugin
|
|
53
|
+
taxonomyManager()
|
|
52
54
|
],
|
|
53
55
|
schema: {
|
|
54
56
|
types: schemaTypes,
|
|
@@ -62,36 +64,34 @@ Use [Structure Builder](https://www.sanity.io/docs/structure-builder-reference)
|
|
|
62
64
|
// ./deskStructure.js
|
|
63
65
|
import {TreeView} from 'sanity-plugin-taxonomy-manager'
|
|
64
66
|
|
|
65
|
-
export const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
S.listItem()
|
|
71
|
-
.title('Concept Schemes')
|
|
72
|
-
.schemaType('skosConceptScheme')
|
|
73
|
-
.child(
|
|
74
|
-
S.documentTypeList('skosConceptScheme')
|
|
67
|
+
export const structure = (S) =>
|
|
68
|
+
S.list()
|
|
69
|
+
.title('Content')
|
|
70
|
+
.items([
|
|
71
|
+
S.listItem()
|
|
75
72
|
.title('Concept Schemes')
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.
|
|
80
|
-
.
|
|
81
|
-
S.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
73
|
+
.schemaType('skosConceptScheme')
|
|
74
|
+
.child(
|
|
75
|
+
S.documentTypeList('skosConceptScheme')
|
|
76
|
+
.title('Concept Schemes')
|
|
77
|
+
.child(id =>
|
|
78
|
+
S.document()
|
|
79
|
+
.schemaType('skosConceptScheme')
|
|
80
|
+
.documentId(id)
|
|
81
|
+
.views([
|
|
82
|
+
S.view.component(TreeView).title('Tree View'),
|
|
83
|
+
S.view.form()
|
|
84
|
+
])
|
|
85
|
+
)
|
|
86
|
+
),
|
|
87
|
+
S.documentTypeListItem("skosConcept").title("Concepts"),
|
|
88
|
+
S.divider(),
|
|
89
|
+
|
|
90
|
+
// Remove Taxonomy Manager types from the default document type list
|
|
91
|
+
...S.documentTypeListItems().filter(
|
|
92
|
+
(listItem) => !['skosConcept', 'skosConceptScheme'].includes(listItem.getId())
|
|
93
|
+
),
|
|
94
|
+
])
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
## Usage
|
|
@@ -107,23 +107,23 @@ export const myStructure = (S) =>
|
|
|
107
107
|
|
|
108
108
|
The concept editor includes filtering and validation to help you create consistent SKOS vocabularies:
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
**SKOS Broader and Related Concepts**
|
|
111
111
|
Adding the same concept to Broader and Related fields is not allowed, and the editor validates disjunction of Related concepts with Broader Transitive up to five hierarchical levels in either direction.
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
**Preferred, Alternative, and Hidden Labels**
|
|
114
114
|
Preferred Labels are validated for uniqueness across concepts, and Preferred, Alternative, and Hidden are validated to prevent duplicates and overlap.
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
**Scope Notes, Definition, and Examples**
|
|
117
117
|
Standard optional SKOS documentation fields are included by default.
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
**Support for Single or Multiple Taxonomy Schemes (or none)**
|
|
120
120
|
For cases where more than one taxonomy is needed, multiple [SKOS Concept Schemes](https://www.w3.org/TR/skos-reference/#schemes) are supported. Schemes can be used to configure filtered views of concepts in Sanity Structure Builder and can be used to scope values for reference arrays.
|
|
121
121
|
|
|
122
122
|
<!-- Concept Scheme views show a hierarchical list (Tree View) of the concepts included in a given scheme. This list allows for easy visualization of Top Concepts, polyhierarchy (concepts that appear in more than one place in the hierarchy), and "Orphan" terms (top level concepts not denoted as a "Top Concept"). -->
|
|
123
123
|
|
|
124
|
-
##
|
|
124
|
+
## SKOS Overview
|
|
125
125
|
|
|
126
|
-
> The Simple Knowledge Organization System (SKOS) is a common data model for sharing and linking knowledge organization systems via the Web.
|
|
126
|
+
> The [Simple Knowledge Organization System (SKOS)](https://www.w3.org/TR/skos-reference/) is a common data model for sharing and linking knowledge organization systems via the Web.
|
|
127
127
|
>
|
|
128
128
|
> 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.
|
|
129
129
|
>
|
package/lib/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useFormValue as e,defineType as t,defineField as i,defineArrayMember as n,useClient as o,definePlugin as r}from"sanity";import{jsxs as a,jsx as s,Fragment as c}from"react/jsx-runtime";import{AiFillTags as l,AiOutlineTag as d,AiFillTag as p}from"react-icons/ai";import{Stack as h,Text as u,Flex as m,Spinner as f,Inline as b,Container as y,Box as v}from"@sanity/ui";import{RiNodeTree as g}from"react-icons/ri";import{useState as C,useEffect as T}from"react";var R=t({name:"skosConcept",title:"Concept",type:"document",icon:l,initialValue:async(e,t)=>{var i;const{getClient:n}=t,o=n({apiVersion:"2021-03-25"});return{baseIri:null!=(i=await o.fetch("\n *[_type == 'skosConcept' && defined(baseIri)]| order(_createdAt desc)[0].baseIri\n "))?i:void 0,broader:[],related:[]}},groups:[{name:"label",title:"Labels",default:!0},{name:"relationship",title:"Relationships"},{name:"note",title:"Documentation"}],fields:[i({name:"prefLabel",title:"Preferred Label",group:"label",type:"string",description:"The preferred lexical label for this concept. This label is also used to unambiguously represent this concept via the concept IRI.",components:{input:function(t){var i;const n=e(["baseIri"]);return a(h,{space:2,children:[t.renderDefault(t),s(u,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:a(c,{children:[s("strong",{children:"Concept IRI: "}),n||"[base URI not defined] ",null==(i=t.value)?void 0:i.replaceAll(" ","")]})})]})}},validation:e=>e.required().custom(((e,t)=>{const{getClient:i}=t;return i({apiVersion:"2022-12-14"}).fetch('*[_type == "skosConcept" && prefLabel == "'.concat(e,'" && !(_id in path("drafts.**"))][0]._id')).then((e=>{var i;return!e||e===(null==(i=t.document)?void 0:i._id.replace("drafts.",""))||"Preferred Label must be unique."}))}))}),i({name:"baseIri",title:"Base IRI",type:"url",group:"label",validation:e=>e.required().error("Please supply a base IRI."),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.",options:{collapsible:!0}}),i({name:"conceptIriBase",title:"Edit the base IRI",type:"baseIri",group:"label"}),i({name:"altLabel",title:"Alternate Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),i({name:"hiddenLabel",title:"Hidden Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),i({name:"broader",title:"Broader Concept(s)",description:"Broader relationships create a hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.",group:"relationship",type:"array",of:[{type:"reference",to:{type:"skosConcept"},options:{filter:e=>{let{document:t}=e;return{filter:'!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',params:{self:t._id.replace("drafts.",""),broader:t.broader.map((e=>{let{_ref:t}=e;return t})),related:t.related.map((e=>{let{_ref:t}=e;return t}))}}}}}]}),i({name:"related",title:"Related Concept(s)",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.',group:"relationship",type:"array",of:[{type:"reference",to:[{type:"skosConcept"}]}]}),i({name:"scopeNote",title:"Scope Note",type:"text",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",rows:3,group:"note"}),i({name:"definition",title:"Definition",type:"text",description:"A complete explanation of the intended meaning of the concept",rows:3,group:"note"}),i({name:"example",title:"Examples",type:"text",description:"An example of the use of the concept.",rows:3,group:"note"}),i({name:"topConcept",title:"Top Concept",group:"relationship",type:"boolean",description:a(c,{children:['NOTE: Top Concepts are determined at the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, set Top Concept to "false."',s("br",{}),s("br",{}),"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."]}),hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.topConcept)}}),i({name:"scheme",title:"Concept Scheme(s)",group:"relationship",type:"reference",hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.scheme)},description:a(c,{children:["NOTE: Concept Scheme inclusion is are determined from the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",s("br",{}),s("br",{}),"Description: Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets."]}),to:[{type:"skosConceptScheme"}],options:{disableNew:!0}})],orderings:[{title:"Top Concepts",name:"topConcept",by:[{field:"topConcept",direction:"desc"},{field:"prefLabel",direction:"asc"}]},{title:"Preferred Label",name:"prefLabel",by:[{field:"prefLabel",direction:"asc"}]}],preview:{select:{title:"prefLabel",topConcept:"topConcept",broader:"broader.0.prefLabel",broaderPlusOne:"broader.0.broader.0.prefLabel",broaderPlusTwo:"broader.0.broader.0.broader.0.prefLabel"},prepare(e){let{title:t,topConcept:i,broader:n,broaderPlusOne:o,broaderPlusTwo:r}=e;const a=[o,n].filter(Boolean),s=a.length>0?"".concat(a.join(" ▷ ")," ▶︎ ").concat(t):"",c=r?"... ".concat(s):s;return{title:t,subtitle:i?"Top Concept":c,media:i?d:p}}}}),_=t({name:"skosConceptScheme",title:"Concept Scheme",type:"document",icon:g,fields:[i({name:"title",title:"Title",type:"string",description:"Taxonomy schemes 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"}),i({name:"description",title:"Description",type:"text",rows:5,description:"Describe the intended use of this scheme."}),i({name:"topConcepts",title:"Top Concepts",type:"array",validation:e=>e.unique(),of:[n({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}}),i({name:"concepts",title:"Concepts",type:"array",validation:e=>e.unique(),of:[n({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}})],preview:{select:{title:"title"},prepare(e){let{title:t}=e;return{title:t,media:g}}}}),I=t({name:"baseIri",title:"Base IRI",type:"object",description:"NOTE: conceptIriBase.iriValue is deprecated in version 2 of this plugin. Please migrate this value to the baseIri field above. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",hidden:e=>{let{document:t}=e;var i;return!(null==(i=null==t?void 0:t.conceptIriBase)?void 0:i.iriValue)},fields:[i({name:"iriValue",title:"IRI Value",type:"url",description:"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."})],options:{collapsible:!0,collapsed:!1}});const w=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return e>6?"":'"childConcepts": *[_id in coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]).concepts[]._ref && ^._id in broader[]._ref ]|order(prefLabel){\n "id": _id,\n "level": '.concat(e,",\n prefLabel,\n ").concat(w(e+1),"\n }")},z=e=>{let{concepts:t}=e;return s("ul",{style:{listStyle:"none"},children:t.map((e=>{var t;return a("li",{style:{fontWeight:"normal",marginTop:".75rem"},children:[e.prefLabel,(null==(t=e.childConcepts)?void 0:t.length)>0&&s(z,{concepts:e.childConcepts})]},e.id)}))})},L=e=>{let{document:t,documentId:i}=e;const n=o({apiVersion:"2021-10-21"}),[r,c]=C([]),[l,d]=C(!0),[p,h]=C(!1),[y,v]=C(!1),[g,R]=C(i);return T((()=>{if(void 0===t.displayed._id)return;(async()=>{var e;console.log(r),R(i),d(!0),h(!1),v(!1),0!=r.length&&g==i&&await(e=1e3,console.log("waiting"),new Promise((t=>setTimeout(t,e)))),await n.fetch('coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]) {\n "topConcepts":topConcepts[]->|order(prefLabel){\n "id": _id,\n "level": 0,\n prefLabel,\n '.concat(w(),"\n },\n \"orphans\": *[\n // filter to concepts in this scheme only:\n _id in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref // filter to concepts in this scheme only\n // filter out concepts that reference a topConcept in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).topConcepts[]._ref]) < 1\n // filter out concepts that reference other concepts in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref]) < 1\n ]|order(prefLabel){\n \"id\": _id,\n \"level\": 0,\n prefLabel,\n ").concat(w(),"\n }\n }"),{id:i}).then((e=>{null==e.topConcepts&&e.orphans.length<1?(d(!1),h(!0)):(d(!1),c(e))})).catch((e=>{console.log("Error: ",e),d(!1),v(!0)}))})()}),[i,t.displayed.concepts,t.displayed.topConcepts]),1==y?s("p",{children:"Sorry, could not get concepts."}):1==p?s("p",{children:"This scheme does not yet have any concepts assigned to it."}):l?a(m,{align:"center",direction:"column",gap:5,height:"fill",justify:"center",style:{paddingTop:"1rem"},onResize:void 0,onResizeCapture:void 0,children:[s(f,{muted:!0,onResize:void 0,onResizeCapture:void 0}),s(u,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:"Loading hierarchy…"})]}):a("ul",{style:{listStyle:"none",paddingLeft:"0",marginTop:"1rem"},children:[r.topConcepts.map((e=>{var t;if(null==e?void 0:e.id)return a("li",{style:{paddingTop:".5rem",fontWeight:"bold",marginTop:".75rem"},children:[a(b,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,s(u,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"top concept"})]}),(null==(t=null==e?void 0:e.childConcepts)?void 0:t.length)>0&&s(z,{concepts:e.childConcepts})]},e.id)})),r.orphans.map((e=>{var t;return a("li",{style:{paddingTop:".5rem",fontWeight:"normal",marginTop:".75rem"},children:[a(b,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,s(u,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"orphan"})]}),(null==(t=e.childConcepts)?void 0:t.length)>0&&s(z,{concepts:e.childConcepts})]},e.id)}))]})},x=e=>{let{document:t,documentId:i}=e;return s(y,{width:1,style:{paddingTop:"1.25rem"},onResize:void 0,onResizeCapture:void 0,children:s(v,{padding:4,onResize:void 0,onResizeCapture:void 0,children:a(h,{space:2,children:[s(u,{size:1,weight:"semibold",onResize:void 0,onResizeCapture:void 0,children:"Hierarchy Tree"}),s(u,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"Concept hierarchy is determined by 'Broader' relationships assigned to each concept.."}),s(L,{document:t,documentId:i})]})})})},P=r({name:"taxonomyManager",schema:{types:[R,_,I]}});export{x as TreeView,P as taxonomyManager};//# sourceMappingURL=index.esm.js.map
|
|
1
|
+
import{useFormValue as e,defineType as t,defineField as i,defineArrayMember as n,useClient as o,definePlugin as r}from"sanity";import{jsxs as a,jsx as s,Fragment as c}from"react/jsx-runtime";import{AiFillTags as l,AiOutlineTag as d,AiFillTag as p}from"react-icons/ai";import{Stack as h,Text as u,Flex as m,Spinner as f,Inline as b,Container as y,Box as v}from"@sanity/ui";import{RiNodeTree as g}from"react-icons/ri";import{useState as C,useEffect as T}from"react";var _=t({name:"skosConcept",title:"Concept",type:"document",icon:l,initialValue:async(e,t)=>{var i;const{getClient:n}=t,o=n({apiVersion:"2021-03-25"});return{baseIri:null!=(i=await o.fetch("\n *[_type == 'skosConcept' && defined(baseIri)]| order(_createdAt desc)[0].baseIri\n "))?i:void 0,broader:[],related:[]}},groups:[{name:"label",title:"Labels",default:!0},{name:"relationship",title:"Relationships"},{name:"note",title:"Documentation"}],fields:[i({name:"prefLabel",title:"Preferred Label",group:"label",type:"string",description:"The preferred lexical label for this concept. This label is also used to unambiguously represent this concept via the concept IRI.",components:{input:function(t){var i;const n=e(["baseIri"]);return a(h,{space:2,children:[t.renderDefault(t),s(u,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:a(c,{children:[s("strong",{children:"Concept IRI: "}),n||"[base URI not defined] ",null==(i=t.value)?void 0:i.replaceAll(" ","")]})})]})}},validation:e=>e.required().custom(((e,t)=>{const{getClient:i}=t;return i({apiVersion:"2022-12-14"}).fetch('*[_type == "skosConcept" && prefLabel == "'.concat(e,'" && !(_id in path("drafts.**"))][0]._id')).then((e=>{var i;return!e||e===(null==(i=t.document)?void 0:i._id.replace("drafts.",""))||"Preferred Label must be unique."}))}))}),i({name:"baseIri",title:"Base IRI",type:"url",group:"label",validation:e=>e.required().error("Please supply a base IRI."),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.",options:{collapsible:!0}}),i({name:"conceptIriBase",title:"Edit the base IRI",type:"baseIri",group:"label"}),i({name:"altLabel",title:"Alternate Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),i({name:"hiddenLabel",title:"Hidden Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),i({name:"broader",title:"Broader Concept(s)",description:"Broader relationships create a hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.",group:"relationship",type:"array",of:[{type:"reference",to:{type:"skosConcept"},options:{filter:e=>{let{document:t}=e;return{filter:'!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',params:{self:t._id.replace("drafts.",""),broader:t.broader.map((e=>{let{_ref:t}=e;return t})),related:t.related.map((e=>{let{_ref:t}=e;return t}))}}}}}]}),i({name:"related",title:"Related Concept(s)",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.',group:"relationship",type:"array",of:[{type:"reference",to:[{type:"skosConcept"}]}]}),i({name:"scopeNote",title:"Scope Note",type:"text",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",rows:3,group:"note"}),i({name:"definition",title:"Definition",type:"text",description:"A complete explanation of the intended meaning of the concept",rows:3,group:"note"}),i({name:"example",title:"Examples",type:"text",description:"An example of the use of the concept.",rows:3,group:"note"}),i({name:"topConcept",title:"Top Concept",group:"relationship",type:"boolean",description:a(c,{children:['NOTE: Top Concepts are determined at the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, set Top Concept to "false."',s("br",{}),s("br",{}),"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."]}),hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.topConcept)}}),i({name:"scheme",title:"Concept Scheme(s)",group:"relationship",type:"reference",hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.scheme)},description:a(c,{children:["NOTE: Concept Scheme inclusion is are determined from the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",s("br",{}),s("br",{}),"Description: Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets."]}),to:[{type:"skosConceptScheme"}],options:{disableNew:!0}})],orderings:[{title:"Top Concepts",name:"topConcept",by:[{field:"topConcept",direction:"desc"},{field:"prefLabel",direction:"asc"}]},{title:"Preferred Label",name:"prefLabel",by:[{field:"prefLabel",direction:"asc"}]}],preview:{select:{title:"prefLabel",topConcept:"topConcept",broader:"broader.0.prefLabel",broaderPlusOne:"broader.0.broader.0.prefLabel",broaderPlusTwo:"broader.0.broader.0.broader.0.prefLabel"},prepare(e){let{title:t,topConcept:i,broader:n,broaderPlusOne:o,broaderPlusTwo:r}=e;const a=[o,n].filter(Boolean),s=a.length>0?"".concat(a.join(" ▷ ")," ▶︎ ").concat(t):"",c=r?"... ".concat(s):s;return{title:t,subtitle:i?"Top Concept":c,media:i?d:p}}}}),R=t({name:"skosConceptScheme",title:"Concept Scheme",type:"document",icon:g,fields:[i({name:"title",title:"Title",type:"string",description:"Taxonomy schemes 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"}),i({name:"description",title:"Description",type:"text",rows:5,description:"Describe the intended use of this scheme."}),i({name:"topConcepts",title:"Top Concepts",type:"array",validation:e=>e.unique(),of:[n({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}}),i({name:"concepts",title:"Concepts",type:"array",validation:e=>e.unique(),of:[n({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}})],preview:{select:{title:"title"},prepare(e){let{title:t}=e;return{title:t,media:g}}}}),I=t({name:"baseIri",title:"Base IRI",type:"object",description:"NOTE: conceptIriBase.iriValue is deprecated in version 2 of this plugin. Please migrate this value to the baseIri field above. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",hidden:e=>{let{document:t}=e;var i;return!(null==(i=null==t?void 0:t.conceptIriBase)?void 0:i.iriValue)},fields:[i({name:"iriValue",title:"IRI Value",type:"url",description:"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."})],options:{collapsible:!0,collapsed:!1}});const z=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return e>6?"":'"childConcepts": *[_id in coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]).concepts[]._ref && ^._id in broader[]._ref ]|order(prefLabel){\n "id": _id,\n "level": '.concat(e,",\n prefLabel,\n ").concat(z(e+1),"\n }")},L=e=>{let{concepts:t}=e;return s("ul",{style:{listStyle:"none"},children:t.map((e=>{var t;return a("li",{style:{fontWeight:"normal",marginTop:".75rem"},children:[e.prefLabel,(null==(t=e.childConcepts)?void 0:t.length)>0&&s(L,{concepts:e.childConcepts})]},e.id)}))})},w=e=>{let{document:t,documentId:i}=e;const n=o({apiVersion:"2021-10-21"}),[r,c]=C([]),[l,d]=C(!0),[p,h]=C(!1),[y,v]=C(!1);return T((()=>{if(void 0===t.displayed._id)return;if(!(i===t.displayed._id.replace(/^drafts\./,"")))return void console.log("document not loaded yet.");(async()=>{d(!0),h(!1),v(!1);try{const e=await n.fetch('coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]) {\n "topConcepts":topConcepts[]->|order(prefLabel){\n "id": _id,\n "level": 0,\n prefLabel,\n '.concat(z(),"\n },\n \"orphans\": *[\n // filter to concepts in this scheme only:\n _id in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref // filter to concepts in this scheme only\n // filter out concepts that reference a topConcept in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).topConcepts[]._ref]) < 1\n // filter out concepts that reference other concepts in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref]) < 1\n ]|order(prefLabel){\n \"id\": _id,\n \"level\": 0,\n prefLabel,\n ").concat(z(),"\n }\n }"),{id:i});null==e.topConcepts&&e.orphans.length<1?h(!0):(d(!1),c(e))}catch(e){console.log("Error: ",e),v(!0)}d(!1)})()}),[i,t.displayed._id,t.displayed.concepts,t.displayed.topConcepts]),1==y?s("p",{children:"Sorry, could not get concepts."}):1==p?s("p",{children:"This scheme does not yet have any concepts assigned to it."}):l?a(m,{align:"center",direction:"column",gap:5,height:"fill",justify:"center",style:{paddingTop:"1rem"},onResize:void 0,onResizeCapture:void 0,children:[s(f,{muted:!0,onResize:void 0,onResizeCapture:void 0}),s(u,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:"Loading hierarchy…"})]}):a("ul",{style:{listStyle:"none",paddingLeft:"0",marginTop:"1rem"},children:[r.topConcepts.map((e=>{var t;if(null==e?void 0:e.id)return a("li",{style:{paddingTop:".5rem",fontWeight:"bold",marginTop:".75rem"},children:[a(b,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,s(u,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"top concept"})]}),(null==(t=null==e?void 0:e.childConcepts)?void 0:t.length)>0&&s(L,{concepts:e.childConcepts})]},e.id)})),r.orphans.map((e=>{var t;return a("li",{style:{paddingTop:".5rem",fontWeight:"normal",marginTop:".75rem"},children:[a(b,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,s(u,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"orphan"})]}),(null==(t=e.childConcepts)?void 0:t.length)>0&&s(L,{concepts:e.childConcepts})]},e.id)}))]})},x=e=>{let{document:t,documentId:i}=e;return s(y,{width:1,style:{paddingTop:"1.25rem"},onResize:void 0,onResizeCapture:void 0,children:s(v,{padding:4,onResize:void 0,onResizeCapture:void 0,children:a(h,{space:2,children:[s(u,{size:1,weight:"semibold",onResize:void 0,onResizeCapture:void 0,children:"Hierarchy Tree"}),s(u,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"Concept hierarchy is determined by 'Broader' relationships assigned to each concept."}),s(w,{document:t,documentId:i})]})})})},P=r({name:"taxonomyManager",schema:{types:[_,R,I]}});export{x as TreeView,P as taxonomyManager};//# sourceMappingURL=index.esm.js.map
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("sanity"),t=require("react/jsx-runtime"),i=require("react-icons/ai"),n=require("@sanity/ui"),o=require("react-icons/ri"),r=require("react");var s=e.defineType({name:"skosConcept",title:"Concept",type:"document",icon:i.AiFillTags,initialValue:async(e,t)=>{var i;const{getClient:n}=t,o=n({apiVersion:"2021-03-25"});return{baseIri:null!=(i=await o.fetch("\n *[_type == 'skosConcept' && defined(baseIri)]| order(_createdAt desc)[0].baseIri\n "))?i:void 0,broader:[],related:[]}},groups:[{name:"label",title:"Labels",default:!0},{name:"relationship",title:"Relationships"},{name:"note",title:"Documentation"}],fields:[e.defineField({name:"prefLabel",title:"Preferred Label",group:"label",type:"string",description:"The preferred lexical label for this concept. This label is also used to unambiguously represent this concept via the concept IRI.",components:{input:function(i){var o;const r=e.useFormValue(["baseIri"]);return t.jsxs(n.Stack,{space:2,children:[i.renderDefault(i),t.jsx(n.Text,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:t.jsxs(t.Fragment,{children:[t.jsx("strong",{children:"Concept IRI: "}),r||"[base URI not defined] ",null==(o=i.value)?void 0:o.replaceAll(" ","")]})})]})}},validation:e=>e.required().custom(((e,t)=>{const{getClient:i}=t;return i({apiVersion:"2022-12-14"}).fetch('*[_type == "skosConcept" && prefLabel == "'.concat(e,'" && !(_id in path("drafts.**"))][0]._id')).then((e=>{var i;return!e||e===(null==(i=t.document)?void 0:i._id.replace("drafts.",""))||"Preferred Label must be unique."}))}))}),e.defineField({name:"baseIri",title:"Base IRI",type:"url",group:"label",validation:e=>e.required().error("Please supply a base IRI."),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.",options:{collapsible:!0}}),e.defineField({name:"conceptIriBase",title:"Edit the base IRI",type:"baseIri",group:"label"}),e.defineField({name:"altLabel",title:"Alternate Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),e.defineField({name:"hiddenLabel",title:"Hidden Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),e.defineField({name:"broader",title:"Broader Concept(s)",description:"Broader relationships create a hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.",group:"relationship",type:"array",of:[{type:"reference",to:{type:"skosConcept"},options:{filter:e=>{let{document:t}=e;return{filter:'!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',params:{self:t._id.replace("drafts.",""),broader:t.broader.map((e=>{let{_ref:t}=e;return t})),related:t.related.map((e=>{let{_ref:t}=e;return t}))}}}}}]}),e.defineField({name:"related",title:"Related Concept(s)",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.',group:"relationship",type:"array",of:[{type:"reference",to:[{type:"skosConcept"}]}]}),e.defineField({name:"scopeNote",title:"Scope Note",type:"text",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",rows:3,group:"note"}),e.defineField({name:"definition",title:"Definition",type:"text",description:"A complete explanation of the intended meaning of the concept",rows:3,group:"note"}),e.defineField({name:"example",title:"Examples",type:"text",description:"An example of the use of the concept.",rows:3,group:"note"}),e.defineField({name:"topConcept",title:"Top Concept",group:"relationship",type:"boolean",description:t.jsxs(t.Fragment,{children:['NOTE: Top Concepts are determined at the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, set Top Concept to "false."',t.jsx("br",{}),t.jsx("br",{}),"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."]}),hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.topConcept)}}),e.defineField({name:"scheme",title:"Concept Scheme(s)",group:"relationship",type:"reference",hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.scheme)},description:t.jsxs(t.Fragment,{children:["NOTE: Concept Scheme inclusion is are determined from the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",t.jsx("br",{}),t.jsx("br",{}),"Description: Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets."]}),to:[{type:"skosConceptScheme"}],options:{disableNew:!0}})],orderings:[{title:"Top Concepts",name:"topConcept",by:[{field:"topConcept",direction:"desc"},{field:"prefLabel",direction:"asc"}]},{title:"Preferred Label",name:"prefLabel",by:[{field:"prefLabel",direction:"asc"}]}],preview:{select:{title:"prefLabel",topConcept:"topConcept",broader:"broader.0.prefLabel",broaderPlusOne:"broader.0.broader.0.prefLabel",broaderPlusTwo:"broader.0.broader.0.broader.0.prefLabel"},prepare(e){let{title:t,topConcept:n,broader:o,broaderPlusOne:r,broaderPlusTwo:s}=e;const a=[r,o].filter(Boolean),l=a.length>0?"".concat(a.join(" ▷ ")," ▶︎ ").concat(t):"",d=s?"... ".concat(l):l;return{title:t,subtitle:n?"Top Concept":d,media:n?i.AiOutlineTag:i.AiFillTag}}}}),a=e.defineType({name:"skosConceptScheme",title:"Concept Scheme",type:"document",icon:o.RiNodeTree,fields:[e.defineField({name:"title",title:"Title",type:"string",description:"Taxonomy schemes 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"}),e.defineField({name:"description",title:"Description",type:"text",rows:5,description:"Describe the intended use of this scheme."}),e.defineField({name:"topConcepts",title:"Top Concepts",type:"array",validation:e=>e.unique(),of:[e.defineArrayMember({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}}),e.defineField({name:"concepts",title:"Concepts",type:"array",validation:e=>e.unique(),of:[e.defineArrayMember({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}})],preview:{select:{title:"title"},prepare(e){let{title:t}=e;return{title:t,media:o.RiNodeTree}}}}),l=e.defineType({name:"baseIri",title:"Base IRI",type:"object",description:"NOTE: conceptIriBase.iriValue is deprecated in version 2 of this plugin. Please migrate this value to the baseIri field above. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",hidden:e=>{let{document:t}=e;var i;return!(null==(i=null==t?void 0:t.conceptIriBase)?void 0:i.iriValue)},fields:[e.defineField({name:"iriValue",title:"IRI Value",type:"url",description:"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."})],options:{collapsible:!0,collapsed:!1}});const d=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return e>6?"":'"childConcepts": *[_id in coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]).concepts[]._ref && ^._id in broader[]._ref ]|order(prefLabel){\n "id": _id,\n "level": '.concat(e,",\n prefLabel,\n ").concat(d(e+1),"\n }")},c=e=>{let{concepts:i}=e;return t.jsx("ul",{style:{listStyle:"none"},children:i.map((e=>{var i;return t.jsxs("li",{style:{fontWeight:"normal",marginTop:".75rem"},children:[e.prefLabel,(null==(i=e.childConcepts)?void 0:i.length)>0&&t.jsx(c,{concepts:e.childConcepts})]},e.id)}))})},p=i=>{let{document:o,documentId:s}=i;const a=e.useClient({apiVersion:"2021-10-21"}),[l,p]=r.useState([]),[u,h]=r.useState(!0),[f,m]=r.useState(!1),[b,y]=r.useState(!1),[v,g]=r.useState(s);return r.useEffect((()=>{if(void 0===o.displayed._id)return;(async()=>{var e;console.log(l),g(s),h(!0),m(!1),y(!1),0!=l.length&&v==s&&await(e=1e3,console.log("waiting"),new Promise((t=>setTimeout(t,e)))),await a.fetch('coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]) {\n "topConcepts":topConcepts[]->|order(prefLabel){\n "id": _id,\n "level": 0,\n prefLabel,\n '.concat(d(),"\n },\n \"orphans\": *[\n // filter to concepts in this scheme only:\n _id in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref // filter to concepts in this scheme only\n // filter out concepts that reference a topConcept in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).topConcepts[]._ref]) < 1\n // filter out concepts that reference other concepts in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref]) < 1\n ]|order(prefLabel){\n \"id\": _id,\n \"level\": 0,\n prefLabel,\n ").concat(d(),"\n }\n }"),{id:s}).then((e=>{null==e.topConcepts&&e.orphans.length<1?(h(!1),m(!0)):(h(!1),p(e))})).catch((e=>{console.log("Error: ",e),h(!1),y(!0)}))})()}),[s,o.displayed.concepts,o.displayed.topConcepts]),1==b?t.jsx("p",{children:"Sorry, could not get concepts."}):1==f?t.jsx("p",{children:"This scheme does not yet have any concepts assigned to it."}):u?t.jsxs(n.Flex,{align:"center",direction:"column",gap:5,height:"fill",justify:"center",style:{paddingTop:"1rem"},onResize:void 0,onResizeCapture:void 0,children:[t.jsx(n.Spinner,{muted:!0,onResize:void 0,onResizeCapture:void 0}),t.jsx(n.Text,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:"Loading hierarchy…"})]}):t.jsxs("ul",{style:{listStyle:"none",paddingLeft:"0",marginTop:"1rem"},children:[l.topConcepts.map((e=>{var i;if(null==e?void 0:e.id)return t.jsxs("li",{style:{paddingTop:".5rem",fontWeight:"bold",marginTop:".75rem"},children:[t.jsxs(n.Inline,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,t.jsx(n.Text,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"top concept"})]}),(null==(i=null==e?void 0:e.childConcepts)?void 0:i.length)>0&&t.jsx(c,{concepts:e.childConcepts})]},e.id)})),l.orphans.map((e=>{var i;return t.jsxs("li",{style:{paddingTop:".5rem",fontWeight:"normal",marginTop:".75rem"},children:[t.jsxs(n.Inline,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,t.jsx(n.Text,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"orphan"})]}),(null==(i=e.childConcepts)?void 0:i.length)>0&&t.jsx(c,{concepts:e.childConcepts})]},e.id)}))]})},u=e.definePlugin({name:"taxonomyManager",schema:{types:[s,a,l]}});exports.TreeView=e=>{let{document:i,documentId:o}=e;return t.jsx(n.Container,{width:1,style:{paddingTop:"1.25rem"},onResize:void 0,onResizeCapture:void 0,children:t.jsx(n.Box,{padding:4,onResize:void 0,onResizeCapture:void 0,children:t.jsxs(n.Stack,{space:2,children:[t.jsx(n.Text,{size:1,weight:"semibold",onResize:void 0,onResizeCapture:void 0,children:"Hierarchy Tree"}),t.jsx(n.Text,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"Concept hierarchy is determined by 'Broader' relationships assigned to each concept.."}),t.jsx(p,{document:i,documentId:o})]})})})},exports.taxonomyManager=u;//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("sanity"),t=require("react/jsx-runtime"),i=require("react-icons/ai"),n=require("@sanity/ui"),o=require("react-icons/ri"),r=require("react");var s=e.defineType({name:"skosConcept",title:"Concept",type:"document",icon:i.AiFillTags,initialValue:async(e,t)=>{var i;const{getClient:n}=t,o=n({apiVersion:"2021-03-25"});return{baseIri:null!=(i=await o.fetch("\n *[_type == 'skosConcept' && defined(baseIri)]| order(_createdAt desc)[0].baseIri\n "))?i:void 0,broader:[],related:[]}},groups:[{name:"label",title:"Labels",default:!0},{name:"relationship",title:"Relationships"},{name:"note",title:"Documentation"}],fields:[e.defineField({name:"prefLabel",title:"Preferred Label",group:"label",type:"string",description:"The preferred lexical label for this concept. This label is also used to unambiguously represent this concept via the concept IRI.",components:{input:function(i){var o;const r=e.useFormValue(["baseIri"]);return t.jsxs(n.Stack,{space:2,children:[i.renderDefault(i),t.jsx(n.Text,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:t.jsxs(t.Fragment,{children:[t.jsx("strong",{children:"Concept IRI: "}),r||"[base URI not defined] ",null==(o=i.value)?void 0:o.replaceAll(" ","")]})})]})}},validation:e=>e.required().custom(((e,t)=>{const{getClient:i}=t;return i({apiVersion:"2022-12-14"}).fetch('*[_type == "skosConcept" && prefLabel == "'.concat(e,'" && !(_id in path("drafts.**"))][0]._id')).then((e=>{var i;return!e||e===(null==(i=t.document)?void 0:i._id.replace("drafts.",""))||"Preferred Label must be unique."}))}))}),e.defineField({name:"baseIri",title:"Base IRI",type:"url",group:"label",validation:e=>e.required().error("Please supply a base IRI."),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.",options:{collapsible:!0}}),e.defineField({name:"conceptIriBase",title:"Edit the base IRI",type:"baseIri",group:"label"}),e.defineField({name:"altLabel",title:"Alternate Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),e.defineField({name:"hiddenLabel",title:"Hidden Label(s)",group:"label",type:"array",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.",of:[{type:"string"}],validation:e=>e.unique()}),e.defineField({name:"broader",title:"Broader Concept(s)",description:"Broader relationships create a hierarchy between concepts, for example to create category/subcategory, part/whole, or class/instance relationships.",group:"relationship",type:"array",of:[{type:"reference",to:{type:"skosConcept"},options:{filter:e=>{let{document:t}=e;return{filter:'!(_id in $broader || _id in $related || _id in path("drafts.**") || _id == $self)',params:{self:t._id.replace("drafts.",""),broader:t.broader.map((e=>{let{_ref:t}=e;return t})),related:t.related.map((e=>{let{_ref:t}=e;return t}))}}}}}]}),e.defineField({name:"related",title:"Related Concept(s)",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.',group:"relationship",type:"array",of:[{type:"reference",to:[{type:"skosConcept"}]}]}),e.defineField({name:"scopeNote",title:"Scope Note",type:"text",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",rows:3,group:"note"}),e.defineField({name:"definition",title:"Definition",type:"text",description:"A complete explanation of the intended meaning of the concept",rows:3,group:"note"}),e.defineField({name:"example",title:"Examples",type:"text",description:"An example of the use of the concept.",rows:3,group:"note"}),e.defineField({name:"topConcept",title:"Top Concept",group:"relationship",type:"boolean",description:t.jsxs(t.Fragment,{children:['NOTE: Top Concepts are determined at the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, set Top Concept to "false."',t.jsx("br",{}),t.jsx("br",{}),"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."]}),hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.topConcept)}}),e.defineField({name:"scheme",title:"Concept Scheme(s)",group:"relationship",type:"reference",hidden:e=>{let{document:t}=e;return!(null==t?void 0:t.scheme)},description:t.jsxs(t.Fragment,{children:["NOTE: Concept Scheme inclusion is are determined from the Concept Scheme for version 2 of this plugin. Please migrate this value accordingly. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",t.jsx("br",{}),t.jsx("br",{}),"Description: Concept schemes are used to group concepts into defined sets, such as thesauri, classification schemes, or facets."]}),to:[{type:"skosConceptScheme"}],options:{disableNew:!0}})],orderings:[{title:"Top Concepts",name:"topConcept",by:[{field:"topConcept",direction:"desc"},{field:"prefLabel",direction:"asc"}]},{title:"Preferred Label",name:"prefLabel",by:[{field:"prefLabel",direction:"asc"}]}],preview:{select:{title:"prefLabel",topConcept:"topConcept",broader:"broader.0.prefLabel",broaderPlusOne:"broader.0.broader.0.prefLabel",broaderPlusTwo:"broader.0.broader.0.broader.0.prefLabel"},prepare(e){let{title:t,topConcept:n,broader:o,broaderPlusOne:r,broaderPlusTwo:s}=e;const a=[r,o].filter(Boolean),l=a.length>0?"".concat(a.join(" ▷ ")," ▶︎ ").concat(t):"",d=s?"... ".concat(l):l;return{title:t,subtitle:n?"Top Concept":d,media:n?i.AiOutlineTag:i.AiFillTag}}}}),a=e.defineType({name:"skosConceptScheme",title:"Concept Scheme",type:"document",icon:o.RiNodeTree,fields:[e.defineField({name:"title",title:"Title",type:"string",description:"Taxonomy schemes 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"}),e.defineField({name:"description",title:"Description",type:"text",rows:5,description:"Describe the intended use of this scheme."}),e.defineField({name:"topConcepts",title:"Top Concepts",type:"array",validation:e=>e.unique(),of:[e.defineArrayMember({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}}),e.defineField({name:"concepts",title:"Concepts",type:"array",validation:e=>e.unique(),of:[e.defineArrayMember({type:"reference",to:[{type:"skosConcept"}]})],options:{sortable:!1}})],preview:{select:{title:"title"},prepare(e){let{title:t}=e;return{title:t,media:o.RiNodeTree}}}}),l=e.defineType({name:"baseIri",title:"Base IRI",type:"object",description:"NOTE: conceptIriBase.iriValue is deprecated in version 2 of this plugin. Please migrate this value to the baseIri field above. This field will be removed in future versions of this plugin. To hide it in the meantime, unset this value (delete it).",hidden:e=>{let{document:t}=e;var i;return!(null==(i=null==t?void 0:t.conceptIriBase)?void 0:i.iriValue)},fields:[e.defineField({name:"iriValue",title:"IRI Value",type:"url",description:"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."})],options:{collapsible:!0,collapsed:!1}});const d=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return e>6?"":'"childConcepts": *[_id in coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]).concepts[]._ref && ^._id in broader[]._ref ]|order(prefLabel){\n "id": _id,\n "level": '.concat(e,",\n prefLabel,\n ").concat(d(e+1),"\n }")},c=e=>{let{concepts:i}=e;return t.jsx("ul",{style:{listStyle:"none"},children:i.map((e=>{var i;return t.jsxs("li",{style:{fontWeight:"normal",marginTop:".75rem"},children:[e.prefLabel,(null==(i=e.childConcepts)?void 0:i.length)>0&&t.jsx(c,{concepts:e.childConcepts})]},e.id)}))})},p=i=>{let{document:o,documentId:s}=i;const a=e.useClient({apiVersion:"2021-10-21"}),[l,p]=r.useState([]),[u,h]=r.useState(!0),[f,m]=r.useState(!1),[b,y]=r.useState(!1);return r.useEffect((()=>{if(void 0===o.displayed._id)return;if(!(s===o.displayed._id.replace(/^drafts\./,"")))return void console.log("document not loaded yet.");(async()=>{h(!0),m(!1),y(!1);try{const e=await a.fetch('coalesce(*[_id == \'drafts.\' + $id][0], *[_id == $id][0]) {\n "topConcepts":topConcepts[]->|order(prefLabel){\n "id": _id,\n "level": 0,\n prefLabel,\n '.concat(d(),"\n },\n \"orphans\": *[\n // filter to concepts in this scheme only:\n _id in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref // filter to concepts in this scheme only\n // filter out concepts that reference a topConcept in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).topConcepts[]._ref]) < 1\n // filter out concepts that reference other concepts in this scheme as a broader term:\n && count((broader[]._ref) [@ in coalesce(*[_id == 'drafts.' + $id][0], *[_id == $id][0]).concepts[]._ref]) < 1\n ]|order(prefLabel){\n \"id\": _id,\n \"level\": 0,\n prefLabel,\n ").concat(d(),"\n }\n }"),{id:s});null==e.topConcepts&&e.orphans.length<1?m(!0):(h(!1),p(e))}catch(e){console.log("Error: ",e),y(!0)}h(!1)})()}),[s,o.displayed._id,o.displayed.concepts,o.displayed.topConcepts]),1==b?t.jsx("p",{children:"Sorry, could not get concepts."}):1==f?t.jsx("p",{children:"This scheme does not yet have any concepts assigned to it."}):u?t.jsxs(n.Flex,{align:"center",direction:"column",gap:5,height:"fill",justify:"center",style:{paddingTop:"1rem"},onResize:void 0,onResizeCapture:void 0,children:[t.jsx(n.Spinner,{muted:!0,onResize:void 0,onResizeCapture:void 0}),t.jsx(n.Text,{muted:!0,size:1,onResize:void 0,onResizeCapture:void 0,children:"Loading hierarchy…"})]}):t.jsxs("ul",{style:{listStyle:"none",paddingLeft:"0",marginTop:"1rem"},children:[l.topConcepts.map((e=>{var i;if(null==e?void 0:e.id)return t.jsxs("li",{style:{paddingTop:".5rem",fontWeight:"bold",marginTop:".75rem"},children:[t.jsxs(n.Inline,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,t.jsx(n.Text,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"top concept"})]}),(null==(i=null==e?void 0:e.childConcepts)?void 0:i.length)>0&&t.jsx(c,{concepts:e.childConcepts})]},e.id)})),l.orphans.map((e=>{var i;return t.jsxs("li",{style:{paddingTop:".5rem",fontWeight:"normal",marginTop:".75rem"},children:[t.jsxs(n.Inline,{space:2,onResize:void 0,onResizeCapture:void 0,children:[null==e?void 0:e.prefLabel,t.jsx(n.Text,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"orphan"})]}),(null==(i=e.childConcepts)?void 0:i.length)>0&&t.jsx(c,{concepts:e.childConcepts})]},e.id)}))]})},u=e.definePlugin({name:"taxonomyManager",schema:{types:[s,a,l]}});exports.TreeView=e=>{let{document:i,documentId:o}=e;return t.jsx(n.Container,{width:1,style:{paddingTop:"1.25rem"},onResize:void 0,onResizeCapture:void 0,children:t.jsx(n.Box,{padding:4,onResize:void 0,onResizeCapture:void 0,children:t.jsxs(n.Stack,{space:2,children:[t.jsx(n.Text,{size:1,weight:"semibold",onResize:void 0,onResizeCapture:void 0,children:"Hierarchy Tree"}),t.jsx(n.Text,{size:1,muted:!0,onResize:void 0,onResizeCapture:void 0,children:"Concept hierarchy is determined by 'Broader' relationships assigned to each concept."}),t.jsx(p,{document:i,documentId:o})]})})})},exports.taxonomyManager=u;//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -79,47 +79,40 @@ const Hierarchy = ({document, documentId}: {document: any, documentId: any}) =>
|
|
|
79
79
|
const [isLoading, setIsLoading] = useState(true)
|
|
80
80
|
const [noConcept, setNoConcept] = useState(false)
|
|
81
81
|
const [isError, setIsError] = useState(false)
|
|
82
|
-
const [currentDoc, setCurrentDoc] = useState(documentId)
|
|
83
82
|
|
|
84
83
|
useEffect(() => {
|
|
85
84
|
if (document.displayed._id === undefined ) return
|
|
86
85
|
|
|
87
|
-
const
|
|
86
|
+
const isReady = documentId === document.displayed._id.replace(/^drafts\./, '')
|
|
88
87
|
|
|
89
|
-
|
|
88
|
+
if (!isReady) {
|
|
89
|
+
console.log('document not loaded yet.')
|
|
90
|
+
return
|
|
91
|
+
}
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
const fetchConcepts = async () => {
|
|
92
94
|
|
|
93
95
|
// reset state variables for new fetch
|
|
94
96
|
setIsLoading(true)
|
|
95
97
|
setNoConcept(false)
|
|
96
98
|
setIsError(false)
|
|
97
99
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
concepts.length != 0 && currentDoc == documentId && await sleep(1000)
|
|
101
|
-
|
|
102
|
-
await client.fetch(
|
|
103
|
-
trunkBuilder(),
|
|
104
|
-
{id: documentId}
|
|
105
|
-
)
|
|
106
|
-
.then(res => {
|
|
100
|
+
try {
|
|
101
|
+
const res = await client.fetch(trunkBuilder(), {id: documentId})
|
|
107
102
|
if (res.topConcepts == null && res.orphans.length < 1) {
|
|
108
|
-
setIsLoading(false)
|
|
109
103
|
setNoConcept(true)
|
|
110
104
|
} else {
|
|
111
105
|
setIsLoading(false)
|
|
112
106
|
setConcepts(res)
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
.catch(error => {
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
116
109
|
console.log('Error: ', error)
|
|
117
|
-
setIsLoading(false)
|
|
118
110
|
setIsError(true)
|
|
119
|
-
}
|
|
111
|
+
}
|
|
112
|
+
setIsLoading(false)
|
|
120
113
|
}
|
|
121
114
|
fetchConcepts()
|
|
122
|
-
}, [documentId, document.displayed.concepts, document.displayed.topConcepts])
|
|
115
|
+
}, [documentId, document.displayed._id, document.displayed.concepts, document.displayed.topConcepts])
|
|
123
116
|
|
|
124
117
|
if (isError == true) {
|
|
125
118
|
return <p>Sorry, could not get concepts.</p>
|
|
@@ -15,7 +15,7 @@ export const TreeView = ({document, documentId}: {document: any; documentId: any
|
|
|
15
15
|
Hierarchy Tree
|
|
16
16
|
</Text>
|
|
17
17
|
<Text size={1} muted={true} onResize={undefined} onResizeCapture={undefined}>
|
|
18
|
-
Concept hierarchy is determined by 'Broader' relationships assigned to each concept
|
|
18
|
+
Concept hierarchy is determined by 'Broader' relationships assigned to each concept.
|
|
19
19
|
</Text>
|
|
20
20
|
<Hierarchy document={document} documentId={documentId} />
|
|
21
21
|
</Stack>
|