@alpaca-editor/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/.prettierrc +3 -0
  2. package/eslint.config.mjs +4 -0
  3. package/images/bg-shape-black.webp +0 -0
  4. package/package.json +52 -0
  5. package/src/client-components/api.ts +6 -0
  6. package/src/client-components/index.ts +19 -0
  7. package/src/components/ActionButton.tsx +43 -0
  8. package/src/components/Error.tsx +57 -0
  9. package/src/config/config.tsx +737 -0
  10. package/src/config/types.ts +263 -0
  11. package/src/editor/ComponentInfo.tsx +77 -0
  12. package/src/editor/ConfirmationDialog.tsx +103 -0
  13. package/src/editor/ContentTree.tsx +654 -0
  14. package/src/editor/ContextMenu.tsx +155 -0
  15. package/src/editor/Editor.tsx +91 -0
  16. package/src/editor/EditorWarning.tsx +34 -0
  17. package/src/editor/EditorWarnings.tsx +33 -0
  18. package/src/editor/FieldEditorPopup.tsx +65 -0
  19. package/src/editor/FieldHistory.tsx +74 -0
  20. package/src/editor/FieldList.tsx +190 -0
  21. package/src/editor/FieldListField.tsx +387 -0
  22. package/src/editor/FieldListFieldWithFallbacks.tsx +211 -0
  23. package/src/editor/FloatingToolbar.tsx +163 -0
  24. package/src/editor/ImageEditor.tsx +129 -0
  25. package/src/editor/InsertMenu.tsx +332 -0
  26. package/src/editor/ItemInfo.tsx +90 -0
  27. package/src/editor/LinkEditorDialog.tsx +192 -0
  28. package/src/editor/MainLayout.tsx +94 -0
  29. package/src/editor/NewEditorClient.tsx +11 -0
  30. package/src/editor/PictureCropper.tsx +505 -0
  31. package/src/editor/PictureEditor.tsx +206 -0
  32. package/src/editor/PictureEditorDialog.tsx +381 -0
  33. package/src/editor/PublishDialog.ignore +74 -0
  34. package/src/editor/ScrollingContentTree.tsx +47 -0
  35. package/src/editor/Terminal.tsx +215 -0
  36. package/src/editor/Titlebar.tsx +23 -0
  37. package/src/editor/ai/AiPopup.tsx +59 -0
  38. package/src/editor/ai/AiResponseMessage.tsx +82 -0
  39. package/src/editor/ai/AiTerminal.tsx +450 -0
  40. package/src/editor/ai/AiToolCall.tsx +46 -0
  41. package/src/editor/ai/EditorAiTerminal.tsx +20 -0
  42. package/src/editor/ai/editorAiContext.ts +18 -0
  43. package/src/editor/client/DialogContext.tsx +49 -0
  44. package/src/editor/client/EditorClient.tsx +1831 -0
  45. package/src/editor/client/GenericDialog.tsx +50 -0
  46. package/src/editor/client/editContext.ts +330 -0
  47. package/src/editor/client/helpers.ts +44 -0
  48. package/src/editor/client/itemsRepository.ts +391 -0
  49. package/src/editor/client/operations.ts +610 -0
  50. package/src/editor/client/pageModelBuilder.ts +182 -0
  51. package/src/editor/commands/commands.ts +23 -0
  52. package/src/editor/commands/componentCommands.tsx +408 -0
  53. package/src/editor/commands/createVersionCommand.ts +33 -0
  54. package/src/editor/commands/deleteVersionCommand.ts +71 -0
  55. package/src/editor/commands/itemCommands.tsx +186 -0
  56. package/src/editor/commands/localizeItem/LocalizeItemDialog.tsx +201 -0
  57. package/src/editor/commands/undo.ts +39 -0
  58. package/src/editor/component-designer/ComponentDesigner.tsx +70 -0
  59. package/src/editor/component-designer/ComponentDesignerAiTerminal.tsx +11 -0
  60. package/src/editor/component-designer/ComponentDesignerMenu.tsx +91 -0
  61. package/src/editor/component-designer/ComponentEditor.tsx +97 -0
  62. package/src/editor/component-designer/ComponentRenderingCodeEditor.tsx +31 -0
  63. package/src/editor/component-designer/ComponentRenderingEditor.tsx +104 -0
  64. package/src/editor/component-designer/ComponentsDropdown.tsx +39 -0
  65. package/src/editor/component-designer/PlaceholdersEditor.tsx +183 -0
  66. package/src/editor/component-designer/RenderingsDropdown.tsx +36 -0
  67. package/src/editor/component-designer/TemplateEditor.tsx +236 -0
  68. package/src/editor/component-designer/aiContext.ts +23 -0
  69. package/src/editor/componentTreeHelper.tsx +114 -0
  70. package/src/editor/control-center/ControlCenterMenu.tsx +71 -0
  71. package/src/editor/control-center/IndexOverview.tsx +50 -0
  72. package/src/editor/control-center/IndexSettings.tsx +266 -0
  73. package/src/editor/control-center/Status.tsx +7 -0
  74. package/src/editor/editor-warnings/ItemLocked.tsx +63 -0
  75. package/src/editor/editor-warnings/NoLanguageWriteAccess.tsx +22 -0
  76. package/src/editor/editor-warnings/NoWorkflowWriteAccess.tsx +23 -0
  77. package/src/editor/editor-warnings/NoWriteAccess.tsx +15 -0
  78. package/src/editor/editor-warnings/ValidationErrors.tsx +54 -0
  79. package/src/editor/field-types/AttachmentEditor.tsx +9 -0
  80. package/src/editor/field-types/CheckboxEditor.tsx +47 -0
  81. package/src/editor/field-types/DropLinkEditor.tsx +75 -0
  82. package/src/editor/field-types/DropListEditor.tsx +84 -0
  83. package/src/editor/field-types/ImageFieldEditor.tsx +65 -0
  84. package/src/editor/field-types/InternalLinkFieldEditor.tsx +112 -0
  85. package/src/editor/field-types/LinkFieldEditor.tsx +85 -0
  86. package/src/editor/field-types/MultiLineText.tsx +63 -0
  87. package/src/editor/field-types/PictureFieldEditor.tsx +121 -0
  88. package/src/editor/field-types/RawEditor.tsx +53 -0
  89. package/src/editor/field-types/ReactQuill.tsx +580 -0
  90. package/src/editor/field-types/RichTextEditor.tsx +22 -0
  91. package/src/editor/field-types/RichTextEditorComponent.tsx +108 -0
  92. package/src/editor/field-types/SingleLineText.tsx +150 -0
  93. package/src/editor/field-types/TreeListEditor.tsx +261 -0
  94. package/src/editor/fieldTypes.ts +140 -0
  95. package/src/editor/media-selector/AiImageSearch.tsx +186 -0
  96. package/src/editor/media-selector/AiImageSearchPrompt.tsx +95 -0
  97. package/src/editor/media-selector/MediaSelector.tsx +42 -0
  98. package/src/editor/media-selector/Preview.tsx +14 -0
  99. package/src/editor/media-selector/Thumbnails.tsx +48 -0
  100. package/src/editor/media-selector/TreeSelector.tsx +292 -0
  101. package/src/editor/media-selector/UploadZone.tsx +137 -0
  102. package/src/editor/menubar/ActionsMenu.tsx +47 -0
  103. package/src/editor/menubar/ActiveUsers.tsx +17 -0
  104. package/src/editor/menubar/ApproveAndPublish.tsx +18 -0
  105. package/src/editor/menubar/BrowseHistory.tsx +37 -0
  106. package/src/editor/menubar/ItemLanguageVersion.tsx +52 -0
  107. package/src/editor/menubar/LanguageSelector.tsx +152 -0
  108. package/src/editor/menubar/Menu.tsx +83 -0
  109. package/src/editor/menubar/NavButtons.tsx +74 -0
  110. package/src/editor/menubar/PageSelector.tsx +139 -0
  111. package/src/editor/menubar/PageViewerControls.tsx +99 -0
  112. package/src/editor/menubar/Separator.tsx +12 -0
  113. package/src/editor/menubar/SiteInfo.tsx +53 -0
  114. package/src/editor/menubar/User.tsx +27 -0
  115. package/src/editor/menubar/VersionSelector.tsx +143 -0
  116. package/src/editor/page-editor-chrome/CommentHighlighting.tsx +287 -0
  117. package/src/editor/page-editor-chrome/CommentHighlightings.tsx +35 -0
  118. package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +44 -0
  119. package/src/editor/page-editor-chrome/FieldActionIndicators.tsx +23 -0
  120. package/src/editor/page-editor-chrome/FieldEditedIndicator.tsx +64 -0
  121. package/src/editor/page-editor-chrome/FieldEditedIndicators.tsx +35 -0
  122. package/src/editor/page-editor-chrome/FrameMenu.tsx +263 -0
  123. package/src/editor/page-editor-chrome/FrameMenus.tsx +48 -0
  124. package/src/editor/page-editor-chrome/InlineEditor.tsx +147 -0
  125. package/src/editor/page-editor-chrome/LockedFieldIndicator.tsx +61 -0
  126. package/src/editor/page-editor-chrome/NoLayout.tsx +36 -0
  127. package/src/editor/page-editor-chrome/PageEditorChrome.tsx +119 -0
  128. package/src/editor/page-editor-chrome/PictureEditorOverlay.tsx +154 -0
  129. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +171 -0
  130. package/src/editor/page-editor-chrome/PlaceholderDropZones.tsx +233 -0
  131. package/src/editor/page-viewer/DeviceToolbar.tsx +70 -0
  132. package/src/editor/page-viewer/EditorForm.tsx +247 -0
  133. package/src/editor/page-viewer/MiniMap.tsx +351 -0
  134. package/src/editor/page-viewer/PageViewer.tsx +127 -0
  135. package/src/editor/page-viewer/PageViewerFrame.tsx +1030 -0
  136. package/src/editor/page-viewer/pageViewContext.ts +186 -0
  137. package/src/editor/pageModel.ts +191 -0
  138. package/src/editor/picture-shared.tsx +53 -0
  139. package/src/editor/reviews/Comment.tsx +265 -0
  140. package/src/editor/reviews/Comments.tsx +50 -0
  141. package/src/editor/reviews/PreviewInfo.tsx +35 -0
  142. package/src/editor/reviews/Reviews.tsx +280 -0
  143. package/src/editor/reviews/reviewCommands.tsx +47 -0
  144. package/src/editor/reviews/useReviews.tsx +70 -0
  145. package/src/editor/services/aiService.ts +155 -0
  146. package/src/editor/services/componentDesignerService.ts +151 -0
  147. package/src/editor/services/contentService.ts +159 -0
  148. package/src/editor/services/editService.ts +462 -0
  149. package/src/editor/services/indexService.ts +24 -0
  150. package/src/editor/services/reviewsService.ts +45 -0
  151. package/src/editor/services/serviceHelper.ts +95 -0
  152. package/src/editor/services/systemService.ts +5 -0
  153. package/src/editor/services/translationService.ts +21 -0
  154. package/src/editor/services-server/api.ts +150 -0
  155. package/src/editor/services-server/graphQL.ts +106 -0
  156. package/src/editor/sidebar/ComponentPalette.tsx +146 -0
  157. package/src/editor/sidebar/ComponentTree.tsx +512 -0
  158. package/src/editor/sidebar/ComponentTree2.tsxx +490 -0
  159. package/src/editor/sidebar/Debug.tsx +105 -0
  160. package/src/editor/sidebar/DictionaryEditor.tsx +261 -0
  161. package/src/editor/sidebar/EditHistory.tsx +134 -0
  162. package/src/editor/sidebar/GraphQL.tsx +164 -0
  163. package/src/editor/sidebar/Insert.tsx +35 -0
  164. package/src/editor/sidebar/MainContentTree.tsx +95 -0
  165. package/src/editor/sidebar/Performance.tsx +53 -0
  166. package/src/editor/sidebar/Sessions.tsx +35 -0
  167. package/src/editor/sidebar/Sidebar.tsx +20 -0
  168. package/src/editor/sidebar/SidebarView.tsx +150 -0
  169. package/src/editor/sidebar/Translations.tsx +276 -0
  170. package/src/editor/sidebar/Validation.tsx +102 -0
  171. package/src/editor/sidebar/ViewSelector.tsx +49 -0
  172. package/src/editor/sidebar/Workbox.tsx +209 -0
  173. package/src/editor/ui/CenteredMessage.tsx +7 -0
  174. package/src/editor/ui/CopyToClipboardButton.tsx +23 -0
  175. package/src/editor/ui/DialogButtons.tsx +11 -0
  176. package/src/editor/ui/Icons.tsx +585 -0
  177. package/src/editor/ui/ItemNameDialog.tsx +94 -0
  178. package/src/editor/ui/ItemNameDialogNew.tsx +118 -0
  179. package/src/editor/ui/ItemSearch.tsx +173 -0
  180. package/src/editor/ui/PerfectTree.tsx +550 -0
  181. package/src/editor/ui/Section.tsx +35 -0
  182. package/src/editor/ui/SimpleIconButton.tsx +43 -0
  183. package/src/editor/ui/SimpleMenu.tsx +48 -0
  184. package/src/editor/ui/SimpleTable.tsx +63 -0
  185. package/src/editor/ui/SimpleTabs.tsx +55 -0
  186. package/src/editor/ui/SimpleToolbar.tsx +7 -0
  187. package/src/editor/ui/Spinner.tsx +7 -0
  188. package/src/editor/ui/Splitter.tsx +247 -0
  189. package/src/editor/ui/StackedPanels.tsx +134 -0
  190. package/src/editor/ui/Toolbar.tsx +7 -0
  191. package/src/editor/utils/id-helper.ts +3 -0
  192. package/src/editor/utils/insertOptions.ts +69 -0
  193. package/src/editor/utils/itemutils.ts +29 -0
  194. package/src/editor/utils/useMemoDebug.ts +28 -0
  195. package/src/editor/utils.ts +435 -0
  196. package/src/editor/views/CompareView.tsx +256 -0
  197. package/src/editor/views/EditView.tsx +27 -0
  198. package/src/editor/views/ItemEditor.tsx +58 -0
  199. package/src/editor/views/SingleEditView.tsx +44 -0
  200. package/src/fonts/Geist-Black.woff2 +0 -0
  201. package/src/fonts/Geist-Bold.woff2 +0 -0
  202. package/src/fonts/Geist-ExtraBold.woff2 +0 -0
  203. package/src/fonts/Geist-ExtraLight.woff2 +0 -0
  204. package/src/fonts/Geist-Light.woff2 +0 -0
  205. package/src/fonts/Geist-Medium.woff2 +0 -0
  206. package/src/fonts/Geist-Regular.woff2 +0 -0
  207. package/src/fonts/Geist-SemiBold.woff2 +0 -0
  208. package/src/fonts/Geist-Thin.woff2 +0 -0
  209. package/src/fonts/Geist[wght].woff2 +0 -0
  210. package/src/index.ts +7 -0
  211. package/src/page-wizard/PageWizard.tsx +163 -0
  212. package/src/page-wizard/SelectWizard.tsx +109 -0
  213. package/src/page-wizard/WizardSteps.tsx +207 -0
  214. package/src/page-wizard/service.ts +35 -0
  215. package/src/page-wizard/startPageWizardCommand.ts +27 -0
  216. package/src/page-wizard/steps/BuildPageStep.tsx +266 -0
  217. package/src/page-wizard/steps/CollectStep.tsx +233 -0
  218. package/src/page-wizard/steps/ComponentTypesSelector.tsx +443 -0
  219. package/src/page-wizard/steps/Components.tsx +193 -0
  220. package/src/page-wizard/steps/CreatePage.tsx +285 -0
  221. package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +384 -0
  222. package/src/page-wizard/steps/EditButton.tsx +34 -0
  223. package/src/page-wizard/steps/FieldEditor.tsx +102 -0
  224. package/src/page-wizard/steps/Generate.tsx +32 -0
  225. package/src/page-wizard/steps/ImagesStep.tsx +318 -0
  226. package/src/page-wizard/steps/LayoutStep.tsx +228 -0
  227. package/src/page-wizard/steps/SelectStep.tsx +256 -0
  228. package/src/page-wizard/steps/schema.ts +180 -0
  229. package/src/page-wizard/steps/usePageCreator.ts +279 -0
  230. package/src/splash-screen/NewPage.tsx +232 -0
  231. package/src/splash-screen/SectionHeadline.tsx +21 -0
  232. package/src/splash-screen/SplashScreen.tsx +156 -0
  233. package/src/tour/Tour.tsx +558 -0
  234. package/src/tour/default-tour.tsx +300 -0
  235. package/src/tour/preview-tour.tsx +127 -0
  236. package/src/types.ts +302 -0
  237. package/styles.css +476 -0
  238. package/tsconfig.build.json +21 -0
  239. package/tsconfig.json +11 -0
@@ -0,0 +1,266 @@
1
+ import { useEffect, useState, useCallback, ReactNode } from "react";
2
+ import {
3
+ getIndexStatus,
4
+ rebuildIndex,
5
+ setupIndex,
6
+ setupRebuildJob,
7
+ } from "../services/indexService";
8
+ import { IndexStatus } from "../../types";
9
+ import { Button } from "primereact/button";
10
+ import { Spinner } from "../ui/Spinner";
11
+ import { useEditContext } from "../client/editContext";
12
+ import { FullItem } from "../pageModel";
13
+ import { ProgressSpinner } from "primereact/progressspinner";
14
+
15
+ export function IndexSettings({ index }: { index: { name: string } }) {
16
+ const editContext = useEditContext();
17
+ const [indexStatus, setIndexStatus] = useState<IndexStatus | undefined>(
18
+ undefined
19
+ );
20
+ const [settingsItem, setSettingsItem] = useState<FullItem | undefined>(
21
+ undefined
22
+ );
23
+ const [rebuildJobItem, setRebuildJobItem] = useState<FullItem | undefined>(
24
+ undefined
25
+ );
26
+
27
+ const fetchStatus = useCallback(() => {
28
+ getIndexStatus(index.name).then(async (result) => {
29
+ setIndexStatus(result);
30
+
31
+ if (result?.settingsItemId) {
32
+ const settingsItem = await editContext?.itemsRepository.getItem({
33
+ id: result.settingsItemId,
34
+ language: "en",
35
+ version: 0,
36
+ });
37
+ setSettingsItem(settingsItem);
38
+
39
+ if (result.rebuildJobItemId) {
40
+ const rebuildJobItem = await editContext?.itemsRepository.getItem({
41
+ id: result.rebuildJobItemId,
42
+ language: "en",
43
+ version: 0,
44
+ });
45
+ setRebuildJobItem(rebuildJobItem);
46
+ } else {
47
+ setRebuildJobItem(undefined);
48
+ }
49
+ } else {
50
+ setSettingsItem(undefined);
51
+ setRebuildJobItem(undefined);
52
+ }
53
+ });
54
+ }, [index]);
55
+
56
+ useEffect(() => {
57
+ let interval: NodeJS.Timeout;
58
+ if (indexStatus?.isRunning) {
59
+ interval = setInterval(() => {
60
+ fetchStatus();
61
+ }, 1000);
62
+ }
63
+ return () => {
64
+ if (interval) {
65
+ clearInterval(interval);
66
+ }
67
+ };
68
+ }, [indexStatus?.isRunning, fetchStatus]);
69
+
70
+ useEffect(() => {
71
+ fetchStatus();
72
+ }, [fetchStatus]);
73
+
74
+ useEffect(() => {
75
+ setIndexStatus(undefined);
76
+ }, [index]);
77
+
78
+ if (!indexStatus) {
79
+ return (
80
+ <div className="flex flex-col h-full justify-center items-center gap-2 text-gray-500">
81
+ <Spinner />
82
+ Loading...
83
+ </div>
84
+ );
85
+ }
86
+
87
+ async function setupIndexAndRefresh(index: string) {
88
+ await setupIndex(index);
89
+ setIndexStatus(undefined);
90
+ fetchStatus();
91
+ }
92
+
93
+ async function setupRebuildJobAndRefresh(index: string) {
94
+ await setupRebuildJob(index);
95
+ setIndexStatus(undefined);
96
+ fetchStatus();
97
+ }
98
+
99
+ async function rebuildIndexAndRefresh(index: string) {
100
+ await rebuildIndex(index);
101
+ setTimeout(() => {
102
+ fetchStatus();
103
+ }, 1000);
104
+ }
105
+
106
+ return (
107
+ <div className="flex flex-col px-2 py-1 h-full">
108
+ <div className="flex flex-row items-center border-b p-1 mb-3">
109
+ <div className="">{index.name}</div>
110
+ </div>
111
+ <div className="ml-2">
112
+ {settingsItem && (
113
+ <>
114
+ <IndexProp headline="Settings">
115
+ <a
116
+ className="cursor-pointer underline"
117
+ onClick={() => {
118
+ if (indexStatus.settingsItemId) {
119
+ editContext?.loadItem(indexStatus.settingsItemId);
120
+ editContext?.switchView("content-editor");
121
+ }
122
+ }}
123
+ >
124
+ {settingsItem.path}
125
+ </a>
126
+ </IndexProp>
127
+ <IndexProp headline="Service">{indexStatus.serviceUrl}</IndexProp>
128
+ <IndexProp headline="Name">{indexStatus.name}</IndexProp>
129
+ <IndexProp headline="Rebuild Job">
130
+ {rebuildJobItem && (
131
+ <>
132
+ <a
133
+ className="cursor-pointer underline"
134
+ onClick={() => {
135
+ if (indexStatus.rebuildJobItemId) {
136
+ editContext?.loadItem(indexStatus.rebuildJobItemId);
137
+ editContext?.switchView("content-editor");
138
+ }
139
+ }}
140
+ >
141
+ {rebuildJobItem.path}
142
+ </a>
143
+ {indexStatus.canRebuild && !indexStatus.isRunning && (
144
+ <div className="my-2">
145
+ <Button
146
+ label="Rebuild Index"
147
+ onClick={() => {
148
+ rebuildIndexAndRefresh(index.name);
149
+ }}
150
+ />
151
+ </div>
152
+ )}
153
+ {indexStatus.isRunning && (
154
+ <div className="my-2 flex flex-row items-center justify-start">
155
+ <div className="mr-2" style={{ width: "20px" }}>
156
+ <ProgressSpinner
157
+ style={{ width: "20px", height: "20px" }}
158
+ />{" "}
159
+ </div>
160
+ Rebuilding... {indexStatus.rebuildCount.toLocaleString()}{" "}
161
+ items, {indexStatus.rebuildTokensCount.toLocaleString()}{" "}
162
+ tokens
163
+ </div>
164
+ )}
165
+ </>
166
+ )}
167
+ {!rebuildJobItem && (
168
+ <>
169
+ <div className="text-sm text-gray-500 mb-2">
170
+ No rebuild job found for this index
171
+ </div>
172
+ <Button
173
+ label="Setup Rebuild Job"
174
+ onClick={() => {
175
+ setupRebuildJobAndRefresh(index.name);
176
+ }}
177
+ />
178
+ </>
179
+ )}
180
+ </IndexProp>
181
+ <IndexProp headline="Last Rebuild">
182
+ {indexStatus.lastRebuildStartDateTime
183
+ ? new Date(
184
+ indexStatus.lastRebuildStartDateTime
185
+ ).toLocaleString()
186
+ : "Never"}
187
+ </IndexProp>
188
+ {indexStatus.exists && (
189
+ <>
190
+ <IndexProp headline="Index Status">
191
+ {Object.entries(indexStatus.languages).map(
192
+ ([language, { numberOfItems, lastUpdated, status }]) => (
193
+ <div
194
+ key={language}
195
+ className="flex items-center gap-2 text-xs"
196
+ >
197
+ <div className="font-bold">{language}:</div>
198
+ <span
199
+ className={`text-gray-500 ml-2 ${
200
+ status === "Available"
201
+ ? "text-green-500"
202
+ : "text-yellow-500"
203
+ }`}
204
+ >
205
+ {status}
206
+ </span>
207
+ <span className="text-gray-500">
208
+ Items: {numberOfItems.toLocaleString()}{" "}
209
+ </span>
210
+ <span className="text-gray-500">
211
+ Last updated: {new Date(lastUpdated).toLocaleString()}
212
+ </span>
213
+ </div>
214
+ )
215
+ )}
216
+ </IndexProp>
217
+ </>
218
+ )}
219
+ {indexStatus.errors?.length > 0 && (
220
+ <div>
221
+ <div>Errors:</div>
222
+ {indexStatus.errors.map((error, index) => (
223
+ <div
224
+ key={index}
225
+ className="mt-2 p-2 bg-red-100 rounded-md text-red-800 border border-red-300 "
226
+ >
227
+ <div className="font-bold">{error.message}</div>
228
+ <div className="text-sm">{error.details}</div>
229
+ </div>
230
+ ))}
231
+ </div>
232
+ )}
233
+ </>
234
+ )}
235
+ {!indexStatus?.exists && (
236
+ <div>
237
+ <div className="text-sm text-gray-500 mb-2">
238
+ Index does not exist
239
+ </div>
240
+ <Button
241
+ label="Setup index"
242
+ onClick={() => {
243
+ setupIndexAndRefresh(index.name);
244
+ }}
245
+ />
246
+ </div>
247
+ )}{" "}
248
+ </div>
249
+ </div>
250
+ );
251
+ }
252
+
253
+ function IndexProp({
254
+ headline,
255
+ children,
256
+ }: {
257
+ headline: ReactNode;
258
+ children: ReactNode;
259
+ }) {
260
+ return (
261
+ <div className="mb-2">
262
+ <div className="font-bold text-sm">{headline}</div>
263
+ <div className="text-sm">{children}</div>
264
+ </div>
265
+ );
266
+ }
@@ -0,0 +1,7 @@
1
+ export function Status() {
2
+ return (
3
+ <div className="flex flex-col justify-center items-center h-full">
4
+ Status
5
+ </div>
6
+ );
7
+ }
@@ -0,0 +1,63 @@
1
+ import { EditorWarning } from "../EditorWarning";
2
+ import { EditorWarningProps } from "../EditorWarnings";
3
+ import { useEditContext } from "../client/editContext";
4
+ import { ItemDescriptor } from "../pageModel";
5
+
6
+ export function ItemLocked({ item }: EditorWarningProps) {
7
+ if (!item.canLock) return;
8
+ var editContext = useEditContext();
9
+ if (!editContext) return;
10
+ if (item.hasLock) {
11
+ return (
12
+ <EditorWarning title="Item locked" severity="warning">
13
+ <button
14
+ onClick={() => {
15
+ const items: ItemDescriptor[] = [item];
16
+ editContext!.operations.unlockItems(items);
17
+ }}
18
+ >
19
+ Release lock
20
+ </button>
21
+ </EditorWarning>
22
+ );
23
+ }
24
+ if (item.lockedBy == null) {
25
+ return (
26
+ <EditorWarning title="Item is locked" severity="warning">
27
+ <div>Locked by {item.lockedBy}</div>
28
+ {/* {item.canLock && (
29
+ <button
30
+ onClick={() => {
31
+ const items: ItemDescriptor[] = [item];
32
+ if ((item as ComponentData).linkedComponentItem)
33
+ items.push((item as ComponentData).linkedComponentItem);
34
+
35
+ editContext!.lockItems(items);
36
+ }}
37
+ >
38
+ Grab lock
39
+ </button>
40
+ )} */}
41
+ </EditorWarning>
42
+ );
43
+ }
44
+ // else {
45
+ // return (
46
+ // <EditorWarning title="Item not locked" severity="warning">
47
+ // {item.canLock && (
48
+ // <button
49
+ // onClick={() => {
50
+ // const items: ItemDescriptor[] = [item];
51
+ // if ((item as ComponentData).linkedComponentItem)
52
+ // items.push((item as ComponentData).linkedComponentItem);
53
+
54
+ // editContext!.lockItems(items);
55
+ // }}
56
+ // >
57
+ // Lock item
58
+ // </button>
59
+ // )}
60
+ // </EditorWarning>
61
+ // );
62
+ // }
63
+ }
@@ -0,0 +1,22 @@
1
+ import { EditorWarning } from "../EditorWarning";
2
+ import { EditorWarningProps } from "../EditorWarnings";
3
+ import { useEditContext } from "../client/editContext";
4
+
5
+ export function NoWriteLanguageAccess({ item }: EditorWarningProps) {
6
+ var editContext = useEditContext();
7
+ if (!editContext) return;
8
+ if (!item.canWriteItem) return;
9
+ if (!item.canWriteLanguage) {
10
+ return (
11
+ <EditorWarning
12
+ title="You dont have language write access."
13
+ severity="warning"
14
+ >
15
+ <p>
16
+ You can't edit this item because you don't have write access for
17
+ language {editContext.page?.item.language}.
18
+ </p>
19
+ </EditorWarning>
20
+ );
21
+ }
22
+ }
@@ -0,0 +1,23 @@
1
+ import { EditorWarning } from "../EditorWarning";
2
+ import { EditorWarningProps } from "../EditorWarnings";
3
+ import { useEditContext } from "../client/editContext";
4
+
5
+ export function NoWorkflowWriteAccess({ item }: EditorWarningProps) {
6
+ var editContext = useEditContext();
7
+ if (!editContext) return;
8
+ if (!item.canWriteItem || !item.canWriteLanguage) return;
9
+ if (!item.canWriteWorkflow) {
10
+ return (
11
+ <EditorWarning
12
+ title="You dont have write access in the current workflow state."
13
+ severity="warning"
14
+ >
15
+ <p>
16
+ The item is in the workflow state{" "}
17
+ <span className="font-bold">{item.workflowState}</span> which
18
+ prevents you from editing.
19
+ </p>
20
+ </EditorWarning>
21
+ );
22
+ }
23
+ }
@@ -0,0 +1,15 @@
1
+ import { EditorWarning } from "../EditorWarning";
2
+ import { EditorWarningProps } from "../EditorWarnings";
3
+ import { useEditContext } from "../client/editContext";
4
+
5
+ export function NoWriteAccess({ item }: EditorWarningProps) {
6
+ var editContext = useEditContext();
7
+ if (!editContext) return;
8
+ if (!item.canWriteItem) {
9
+ return (
10
+ <EditorWarning title="You dont have write access." severity="warning">
11
+ <p>You can't edit this item because you don't have write access.</p>
12
+ </EditorWarning>
13
+ );
14
+ }
15
+ }
@@ -0,0 +1,54 @@
1
+ import { EditorWarning } from "../EditorWarning";
2
+ import { EditorWarningProps } from "../EditorWarnings";
3
+
4
+ export function ValidationErrors({ item, editContext }: EditorWarningProps) {
5
+ let validationResult = editContext.validationResult
6
+ ?.find(
7
+ (x) =>
8
+ x.item.id === item.id &&
9
+ x.item.language === item.language &&
10
+ x.item.version === item.version
11
+ )
12
+ ?.results.filter((x) => x.itemId === item.id);
13
+
14
+ if (!validationResult) {
15
+ const pageResult = editContext.validationResult?.find(
16
+ (x) => x.item.id === editContext?.page?.item.id
17
+ );
18
+
19
+ if (pageResult)
20
+ validationResult = pageResult.results.filter((x) => x.itemId === item.id);
21
+ }
22
+
23
+ if (!validationResult?.length) return null;
24
+ const fields = validationResult?.filter((x) => x.fieldId);
25
+
26
+ return (
27
+ <EditorWarning title="Validation" severity="warning">
28
+ {validationResult
29
+ ?.filter((x) => !x.fieldId)
30
+ .map((x) => (
31
+ <div key={x.validator}>{x.message}</div>
32
+ ))}
33
+ {fields?.length > 0 && (
34
+ <div>
35
+ The following fields have validation messages:{" "}
36
+ {fields.map((x) => (
37
+ <span
38
+ className="cursor-pointer font-bold"
39
+ key={x.validator + x.fieldId}
40
+ onClick={() => {
41
+ const field = Object.values(item.fields).find(
42
+ (f) => f.id === x.fieldId
43
+ );
44
+ if (field) editContext.setFocusedField(field.descriptor, false);
45
+ }}
46
+ >
47
+ {x.fieldName}
48
+ </span>
49
+ ))}
50
+ </div>
51
+ )}
52
+ </EditorWarning>
53
+ );
54
+ }
@@ -0,0 +1,9 @@
1
+ import { AttachmentField } from "../fieldTypes";
2
+
3
+ export function AttachmentEditor({ field }: { field: AttachmentField }) {
4
+ return (
5
+ <div>
6
+ <img src={field.value.src} />
7
+ </div>
8
+ );
9
+ }
@@ -0,0 +1,47 @@
1
+ "use client";
2
+
3
+ import { useEditContext } from "../client/editContext";
4
+
5
+ import { Checkbox } from "primereact/checkbox";
6
+ import { useEffect, useState } from "react";
7
+ import { ProgressSpinner } from "primereact/progressspinner";
8
+ import { CheckboxField } from "../fieldTypes";
9
+
10
+ export function CheckboxEditor({
11
+ field,
12
+ readOnly,
13
+ }: {
14
+ field: CheckboxField;
15
+ readOnly?: boolean;
16
+ }) {
17
+ const editContext = useEditContext();
18
+ const [isUpdating, setIsUpdating] = useState(false);
19
+
20
+ useEffect(() => {
21
+ setIsUpdating(false);
22
+ }, [field]);
23
+
24
+ if (!editContext) return;
25
+ const fieldItem = field.descriptor.item;
26
+ if (!fieldItem) return;
27
+
28
+ if (isUpdating) {
29
+ return <ProgressSpinner style={{ width: "18px", height: "18px" }} />;
30
+ }
31
+
32
+ return (
33
+ <Checkbox
34
+ key={fieldItem.id + field.id + fieldItem.language + fieldItem.version}
35
+ checked={field.value}
36
+ disabled={readOnly}
37
+ onClick={() => {
38
+ setIsUpdating(true);
39
+ editContext.operations.editField({
40
+ field: field.descriptor,
41
+ rawValue: field.value ? "0" : "1",
42
+ refresh: "immediate",
43
+ });
44
+ }}
45
+ />
46
+ );
47
+ }
@@ -0,0 +1,75 @@
1
+ "use client";
2
+
3
+ import { Dropdown, DropdownChangeEvent } from "primereact/dropdown";
4
+
5
+ import { useEditContext } from "../client/editContext";
6
+ import { useEffect, useState } from "react";
7
+
8
+ import { getLookupSources } from "../services/editService";
9
+ import { InternalLinkField } from "../fieldTypes";
10
+ import { ItemIdAndName } from "../pageModel";
11
+ import { normalizeGuid } from "../utils";
12
+
13
+ export function DropLinkEditor({
14
+ field,
15
+ readOnly,
16
+ }: {
17
+ field: InternalLinkField;
18
+ readOnly?: boolean;
19
+ }) {
20
+ const editContext = useEditContext();
21
+
22
+ const [lazyItems, setLazyItems] = useState<ItemIdAndName[]>([]);
23
+ const [lazyLoading, setLazyLoading] = useState<boolean>(true);
24
+
25
+ if (!field) return;
26
+
27
+ if (!editContext) return;
28
+
29
+ useEffect(() => {
30
+ onLazyLoad();
31
+ }, [field.descriptor]);
32
+
33
+ const onLazyLoad = async () => {
34
+ setLazyLoading(true);
35
+ const options = await getLookupSources(field, editContext.sessionId);
36
+ setLazyItems(options);
37
+ setLazyLoading(false);
38
+ };
39
+
40
+ return (
41
+ <Dropdown
42
+ value={field.value?.targetItemId}
43
+ disabled={readOnly}
44
+ onChange={(e: DropdownChangeEvent) => {
45
+ editContext?.operations.editField({
46
+ field: field.descriptor,
47
+ rawValue: normalizeGuid(e.value), // typeof e.value === "string" ? e.value : e.value.id, // This has changed in primereact
48
+ });
49
+ }}
50
+ options={lazyItems}
51
+ optionLabel="name"
52
+ optionValue="id"
53
+ placeholder="Select"
54
+ className="w-full md:w-14rem"
55
+ virtualScrollerOptions={{
56
+ lazy: true,
57
+ onLazyLoad: onLazyLoad,
58
+ itemSize: 38,
59
+ // showLoader: true,
60
+ loading: lazyLoading,
61
+ //delay: 250,
62
+ // loadingTemplate: (options) => {
63
+ // return (
64
+ // <div
65
+ // className="flex align-items-center p-2"
66
+ // style={{ height: "38px" }}
67
+ // >
68
+ // <Skeleton width={options.even ? "60%" : "50%"} height="1rem" />
69
+ // </div>
70
+ // );
71
+ // },
72
+ }}
73
+ />
74
+ );
75
+ }
@@ -0,0 +1,84 @@
1
+ "use client";
2
+
3
+ import { Dropdown, DropdownChangeEvent } from "primereact/dropdown";
4
+
5
+ import { useEditContext } from "../client/editContext";
6
+ import { useEffect, useState } from "react";
7
+
8
+ import { getLookupSources } from "../services/editService";
9
+ import { TextField } from "../fieldTypes";
10
+ import { ItemIdAndName } from "../pageModel";
11
+
12
+ export function DropListEditor({
13
+ field,
14
+ readOnly,
15
+ }: {
16
+ field: TextField;
17
+ readOnly?: boolean;
18
+ }) {
19
+ const editContext = useEditContext();
20
+
21
+ const [lazyItems, setLazyItems] = useState<ItemIdAndName[]>([]);
22
+ const [lazyLoading, setLazyLoading] = useState<boolean>(true);
23
+
24
+ if (!field) return;
25
+
26
+ if (!editContext) return;
27
+
28
+ useEffect(() => {
29
+ onLazyLoad();
30
+ }, [field.descriptor]);
31
+
32
+ const onLazyLoad = async () => {
33
+ setLazyLoading(true);
34
+ const options = await getLookupSources(field, editContext.sessionId);
35
+ if (field.value && !options.find((o) => o.name === field.value)) {
36
+ console.log("Adding unknown option", field.value);
37
+ options.unshift({
38
+ id: "unknown",
39
+ name: `[Unknown: ${field.value}]`,
40
+ });
41
+ }
42
+ setLazyItems(options);
43
+ setLazyLoading(false);
44
+ };
45
+
46
+ return (
47
+ <Dropdown
48
+ value={
49
+ lazyItems.find((o) => o.name === field.value)?.name ||
50
+ "[Unknown: " + field.value + "]"
51
+ }
52
+ disabled={readOnly}
53
+ onChange={(e: DropdownChangeEvent) => {
54
+ editContext?.operations.editField({
55
+ field: field.descriptor,
56
+ rawValue: e.value,
57
+ });
58
+ }}
59
+ options={lazyItems}
60
+ optionLabel="name"
61
+ optionValue="name"
62
+ placeholder="Select"
63
+ className="w-full md:w-14rem"
64
+ virtualScrollerOptions={{
65
+ lazy: true,
66
+ onLazyLoad: onLazyLoad,
67
+ itemSize: 38,
68
+ // showLoader: true,
69
+ loading: lazyLoading,
70
+ //delay: 250,
71
+ // loadingTemplate: (options) => {
72
+ // return (
73
+ // <div
74
+ // className="flex align-items-center p-2"
75
+ // style={{ height: "38px" }}
76
+ // >
77
+ // <Skeleton width={options.even ? "60%" : "50%"} height="1rem" />
78
+ // </div>
79
+ // );
80
+ // },
81
+ }}
82
+ />
83
+ );
84
+ }