@actuate-media/cms-admin 0.33.0 → 0.35.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 (51) hide show
  1. package/dist/__tests__/views/ai-settings.render.test.d.ts +2 -0
  2. package/dist/__tests__/views/ai-settings.render.test.d.ts.map +1 -0
  3. package/dist/__tests__/views/ai-settings.render.test.js +229 -0
  4. package/dist/__tests__/views/ai-settings.render.test.js.map +1 -0
  5. package/dist/actuate-admin.css +1 -1
  6. package/dist/views/Settings.d.ts.map +1 -1
  7. package/dist/views/Settings.js +2 -46
  8. package/dist/views/Settings.js.map +1 -1
  9. package/dist/views/settings/AISettingsTab.d.ts +6 -0
  10. package/dist/views/settings/AISettingsTab.d.ts.map +1 -0
  11. package/dist/views/settings/AISettingsTab.js +138 -0
  12. package/dist/views/settings/AISettingsTab.js.map +1 -0
  13. package/dist/views/settings/AiFeaturesCard.d.ts +17 -0
  14. package/dist/views/settings/AiFeaturesCard.d.ts.map +1 -0
  15. package/dist/views/settings/AiFeaturesCard.js +35 -0
  16. package/dist/views/settings/AiFeaturesCard.js.map +1 -0
  17. package/dist/views/settings/CapabilityBadges.d.ts +5 -0
  18. package/dist/views/settings/CapabilityBadges.d.ts.map +1 -0
  19. package/dist/views/settings/CapabilityBadges.js +26 -0
  20. package/dist/views/settings/CapabilityBadges.js.map +1 -0
  21. package/dist/views/settings/ModelSelector.d.ts +12 -0
  22. package/dist/views/settings/ModelSelector.d.ts.map +1 -0
  23. package/dist/views/settings/ModelSelector.js +29 -0
  24. package/dist/views/settings/ModelSelector.js.map +1 -0
  25. package/dist/views/settings/MonthlyUsageCard.d.ts +14 -0
  26. package/dist/views/settings/MonthlyUsageCard.d.ts.map +1 -0
  27. package/dist/views/settings/MonthlyUsageCard.js +30 -0
  28. package/dist/views/settings/MonthlyUsageCard.js.map +1 -0
  29. package/dist/views/settings/ProviderConnectionCard.d.ts +13 -0
  30. package/dist/views/settings/ProviderConnectionCard.d.ts.map +1 -0
  31. package/dist/views/settings/ProviderConnectionCard.js +48 -0
  32. package/dist/views/settings/ProviderConnectionCard.js.map +1 -0
  33. package/dist/views/settings/featureModel.d.ts +25 -0
  34. package/dist/views/settings/featureModel.d.ts.map +1 -0
  35. package/dist/views/settings/featureModel.js +45 -0
  36. package/dist/views/settings/featureModel.js.map +1 -0
  37. package/dist/views/settings/useAiSettings.d.ts +149 -0
  38. package/dist/views/settings/useAiSettings.d.ts.map +1 -0
  39. package/dist/views/settings/useAiSettings.js +297 -0
  40. package/dist/views/settings/useAiSettings.js.map +1 -0
  41. package/package.json +3 -3
  42. package/src/__tests__/views/ai-settings.render.test.tsx +286 -0
  43. package/src/views/Settings.tsx +2 -139
  44. package/src/views/settings/AISettingsTab.tsx +418 -0
  45. package/src/views/settings/AiFeaturesCard.tsx +154 -0
  46. package/src/views/settings/CapabilityBadges.tsx +66 -0
  47. package/src/views/settings/ModelSelector.tsx +115 -0
  48. package/src/views/settings/MonthlyUsageCard.tsx +118 -0
  49. package/src/views/settings/ProviderConnectionCard.tsx +245 -0
  50. package/src/views/settings/featureModel.ts +64 -0
  51. package/src/views/settings/useAiSettings.ts +476 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ai-settings.render.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-settings.render.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/views/ai-settings.render.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,229 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // @vitest-environment happy-dom
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
4
+ import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
5
+ /**
6
+ * Settings > AI reads three backends: /ai/settings (defaults + masked
7
+ * providers), /ai/models (catalog), /ai/usage/summary. Provider connection
8
+ * actions hit /ai/providers/*. Keys are never returned — only a masked last4.
9
+ */
10
+ const SETTINGS_RESPONSE = {
11
+ settings: {
12
+ defaultProviderId: 'p1',
13
+ defaultModelId: 'anthropic:claude-sonnet-4-latest',
14
+ features: [
15
+ {
16
+ key: 'ai.features.contentWriting',
17
+ label: 'Content writing suggestions',
18
+ description: 'Draft, rewrite, summarize content.',
19
+ enabled: true,
20
+ category: 'content',
21
+ requiredCapabilities: ['text'],
22
+ },
23
+ {
24
+ key: 'ai.features.redirectChainFlattening',
25
+ label: 'Redirect chain flattening',
26
+ description: 'Suggest single-hop redirects.',
27
+ enabled: false,
28
+ category: 'seo',
29
+ requiredCapabilities: ['text'],
30
+ },
31
+ ],
32
+ budget: { monthlyTokenLimit: 1000000 },
33
+ },
34
+ providers: [
35
+ {
36
+ id: 'p1',
37
+ provider: 'anthropic',
38
+ displayName: 'Anthropic (Claude)',
39
+ enabled: true,
40
+ status: 'connected',
41
+ apiKeyLast4: 'f12a',
42
+ apiKeySource: 'database',
43
+ keyManagedExternally: false,
44
+ hasKey: true,
45
+ createdAt: '2026-01-01T00:00:00.000Z',
46
+ updatedAt: '2026-01-01T00:00:00.000Z',
47
+ updatedBy: 'u1',
48
+ },
49
+ ],
50
+ defaultModel: null,
51
+ };
52
+ const MODELS = [
53
+ {
54
+ id: 'anthropic:claude-sonnet-4-latest',
55
+ provider: 'anthropic',
56
+ providerModelId: 'claude-sonnet-4-latest',
57
+ displayName: 'Claude Sonnet (balanced)',
58
+ status: 'available',
59
+ capabilities: { text: true, vision: true, toolCalling: true },
60
+ contextWindow: 200000,
61
+ inputModalities: ['text', 'image'],
62
+ outputModalities: ['text'],
63
+ pricing: { inputPerMillion: 3, outputPerMillion: 15 },
64
+ lastSyncedAt: '2026-01-01T00:00:00.000Z',
65
+ source: 'config',
66
+ },
67
+ {
68
+ id: 'anthropic:claude-haiku',
69
+ provider: 'anthropic',
70
+ providerModelId: 'claude-haiku',
71
+ displayName: 'Claude Haiku (fast)',
72
+ status: 'available',
73
+ capabilities: { text: true },
74
+ contextWindow: 200000,
75
+ inputModalities: ['text'],
76
+ outputModalities: ['text'],
77
+ pricing: { inputPerMillion: 0.8, outputPerMillion: 4 },
78
+ lastSyncedAt: '2026-01-01T00:00:00.000Z',
79
+ source: 'config',
80
+ },
81
+ ];
82
+ const USAGE = {
83
+ totalTokens: 412000,
84
+ promptTokens: 0,
85
+ completionTokens: 0,
86
+ monthlyTokenLimit: 1000000,
87
+ periodStart: '2026-06-01T00:00:00.000Z',
88
+ periodEnd: '2026-07-01T00:00:00.000Z',
89
+ runCount: 5,
90
+ };
91
+ // Mutable overrides so individual tests can tweak the loaded shape.
92
+ let settingsResponse = SETTINGS_RESPONSE;
93
+ const cmsApi = vi.fn(async (endpoint, options) => {
94
+ const method = options?.method ?? 'GET';
95
+ if (endpoint === '/ai/settings' && method === 'GET')
96
+ return { data: settingsResponse, status: 200 };
97
+ if (endpoint === '/ai/settings' && method === 'PUT')
98
+ return { data: settingsResponse, status: 200 };
99
+ if (endpoint === '/ai/models' && method === 'GET')
100
+ return { data: { models: MODELS }, status: 200 };
101
+ if (endpoint === '/ai/usage/summary')
102
+ return { data: USAGE, status: 200 };
103
+ if (endpoint === '/ai/providers/p1/test' && method === 'POST') {
104
+ return {
105
+ data: {
106
+ provider: settingsResponse.providers[0],
107
+ result: { ok: true, status: 'connected', message: 'Connection successful.' },
108
+ },
109
+ status: 200,
110
+ };
111
+ }
112
+ if (endpoint === '/ai/providers/p1/sync-models' && method === 'POST') {
113
+ return { data: { models: MODELS, fromFallback: false, warning: null }, status: 200 };
114
+ }
115
+ return { data: {}, status: 200 };
116
+ });
117
+ vi.mock('../../lib/api.js', () => ({
118
+ cmsApi: (e, o) => cmsApi(e, o),
119
+ ensureCsrfToken: vi.fn(async () => { }),
120
+ }));
121
+ vi.mock('sonner', () => ({
122
+ toast: { success: vi.fn(), error: vi.fn(), warning: vi.fn(), loading: vi.fn() },
123
+ }));
124
+ const { AISettingsTab } = await import('../../views/settings/AISettingsTab.js');
125
+ function deepClone(v) {
126
+ return JSON.parse(JSON.stringify(v));
127
+ }
128
+ beforeEach(() => {
129
+ cmsApi.mockClear();
130
+ settingsResponse = deepClone(SETTINGS_RESPONSE);
131
+ });
132
+ describe('AISettingsTab', () => {
133
+ it('loads the default provider, model, and capability badges', async () => {
134
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
135
+ expect(await screen.findByText('AI Assistant')).toBeTruthy();
136
+ const assistant = screen.getByRole('region', { name: 'AI Assistant' });
137
+ expect(within(assistant).getByLabelText('Default model').value).toBe('anthropic:claude-sonnet-4-latest');
138
+ // Capability badges render as text (not color-only).
139
+ expect(within(assistant).getByText('Vision')).toBeTruthy();
140
+ expect(within(assistant).getByText('200,000 token context')).toBeTruthy();
141
+ });
142
+ it('shows real monthly usage (never a fabricated number)', async () => {
143
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
144
+ expect(await screen.findByText('412K tokens used')).toBeTruthy();
145
+ expect(screen.getByRole('progressbar').getAttribute('aria-valuenow')).toBe('41');
146
+ });
147
+ it('refreshes the model catalog via the provider sync endpoint', async () => {
148
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
149
+ const assistant = await screen.findByRole('region', { name: 'AI Assistant' });
150
+ fireEvent.click(within(assistant).getByRole('button', { name: 'Refresh models' }));
151
+ await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/ai/providers/p1/sync-models', expect.objectContaining({ method: 'POST' })));
152
+ });
153
+ it('tests a provider connection', async () => {
154
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
155
+ await screen.findByText('AI Assistant');
156
+ fireEvent.click(screen.getByRole('button', { name: 'Test connection' }));
157
+ await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/ai/providers/p1/test', expect.objectContaining({ method: 'POST' })));
158
+ });
159
+ it('toggles a feature and saves it to /ai/settings', async () => {
160
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
161
+ await screen.findByText('AI Features');
162
+ fireEvent.click(screen.getByRole('switch', { name: 'Content writing suggestions' }));
163
+ const save = screen.getByRole('button', { name: 'Save Changes' });
164
+ expect(save.disabled).toBe(false);
165
+ fireEvent.click(save);
166
+ await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/ai/settings', expect.objectContaining({ method: 'PUT' })));
167
+ const putCall = cmsApi.mock.calls.find(([e, o]) => e === '/ai/settings' && o?.method === 'PUT');
168
+ const body = JSON.parse(putCall[1].body);
169
+ const cw = body.features.find((f) => f.key === 'ai.features.contentWriting');
170
+ expect(cw.enabled).toBe(false);
171
+ });
172
+ it('routes a feature to a specific model and persists the override', async () => {
173
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
174
+ await screen.findByText('AI Features');
175
+ // Only the enabled content-writing feature exposes a per-feature Model select.
176
+ const featuresRegion = screen.getByRole('region', { name: 'AI Features' });
177
+ const select = within(featuresRegion).getByLabelText('Model');
178
+ expect(select.value).toBe(''); // inherits the default
179
+ fireEvent.change(select, { target: { value: 'anthropic:claude-haiku' } });
180
+ const save = screen.getByRole('button', { name: 'Save Changes' });
181
+ expect(save.disabled).toBe(false);
182
+ fireEvent.click(save);
183
+ await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/ai/settings', expect.objectContaining({ method: 'PUT' })));
184
+ const putCall = cmsApi.mock.calls.find(([e, o]) => e === '/ai/settings' && o?.method === 'PUT');
185
+ const body = JSON.parse(putCall[1].body);
186
+ const cw = body.features.find((f) => f.key === 'ai.features.contentWriting');
187
+ expect(cw.modelId).toBe('anthropic:claude-haiku');
188
+ });
189
+ it('warns when a feature would run on a model missing a required capability', async () => {
190
+ settingsResponse = deepClone(SETTINGS_RESPONSE);
191
+ // Alt-text needs vision; route it through the text-only Haiku model.
192
+ settingsResponse.settings.features.push({
193
+ key: 'ai.features.mediaAltText',
194
+ label: 'Auto alt-text for media',
195
+ description: 'Generate alt text for images.',
196
+ enabled: true,
197
+ category: 'media',
198
+ requiredCapabilities: ['vision'],
199
+ modelId: 'anthropic:claude-haiku',
200
+ });
201
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
202
+ await screen.findByText('AI Features');
203
+ expect(await screen.findByText(/can't do vision/i)).toBeTruthy();
204
+ });
205
+ it('is read-only for non-admins', async () => {
206
+ render(_jsx(AISettingsTab, { role: "EDITOR" }));
207
+ expect(await screen.findByText(/read-only access to AI settings/i)).toBeTruthy();
208
+ const assistant = screen.getByRole('region', { name: 'AI Assistant' });
209
+ expect(within(assistant).getByLabelText('Default model').disabled).toBe(true);
210
+ expect(screen.getByRole('switch', { name: 'Content writing suggestions' })
211
+ .disabled).toBe(true);
212
+ });
213
+ it('renders an env-managed key as read-only', async () => {
214
+ settingsResponse = deepClone(SETTINGS_RESPONSE);
215
+ settingsResponse.providers[0].keyManagedExternally = true;
216
+ settingsResponse.providers[0].apiKeySource = 'environment';
217
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
218
+ expect(await screen.findByText('Managed by environment')).toBeTruthy();
219
+ expect(screen.getByText(/set via an environment variable/i)).toBeTruthy();
220
+ });
221
+ it('warns when the configured default model is no longer available', async () => {
222
+ settingsResponse = deepClone(SETTINGS_RESPONSE);
223
+ settingsResponse.settings.defaultModelId = 'anthropic:ghost-model';
224
+ render(_jsx(AISettingsTab, { role: "ADMIN" }));
225
+ await screen.findByText('AI Assistant');
226
+ expect(await screen.findByText(/selected model is no longer offered by the provider/i)).toBeTruthy();
227
+ });
228
+ });
229
+ //# sourceMappingURL=ai-settings.render.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-settings.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/ai-settings.render.test.tsx"],"names":[],"mappings":"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"}