@arpproject/recrate 0.1.2

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.
Files changed (286) hide show
  1. package/.eslintrc.json +37 -0
  2. package/.storybook/main.ts +40 -0
  3. package/.storybook/preview.tsx +46 -0
  4. package/LICENCE +18 -0
  5. package/README.md +83 -0
  6. package/babel.config.json +5 -0
  7. package/dist/app/App.d.ts +2 -0
  8. package/dist/app/EmbeddedComponent.d.ts +3 -0
  9. package/dist/app/index.d.ts +0 -0
  10. package/dist/app/lookup.d.ts +82 -0
  11. package/dist/crate-builder/CrateManager/contexts.d.ts +6 -0
  12. package/dist/crate-builder/CrateManager/crate-manager-benchmarking.spec.d.ts +1 -0
  13. package/dist/crate-builder/CrateManager/crate-manager-loading-exporting.spec.d.ts +1 -0
  14. package/dist/crate-builder/CrateManager/crate-manager-operations.spec.d.ts +0 -0
  15. package/dist/crate-builder/CrateManager/crate-manager.d.ts +641 -0
  16. package/dist/crate-builder/CrateManager/crate-manager.spec.d.ts +1 -0
  17. package/dist/crate-builder/CrateManager/lib.d.ts +26 -0
  18. package/dist/crate-builder/CrateManager/lib.spec.d.ts +1 -0
  19. package/dist/crate-builder/CrateManager/profile-manager.d.ts +143 -0
  20. package/dist/crate-builder/CrateManager/profile-manager.spec.d.ts +1 -0
  21. package/dist/crate-builder/CrateManager/schema-type-definitions.json.d.ts +35125 -0
  22. package/dist/crate-builder/CrateManager/validate-identifier.d.ts +10 -0
  23. package/dist/crate-builder/CrateManager/validate-identifier.spec.d.ts +1 -0
  24. package/dist/crate-builder/RenderEntity/Add.d.ts +26 -0
  25. package/dist/crate-builder/RenderEntity/AddControl.d.ts +14 -0
  26. package/dist/crate-builder/RenderEntity/AddControl.stories.d.ts +29 -0
  27. package/dist/crate-builder/RenderEntity/AutoComplete.d.ts +12 -0
  28. package/dist/crate-builder/RenderEntity/BulkAdd.d.ts +10 -0
  29. package/dist/crate-builder/RenderEntity/DeleteProperty.d.ts +8 -0
  30. package/dist/crate-builder/RenderEntity/DialogAddProperty.d.ts +9 -0
  31. package/dist/crate-builder/RenderEntity/DialogBrowseEntities.d.ts +8 -0
  32. package/dist/crate-builder/RenderEntity/DialogEditContext.d.ts +8 -0
  33. package/dist/crate-builder/RenderEntity/DialogPreviewCrate.d.ts +7 -0
  34. package/dist/crate-builder/RenderEntity/DialogSaveCrateAsTemplate.d.ts +13 -0
  35. package/dist/crate-builder/RenderEntity/DialogSaveEntityTemplate.d.ts +14 -0
  36. package/dist/crate-builder/RenderEntity/DisplayPropertyName.d.ts +8 -0
  37. package/dist/crate-builder/RenderEntity/DisplayPropertyName.stories.d.ts +6 -0
  38. package/dist/crate-builder/RenderEntity/EntityId.d.ts +13 -0
  39. package/dist/crate-builder/RenderEntity/EntityName.d.ts +13 -0
  40. package/dist/crate-builder/RenderEntity/EntityProperty.d.ts +19 -0
  41. package/dist/crate-builder/RenderEntity/EntityPropertyInstance.d.ts +25 -0
  42. package/dist/crate-builder/RenderEntity/EntityType.d.ts +12 -0
  43. package/dist/crate-builder/RenderEntity/ItemLink.d.ts +14 -0
  44. package/dist/crate-builder/RenderEntity/PaginateLinkedEntities.d.ts +23 -0
  45. package/dist/crate-builder/RenderEntity/PaginateLinkedEntities.stories.d.ts +7 -0
  46. package/dist/crate-builder/RenderEntity/PropertyHelp.d.ts +6 -0
  47. package/dist/crate-builder/RenderEntity/RenderControls.d.ts +22 -0
  48. package/dist/crate-builder/RenderEntity/RenderLinkedItem.d.ts +20 -0
  49. package/dist/crate-builder/RenderEntity/RenderPropertyHelp.d.ts +6 -0
  50. package/dist/crate-builder/RenderEntity/RenderReverseConnections.d.ts +16 -0
  51. package/dist/crate-builder/RenderEntity/RenderTypes.d.ts +6 -0
  52. package/dist/crate-builder/RenderEntity/Shell2.d.ts +14 -0
  53. package/dist/crate-builder/RenderEntity/UnlinkEntity.d.ts +14 -0
  54. package/dist/crate-builder/RenderEntity/auto-complete.lib.d.ts +25 -0
  55. package/dist/crate-builder/RenderEntity/keys.d.ts +4 -0
  56. package/dist/crate-builder/RenderEntity/layout.d.ts +14 -0
  57. package/dist/crate-builder/RenderEntity/layout.spec.d.ts +1 -0
  58. package/dist/crate-builder/Shell.d.ts +40 -0
  59. package/dist/crate-builder/editor-state.d.ts +72 -0
  60. package/dist/crate-builder/helpers.d.ts +9 -0
  61. package/dist/crate-builder/i18n.d.ts +2 -0
  62. package/dist/crate-builder/lib/validate-iri.d.ts +6 -0
  63. package/dist/crate-builder/locales/en.d.ts +79 -0
  64. package/dist/crate-builder/locales/hu.d.ts +79 -0
  65. package/dist/crate-builder/primitives/Boolean.d.ts +11 -0
  66. package/dist/crate-builder/primitives/Boolean.stories.d.ts +7 -0
  67. package/dist/crate-builder/primitives/Date.d.ts +11 -0
  68. package/dist/crate-builder/primitives/Date.stories.d.ts +5 -0
  69. package/dist/crate-builder/primitives/DateTime.d.ts +11 -0
  70. package/dist/crate-builder/primitives/DateTime.stories.d.ts +5 -0
  71. package/dist/crate-builder/primitives/Geo.d.ts +12 -0
  72. package/dist/crate-builder/primitives/Geo.stories.d.ts +26 -0
  73. package/dist/crate-builder/primitives/Map.SelectArea.d.ts +9 -0
  74. package/dist/crate-builder/primitives/Map.d.ts +15 -0
  75. package/dist/crate-builder/primitives/Map.stories.d.ts +6 -0
  76. package/dist/crate-builder/primitives/Number.d.ts +16 -0
  77. package/dist/crate-builder/primitives/Number.stories.d.ts +10 -0
  78. package/dist/crate-builder/primitives/Select.d.ts +15 -0
  79. package/dist/crate-builder/primitives/Select.stories.d.ts +9 -0
  80. package/dist/crate-builder/primitives/SelectObject.d.ts +13 -0
  81. package/dist/crate-builder/primitives/SelectObject.stories.d.ts +5 -0
  82. package/dist/crate-builder/primitives/SelectUrl.d.ts +14 -0
  83. package/dist/crate-builder/primitives/SelectUrl.stories.d.ts +7 -0
  84. package/dist/crate-builder/primitives/Text.d.ts +19 -0
  85. package/dist/crate-builder/primitives/Text.stories.d.ts +13 -0
  86. package/dist/crate-builder/primitives/Time.d.ts +11 -0
  87. package/dist/crate-builder/primitives/Time.stories.d.ts +7 -0
  88. package/dist/crate-builder/primitives/Url.d.ts +11 -0
  89. package/dist/crate-builder/primitives/Url.stories.d.ts +7 -0
  90. package/dist/crate-builder/primitives/Value.d.ts +7 -0
  91. package/dist/crate-builder/primitives/Value.stories.d.ts +7 -0
  92. package/dist/crate-builder/primitives/date-libs.d.ts +1 -0
  93. package/dist/crate-builder/property-definitions.d.ts +78 -0
  94. package/dist/crate-builder/store.d.ts +8 -0
  95. package/dist/favicon.ico +0 -0
  96. package/dist/index.d.ts +3 -0
  97. package/dist/index.html +43 -0
  98. package/dist/logo192.png +0 -0
  99. package/dist/logo512.png +0 -0
  100. package/dist/manifest.json +25 -0
  101. package/dist/marker-icon.png +0 -0
  102. package/dist/marker-shadow.png +0 -0
  103. package/dist/recrate.es.js +158699 -0
  104. package/dist/recrate.umd.js +158717 -0
  105. package/dist/robots.txt +3 -0
  106. package/dist/style.css +1721 -0
  107. package/dist/types.d.ts +42 -0
  108. package/docker-compose.yml +30 -0
  109. package/docs/.nojekyll +1 -0
  110. package/docs/assets/highlight.css +99 -0
  111. package/docs/assets/icons.js +18 -0
  112. package/docs/assets/icons.svg +1 -0
  113. package/docs/assets/main.js +60 -0
  114. package/docs/assets/navigation.js +1 -0
  115. package/docs/assets/search.js +1 -0
  116. package/docs/assets/style.css +1448 -0
  117. package/docs/classes/src_crate_builder_CrateManager_crate_manager.CrateManager.html +240 -0
  118. package/docs/classes/src_crate_builder_CrateManager_profile_manager.ProfileManager.html +42 -0
  119. package/docs/classes/src_crate_builder_editor_state.EditorState.html +28 -0
  120. package/docs/classes/src_crate_builder_types.CrateManagerType.html +57 -0
  121. package/docs/classes/src_crate_builder_types.ProfileManagerType.html +13 -0
  122. package/docs/functions/src_crate_builder_CrateManager_lib.isURL.html +2 -0
  123. package/docs/functions/src_crate_builder_CrateManager_lib.mintNewCrate.html +3 -0
  124. package/docs/functions/src_crate_builder_CrateManager_lib.normalise.html +5 -0
  125. package/docs/functions/src_crate_builder_CrateManager_lib.normaliseEntityType.html +1 -0
  126. package/docs/index.html +58 -0
  127. package/docs/interfaces/src_crate_builder_types.NormalisedCrate.html +3 -0
  128. package/docs/interfaces/src_crate_builder_types.NormalisedEntityDefinition.html +4 -0
  129. package/docs/interfaces/src_crate_builder_types.NormalisedProfile.html +9 -0
  130. package/docs/interfaces/src_crate_builder_types.ProfileLayout.html +2 -0
  131. package/docs/interfaces/src_crate_builder_types.ProfileLayoutGroup.html +9 -0
  132. package/docs/interfaces/src_crate_builder_types.UnverifiedCrate.html +3 -0
  133. package/docs/interfaces/src_crate_builder_types.UnverifiedEntityDefinition.html +4 -0
  134. package/docs/modules/src_crate_builder_CrateManager_crate_manager.html +2 -0
  135. package/docs/modules/src_crate_builder_CrateManager_lib.html +6 -0
  136. package/docs/modules/src_crate_builder_CrateManager_profile_manager.html +2 -0
  137. package/docs/modules/src_crate_builder_editor_state.html +2 -0
  138. package/docs/modules/src_crate_builder_types.html +16 -0
  139. package/docs/types/src_crate_builder_types.EntityReference.html +1 -0
  140. package/docs/types/src_crate_builder_types.NormalisedContext.html +1 -0
  141. package/docs/types/src_crate_builder_types.PrimitiveType.html +1 -0
  142. package/docs/types/src_crate_builder_types.ProfileAssociation.html +1 -0
  143. package/docs/types/src_crate_builder_types.ProfileInput.html +1 -0
  144. package/docs/types/src_crate_builder_types.UnverifiedContext.html +1 -0
  145. package/docs/variables/src_crate_builder_CrateManager_lib.urlProtocols.html +1 -0
  146. package/index.html +13 -0
  147. package/load-data-packs.cjs +38 -0
  148. package/package.json +135 -0
  149. package/postcss.config.cjs +6 -0
  150. package/public/favicon.ico +0 -0
  151. package/public/index.html +43 -0
  152. package/public/logo192.png +0 -0
  153. package/public/logo512.png +0 -0
  154. package/public/manifest.json +25 -0
  155. package/public/marker-icon.png +0 -0
  156. package/public/marker-shadow.png +0 -0
  157. package/public/robots.txt +3 -0
  158. package/react-app-env.d.ts +1 -0
  159. package/rollup.config.js +26 -0
  160. package/src/app/App.tsx +13 -0
  161. package/src/app/EmbeddedComponent.tsx +432 -0
  162. package/src/app/index.html +20 -0
  163. package/src/app/index.tsx +19 -0
  164. package/src/app/lookup.ts +141 -0
  165. package/src/app/override-styles.css +96 -0
  166. package/src/crate-builder/CrateManager/contexts/1.1-context.jsonld +2660 -0
  167. package/src/crate-builder/CrateManager/contexts/1.2-DRAFT-context.jsonld +2918 -0
  168. package/src/crate-builder/CrateManager/contexts.ts +42 -0
  169. package/src/crate-builder/CrateManager/crate-manager-benchmarking.spec.ts +31 -0
  170. package/src/crate-builder/CrateManager/crate-manager-loading-exporting.spec.ts +431 -0
  171. package/src/crate-builder/CrateManager/crate-manager-operations.spec.ts +298 -0
  172. package/src/crate-builder/CrateManager/crate-manager.spec.ts +2336 -0
  173. package/src/crate-builder/CrateManager/crate-manager.ts +2111 -0
  174. package/src/crate-builder/CrateManager/lib.spec.ts +133 -0
  175. package/src/crate-builder/CrateManager/lib.ts +170 -0
  176. package/src/crate-builder/CrateManager/profile-manager.spec.ts +593 -0
  177. package/src/crate-builder/CrateManager/profile-manager.ts +367 -0
  178. package/src/crate-builder/CrateManager/schema-type-definitions.json +35122 -0
  179. package/src/crate-builder/CrateManager/validate-identifier.spec.ts +82 -0
  180. package/src/crate-builder/CrateManager/validate-identifier.ts +65 -0
  181. package/src/crate-builder/RenderEntity/Add.tsx +249 -0
  182. package/src/crate-builder/RenderEntity/AddControl.stories.tsx +126 -0
  183. package/src/crate-builder/RenderEntity/AddControl.tsx +84 -0
  184. package/src/crate-builder/RenderEntity/AutoComplete.tsx +215 -0
  185. package/src/crate-builder/RenderEntity/BulkAdd.tsx +136 -0
  186. package/src/crate-builder/RenderEntity/DeleteProperty.tsx +33 -0
  187. package/src/crate-builder/RenderEntity/DialogAddProperty.tsx +83 -0
  188. package/src/crate-builder/RenderEntity/DialogBrowseEntities.tsx +136 -0
  189. package/src/crate-builder/RenderEntity/DialogEditContext.tsx +107 -0
  190. package/src/crate-builder/RenderEntity/DialogPreviewCrate.tsx +54 -0
  191. package/src/crate-builder/RenderEntity/DialogSaveCrateAsTemplate.tsx +65 -0
  192. package/src/crate-builder/RenderEntity/DialogSaveEntityTemplate.tsx +87 -0
  193. package/src/crate-builder/RenderEntity/DisplayPropertyName.stories.tsx +30 -0
  194. package/src/crate-builder/RenderEntity/DisplayPropertyName.tsx +21 -0
  195. package/src/crate-builder/RenderEntity/EntityId.tsx +75 -0
  196. package/src/crate-builder/RenderEntity/EntityName.tsx +49 -0
  197. package/src/crate-builder/RenderEntity/EntityProperty.tsx +188 -0
  198. package/src/crate-builder/RenderEntity/EntityPropertyInstance.tsx +255 -0
  199. package/src/crate-builder/RenderEntity/EntityType.tsx +95 -0
  200. package/src/crate-builder/RenderEntity/ItemLink.tsx +37 -0
  201. package/src/crate-builder/RenderEntity/PaginateLinkedEntities.stories.tsx +43 -0
  202. package/src/crate-builder/RenderEntity/PaginateLinkedEntities.tsx +141 -0
  203. package/src/crate-builder/RenderEntity/PropertyHelp.tsx +39 -0
  204. package/src/crate-builder/RenderEntity/RenderControls.tsx +278 -0
  205. package/src/crate-builder/RenderEntity/RenderLinkedItem.tsx +139 -0
  206. package/src/crate-builder/RenderEntity/RenderPropertyHelp.tsx +41 -0
  207. package/src/crate-builder/RenderEntity/RenderReverseConnections.tsx +150 -0
  208. package/src/crate-builder/RenderEntity/RenderTypes.tsx +102 -0
  209. package/src/crate-builder/RenderEntity/Shell2.tsx +576 -0
  210. package/src/crate-builder/RenderEntity/UnlinkEntity.tsx +30 -0
  211. package/src/crate-builder/RenderEntity/auto-complete.lib.ts +184 -0
  212. package/src/crate-builder/RenderEntity/keys.ts +4 -0
  213. package/src/crate-builder/RenderEntity/layout.spec.js +593 -0
  214. package/src/crate-builder/RenderEntity/layout.ts +220 -0
  215. package/src/crate-builder/Shell.tsx +323 -0
  216. package/src/crate-builder/component.css +65 -0
  217. package/src/crate-builder/editor-state.ts +114 -0
  218. package/src/crate-builder/helpers.ts +16 -0
  219. package/src/crate-builder/i18n.ts +22 -0
  220. package/src/crate-builder/lib/validate-iri.js +69 -0
  221. package/src/crate-builder/lib/validate-iri.ts +57 -0
  222. package/src/crate-builder/locales/en.js +149 -0
  223. package/src/crate-builder/locales/hu.js +147 -0
  224. package/src/crate-builder/primitives/Boolean.stories.tsx +33 -0
  225. package/src/crate-builder/primitives/Boolean.tsx +67 -0
  226. package/src/crate-builder/primitives/Date.stories.tsx +32 -0
  227. package/src/crate-builder/primitives/Date.tsx +58 -0
  228. package/src/crate-builder/primitives/DateTime.stories.tsx +32 -0
  229. package/src/crate-builder/primitives/DateTime.tsx +64 -0
  230. package/src/crate-builder/primitives/Geo.stories.tsx +57 -0
  231. package/src/crate-builder/primitives/Geo.tsx +225 -0
  232. package/src/crate-builder/primitives/Map.SelectArea.js +359 -0
  233. package/src/crate-builder/primitives/Map.stories.tsx +61 -0
  234. package/src/crate-builder/primitives/Map.tsx +124 -0
  235. package/src/crate-builder/primitives/Number.stories.tsx +74 -0
  236. package/src/crate-builder/primitives/Number.tsx +166 -0
  237. package/src/crate-builder/primitives/Select.stories.tsx +66 -0
  238. package/src/crate-builder/primitives/Select.tsx +122 -0
  239. package/src/crate-builder/primitives/SelectObject.stories.tsx +29 -0
  240. package/src/crate-builder/primitives/SelectObject.tsx +105 -0
  241. package/src/crate-builder/primitives/SelectUrl.stories.tsx +42 -0
  242. package/src/crate-builder/primitives/SelectUrl.tsx +110 -0
  243. package/src/crate-builder/primitives/Text.stories.tsx +106 -0
  244. package/src/crate-builder/primitives/Text.tsx +197 -0
  245. package/src/crate-builder/primitives/Time.stories.tsx +38 -0
  246. package/src/crate-builder/primitives/Time.tsx +71 -0
  247. package/src/crate-builder/primitives/Url.stories.tsx +43 -0
  248. package/src/crate-builder/primitives/Url.tsx +75 -0
  249. package/src/crate-builder/primitives/Value.stories.tsx +37 -0
  250. package/src/crate-builder/primitives/Value.tsx +30 -0
  251. package/src/crate-builder/primitives/date-libs.ts +12 -0
  252. package/src/crate-builder/profile-schema.json +145 -0
  253. package/src/crate-builder/property-definitions.ts +78 -0
  254. package/src/crate-builder/store.ts +14 -0
  255. package/src/crate-builder/tailwind.css +7 -0
  256. package/src/crate-builder/types.d.ts +318 -0
  257. package/src/examples/collection/collections-entity-example.json +131 -0
  258. package/src/examples/collection/crate-builder-entity-example.json +33 -0
  259. package/src/examples/item/complex-collection/ro-crate-metadata.json +174 -0
  260. package/src/examples/item/complex-item/ro-crate-metadata.json +769 -0
  261. package/src/examples/item/crate-with-language.json +38 -0
  262. package/src/examples/item/empty/ro-crate-metadata.json +20 -0
  263. package/src/examples/item/item-with-relationship-and-action/ro-crate-metadata.json +66 -0
  264. package/src/examples/item/large-crate/ro-crate-metadata.json +5762 -0
  265. package/src/examples/item/multiple-types/ro-crate-metadata.json +20 -0
  266. package/src/examples/item/ridiculously-big-collection/ro-crate-metadata.json +162977 -0
  267. package/src/examples/profile/aroma.complex.profile.json +11098 -0
  268. package/src/examples/profile/aroma.profile.json +9158 -0
  269. package/src/examples/profile/nyingarn-item-profile.json +426 -0
  270. package/src/examples/profile/profile-to-test-inverse-associations.json +73 -0
  271. package/src/examples/profile/profile-to-test-multiple-types.json +31 -0
  272. package/src/examples/profile/profile-with-all-primitives-and-groups.json +207 -0
  273. package/src/examples/profile/profile-with-all-primitives.json +244 -0
  274. package/src/examples/profile/profile-with-constraints.json +446 -0
  275. package/src/examples/profile/profile-with-resolve.json +57 -0
  276. package/src/examples/profile/vocabulary-creation-profile.json +231 -0
  277. package/src/images.d.ts +5 -0
  278. package/src/index.ts +10 -0
  279. package/src/types.ts +104 -0
  280. package/tailwind.config.js +20 -0
  281. package/tsconfig.app.json +31 -0
  282. package/tsconfig.json +26 -0
  283. package/typedoc.json +11 -0
  284. package/update-deps.sh +4 -0
  285. package/vite-env.d.ts +1 -0
  286. package/vite.config.ts +41 -0
@@ -0,0 +1,576 @@
1
+ import React, { forwardRef, useImperativeHandle, useContext, useState, useEffect, useRef, useMemo } from 'react';
2
+ import { Flex, Tabs, Drawer } from 'antd';
3
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
+ import { faTriangleExclamation, faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
5
+ import { faCircleCheck, faCircleXmark } from '@fortawesome/free-regular-svg-icons';
6
+ import EntityId from './EntityId';
7
+ import EntityType from './EntityType';
8
+ import EntityName from './EntityName';
9
+ import EntityProperty from './EntityProperty';
10
+ import RenderControls from './RenderControls';
11
+ import RenderReverseConnections from './RenderReverseConnections';
12
+ import { ProfileManagerContext, CrateManagerContext } from '../Shell';
13
+ import { useStateStore } from '../store';
14
+ import { applyLayout } from "./layout";
15
+ import { isURL } from '../CrateManager/lib';
16
+
17
+ interface RenderEntityProps {
18
+ entity: any;
19
+ onLoadEntity: (params: { id: string; updateState?: boolean }) => void;
20
+ onSaveCrate: () => void;
21
+ onSaveEntityTemplate: () => void;
22
+ onWarning: () => void;
23
+ onError: () => void;
24
+ }
25
+
26
+ const RenderEntity = forwardRef<any, RenderEntityProps>((props, ref) => {
27
+ const { entity, onLoadEntity, onSaveCrate, onSaveEntityTemplate, onWarning, onError } = props;
28
+ const state = useStateStore();
29
+ const profileManager = useContext(ProfileManagerContext);
30
+ const crateManager = useContext(CrateManagerContext);
31
+
32
+ // State variables
33
+ const [contextEntity, setContextEntity] = useState<any>(entity);
34
+ const [activeTab, setActiveTab] = useState("about");
35
+ const [reverseSidebarVisible, setReverseSidebarVisible] = useState(false);
36
+ const [highlightRequiredProperties, setHighlightRequiredProperties] = useState(false);
37
+ const [missingRequiredData, setMissingRequiredData] = useState(false);
38
+ const [renderTabs, setRenderTabs] = useState(false);
39
+ const [extraProperties, setExtraProperties] = useState<string[]>([]);
40
+ const [savedProperty, setSavedProperty] = useState<string | undefined>(undefined);
41
+ const [tabs, setTabs] = useState<any[]>([]);
42
+
43
+ // Expose methods to parent component
44
+ useImperativeHandle(ref, () => ({
45
+ setTab: (tabName: string) => {
46
+ setActiveTab(tabName);
47
+ },
48
+ toggleReverseLinkBrowser: () => {
49
+ setReverseSidebarVisible(!reverseSidebarVisible);
50
+ }
51
+ }));
52
+
53
+ // Initialize component with entity data
54
+ useEffect(() => {
55
+ setExtraProperties([]); // Reset extraProperties when entity changes
56
+ init({ entity });
57
+ }, [entity]);
58
+
59
+ // Force re-render when profile changes
60
+ useEffect(() => {
61
+ if (profileManager && profileManager.$key) {
62
+ const entityObj = crateManager.getEntity({ id: entity['@id'] });
63
+ init({ entity: entityObj });
64
+ }
65
+ }, [profileManager?.$key]);
66
+
67
+ // Initialize the component with entity data
68
+ const init = ({ entity }: { entity: any }) => {
69
+ if (!entity['@id']) return;
70
+
71
+ // Scroll to top when entity changes
72
+ if (entity['@id'] !== contextEntity['@id']) {
73
+ window.scrollTo(0, 0);
74
+ }
75
+
76
+ // Apply layout based on profile and entity
77
+ const layout = applyLayout({
78
+ configuration: state.configuration,
79
+ profileManager,
80
+ entity,
81
+ extraProperties,
82
+ });
83
+
84
+ setContextEntity(layout.entity);
85
+ setRenderTabs(layout.renderTabs);
86
+ setMissingRequiredData(layout.missingRequiredData);
87
+ setTabs(layout.tabs);
88
+
89
+ // Update editor state with tab information
90
+ if (layout.renderTabs) {
91
+ state.editorState.update({ id: entity['@id'], tab: activeTab });
92
+ } else {
93
+ state.editorState.deleteFromState({ property: "tab" });
94
+ }
95
+ };
96
+
97
+ // Refresh the component with latest entity data
98
+ const refresh = () => {
99
+ const entityObj = crateManager.getEntity({ id: entity['@id'] });
100
+ init({ entity: entityObj });
101
+ };
102
+
103
+ // Save tab to editor state
104
+ const saveTabToState = (tabName: string) => {
105
+ state.editorState.update({ id: entity['@id'], tab: tabName });
106
+ };
107
+
108
+ // Add property placeholder
109
+ // Add this effect near your other useEffect hooks
110
+ useEffect(() => {
111
+ if (entity?.['@id']) {
112
+ const entityObj = crateManager.getEntity({ id: entity['@id'] });
113
+ init({ entity: entityObj });
114
+ refresh();
115
+ }
116
+ }, [extraProperties]); // This will run whenever extraProperties changes
117
+
118
+ const handleAddPropertyPlaceholder = (property: string) => {
119
+ try {
120
+ const newExtraProperties = [...extraProperties, property];
121
+ setExtraProperties(newExtraProperties);
122
+ } catch (error) {
123
+ console.error(error);
124
+ onError();
125
+ }
126
+ };
127
+
128
+ // Notify that a property was saved (for highlighting)
129
+ const notifySave = (property: string) => {
130
+ setSavedProperty(property);
131
+ setTimeout(() => {
132
+ setSavedProperty(undefined);
133
+ }, 1500);
134
+ };
135
+
136
+ // Entity update handlers
137
+ const handleUpdateEntity = (data: { property: string; value: any }) => {
138
+ try {
139
+ // Don't update core properties if value hasn't changed
140
+ if (["@id", "@type", "name"].includes(data.property)) {
141
+ if (contextEntity[data.property] === data.value) return;
142
+ }
143
+
144
+ // Update the property
145
+ const updatedEntity = crateManager.updateProperty({
146
+ id: entity['@id'],
147
+ ...data
148
+ });
149
+
150
+ // Handle entity ID changes
151
+ if (updatedEntity["@id"] !== entity["@id"]) {
152
+ onLoadEntity({ id: updatedEntity["@id"] });
153
+ } else {
154
+ refresh();
155
+ }
156
+
157
+ // Update editor state if ID changed
158
+ if (data.property === "@id" && updatedEntity?.["@id"]) {
159
+ state.editorState.replaceId({ id: entity["@id"], newId: updatedEntity["@id"] });
160
+ }
161
+
162
+ onSaveCrate();
163
+ notifySave(data.property);
164
+ } catch (error) {
165
+ console.error(error)
166
+ onError();
167
+ }
168
+ };
169
+
170
+ const handleCreateProperty = (data: { property: string; value: any }) => {
171
+ try {
172
+ if (isURL(data.value) && state.configuration?.enableUrlMarkup) {
173
+ handleCreateEntity({
174
+ property: data.property,
175
+ json: {
176
+ "@id": data.value,
177
+ "@type": "URL",
178
+ name: data.value,
179
+ },
180
+ });
181
+ } else {
182
+ crateManager.setProperty({
183
+ id: entity['@id'],
184
+ ...data
185
+ });
186
+ }
187
+ refresh();
188
+ onSaveCrate();
189
+ notifySave(data.property);
190
+ } catch (error) {
191
+ onError();
192
+ }
193
+ };
194
+
195
+ const handleCreateEntity = (data: any) => {
196
+ try {
197
+ delete data.json?.type;
198
+
199
+ crateManager.ingestAndLink({
200
+ id: entity['@id'],
201
+ property: data.property,
202
+ propertyId: data.propertyId,
203
+ json: data.json,
204
+ });
205
+
206
+ let warnings = crateManager.getWarnings();
207
+ if (warnings.hasWarning) {
208
+ onWarning();
209
+ }
210
+ refresh();
211
+ onSaveCrate();
212
+ return data.json['@id'];
213
+ } catch (error) {
214
+ onError();
215
+ return null;
216
+ }
217
+ };
218
+
219
+ const handleLinkEntity = (data: any) => {
220
+ try {
221
+ crateManager.linkEntity({
222
+ id: entity['@id'],
223
+ property: data.property,
224
+ propertyId: data.propertyId,
225
+ value: { "@id": data.json["@id"] },
226
+ });
227
+ refresh();
228
+ onSaveCrate();
229
+ } catch (error) {
230
+ onError();
231
+ }
232
+ };
233
+
234
+ const handleDeleteProperty = (data: { property: string; idx: number }) => {
235
+ try {
236
+ crateManager.deleteProperty({
237
+ id: entity['@id'],
238
+ property: data.property,
239
+ idx: data.idx
240
+ });
241
+ refresh();
242
+ onSaveCrate();
243
+ } catch (error) {
244
+ onError();
245
+ }
246
+ };
247
+
248
+ const handleUnlinkEntity = (data: { property: string; tgtEntityId: string }) => {
249
+ try {
250
+ crateManager.unlinkEntity({
251
+ id: entity['@id'],
252
+ property: data.property,
253
+ value: { "@id": data.tgtEntityId },
254
+ });
255
+ refresh();
256
+ onSaveCrate();
257
+ } catch (error) {
258
+ console.error(error);
259
+ onError();
260
+ }
261
+ };
262
+
263
+ const handleDeleteEntity = (data: { id: string }) => {
264
+ try {
265
+ crateManager.deleteEntity({ id: data.id });
266
+ onLoadEntity({ id: './' }); // Navigate to root after deletion
267
+ onSaveCrate();
268
+ } catch (error) {
269
+ onError();
270
+ }
271
+ };
272
+
273
+ const handleUpdateContext = (context: any) => {
274
+ try {
275
+ crateManager.setContext(context);
276
+ onSaveCrate();
277
+ } catch (error) {
278
+ onError();
279
+ }
280
+ };
281
+
282
+ if (!entity || !entity['@id']) {
283
+ return <div>No entity selected</div>;
284
+ }
285
+
286
+ return (
287
+ <div className="flex flex-row">
288
+ <div className="flex flex-col w-full">
289
+ {state.configuration?.showControls && (
290
+ <div className="flex flex-row place-content-between pb-1 border-b border-slate-700">
291
+ <RenderControls
292
+ entity={contextEntity}
293
+ onLoadEntity={onLoadEntity}
294
+ onBack={() => state.editorState.back()}
295
+ onForward={() => state.editorState.forward()}
296
+ onAddPropertyPlaceholder={handleAddPropertyPlaceholder}
297
+ onDeleteEntity={handleDeleteEntity}
298
+ onSaveEntityTemplate={onSaveEntityTemplate}
299
+ onUpdateContext={handleUpdateContext}
300
+ />
301
+ <div className="flex-grow"></div>
302
+
303
+ {/* Toggle reverse links panel button */}
304
+ {state.configuration?.enableReverseLinkBrowser && (
305
+ <button
306
+ className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded text-sm"
307
+ onClick={() => setReverseSidebarVisible(!reverseSidebarVisible)}
308
+ >
309
+ <FontAwesomeIcon
310
+ icon={reverseSidebarVisible ? faChevronRight : faChevronLeft}
311
+ size="sm"
312
+ />
313
+ </button>
314
+ )}
315
+ </div>
316
+ )}
317
+
318
+ {/* Untabbed layout */}
319
+ {!renderTabs && (
320
+ <div>
321
+ <div className="flex flex-row space-x-2 my-2 p-2">
322
+ <div
323
+ className={`flex-grow describo-property describo-property-name-id ${
324
+ savedProperty === '@id' ? 'bg-green-200 rounded p-1 my-1' : ''
325
+ }`}
326
+ >
327
+ <EntityId entity={contextEntity} onUpdate={handleUpdateEntity} />
328
+ </div>
329
+
330
+ {/* Highlight required properties button */}
331
+ {!state.configuration?.readonly && missingRequiredData && (
332
+ <button
333
+ className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
334
+ onClick={() => setHighlightRequiredProperties(!highlightRequiredProperties)}
335
+ >
336
+ <FontAwesomeIcon icon={faTriangleExclamation} size="lg" />
337
+ </button>
338
+ )}
339
+ </div>
340
+
341
+ <div className={`my-2 p-2 describo-property describo-property-name-type`}>
342
+ <EntityType entity={contextEntity} onUpdateEntity={handleUpdateEntity} />
343
+ </div>
344
+
345
+ <div
346
+ className={`my-2 p-2 describo-property describo-property-name-name ${
347
+ savedProperty === 'name' ? 'bg-green-200 rounded p-1 my-1' : ''
348
+ }`}
349
+ >
350
+ <EntityName entity={contextEntity} onUpdate={handleUpdateEntity} />
351
+ </div>
352
+
353
+ {/* Render entity properties */}
354
+ {Object.keys(contextEntity).sort().map(property => {
355
+ if (!['@id', '@type', 'name', '@reverse'].includes(property)) {
356
+ return (
357
+ <div
358
+ key={property}
359
+ className={`my-2 hover:bg-sky-100 ${
360
+ savedProperty === property ? 'bg-green-200 hover:bg-green-200' : ''
361
+ }`}
362
+ >
363
+ <EntityProperty
364
+ entity={contextEntity}
365
+ property={property}
366
+ values={Array.isArray(contextEntity[property]) ? contextEntity[property] : [contextEntity[property]]}
367
+ highlightRequired={highlightRequiredProperties}
368
+ savedProperty={savedProperty === property}
369
+ onLoadEntity={onLoadEntity}
370
+ onCreateEntity={handleCreateEntity}
371
+ onLinkEntity={handleLinkEntity}
372
+ onUnlinkEntity={handleUnlinkEntity}
373
+ onCreateProperty={handleCreateProperty}
374
+ onSaveProperty={handleUpdateEntity}
375
+ onDeleteProperty={handleDeleteProperty}
376
+ />
377
+ </div>
378
+ );
379
+ }
380
+ return null;
381
+ })}
382
+ </div>
383
+ )}
384
+
385
+ {/* Tabbed layout */}
386
+ {renderTabs && (
387
+ <div className="flex" style={{
388
+ flexDirection: state.configuration?.tabLocation === 'left' || state.configuration?.tabLocation === 'right' ? 'row' : 'column'
389
+ }}>
390
+ <Tabs
391
+ activeKey={activeTab}
392
+ onChange={(key) => {
393
+ setActiveTab(key);
394
+ saveTabToState(key);
395
+ }}
396
+ tabPosition={state.configuration?.tabLocation === 'left' ? 'left' : state.configuration?.tabLocation === 'right' ? 'right' : 'top'}
397
+ >
398
+ {tabs.map((tab) => (
399
+ <Tabs.TabPane
400
+ key={tab.name}
401
+ tab={
402
+ <div className="flex flex-col w-full">
403
+ <div className="flex flex-row items-center justify-between w-full">
404
+ <div className="text-left text-base font-medium text-gray-700 describo-tab-label">
405
+ {tab.label || tab.name}
406
+ </div>
407
+ <div className="ml-2">
408
+ {tab.missingRequiredData && (
409
+ <div className="text-red-600">
410
+ <FontAwesomeIcon icon={faCircleXmark} size="lg" />
411
+ </div>
412
+ )}
413
+ {tab.hasData && !tab.missingRequiredData && (
414
+ <div className="text-green-600">
415
+ <FontAwesomeIcon icon={faCircleCheck} size="lg" />
416
+ </div>
417
+ )}
418
+ </div>
419
+ </div>
420
+ {tab.description && (
421
+ <div className="text-left text-gray-500 font-light text-xs describo-tab-description">
422
+ {tab.description}
423
+ </div>
424
+ )}
425
+ </div>
426
+ }
427
+ />
428
+ ))}
429
+ </Tabs>
430
+
431
+ <div className="flex-grow p-3">
432
+ {/* Required properties warning button */}
433
+ {!state.configuration?.readonly &&
434
+ tabs.find(t => t.name === activeTab)?.missingRequiredData && (
435
+ <div className="text-red-600 float-right mb-2">
436
+ <button
437
+ className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded text-sm"
438
+ onClick={() => setHighlightRequiredProperties(!highlightRequiredProperties)}
439
+ >
440
+ <FontAwesomeIcon icon={faTriangleExclamation} size="lg" />
441
+ </button>
442
+ </div>
443
+ )}
444
+
445
+ {/* About tab content */}
446
+ {activeTab === 'about' && (
447
+ <div className="space-y-3">
448
+ <div
449
+ className={`p-2 describo-property describo-property-name-id ${
450
+ savedProperty === '@id' ? 'bg-green-200 rounded' : ''
451
+ }`}
452
+ >
453
+ <EntityId entity={contextEntity} onUpdate={handleUpdateEntity} />
454
+ </div>
455
+ <div className="p-2 describo-property describo-property-name-type">
456
+ <EntityType entity={contextEntity} onUpdateEntity={handleUpdateEntity} />
457
+ </div>
458
+ <div
459
+ className={`p-2 describo-property describo-property-name-name ${
460
+ savedProperty === 'name' ? 'bg-green-200 rounded' : ''
461
+ }`}
462
+ >
463
+ <EntityName entity={contextEntity} onUpdate={handleUpdateEntity} />
464
+ </div>
465
+
466
+ {/* Add this section to render additional properties in the about tab */}
467
+ {tabs.find(tab => tab.name === 'about')?.inputs.map((input: any) => {
468
+ if (!['@id', '@type', 'name', '@reverse'].includes(input.name)) {
469
+ return (
470
+ <div
471
+ key={input.name}
472
+ className={`p-2 hover:bg-sky-100 ${
473
+ savedProperty === input.name ? 'bg-green-200 hover:bg-green-200' : ''
474
+ }`}
475
+ >
476
+ <EntityProperty
477
+ entity={contextEntity}
478
+ property={input.name}
479
+ values={Array.isArray(contextEntity[input.name]) ? contextEntity[input.name] : [contextEntity[input.name]]}
480
+ highlightRequired={highlightRequiredProperties}
481
+ savedProperty={savedProperty === input.name}
482
+ onLoadEntity={onLoadEntity}
483
+ onCreateEntity={handleCreateEntity}
484
+ onLinkEntity={handleLinkEntity}
485
+ onUnlinkEntity={handleUnlinkEntity}
486
+ onCreateProperty={handleCreateProperty}
487
+ onSaveProperty={handleUpdateEntity}
488
+ onDeleteProperty={handleDeleteProperty}
489
+ />
490
+ </div>
491
+ );
492
+ }
493
+ return null;
494
+ })}
495
+ </div>
496
+ )}
497
+
498
+ {/* Tab content for other tabs */}
499
+ {tabs.map(tab => {
500
+ if (tab.name === activeTab && tab.name !== 'about') {
501
+ return (
502
+ <div key={tab.name} className="space-y-3">
503
+ {tab.inputs.map((input: any) => {
504
+ if (!['@id', '@type', 'name', '@reverse'].includes(input.name)) {
505
+ return (
506
+ <div
507
+ key={input.name}
508
+ className={`p-2 hover:bg-sky-100 ${
509
+ savedProperty === input.name ? 'bg-green-200 hover:bg-green-200' : ''
510
+ }`}
511
+ >
512
+ <EntityProperty
513
+ entity={contextEntity}
514
+ property={input.name}
515
+ values={Array.isArray(contextEntity[input.name]) ? contextEntity[input.name] : [contextEntity[input.name]]}
516
+ highlightRequired={highlightRequiredProperties}
517
+ savedProperty={savedProperty === input.name}
518
+ onLoadEntity={onLoadEntity}
519
+ onCreateEntity={handleCreateEntity}
520
+ onLinkEntity={handleLinkEntity}
521
+ onUnlinkEntity={handleUnlinkEntity}
522
+ onCreateProperty={handleCreateProperty}
523
+ onSaveProperty={handleUpdateEntity}
524
+ onDeleteProperty={handleDeleteProperty}
525
+ />
526
+ </div>
527
+ );
528
+ }
529
+ return null;
530
+ })}
531
+ </div>
532
+ );
533
+ }
534
+ return null;
535
+ })}
536
+ </div>
537
+ </div>
538
+ )}
539
+ </div>
540
+
541
+ {/* Remove this entire block */}
542
+ {/* Reverse links toggle button (when sidebar is not visible) */}
543
+ {/* {state.configuration?.enableReverseLinkBrowser && !reverseSidebarVisible && (
544
+ <div
545
+ className="p-1 h-8 rounded text-lg bg-gray-200 text-blue-600 cursor-pointer"
546
+ onClick={() => setReverseSidebarVisible(!reverseSidebarVisible)}
547
+ >
548
+ <FontAwesomeIcon icon={faChevronLeft} size="sm" />
549
+ </div>
550
+ )} */}
551
+
552
+ {/* Reverse links drawer */}
553
+ <Drawer
554
+ placement="right"
555
+ open={reverseSidebarVisible}
556
+ onClose={() => setReverseSidebarVisible(false)}
557
+ width={600}
558
+ >
559
+ <div className="p-2">
560
+ <RenderReverseConnections
561
+ key={contextEntity['@id']}
562
+ entity={contextEntity}
563
+ onLoadEntity={(data) => {
564
+ onLoadEntity(data);
565
+ setReverseSidebarVisible(false);
566
+ }}
567
+ />
568
+ </div>
569
+ </Drawer>
570
+ </div>
571
+ );
572
+ });
573
+
574
+ RenderEntity.displayName = 'RenderEntity';
575
+
576
+ export default RenderEntity;
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { Button } from 'antd';
3
+ import { LinkOutlined } from '@ant-design/icons';
4
+
5
+ interface UnlinkEntityProps {
6
+ entity: {
7
+ '@id': string;
8
+ [key: string]: any;
9
+ };
10
+ onUnlinkEntity: (data: { entity: { '@id': string } }) => void;
11
+ }
12
+
13
+ const UnlinkEntity: React.FC<UnlinkEntityProps> = ({ entity, onUnlinkEntity }) => {
14
+ const handleUnlink = () => {
15
+ onUnlinkEntity({ entity: { '@id': entity['@id'] } });
16
+ };
17
+
18
+ return (
19
+ <Button
20
+ onClick={handleUnlink}
21
+ danger
22
+ variant="text"
23
+ color='red'
24
+ size="large"
25
+ icon={<LinkOutlined />}
26
+ />
27
+ );
28
+ };
29
+
30
+ export default UnlinkEntity;