@alpaca-editor/core 1.0.3896 → 1.0.3898

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 (124) hide show
  1. package/dist/components/ActionButton.js +2 -2
  2. package/dist/components/ActionButton.js.map +1 -1
  3. package/dist/components/ui/button.js +3 -3
  4. package/dist/components/ui/button.js.map +1 -1
  5. package/dist/config/config.js +44 -22
  6. package/dist/config/config.js.map +1 -1
  7. package/dist/editor/FieldListField.js +1 -1
  8. package/dist/editor/FieldListField.js.map +1 -1
  9. package/dist/editor/Titlebar.js +2 -1
  10. package/dist/editor/Titlebar.js.map +1 -1
  11. package/dist/editor/client/EditorClient.d.ts +27 -2
  12. package/dist/editor/client/EditorClient.js +140 -1
  13. package/dist/editor/client/EditorClient.js.map +1 -1
  14. package/dist/editor/client/editContext.d.ts +6 -1
  15. package/dist/editor/client/editContext.js.map +1 -1
  16. package/dist/editor/client/itemsRepository.js +1 -1
  17. package/dist/editor/client/itemsRepository.js.map +1 -1
  18. package/dist/editor/client/operations.js +1 -1
  19. package/dist/editor/client/operations.js.map +1 -1
  20. package/dist/editor/control-center/About.d.ts +1 -0
  21. package/dist/editor/control-center/About.js +8 -0
  22. package/dist/editor/control-center/About.js.map +1 -0
  23. package/dist/editor/control-center/ControlCenterMenu.js +3 -0
  24. package/dist/editor/control-center/ControlCenterMenu.js.map +1 -1
  25. package/dist/editor/control-center/Info.d.ts +1 -0
  26. package/dist/editor/control-center/Info.js +10 -0
  27. package/dist/editor/control-center/Info.js.map +1 -0
  28. package/dist/editor/control-center/QuotaInfo.d.ts +1 -0
  29. package/dist/editor/control-center/QuotaInfo.js +102 -0
  30. package/dist/editor/control-center/QuotaInfo.js.map +1 -0
  31. package/dist/editor/control-center/Status.js +69 -2
  32. package/dist/editor/control-center/Status.js.map +1 -1
  33. package/dist/editor/control-center/WebSocketMessages.d.ts +1 -0
  34. package/dist/editor/control-center/WebSocketMessages.js +66 -0
  35. package/dist/editor/control-center/WebSocketMessages.js.map +1 -0
  36. package/dist/editor/page-editor-chrome/FieldActionIndicator.js +7 -6
  37. package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
  38. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  39. package/dist/editor/services/aiService.d.ts +7 -1
  40. package/dist/editor/services/aiService.js +8 -1
  41. package/dist/editor/services/aiService.js.map +1 -1
  42. package/dist/editor/sidebar/ComponentTree.js +1 -1
  43. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  44. package/dist/editor/sidebar/ViewSelector.js +9 -4
  45. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  46. package/dist/editor/ui/Icons.d.ts +19 -1
  47. package/dist/editor/ui/Icons.js +23 -5
  48. package/dist/editor/ui/Icons.js.map +1 -1
  49. package/dist/editor/ui/SimpleMenu.js +1 -1
  50. package/dist/editor/ui/SimpleMenu.js.map +1 -1
  51. package/dist/fonts/index.d.ts +4 -0
  52. package/dist/fonts/index.js +9 -0
  53. package/dist/fonts/index.js.map +1 -0
  54. package/dist/images/wizard-bg.png +0 -0
  55. package/dist/index.d.ts +2 -1
  56. package/dist/index.js +1 -0
  57. package/dist/index.js.map +1 -1
  58. package/dist/page-wizard/WizardBox.d.ts +8 -0
  59. package/dist/page-wizard/WizardBox.js +6 -0
  60. package/dist/page-wizard/WizardBox.js.map +1 -0
  61. package/dist/page-wizard/WizardBoxConnector.d.ts +3 -0
  62. package/dist/page-wizard/WizardBoxConnector.js +6 -0
  63. package/dist/page-wizard/WizardBoxConnector.js.map +1 -0
  64. package/dist/page-wizard/WizardSteps.d.ts +4 -2
  65. package/dist/page-wizard/WizardSteps.js +44 -18
  66. package/dist/page-wizard/WizardSteps.js.map +1 -1
  67. package/dist/page-wizard/steps/CollectStep.js +16 -21
  68. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  69. package/dist/page-wizard/steps/ComponentTypesSelector.js +50 -45
  70. package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
  71. package/dist/page-wizard/steps/CreatePage.js +6 -3
  72. package/dist/page-wizard/steps/CreatePage.js.map +1 -1
  73. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +21 -28
  74. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js.map +1 -1
  75. package/dist/page-wizard/steps/Generate.js +27 -5
  76. package/dist/page-wizard/steps/Generate.js.map +1 -1
  77. package/dist/page-wizard/steps/ImagesStep.js +46 -44
  78. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  79. package/dist/page-wizard/steps/SelectStep.js +11 -19
  80. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  81. package/dist/page-wizard/steps/usePageCreator.js +41 -12
  82. package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
  83. package/dist/revision.d.ts +2 -2
  84. package/dist/revision.js +2 -2
  85. package/dist/styles.css +236 -120
  86. package/images/wizard-bg.png +0 -0
  87. package/package.json +1 -1
  88. package/src/components/ActionButton.tsx +6 -8
  89. package/src/components/ui/button.tsx +3 -3
  90. package/src/config/config.tsx +54 -22
  91. package/src/editor/FieldListField.tsx +2 -2
  92. package/src/editor/Titlebar.tsx +2 -1
  93. package/src/editor/client/EditorClient.tsx +192 -9
  94. package/src/editor/client/editContext.ts +12 -2
  95. package/src/editor/client/itemsRepository.ts +1 -1
  96. package/src/editor/client/operations.ts +1 -1
  97. package/src/editor/control-center/About.tsx +342 -0
  98. package/src/editor/control-center/ControlCenterMenu.tsx +5 -0
  99. package/src/editor/control-center/Info.tsx +104 -0
  100. package/src/editor/control-center/QuotaInfo.tsx +301 -0
  101. package/src/editor/control-center/Status.tsx +108 -2
  102. package/src/editor/control-center/WebSocketMessages.tsx +155 -0
  103. package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +20 -5
  104. package/src/editor/page-viewer/PageViewer.tsx +1 -1
  105. package/src/editor/services/aiService.ts +17 -2
  106. package/src/editor/sidebar/ComponentTree.tsx +1 -1
  107. package/src/editor/sidebar/ViewSelector.tsx +10 -11
  108. package/src/editor/ui/Icons.tsx +146 -26
  109. package/src/editor/ui/SimpleMenu.tsx +1 -1
  110. package/src/fonts/index.ts +10 -0
  111. package/src/index.ts +7 -1
  112. package/src/page-wizard/WizardBox.tsx +40 -0
  113. package/src/page-wizard/WizardBoxConnector.tsx +21 -0
  114. package/src/page-wizard/WizardSteps.tsx +236 -116
  115. package/src/page-wizard/steps/CollectStep.tsx +129 -67
  116. package/src/page-wizard/steps/ComponentTypesSelector.tsx +32 -11
  117. package/src/page-wizard/steps/CreatePage.tsx +130 -84
  118. package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +47 -30
  119. package/src/page-wizard/steps/Generate.tsx +45 -17
  120. package/src/page-wizard/steps/ImagesStep.tsx +161 -141
  121. package/src/page-wizard/steps/SelectStep.tsx +92 -76
  122. package/src/page-wizard/steps/usePageCreator.ts +40 -14
  123. package/src/revision.ts +2 -2
  124. package/styles.css +49 -8
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpaca-editor/core",
3
- "version": "1.0.3896",
3
+ "version": "1.0.3898",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,5 +1,6 @@
1
1
  import { classNames } from "primereact/utils";
2
2
  import React from "react";
3
+ import { Button } from "./ui/button";
3
4
 
4
5
  interface ActionButtonProps {
5
6
  isLoading: boolean;
@@ -21,23 +22,20 @@ export const ActionButton: React.FC<ActionButtonProps> = ({
21
22
  className = "",
22
23
  }) => {
23
24
  return (
24
- <button
25
+ <Button
25
26
  type={type}
26
27
  onClick={onClick}
27
28
  disabled={disabled || isLoading}
28
- className={classNames(
29
- "bg-canvas-pink text-white px-4 py-2 rounded-lg font-medium hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed border hover:border-canvas-pink hover:text-canvas-pink",
30
- className
31
- )}
29
+ className={className}
32
30
  >
33
31
  {isLoading ? (
34
- <div className="flex items-center gap-2 justify-center">
35
- <div className="animate-spin mr-2 h-4 w-4 border-2 border-white border-t-transparent rounded-full"></div>
32
+ <div className="flex items-center justify-center gap-2">
33
+ <div className="mr-2 h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent"></div>
36
34
  <div>{loadingText}</div>
37
35
  </div>
38
36
  ) : (
39
37
  children
40
38
  )}
41
- </button>
39
+ </Button>
42
40
  );
43
41
  };
@@ -10,11 +10,11 @@ const buttonVariants = cva(
10
10
  variants: {
11
11
  variant: {
12
12
  default:
13
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
13
+ "bg-theme-secondary text-primary-foreground shadow-xs hover:bg-theme-secondary/80",
14
14
  destructive:
15
15
  "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16
16
  outline:
17
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
17
+ "border bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18
18
  secondary:
19
19
  "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20
20
  ghost:
@@ -22,7 +22,7 @@ const buttonVariants = cva(
22
22
  link: "text-primary underline-offset-4 hover:underline",
23
23
  },
24
24
  size: {
25
- default: "h-8 px-3 py-2 has-[>svg]:px-3",
25
+ default: "h-8 px-7 py-5 has-[>svg]:px-3",
26
26
  sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27
27
  lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28
28
  icon: "size-9",
@@ -33,7 +33,10 @@ import {
33
33
  GraphQLIcon,
34
34
  JsonIcon,
35
35
  PageWizardIcon,
36
+ TreeIcon,
36
37
  WizardIcon,
38
+ WorkboxIcon,
39
+ UsersIcon,
37
40
  } from "../editor/ui/Icons";
38
41
  import { Debug } from "../editor/sidebar/Debug";
39
42
  import { GraphQL } from "../editor/sidebar/GraphQL";
@@ -68,9 +71,13 @@ import { getDefaultTourSteps } from "../tour/default-tour";
68
71
  import { Translation } from "../editor/sidebar/Translations";
69
72
  import { EditView } from "../editor/views/EditView";
70
73
  import { InsertMenuTemplate } from "../editor/context-menu/InsertMenu";
71
- import { ControlCenterMenu } from "../editor/control-center/ControlCenterMenu";
74
+
72
75
  import { Status } from "../editor/control-center/Status";
73
76
  import { IndexOverview } from "../editor/control-center/IndexOverview";
77
+ import { Info } from "../editor/control-center/Info";
78
+ import { QuotaInfo } from "../editor/control-center/QuotaInfo";
79
+ import { About } from "../editor/control-center/About";
80
+ import { WebSocketMessages } from "../editor/control-center/WebSocketMessages";
74
81
  import { MainContentTree } from "../editor/sidebar/MainContentTree";
75
82
  import { AttachmentEditor } from "../editor/field-types/AttachmentEditor";
76
83
  import { Comments } from "../editor/reviews/Comments";
@@ -93,14 +100,20 @@ import { getWizards } from "../page-wizard/service";
93
100
  import { startPageWizardCommand } from "../page-wizard/startPageWizardCommand";
94
101
  import { ImageFieldEditor } from "../editor/field-types/ImageFieldEditor";
95
102
 
96
- import { Ghost, Layers } from "lucide-react";
103
+ import {
104
+ BookA,
105
+ Ghost,
106
+ Languages,
107
+ Layers,
108
+ MessageCircleMore,
109
+ Settings,
110
+ } from "lucide-react";
97
111
  import { GhostWriter } from "../editor/ai/GhostWriter";
98
112
  import { SecondaryControls } from "../editor/menubar/SecondaryControls";
99
113
 
100
114
  import { Command } from "../editor/commands/commands";
101
115
  import { PreviewSecondaryControls } from "../editor/menubar/PreviewSecondaryControls";
102
116
  import { AboutDialog } from "../editor/client/AboutDialog";
103
- import { CopyMoveMenuTemplate } from "../editor/context-menu/CopyMoveMenu";
104
117
 
105
118
  const defaultRichTextEditorProfile: RichTextEditorProfile = {
106
119
  toolbar: {
@@ -316,6 +329,36 @@ export const getConfiguration = (): EditorConfiguration => {
316
329
 
317
330
  controlCenter: {
318
331
  groups: [
332
+ {
333
+ title: "System",
334
+ icon: <i className="pi pi-info-circle" />,
335
+ panels: [
336
+ {
337
+ id: "info",
338
+ title: "System Info",
339
+ icon: <i className="pi pi-info-circle" />,
340
+ content: <Info />,
341
+ },
342
+ {
343
+ id: "quota",
344
+ title: "AI Quota",
345
+ icon: <i className="pi pi-chart-bar" />,
346
+ content: <QuotaInfo />,
347
+ },
348
+ {
349
+ id: "about",
350
+ title: "About",
351
+ icon: <i className="pi pi-info" />,
352
+ content: <About />,
353
+ },
354
+ {
355
+ id: "websocket-messages",
356
+ title: "WebSocket Messages",
357
+ icon: <i className="pi pi-comments" />,
358
+ content: <WebSocketMessages />,
359
+ },
360
+ ],
361
+ },
319
362
  {
320
363
  title: "Indexing",
321
364
  icon: <i className="pi pi-search" />,
@@ -390,7 +433,7 @@ export const getConfiguration = (): EditorConfiguration => {
390
433
  },
391
434
  {
392
435
  name: "translate",
393
- icon: "pi pi-language",
436
+ icon: <Languages />,
394
437
  title: "Translate",
395
438
  leftSidebar: {
396
439
  panels: [
@@ -408,7 +451,7 @@ export const getConfiguration = (): EditorConfiguration => {
408
451
  {
409
452
  name: "reviews",
410
453
  title: "Reviews",
411
- icon: "pi pi-comments",
454
+ icon: <MessageCircleMore />,
412
455
  leftSidebar: {
413
456
  panels: [
414
457
  {
@@ -434,7 +477,7 @@ export const getConfiguration = (): EditorConfiguration => {
434
477
  {
435
478
  name: "publish",
436
479
  title: "Publish",
437
- icon: "pi pi-globe",
480
+ icon: <WorkboxIcon />,
438
481
 
439
482
  leftSidebar: {
440
483
  panels: [
@@ -460,13 +503,13 @@ export const getConfiguration = (): EditorConfiguration => {
460
503
  {
461
504
  name: "content-editor",
462
505
  title: "Content Editor",
463
- icon: "pi pi-sitemap",
506
+ icon: <TreeIcon />,
464
507
  defaultCenterPanelView: editView,
465
508
  leftSidebar: {
466
509
  panels: [
467
510
  {
468
511
  name: "tree",
469
- icon: "pi pi-sitemap",
512
+ icon: <TreeIcon />,
470
513
  title: "Content",
471
514
  content: <MainContentTree mode="normal" />,
472
515
  initialSize: 80,
@@ -481,7 +524,7 @@ export const getConfiguration = (): EditorConfiguration => {
481
524
  {
482
525
  name: "dictionary",
483
526
  title: "Dictionary",
484
- icon: "pi pi-book",
527
+ icon: <BookA />,
485
528
  leftSidebar: {
486
529
  panels: [
487
530
  {
@@ -498,7 +541,7 @@ export const getConfiguration = (): EditorConfiguration => {
498
541
  {
499
542
  name: "sessions",
500
543
  title: "Sessions",
501
- icon: "pi pi-users",
544
+ icon: <UsersIcon />,
502
545
  leftSidebar: {
503
546
  panels: [
504
547
  {
@@ -610,20 +653,9 @@ export const getConfiguration = (): EditorConfiguration => {
610
653
  {
611
654
  name: "control-center",
612
655
  title: "Control Center",
613
- icon: "pi pi-cog",
656
+ icon: <Settings />,
614
657
  defaultCenterPanelView: <Status />,
615
658
  menuBar: <></>,
616
- leftSidebar: {
617
- panels: [
618
- {
619
- name: "settings",
620
- icon: "pi pi-cog",
621
- title: "Control Center",
622
- content: <ControlCenterMenu />,
623
- initialSize: 30,
624
- },
625
- ],
626
- },
627
659
  },
628
660
  ],
629
661
 
@@ -170,9 +170,9 @@ export default function FieldListField({
170
170
  ></SimpleIconButton>
171
171
  )}
172
172
  {executingAction && executingAction.state === "running" && (
173
- <div className="ml-auto flex items-center gap-3 text-xs">
173
+ <div className="ml-auto flex items-center gap-1.5 text-xs">
174
174
  <i className="pi pi-spin pi-spinner flex items-center text-xs" />{" "}
175
- {executingAction?.actionButton.label}
175
+ {executingAction?.label}
176
176
  </div>
177
177
  )}
178
178
  <OverlayPanel ref={generatorsOverlay} className="p-1">
@@ -2,6 +2,7 @@ import { MenuIcon } from "lucide-react";
2
2
  import { useEditContext } from "./client/editContext";
3
3
  import { useEffect, useState, useRef } from "react";
4
4
  import { createPortal } from "react-dom";
5
+ import { Logo } from "./ui/Icons";
5
6
 
6
7
  export function Titlebar() {
7
8
  const editContext = useEditContext();
@@ -43,7 +44,7 @@ export function Titlebar() {
43
44
  href="/sitecore/shell/sitecore/client/Applications/Launchpad"
44
45
  className="glow-text flex items-center"
45
46
  >
46
- <i className="pi pi-sparkles text-pink-400" />
47
+ <Logo className="h-6 w-6" />
47
48
  <span className="ml-2 font-mono">workbench</span>
48
49
  </a>
49
50
  </div>
@@ -118,23 +118,43 @@ import uuid from "react-uuid";
118
118
  import { flushSync } from "react-dom";
119
119
  import { getSuggestedEdits } from "../services/suggestedEditsService";
120
120
  import { usePageWizard } from "../../page-wizard/usePageWizard";
121
+ import { requestQuota } from "../services/aiService";
121
122
 
122
123
  export type FieldAction = {
123
124
  field: FieldDescriptor;
124
- actionButton: FieldButton;
125
125
  message?: string;
126
126
  state: "running" | "success" | "error";
127
+ label?: string;
127
128
  };
128
129
 
129
- export type WindowSize = {
130
- width: number;
131
- height: number;
132
- };
133
-
130
+ export type WindowSize = { width: number; height: number };
134
131
  export type InsertingState = {
135
132
  positionElement: Element;
136
133
  positionAnchor: "left" | "right" | "top" | "bottom";
137
134
  };
135
+ export type QuotaUsage = {
136
+ totalTokens: number;
137
+ totalImages: number;
138
+ dailyTokens: number;
139
+ dailyImages: number;
140
+ };
141
+ export type QuotaLimits = {
142
+ totalTokens: number;
143
+ dailyTokens: number;
144
+ monthlyTokens: number;
145
+ totalImages: number;
146
+ dailyImages: number;
147
+ monthlyImages: number;
148
+ };
149
+ export type QuotaInfo = { usage: QuotaUsage; limits: QuotaLimits };
150
+
151
+ export type WebSocketMessage = {
152
+ id: string;
153
+ timestamp: string;
154
+ type: string;
155
+ payload: any;
156
+ rawMessage: string;
157
+ };
138
158
 
139
159
  export function EditorClient({
140
160
  configuration,
@@ -284,9 +304,13 @@ export function EditorClient({
284
304
  const [focusFieldComponentId, setFocusFieldComponentId] = useState<string>();
285
305
 
286
306
  const [enableCompletions, setEnableCompletions] = useState(false);
287
-
307
+ const [quotaInfo, setQuotaInfo] = useState<QuotaInfo | null>(null);
288
308
  const pageWizard = usePageWizard();
289
309
 
310
+ const [webSocketMessages, setWebSocketMessages] = useState<
311
+ WebSocketMessage[]
312
+ >([]);
313
+
290
314
  useEffect(() => {
291
315
  const queryMode = searchParams.get("mode");
292
316
  if (queryMode) setMode(queryMode as EditorMode);
@@ -390,6 +414,25 @@ export function EditorClient({
390
414
  if (!event.data.startsWith("{")) return;
391
415
  const message = JSON.parse(event.data);
392
416
 
417
+ // Track all WebSocket messages for debugging/monitoring
418
+ try {
419
+ const webSocketMessage: WebSocketMessage = {
420
+ id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
421
+ timestamp: new Date().toISOString(),
422
+ type: message.type || "unknown",
423
+ payload: message.payload,
424
+ rawMessage: JSON.stringify(message, null, 2),
425
+ };
426
+
427
+ setWebSocketMessages((prev) => {
428
+ const updated = [webSocketMessage, ...prev];
429
+ // Keep only the latest 1000 messages
430
+ return updated.slice(0, 1000);
431
+ });
432
+ } catch (error) {
433
+ console.error("Error tracking WebSocket message:", error);
434
+ }
435
+
393
436
  if (message.type === "active-sessions") {
394
437
  setActiveSessions(() => {
395
438
  return message.payload;
@@ -459,6 +502,69 @@ export function EditorClient({
459
502
  });
460
503
  }
461
504
 
505
+ if (message.type === "executing-field-action") {
506
+ setActiveFieldActions((x) => {
507
+ const payload = message.payload;
508
+ const fieldId = payload.fieldId;
509
+ const item = payload.item;
510
+ const status = payload.status;
511
+ const msg = payload.message;
512
+ const label = payload.label;
513
+
514
+ // Map backend status to FieldAction state
515
+ let state: "running" | "success" | "error";
516
+ switch (status?.toLowerCase()) {
517
+ case "completed":
518
+ case "success":
519
+ state = "success";
520
+ break;
521
+ case "failed":
522
+ case "error":
523
+ state = "error";
524
+ break;
525
+ default:
526
+ state = "running";
527
+ break;
528
+ }
529
+
530
+ // Check if action already exists
531
+ const existingActionIndex = x.findIndex(
532
+ (action) =>
533
+ action.field.fieldId === fieldId &&
534
+ action.field.item.id === item.id &&
535
+ action.field.item.language === item.language &&
536
+ action.field.item.version === item.version,
537
+ );
538
+
539
+ if (existingActionIndex !== -1) {
540
+ // Update existing action
541
+ const newActions = [...x];
542
+ newActions[existingActionIndex]!.state = state;
543
+ newActions[existingActionIndex]!.message = msg;
544
+ return newActions;
545
+ } else {
546
+ // Insert new action
547
+ const fieldDescriptor: FieldDescriptor = {
548
+ fieldId: fieldId,
549
+ item: item,
550
+ };
551
+
552
+ const newAction: FieldAction = {
553
+ field: fieldDescriptor,
554
+ state,
555
+ message: msg,
556
+ label: label,
557
+ };
558
+ console.log(newAction);
559
+ return [...x, newAction];
560
+ }
561
+ });
562
+ }
563
+
564
+ if (message.type === "update-quota") {
565
+ setQuotaInfo(message.payload);
566
+ }
567
+
462
568
  if (message.type === "edit-operation") {
463
569
  const op = message.payload as EditOperation;
464
570
 
@@ -605,7 +711,7 @@ export function EditorClient({
605
711
  socket.addEventListener("open", () => {
606
712
  console.log("Connected!");
607
713
  sendClientInfo();
608
-
714
+ requestQuota();
609
715
  //TODO: Load clients
610
716
  });
611
717
 
@@ -1432,6 +1538,73 @@ export function EditorClient({
1432
1538
  router.push(url.toString(), { scroll: false });
1433
1539
  }, []);
1434
1540
 
1541
+ // Quota checking functions
1542
+ const isQuotaExceeded = useCallback(() => {
1543
+ if (!quotaInfo) return false;
1544
+
1545
+ const { usage, limits } = quotaInfo;
1546
+
1547
+ // Check absolute limits
1548
+ if (limits.totalTokens > 0 && usage.totalTokens >= limits.totalTokens)
1549
+ return true;
1550
+ if (limits.totalImages > 0 && usage.totalImages >= limits.totalImages)
1551
+ return true;
1552
+
1553
+ // For now, we're only checking absolute limits as daily/monthly would require server-side logic
1554
+ // You can extend this to check daily/monthly limits if the server provides that information
1555
+
1556
+ return false;
1557
+ }, [quotaInfo]);
1558
+
1559
+ const getQuotaWarningMessage = useCallback(() => {
1560
+ if (!quotaInfo) return null;
1561
+
1562
+ const { usage, limits } = quotaInfo;
1563
+ const warnings: string[] = [];
1564
+
1565
+ // Check tokens
1566
+ if (limits.totalTokens > 0) {
1567
+ const tokenPercentage = (usage.totalTokens / limits.totalTokens) * 100;
1568
+ if (tokenPercentage >= 100) {
1569
+ warnings.push(
1570
+ `Token limit exceeded (${usage.totalTokens}/${limits.totalTokens})`,
1571
+ );
1572
+ } else if (tokenPercentage >= 90) {
1573
+ warnings.push(
1574
+ `Token usage high: ${Math.round(tokenPercentage)}% (${usage.totalTokens}/${limits.totalTokens})`,
1575
+ );
1576
+ }
1577
+ }
1578
+
1579
+ // Check images
1580
+ if (limits.totalImages > 0) {
1581
+ const imagePercentage = (usage.totalImages / limits.totalImages) * 100;
1582
+ if (imagePercentage >= 100) {
1583
+ warnings.push(
1584
+ `Image limit exceeded (${usage.totalImages}/${limits.totalImages})`,
1585
+ );
1586
+ } else if (imagePercentage >= 90) {
1587
+ warnings.push(
1588
+ `Image usage high: ${Math.round(imagePercentage)}% (${usage.totalImages}/${limits.totalImages})`,
1589
+ );
1590
+ }
1591
+ }
1592
+
1593
+ return warnings.length > 0 ? warnings.join(", ") : null;
1594
+ }, [quotaInfo]);
1595
+
1596
+ // Show warning when quota is exceeded
1597
+ useEffect(() => {
1598
+ const warningMessage = getQuotaWarningMessage();
1599
+ if (warningMessage) {
1600
+ const isExceeded = isQuotaExceeded();
1601
+ showErrorToast({
1602
+ summary: isExceeded ? "AI Quota Exceeded" : "AI Quota Warning",
1603
+ details: warningMessage,
1604
+ });
1605
+ }
1606
+ }, [quotaInfo, getQuotaWarningMessage, isQuotaExceeded, showErrorToast]);
1607
+
1435
1608
  const editContext = useMemo(() => {
1436
1609
  return {
1437
1610
  operations: operationsContext.ops,
@@ -1600,7 +1773,8 @@ export function EditorClient({
1600
1773
 
1601
1774
  const op: FieldAction = {
1602
1775
  field: fieldDescriptor,
1603
- actionButton,
1776
+ // actionButton,
1777
+ label: actionButton.label,
1604
1778
  state: "running",
1605
1779
  };
1606
1780
  const fieldItem = fieldDescriptor.item;
@@ -1807,9 +1981,14 @@ export function EditorClient({
1807
1981
  setShowSuggestedEditsDiff,
1808
1982
  enableCompletions,
1809
1983
  setEnableCompletions,
1984
+ quotaInfo,
1985
+ isQuotaExceeded: isQuotaExceeded(),
1986
+ getQuotaWarningMessage,
1810
1987
  isMobile,
1811
1988
  openDialog,
1812
1989
  pageWizard,
1990
+ webSocketMessages,
1991
+ clearWebSocketMessages: () => setWebSocketMessages([]),
1813
1992
  };
1814
1993
  }, [
1815
1994
  operations,
@@ -1883,9 +2062,13 @@ export function EditorClient({
1883
2062
  setShowSuggestedEdits,
1884
2063
  showSuggestedEditsDiff,
1885
2064
  setShowSuggestedEditsDiff,
2065
+ quotaInfo,
2066
+ isQuotaExceeded,
2067
+ getQuotaWarningMessage,
1886
2068
  isMobile,
1887
2069
  openDialog,
1888
2070
  pageWizard,
2071
+ webSocketMessages,
1889
2072
  ]);
1890
2073
 
1891
2074
  const modifiedFieldsContext = useMemo(() => {
@@ -10,7 +10,12 @@ import React, {
10
10
  import { ToastMessage } from "primereact/toast";
11
11
 
12
12
  import { EditorConfiguration, EditorView } from "../../config/types";
13
- import { FieldAction, InsertingState } from "./EditorClient";
13
+ import {
14
+ FieldAction,
15
+ InsertingState,
16
+ QuotaInfo,
17
+ WebSocketMessage,
18
+ } from "./EditorClient";
14
19
  import { MenuItem } from "primereact/menuitem";
15
20
  import { Command, CommandData } from "../commands/commands";
16
21
  import { ComponentDetails } from "../services/componentDesignerService";
@@ -303,7 +308,9 @@ export type EditContextType = {
303
308
 
304
309
  enableCompletions: boolean;
305
310
  setEnableCompletions: React.Dispatch<React.SetStateAction<boolean>>;
306
-
311
+ quotaInfo: QuotaInfo | null;
312
+ isQuotaExceeded: boolean;
313
+ getQuotaWarningMessage: () => string | null;
307
314
  isMobile: boolean;
308
315
 
309
316
  openDialog: OpenDialog;
@@ -316,6 +323,9 @@ export type EditContextType = {
316
323
  React.SetStateAction<ItemDescriptor | undefined>
317
324
  >;
318
325
  };
326
+
327
+ webSocketMessages: WebSocketMessage[];
328
+ clearWebSocketMessages: () => void;
319
329
  };
320
330
 
321
331
  const EditContext = React.createContext<EditContextType | undefined>(undefined);
@@ -66,7 +66,7 @@ export function useItemsRepository(
66
66
  itemsToLoad.forEach((item) => {
67
67
  const key = generateKey(item);
68
68
  if (!requestGroups.has(key)) {
69
- requestGroups.set(key, item);
69
+ requestGroups.set(key, getItemDescriptor(item));
70
70
  }
71
71
  });
72
72
 
@@ -387,7 +387,7 @@ export function getOperationsContext(
387
387
  value,
388
388
  rawValue,
389
389
  );
390
- editFieldImmediate({ field, value, rawValue, refresh });
390
+ return editFieldImmediate({ field, value, rawValue, refresh });
391
391
  },
392
392
  state.configuration.debounceFieldEditsInterval * 2,
393
393
  { trailing: true },