aimeat 1.17.0 → 1.18.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 (266) hide show
  1. package/dist/.env.example +6 -1
  2. package/dist/locales/en.json +135 -4
  3. package/dist/locales/fi.json +135 -4
  4. package/dist/public/components/Card.js +17 -3
  5. package/dist/public/components/Collapsible.js +39 -0
  6. package/dist/public/components/CopyButton.js +55 -24
  7. package/dist/public/components/DataTable.js +57 -0
  8. package/dist/public/components/EmptyState.js +28 -0
  9. package/dist/public/components/KeyValueRow.js +37 -0
  10. package/dist/public/components/Modal.js +22 -5
  11. package/dist/public/components/Pagination.js +70 -0
  12. package/dist/public/components/SearchBar.js +44 -0
  13. package/dist/public/components/StatusDot.js +29 -0
  14. package/dist/public/components/TagList.js +53 -0
  15. package/dist/public/components/ToggleSwitch.js +28 -0
  16. package/dist/public/components/index.js +41 -1
  17. package/dist/public/css/components/tags.css +24 -0
  18. package/dist/public/css/style-testbed.css +135 -0
  19. package/dist/public/css/theme.css +556 -34
  20. package/dist/public/css/views/admin-agent-integration.css +2 -33
  21. package/dist/public/css/views/admin.css +730 -686
  22. package/dist/public/css/views/agents-detail.css +295 -26
  23. package/dist/public/css/views/help.css +2 -1
  24. package/dist/public/css/views/hobbies.css +53 -33
  25. package/dist/public/css/views/marketplace.css +73 -60
  26. package/dist/public/css/views/openclaw.css +12 -6
  27. package/dist/public/css/views/portal-classic.css +34 -26
  28. package/dist/public/css/views/portal-dev.css +41 -32
  29. package/dist/public/css/views/portal.css +14 -18
  30. package/dist/public/css/views/profile.css +252 -164
  31. package/dist/public/css/views/public-knowledge-viewer.css +18 -6
  32. package/dist/public/css/views/scheduler.css +100 -0
  33. package/dist/public/js/format.js +41 -0
  34. package/dist/public/js/services/generator-spec-validate.js +5 -1
  35. package/dist/public/js/services/schedules.js +53 -0
  36. package/dist/public/js/style-testbed.js +170 -0
  37. package/dist/public/js/theme.js +114 -0
  38. package/dist/public/spa.html +74 -16
  39. package/dist/public/style-testbed.html +420 -0
  40. package/dist/public/views/admin/agent-integration-tab.js +23 -38
  41. package/dist/public/views/admin/agent-tasks-tab.js +14 -21
  42. package/dist/public/views/admin/chat-instances-tab.js +1 -1
  43. package/dist/public/views/admin/config-tab.js +7 -2
  44. package/dist/public/views/admin/cortex-tab.js +20 -14
  45. package/dist/public/views/admin/csm-tab.js +22 -18
  46. package/dist/public/views/admin/directory-tab.js +3 -3
  47. package/dist/public/views/admin/email-tab.js +23 -28
  48. package/dist/public/views/admin/federation-tab.js +15 -5
  49. package/dist/public/views/admin/generator-debug-tab.js +10 -8
  50. package/dist/public/views/admin/genesis-tab.js +4 -4
  51. package/dist/public/views/admin/ghii-tab.js +3 -3
  52. package/dist/public/views/admin/knowledge-tab.js +15 -5
  53. package/dist/public/views/admin/matching-tab.js +3 -3
  54. package/dist/public/views/admin/memory-tab.js +16 -20
  55. package/dist/public/views/admin/msm-tab.js +30 -17
  56. package/dist/public/views/admin/overview-tab.js +7 -7
  57. package/dist/public/views/admin/packages-tab.js +10 -9
  58. package/dist/public/views/admin/portal-tab.js +14 -4
  59. package/dist/public/views/admin/prompts-tab.js +5 -5
  60. package/dist/public/views/admin/push-tab.js +15 -4
  61. package/dist/public/views/admin/realtime-tab.js +3 -3
  62. package/dist/public/views/admin/services-tab.js +18 -27
  63. package/dist/public/views/admin/shared.js +48 -58
  64. package/dist/public/views/admin/sharing-groups-tab.js +5 -10
  65. package/dist/public/views/admin/stats-tab.js +3 -3
  66. package/dist/public/views/guides.js +9 -13
  67. package/dist/public/views/help.js +3 -24
  68. package/dist/public/views/hobbies.js +47 -41
  69. package/dist/public/views/marketplace.js +42 -34
  70. package/dist/public/views/openclaw.js +0 -1
  71. package/dist/public/views/portal-classic.js +4 -15
  72. package/dist/public/views/portal-dev.js +28 -30
  73. package/dist/public/views/portal.js +16 -21
  74. package/dist/public/views/portfolio.js +11 -12
  75. package/dist/public/views/profile/access-tab.js +250 -1
  76. package/dist/public/views/profile/agents/agent-card.js +75 -4
  77. package/dist/public/views/profile/agents/tab-activity.js +15 -13
  78. package/dist/public/views/profile/agents/tab-agent-config.js +60 -6
  79. package/dist/public/views/profile/agents/tab-integration.js +37 -60
  80. package/dist/public/views/profile/agents/tab-messages.js +10 -1
  81. package/dist/public/views/profile/agents/tab-quality.js +25 -19
  82. package/dist/public/views/profile/agents/tab-schedules.js +110 -0
  83. package/dist/public/views/profile/agents-activity-subtab.js +4 -4
  84. package/dist/public/views/profile/agents-services-subtab.js +5 -4
  85. package/dist/public/views/profile/agents-tab.js +141 -37
  86. package/dist/public/views/profile/agents-tasks-subtab.js +93 -13
  87. package/dist/public/views/profile/calibrator-batch.js +5 -11
  88. package/dist/public/views/profile/calibrator-tab.js +4 -9
  89. package/dist/public/views/profile/chat-sessions-tab.js +9 -5
  90. package/dist/public/views/profile/email-tab.js +2 -2
  91. package/dist/public/views/profile/extensions-tab.js +27 -22
  92. package/dist/public/views/profile/federation-tab.js +4 -1
  93. package/dist/public/views/profile/foundry-detail.js +22 -23
  94. package/dist/public/views/profile/foundry-tab.js +12 -13
  95. package/dist/public/views/profile/generator-dashboard/DebugPanel.js +4 -7
  96. package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +4 -1
  97. package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +3 -2
  98. package/dist/public/views/profile/generator-detail.js +26 -30
  99. package/dist/public/views/profile/generator-tab.js +5 -5
  100. package/dist/public/views/profile/knowledge-tab.js +12 -12
  101. package/dist/public/views/profile/landing-page.js +100 -149
  102. package/dist/public/views/profile/memory-tab.js +15 -11
  103. package/dist/public/views/profile/node-stats-tab.js +3 -3
  104. package/dist/public/views/profile/nodes-tab.js +10 -3
  105. package/dist/public/views/profile/notifications-tab.js +3 -3
  106. package/dist/public/views/profile/packages-tab.js +14 -14
  107. package/dist/public/views/profile/scheduler-tab.js +340 -0
  108. package/dist/public/views/profile/services-tab.js +1 -1
  109. package/dist/public/views/profile/shared.js +16 -12
  110. package/dist/public/views/profile/wallet-tab.js +27 -50
  111. package/dist/public/views/profile/work-tab.js +29 -31
  112. package/dist/public/views/profile.js +24 -0
  113. package/dist/public/views/public-knowledge-viewer.js +9 -18
  114. package/dist/src/auth/middleware.d.ts +3 -2
  115. package/dist/src/auth/middleware.d.ts.map +1 -1
  116. package/dist/src/auth/middleware.js +78 -3
  117. package/dist/src/auth/middleware.js.map +1 -1
  118. package/dist/src/cli/init-wizard.d.ts.map +1 -1
  119. package/dist/src/cli/init-wizard.js +13 -1
  120. package/dist/src/cli/init-wizard.js.map +1 -1
  121. package/dist/src/config.d.ts +4 -0
  122. package/dist/src/config.d.ts.map +1 -1
  123. package/dist/src/config.js +10 -1
  124. package/dist/src/config.js.map +1 -1
  125. package/dist/src/generated/api-types.d.ts +625 -3
  126. package/dist/src/generated/api-types.d.ts.map +1 -1
  127. package/dist/src/mcp/agent-schedules.d.ts +23 -0
  128. package/dist/src/mcp/agent-schedules.d.ts.map +1 -0
  129. package/dist/src/mcp/agent-schedules.js +175 -0
  130. package/dist/src/mcp/agent-schedules.js.map +1 -0
  131. package/dist/src/mcp/annotations.d.ts.map +1 -1
  132. package/dist/src/mcp/annotations.js +6 -0
  133. package/dist/src/mcp/annotations.js.map +1 -1
  134. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  135. package/dist/src/mcp/catalog/definitions.js +55 -0
  136. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  137. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  138. package/dist/src/mcp/catalog/scopes.js +12 -0
  139. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  140. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  141. package/dist/src/mcp/catalog/surfaces.js +2 -0
  142. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  143. package/dist/src/mcp/index.d.ts.map +1 -1
  144. package/dist/src/mcp/index.js +2 -0
  145. package/dist/src/mcp/index.js.map +1 -1
  146. package/dist/src/models/schemas.d.ts +1 -0
  147. package/dist/src/models/schemas.d.ts.map +1 -1
  148. package/dist/src/models/schemas.js +4 -0
  149. package/dist/src/models/schemas.js.map +1 -1
  150. package/dist/src/routes/access-tokens.d.ts +17 -0
  151. package/dist/src/routes/access-tokens.d.ts.map +1 -0
  152. package/dist/src/routes/access-tokens.js +164 -0
  153. package/dist/src/routes/access-tokens.js.map +1 -0
  154. package/dist/src/routes/agents.d.ts.map +1 -1
  155. package/dist/src/routes/agents.js +46 -0
  156. package/dist/src/routes/agents.js.map +1 -1
  157. package/dist/src/routes/ai.d.ts +6 -9
  158. package/dist/src/routes/ai.d.ts.map +1 -1
  159. package/dist/src/routes/ai.js +26 -175
  160. package/dist/src/routes/ai.js.map +1 -1
  161. package/dist/src/routes/apps.d.ts.map +1 -1
  162. package/dist/src/routes/apps.js +104 -34
  163. package/dist/src/routes/apps.js.map +1 -1
  164. package/dist/src/routes/auth.d.ts.map +1 -1
  165. package/dist/src/routes/auth.js +77 -4
  166. package/dist/src/routes/auth.js.map +1 -1
  167. package/dist/src/routes/cortex.d.ts +2 -1
  168. package/dist/src/routes/cortex.d.ts.map +1 -1
  169. package/dist/src/routes/cortex.js +13 -8
  170. package/dist/src/routes/cortex.js.map +1 -1
  171. package/dist/src/routes/extensions.d.ts.map +1 -1
  172. package/dist/src/routes/extensions.js +85 -51
  173. package/dist/src/routes/extensions.js.map +1 -1
  174. package/dist/src/routes/generator.d.ts.map +1 -1
  175. package/dist/src/routes/generator.js +109 -43
  176. package/dist/src/routes/generator.js.map +1 -1
  177. package/dist/src/routes/ghii.d.ts.map +1 -1
  178. package/dist/src/routes/ghii.js +34 -13
  179. package/dist/src/routes/ghii.js.map +1 -1
  180. package/dist/src/routes/libs.d.ts +15 -0
  181. package/dist/src/routes/libs.d.ts.map +1 -1
  182. package/dist/src/routes/libs.js +178 -55
  183. package/dist/src/routes/libs.js.map +1 -1
  184. package/dist/src/routes/portal.d.ts.map +1 -1
  185. package/dist/src/routes/portal.js +1 -0
  186. package/dist/src/routes/portal.js.map +1 -1
  187. package/dist/src/routes/schedules.d.ts +33 -0
  188. package/dist/src/routes/schedules.d.ts.map +1 -0
  189. package/dist/src/routes/schedules.js +380 -0
  190. package/dist/src/routes/schedules.js.map +1 -0
  191. package/dist/src/server-bootstrap/config-init.js +2 -2
  192. package/dist/src/server-bootstrap/config-init.js.map +1 -1
  193. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  194. package/dist/src/server-bootstrap/routes-loader.js +7 -0
  195. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  196. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  197. package/dist/src/server-bootstrap/service-init.js +2 -1
  198. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  199. package/dist/src/services/access-token.d.ts +28 -0
  200. package/dist/src/services/access-token.d.ts.map +1 -0
  201. package/dist/src/services/access-token.js +37 -0
  202. package/dist/src/services/access-token.js.map +1 -0
  203. package/dist/src/services/ai-completion.d.ts +83 -0
  204. package/dist/src/services/ai-completion.d.ts.map +1 -0
  205. package/dist/src/services/ai-completion.js +187 -0
  206. package/dist/src/services/ai-completion.js.map +1 -0
  207. package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
  208. package/dist/src/services/generator-prompt-seeds.js +6 -3
  209. package/dist/src/services/generator-prompt-seeds.js.map +1 -1
  210. package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
  211. package/dist/src/services/generator-prompts/spec-validate.js +6 -2
  212. package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
  213. package/dist/src/services/generator-registration.d.ts +12 -4
  214. package/dist/src/services/generator-registration.d.ts.map +1 -1
  215. package/dist/src/services/generator-registration.js +71 -0
  216. package/dist/src/services/generator-registration.js.map +1 -1
  217. package/dist/src/services/generator-validate.d.ts +10 -0
  218. package/dist/src/services/generator-validate.d.ts.map +1 -1
  219. package/dist/src/services/generator-validate.js +180 -36
  220. package/dist/src/services/generator-validate.js.map +1 -1
  221. package/dist/src/services/owner-session.d.ts +43 -0
  222. package/dist/src/services/owner-session.d.ts.map +1 -0
  223. package/dist/src/services/owner-session.js +175 -0
  224. package/dist/src/services/owner-session.js.map +1 -0
  225. package/dist/src/services/schedule-constraints.d.ts +65 -0
  226. package/dist/src/services/schedule-constraints.d.ts.map +1 -0
  227. package/dist/src/services/schedule-constraints.js +106 -0
  228. package/dist/src/services/schedule-constraints.js.map +1 -0
  229. package/dist/src/services/scheduler.d.ts +34 -0
  230. package/dist/src/services/scheduler.d.ts.map +1 -1
  231. package/dist/src/services/scheduler.js +266 -22
  232. package/dist/src/services/scheduler.js.map +1 -1
  233. package/dist/src/services/skill-bundle/generator.js +19 -0
  234. package/dist/src/services/skill-bundle/generator.js.map +1 -1
  235. package/dist/src/storage/interface.d.ts +47 -4
  236. package/dist/src/storage/interface.d.ts.map +1 -1
  237. package/dist/src/storage/interface.js.map +1 -1
  238. package/dist/src/storage/providers/mongodb/index.d.ts +31 -0
  239. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  240. package/dist/src/storage/providers/mongodb/index.js +184 -9
  241. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  242. package/dist/src/storage/providers/sqlite/index.d.ts +31 -0
  243. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  244. package/dist/src/storage/providers/sqlite/index.js +131 -8
  245. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  246. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  247. package/dist/src/storage/providers/sqlite/schema.js +75 -7
  248. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  249. package/dist/src/storage/repositories/pat.repository.d.ts +40 -0
  250. package/dist/src/storage/repositories/pat.repository.d.ts.map +1 -0
  251. package/dist/src/storage/repositories/pat.repository.js +14 -0
  252. package/dist/src/storage/repositories/pat.repository.js.map +1 -0
  253. package/dist/src/storage/repositories/scheduler.repository.d.ts +2 -0
  254. package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -1
  255. package/dist/src/storage/repositories/session.repository.d.ts +51 -0
  256. package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
  257. package/dist/src/storage/repositories/session.repository.js +12 -0
  258. package/dist/src/storage/repositories/session.repository.js.map +1 -1
  259. package/dist/src/utils/env-config.d.ts.map +1 -1
  260. package/dist/src/utils/env-config.js +25 -1
  261. package/dist/src/utils/env-config.js.map +1 -1
  262. package/dist/src/utils/env-validator.d.ts.map +1 -1
  263. package/dist/src/utils/env-validator.js +4 -0
  264. package/dist/src/utils/env-validator.js.map +1 -1
  265. package/package.json +1 -1
  266. package/prisma/schema.prisma +47 -0
package/dist/.env.example CHANGED
@@ -84,7 +84,12 @@ AIMEAT_PORT=40050
84
84
  # AIMEAT_FEDERATION_DEFAULT_SCOPES=memory:read,catalogue:read
85
85
 
86
86
  # ── Auth & Tokens ──────────────────────────────────────────────
87
- # AIMEAT_JWT_TTL=3600 # JWT lifetime in seconds (default: 1h)
87
+ # AIMEAT_JWT_TTL=3600 # Legacy / agent JWT lifetime in seconds (default: 1h)
88
+ # Owner sessions: short access token + rotating httpOnly refresh cookie (no key re-signing).
89
+ # AIMEAT_ACCESS_TTL=900 # Owner access-token (JWT) lifetime in seconds (default: 15min)
90
+ # AIMEAT_REFRESH_IDLE_DAYS=30 # Owner refresh-cookie idle window in days (default: 30)
91
+ # AIMEAT_REFRESH_ABSOLUTE_DAYS=90 # Owner refresh-cookie hard cap in days, never extended (default: 90)
92
+ # AIMEAT_REFRESH_GRACE_MS=60000 # Refresh-rotation grace window in ms for concurrency (default: 60s)
88
93
  # AIMEAT_OTK_TTL_MS=300000 # OTK expiry in ms (default: 5min)
89
94
  # AIMEAT_OTK_GRACE_MS=60000 # OTK grace period in ms (default: 1min)
90
95
 
@@ -1,4 +1,85 @@
1
1
  {
2
+ "profile.landing.home": "Home",
3
+ "profile.landing.menu": "Menu",
4
+ "profile.tabs.scheduler": "Scheduler",
5
+ "profile.agents.detail.tabs.schedules": "Schedules",
6
+ "profile.scheduler.title": "Scheduler",
7
+ "profile.scheduler.desc": "Every recurring job running for your profile — AIMEAT-managed and your agents' own.",
8
+ "profile.scheduler.loading": "Loading schedules…",
9
+ "profile.scheduler.newSchedule": "New schedule",
10
+ "profile.scheduler.close": "Close",
11
+ "profile.scheduler.triggered": "Schedule run started",
12
+ "profile.scheduler.cancelled": "Schedule cancelled",
13
+ "profile.scheduler.created": "Schedule created",
14
+ "profile.scheduler.saving": "Saving…",
15
+ "profile.scheduler.create": "Create schedule",
16
+ "profile.scheduler.confirmCancel": "Cancel this schedule? Future runs will stop.",
17
+ "profile.scheduler.managedTitle": "AIMEAT-managed",
18
+ "profile.scheduler.noManaged": "No managed schedules yet.",
19
+ "profile.scheduler.extTitle": "Extension cron jobs",
20
+ "profile.scheduler.internalTitle": "Agent internal",
21
+ "profile.scheduler.internalNote": "Self-reported by your agents. AIMEAT displays these but does not run them.",
22
+ "profile.scheduler.never": "Never",
23
+ "profile.scheduler.byAgent": "created by agent",
24
+ "profile.scheduler.pause": "Pause",
25
+ "profile.scheduler.resume": "Resume",
26
+ "profile.scheduler.runNow": "Run now",
27
+ "profile.scheduler.cancel": "Cancel",
28
+ "profile.scheduler.agentDesc": "Schedules running for this agent.",
29
+ "profile.scheduler.dispatchedTitle": "AIMEAT-dispatched",
30
+ "profile.scheduler.noDispatched": "No schedules for this agent yet.",
31
+ "profile.scheduler.noInternal": "This agent has not reported any internal schedules.",
32
+ "profile.scheduler.col.name": "Name",
33
+ "profile.scheduler.col.kind": "Type",
34
+ "profile.scheduler.col.cron": "Schedule",
35
+ "profile.scheduler.col.agent": "Agent",
36
+ "profile.scheduler.col.lastRun": "Last run",
37
+ "profile.scheduler.col.nextRun": "Next run",
38
+ "profile.scheduler.col.runs": "Runs",
39
+ "profile.scheduler.col.extension": "Extension",
40
+ "profile.scheduler.kind.ai": "AI",
41
+ "profile.scheduler.kind.agent_task": "Agent task",
42
+ "profile.scheduler.kind.extension": "Extension",
43
+ "profile.scheduler.kind.core": "Core",
44
+ "profile.scheduler.kindHint.ai": "server runs a model on your key",
45
+ "profile.scheduler.kindHint.agent_task": "queues a task for an agent",
46
+ "profile.scheduler.kindHint.extension": "runs an extension action (free)",
47
+ "profile.scheduler.field.kind": "Type",
48
+ "profile.scheduler.field.displayName": "Name",
49
+ "profile.scheduler.field.schedule": "Schedule",
50
+ "profile.scheduler.field.inputKeys": "Input memory keys (comma-separated)",
51
+ "profile.scheduler.field.prompt": "Prompt",
52
+ "profile.scheduler.field.outputKey": "Output memory key (optional)",
53
+ "profile.scheduler.field.agent": "Agent",
54
+ "profile.scheduler.field.taskTitle": "Task title",
55
+ "profile.scheduler.field.taskDescription": "Task description",
56
+ "profile.scheduler.field.extensionName": "Extension name",
57
+ "profile.scheduler.field.actionId": "Action id",
58
+ "profile.scheduler.field.purpose": "Purpose (optional)",
59
+ "profile.scheduler.ph.displayName": "e.g. Morning news translation",
60
+ "profile.scheduler.ph.timezone": "IANA timezone, e.g. Europe/Helsinki",
61
+ "profile.scheduler.ph.inputKeys": "e.g. news.morning.raw, news.sources",
62
+ "profile.scheduler.ph.prompt": "e.g. Translate the news below into Finnish and summarise the top 5 items.",
63
+ "profile.scheduler.ph.outputKey": "auto-generated if left blank",
64
+ "profile.scheduler.ph.agent": "Select an agent…",
65
+ "profile.scheduler.ph.purpose": "Why this runs",
66
+ "profile.scheduler.preset.morning": "Every morning",
67
+ "profile.scheduler.preset.evening": "Every evening",
68
+ "profile.scheduler.preset.hourly": "Hourly",
69
+ "profile.scheduler.preset.custom": "Custom",
70
+ "profile.scheduler.constraints": "Budget guards (optional)",
71
+ "profile.scheduler.maxRuns": "Stop after N runs",
72
+ "profile.scheduler.dailyLimit": "Daily AI spend limit (USD)",
73
+ "profile.scheduler.err.name": "Name is required",
74
+ "profile.scheduler.err.cron": "Schedule (cron) is required",
75
+ "profile.scheduler.err.prompt": "Prompt is required for AI schedules",
76
+ "profile.scheduler.err.agent": "Select an agent",
77
+ "profile.scheduler.err.taskTitle": "Task title is required",
78
+ "profile.scheduler.err.ext": "Extension name and action id are required",
79
+ "profile.scheduler.budgetTitle": "Schedule budget guards",
80
+ "profile.scheduler.budgetDesc": "Default opt-in limits applied to schedules created for this agent.",
81
+ "profile.scheduler.budgetSave": "Save budget guards",
82
+ "profile.scheduler.budgetSaved": "Budget guards saved",
2
83
  "common": {
3
84
  "cancel": "Cancel",
4
85
  "confirm": "Confirm",
@@ -14,7 +95,10 @@
14
95
  "name": "Name",
15
96
  "add": "Add",
16
97
  "yes": "Yes",
17
- "no": "No"
98
+ "no": "No",
99
+ "copy": "Copy",
100
+ "copied": "✓ Copied",
101
+ "error": "Error"
18
102
  },
19
103
  "nav": {
20
104
  "try": "Try it",
@@ -25,7 +109,9 @@
25
109
  "logout": "Log Out",
26
110
  "loggedInAs": "logged in as",
27
111
  "help": "Help",
28
- "admin": "Admin"
112
+ "admin": "Admin",
113
+ "themeToDark": "Switch to dark mode",
114
+ "themeToLight": "Switch to light mode"
29
115
  },
30
116
  "hero": {
31
117
  "title": "Your data is yours. Your AI works for you.",
@@ -325,6 +411,8 @@
325
411
  "domainCatalogue": "Catalogue",
326
412
  "domainGenerator": "Generator",
327
413
  "domainTask": "Tasks",
414
+ "domainCortex": "Cortex (install/activate browser libraries)",
415
+ "domainExt": "Extensions (activate server-side extensions)",
328
416
  "permExecute": "Execute",
329
417
  "permRead": "Read",
330
418
  "permWrite": "Write",
@@ -703,13 +791,16 @@
703
791
  "integration": "Integration",
704
792
  "tasks": "Tasks",
705
793
  "messages": "Messages",
706
- "data_access": "Data Access",
794
+ "data_access": "Memory",
707
795
  "directives": "Directives",
708
796
  "agent_config": "Agent Config",
709
797
  "activity": "Activity",
710
798
  "services": "Services",
711
799
  "quality": "Quality"
712
800
  },
801
+ "changes": {
802
+ "title": "New since you last looked"
803
+ },
713
804
  "quality": {
714
805
  "performanceTitle": "Performance",
715
806
  "performanceDesc": "How much this agent has done and how fast — computed from its tasks.",
@@ -970,7 +1061,7 @@
970
1061
  "readme": "No README published",
971
1062
  "tasks": "No tasks yet. Create a task to give this agent work.",
972
1063
  "messages": "No messages yet. Send a message or use a command.",
973
- "data_access": "No data access configured. Use the buttons below to add tags, memory areas, or knowledge packages.",
1064
+ "data_access": "No memory configured yet. Use the buttons below to add tags, memory areas, or knowledge packages.",
974
1065
  "agent_config": "No configuration files. The agent will push its config files after the skill bundle is installed.",
975
1066
  "activity": "No activity recorded yet. Events will appear here once the agent starts working.",
976
1067
  "services": "No services declared. The agent can declare services during Hello Integration Step 11."
@@ -1423,6 +1514,46 @@
1423
1514
  "hoverReveal": "Click to copy",
1424
1515
  "keepSafe": "Keep this safe — it's your owner recovery key.",
1425
1516
  "keyCopied": "Key copied to clipboard!",
1517
+ "patTitle": "Agent Access Tokens",
1518
+ "patDesc": "Create a revocable token an agent can use (as a Bearer header) to log in and test your apps. One token can be shared across all your agents.",
1519
+ "patLabelRequired": "Give the token a name",
1520
+ "patScopeRequired": "Select at least one scope, or Full / Operator",
1521
+ "patCreateError": "Failed to create token",
1522
+ "patConfirmRevoke": "Revoke token \"{name}\"? Agents using it lose access immediately.",
1523
+ "patRevoked": "Token revoked",
1524
+ "patOperator": "Operator",
1525
+ "patFullOwner": "Full owner",
1526
+ "patScopes": "scopes",
1527
+ "patCreatedTitle": "Token created — copy it now",
1528
+ "patShownOnce": "This token is shown only once. Store it now; you cannot see it again.",
1529
+ "patCopied": "Token copied",
1530
+ "patAgentPrompt": "Ready-made agent prompt",
1531
+ "patPromptCopied": "Prompt copied",
1532
+ "patDone": "Done",
1533
+ "patLoading": "Loading...",
1534
+ "patEmpty": "No access tokens yet.",
1535
+ "patCreatedAt": "Created",
1536
+ "patLastUsed": "Last used",
1537
+ "patNever": "never",
1538
+ "patExpires": "Expires",
1539
+ "patNoExpiry": "No expiry",
1540
+ "patRevoke": "Revoke",
1541
+ "patCreate": "New Token",
1542
+ "patCreateTitle": "Create Access Token",
1543
+ "patLabel": "Name",
1544
+ "patLabelPlaceholder": "e.g. App tester",
1545
+ "patLevel": "Permissions",
1546
+ "patFullOwnerHint": "acts as you; sees all apps & data",
1547
+ "patOperatorHint": "full node administration (master key)",
1548
+ "patMasterKeyWarn": "Master key — guard it like a password",
1549
+ "patSelectScopes": "Scopes",
1550
+ "patReadOwnerData": "Also read my data (otherwise a clean sandbox)",
1551
+ "patExpiry": "Expiry",
1552
+ "patExpiry1d": "24 hours",
1553
+ "patExpiry7d": "7 days",
1554
+ "patExpiry30d": "30 days",
1555
+ "patCreateBtn": "Create Token",
1556
+ "patCancel": "Cancel",
1426
1557
  "mcpEndpoint": "MCP Endpoint",
1427
1558
  "mcpDesc": "Use this URL to connect MCP-compatible AI platforms to your node.",
1428
1559
  "fedTitle": "Federation Access",
@@ -1,4 +1,85 @@
1
1
  {
2
+ "profile.landing.home": "Etusivu",
3
+ "profile.landing.menu": "Valikko",
4
+ "profile.tabs.scheduler": "Ajastin",
5
+ "profile.agents.detail.tabs.schedules": "Ajastukset",
6
+ "profile.scheduler.title": "Ajastin",
7
+ "profile.scheduler.desc": "Kaikki profiilisi toistuvat ajastukset — AIMEATin hallinnoimat ja agenttiesi omat.",
8
+ "profile.scheduler.loading": "Ladataan ajastuksia…",
9
+ "profile.scheduler.newSchedule": "Uusi ajastus",
10
+ "profile.scheduler.close": "Sulje",
11
+ "profile.scheduler.triggered": "Ajastuksen suoritus käynnistetty",
12
+ "profile.scheduler.cancelled": "Ajastus peruttu",
13
+ "profile.scheduler.created": "Ajastus luotu",
14
+ "profile.scheduler.saving": "Tallennetaan…",
15
+ "profile.scheduler.create": "Luo ajastus",
16
+ "profile.scheduler.confirmCancel": "Perutaanko tämä ajastus? Tulevat suoritukset pysäytetään.",
17
+ "profile.scheduler.managedTitle": "AIMEATin hallinnoimat",
18
+ "profile.scheduler.noManaged": "Ei vielä hallinnoituja ajastuksia.",
19
+ "profile.scheduler.extTitle": "Laajennusten cron-työt",
20
+ "profile.scheduler.internalTitle": "Agentin sisäiset",
21
+ "profile.scheduler.internalNote": "Agenttiesi itse ilmoittamat. AIMEAT näyttää nämä mutta ei suorita niitä.",
22
+ "profile.scheduler.never": "Ei koskaan",
23
+ "profile.scheduler.byAgent": "agentin luoma",
24
+ "profile.scheduler.pause": "Keskeytä",
25
+ "profile.scheduler.resume": "Jatka",
26
+ "profile.scheduler.runNow": "Suorita nyt",
27
+ "profile.scheduler.cancel": "Peruuta",
28
+ "profile.scheduler.agentDesc": "Tälle agentille ajossa olevat ajastukset.",
29
+ "profile.scheduler.dispatchedTitle": "AIMEATin lähettämät",
30
+ "profile.scheduler.noDispatched": "Ei vielä ajastuksia tälle agentille.",
31
+ "profile.scheduler.noInternal": "Tämä agentti ei ole ilmoittanut sisäisiä ajastuksia.",
32
+ "profile.scheduler.col.name": "Nimi",
33
+ "profile.scheduler.col.kind": "Tyyppi",
34
+ "profile.scheduler.col.cron": "Ajastus",
35
+ "profile.scheduler.col.agent": "Agentti",
36
+ "profile.scheduler.col.lastRun": "Edellinen ajo",
37
+ "profile.scheduler.col.nextRun": "Seuraava ajo",
38
+ "profile.scheduler.col.runs": "Ajot",
39
+ "profile.scheduler.col.extension": "Laajennus",
40
+ "profile.scheduler.kind.ai": "Tekoäly",
41
+ "profile.scheduler.kind.agent_task": "Agenttitehtävä",
42
+ "profile.scheduler.kind.extension": "Laajennus",
43
+ "profile.scheduler.kind.core": "Ydin",
44
+ "profile.scheduler.kindHint.ai": "palvelin ajaa mallin avaimellasi",
45
+ "profile.scheduler.kindHint.agent_task": "lisää tehtävän agentin jonoon",
46
+ "profile.scheduler.kindHint.extension": "ajaa laajennuksen toiminnon (ilmainen)",
47
+ "profile.scheduler.field.kind": "Tyyppi",
48
+ "profile.scheduler.field.displayName": "Nimi",
49
+ "profile.scheduler.field.schedule": "Ajastus",
50
+ "profile.scheduler.field.inputKeys": "Syötteen muistiavaimet (pilkuin eroteltuna)",
51
+ "profile.scheduler.field.prompt": "Kehote",
52
+ "profile.scheduler.field.outputKey": "Tuloksen muistiavain (valinnainen)",
53
+ "profile.scheduler.field.agent": "Agentti",
54
+ "profile.scheduler.field.taskTitle": "Tehtävän otsikko",
55
+ "profile.scheduler.field.taskDescription": "Tehtävän kuvaus",
56
+ "profile.scheduler.field.extensionName": "Laajennuksen nimi",
57
+ "profile.scheduler.field.actionId": "Toiminnon tunnus",
58
+ "profile.scheduler.field.purpose": "Tarkoitus (valinnainen)",
59
+ "profile.scheduler.ph.displayName": "esim. Aamu-uutisten käännös",
60
+ "profile.scheduler.ph.timezone": "IANA-aikavyöhyke, esim. Europe/Helsinki",
61
+ "profile.scheduler.ph.inputKeys": "esim. news.morning.raw, news.sources",
62
+ "profile.scheduler.ph.prompt": "esim. Käännä alla olevat uutiset suomeksi ja tiivistä 5 tärkeintä.",
63
+ "profile.scheduler.ph.outputKey": "luodaan automaattisesti jos tyhjä",
64
+ "profile.scheduler.ph.agent": "Valitse agentti…",
65
+ "profile.scheduler.ph.purpose": "Miksi tämä ajetaan",
66
+ "profile.scheduler.preset.morning": "Joka aamu",
67
+ "profile.scheduler.preset.evening": "Joka ilta",
68
+ "profile.scheduler.preset.hourly": "Tunneittain",
69
+ "profile.scheduler.preset.custom": "Mukautettu",
70
+ "profile.scheduler.constraints": "Budjettirajat (valinnainen)",
71
+ "profile.scheduler.maxRuns": "Pysäytä N ajon jälkeen",
72
+ "profile.scheduler.dailyLimit": "Päivittäinen tekoälykulujen raja (USD)",
73
+ "profile.scheduler.err.name": "Nimi vaaditaan",
74
+ "profile.scheduler.err.cron": "Ajastus (cron) vaaditaan",
75
+ "profile.scheduler.err.prompt": "Kehote vaaditaan tekoälyajastuksille",
76
+ "profile.scheduler.err.agent": "Valitse agentti",
77
+ "profile.scheduler.err.taskTitle": "Tehtävän otsikko vaaditaan",
78
+ "profile.scheduler.err.ext": "Laajennuksen nimi ja toiminnon tunnus vaaditaan",
79
+ "profile.scheduler.budgetTitle": "Ajastusten budjettirajat",
80
+ "profile.scheduler.budgetDesc": "Oletusarvoiset valinnaiset rajat, jotka koskevat tälle agentille luotuja ajastuksia.",
81
+ "profile.scheduler.budgetSave": "Tallenna budjettirajat",
82
+ "profile.scheduler.budgetSaved": "Budjettirajat tallennettu",
2
83
  "common": {
3
84
  "cancel": "Peruuta",
4
85
  "confirm": "Vahvista",
@@ -14,7 +95,10 @@
14
95
  "name": "Nimi",
15
96
  "add": "Lisää",
16
97
  "yes": "Kyllä",
17
- "no": "Ei"
98
+ "no": "Ei",
99
+ "copy": "Kopioi",
100
+ "copied": "✓ Kopioitu",
101
+ "error": "Virhe"
18
102
  },
19
103
  "nav": {
20
104
  "try": "Kokeile",
@@ -25,7 +109,9 @@
25
109
  "logout": "Kirjaudu ulos",
26
110
  "loggedInAs": "kirjautuneena",
27
111
  "help": "Apua",
28
- "admin": "Hallinta"
112
+ "admin": "Hallinta",
113
+ "themeToDark": "Vaihda tummaan tilaan",
114
+ "themeToLight": "Vaihda vaaleaan tilaan"
29
115
  },
30
116
  "hero": {
31
117
  "title": "Tietosi on sinun. AI:si työskentelee puolestasi.",
@@ -325,6 +411,8 @@
325
411
  "domainCatalogue": "Hakemisto",
326
412
  "domainGenerator": "Generaattori",
327
413
  "domainTask": "Tehtävät",
414
+ "domainCortex": "Cortex (asenna/aktivoi selainkirjastoja)",
415
+ "domainExt": "Laajennukset (aktivoi palvelinpuolen laajennuksia)",
328
416
  "permExecute": "Suoritus",
329
417
  "permRead": "Luku",
330
418
  "permWrite": "Kirjoitus",
@@ -703,13 +791,16 @@
703
791
  "integration": "Integraatio",
704
792
  "tasks": "Tehtävät",
705
793
  "messages": "Viestit",
706
- "data_access": "Datayhteydet",
794
+ "data_access": "Muisti",
707
795
  "directives": "Ohjeistukset",
708
796
  "agent_config": "Agenttiasetukset",
709
797
  "activity": "Toiminta",
710
798
  "services": "Palvelut",
711
799
  "quality": "Laatu"
712
800
  },
801
+ "changes": {
802
+ "title": "Uutta sitten kun viimeksi katsoit"
803
+ },
713
804
  "quality": {
714
805
  "performanceTitle": "Suorituskyky",
715
806
  "performanceDesc": "Kuinka paljon agentti on tehnyt ja kuinka nopeasti — laskettu sen tehtävistä.",
@@ -970,7 +1061,7 @@
970
1061
  "readme": "Ei README:tä julkaistu",
971
1062
  "tasks": "Ei tehtäviä. Luo tehtävä antaaksesi agentille työtä.",
972
1063
  "messages": "Ei viestejä. Lähetä viesti tai käytä komentoa.",
973
- "data_access": "Ei datayhteyksien asetuksia. Lisää tunnisteita, muistialueita tai tietopaketteja alla olevilla painikkeilla.",
1064
+ "data_access": "Ei muistia määritetty. Lisää tunnisteita, muistialueita tai tietopaketteja alla olevilla painikkeilla.",
974
1065
  "agent_config": "Ei asetustiedostoja. Agentti lähettää asetustiedostot taitopaketin asennuksen jälkeen.",
975
1066
  "activity": "Ei tallennettua toimintaa. Tapahtumat ilmestyvät tähän kun agentti aloittaa työskentelyn.",
976
1067
  "services": "Ei ilmoitettuja palveluja. Agentti voi ilmoittaa palvelut Hello-integraation vaiheessa 11."
@@ -1423,6 +1514,46 @@
1423
1514
  "hoverReveal": "Klikkaa kopioidaksesi",
1424
1515
  "keepSafe": "Pidä tämä turvassa — se on palautusavaimesi.",
1425
1516
  "keyCopied": "Avain kopioitu leikepöydälle!",
1517
+ "patTitle": "Agenttien käyttötokenit",
1518
+ "patDesc": "Luo peruutettava token, jota agentti voi käyttää (Bearer-headerina) kirjautuakseen ja testatakseen appejasi. Yhtä tokenia voi jakaa kaikille agenteillesi.",
1519
+ "patLabelRequired": "Anna tokenille nimi",
1520
+ "patScopeRequired": "Valitse vähintään yksi scope, tai Full / Operator",
1521
+ "patCreateError": "Tokenin luonti epäonnistui",
1522
+ "patConfirmRevoke": "Peruutetaanko token \"{name}\"? Sitä käyttävät agentit menettävät pääsyn heti.",
1523
+ "patRevoked": "Token peruutettu",
1524
+ "patOperator": "Operaattori",
1525
+ "patFullOwner": "Täysi omistaja",
1526
+ "patScopes": "scopea",
1527
+ "patCreatedTitle": "Token luotu — kopioi se nyt",
1528
+ "patShownOnce": "Token näytetään vain kerran. Tallenna se nyt; et näe sitä enää uudelleen.",
1529
+ "patCopied": "Token kopioitu",
1530
+ "patAgentPrompt": "Valmis agentti-promptti",
1531
+ "patPromptCopied": "Promptti kopioitu",
1532
+ "patDone": "Valmis",
1533
+ "patLoading": "Ladataan...",
1534
+ "patEmpty": "Ei käyttötokeneita vielä.",
1535
+ "patCreatedAt": "Luotu",
1536
+ "patLastUsed": "Viimeksi käytetty",
1537
+ "patNever": "ei koskaan",
1538
+ "patExpires": "Vanhenee",
1539
+ "patNoExpiry": "Ei vanhene",
1540
+ "patRevoke": "Peruuta",
1541
+ "patCreate": "Uusi token",
1542
+ "patCreateTitle": "Luo käyttötoken",
1543
+ "patLabel": "Nimi",
1544
+ "patLabelPlaceholder": "esim. App-testaaja",
1545
+ "patLevel": "Oikeudet",
1546
+ "patFullOwnerHint": "toimii sinuna; näkee kaikki appsit ja datan",
1547
+ "patOperatorHint": "koko noden hallinta (master-avain)",
1548
+ "patMasterKeyWarn": "Master-avain — säilytä kuin salasana",
1549
+ "patSelectScopes": "Scopet",
1550
+ "patReadOwnerData": "Lue myös minun dataani (muuten puhdas hiekkalaatikko)",
1551
+ "patExpiry": "Vanheneminen",
1552
+ "patExpiry1d": "24 tuntia",
1553
+ "patExpiry7d": "7 päivää",
1554
+ "patExpiry30d": "30 päivää",
1555
+ "patCreateBtn": "Luo token",
1556
+ "patCancel": "Peruuta",
1426
1557
  "mcpEndpoint": "MCP-päätepiste",
1427
1558
  "mcpDesc": "Käytä tätä URL:iä yhdistääksesi MCP-yhteensopivat AI-alustat solmuusi.",
1428
1559
  "fedTitle": "Federaatioyhteys",
@@ -1,14 +1,28 @@
1
+ /**
2
+ * @file Card.js
3
+ * @description Canonical themed card container (.card). Renders an optional
4
+ * header (title/subtitle) and arbitrary children. The `variant` prop selects
5
+ * a tokenized modifier — `variant="glass"` adds `.card-glass` (the former
6
+ * profile `.pf-glass-card` appearance) so profile's GlassCard can delegate here.
7
+ * @structure Card({ title, subtitle, onClick, hoverable, className, variant, children })
8
+ * @usage import { Card } from '/components/Card.js'; html`<${Card} variant="glass">…<//>`
9
+ * @version-history
10
+ * v1.0.0 — prior — Initial canonical card (title/subtitle/hoverable/className).
11
+ * v1.1.0 — 2026-06-02 — Component unification (#22): add `variant` prop;
12
+ * `variant="glass"` appends `.card-glass` so profile's GlassCard folds into Card.
13
+ */
1
14
  import { h } from 'preact';
2
15
  import htm from 'htm';
3
16
  const html = htm.bind(h);
4
17
 
5
18
  /**
6
19
  * Card — themed card container.
7
- * @param {{ title?: string, subtitle?: string, onClick?: () => void, hoverable?: boolean, className?: string, children: any }} props
20
+ * @param {{ title?: string, subtitle?: string, onClick?: () => void, hoverable?: boolean, className?: string, variant?: 'glass', children: any }} props
8
21
  */
9
- export function Card({ title, subtitle, onClick, hoverable = true, className = '', children }) {
22
+ export function Card({ title, subtitle, onClick, hoverable = true, className = '', variant, children }) {
23
+ const variantClass = variant === 'glass' ? 'card-glass' : '';
10
24
  return html`
11
- <div class="card ${hoverable ? 'card-hoverable' : ''} ${className}" onClick=${onClick}>
25
+ <div class="card ${variantClass} ${hoverable ? 'card-hoverable' : ''} ${className}" onClick=${onClick}>
12
26
  ${(title || subtitle) && html`
13
27
  <div class="card-header">
14
28
  ${title && html`<span class="card-title">${title}</span>`}
@@ -0,0 +1,39 @@
1
+ import { h } from 'preact';
2
+ import htm from 'htm';
3
+ const html = htm.bind(h);
4
+
5
+ /**
6
+ * @file Collapsible.js
7
+ * @description Canonical expand/collapse (chevron) section — a clickable header
8
+ * (title + a chevron that rotates 180° when open) with its body rendered only
9
+ * while open. CONTROLLED component: the parent owns the `open` state and is
10
+ * notified via `onToggle`. Backed by `.collapsible*` in theme.css, whose colors
11
+ * are all theme tokens so it flips correctly in dark mode. Establishes the
12
+ * canonical shape for the hand-rolled toggles scattered across views
13
+ * (.expand-btn + .pf-chevron, .scope-advanced-toggle, .pkv-entry-arrow); those
14
+ * bespoke toggles are left in place where their expanded markup is wired into
15
+ * view state — this is the target for new collapsible sections.
16
+ * @structure Collapsible({ title, open, onToggle, children }) — renders
17
+ * `<div class="collapsible">` containing a `.collapsible-header` button
18
+ * (title + `.collapsible-chevron` with an `.open` modifier) and, when open, a
19
+ * `.collapsible-body` wrapping the children.
20
+ * @usage
21
+ * import { Collapsible } from '/components/index.js';
22
+ * const [open, setOpen] = useState(false);
23
+ * html`<${Collapsible} title=${t('...')} open=${open} onToggle=${() => setOpen(!open)}>
24
+ * ${body}
25
+ * <//>`
26
+ * @version-history
27
+ * v1.0.0 — 2026-06-02 — Component unification (#23): created canonical
28
+ * expand/collapse section, consolidating the .expand-btn + .pf-chevron,
29
+ * .scope-advanced-toggle and .pkv-entry-arrow toggle patterns.
30
+ */
31
+ export function Collapsible({ title, open, onToggle, children }) {
32
+ return html`<div class="collapsible">
33
+ <button type="button" class="collapsible-header" aria-expanded=${!!open} onClick=${onToggle}>
34
+ <span class="collapsible-title">${title}</span>
35
+ <span class="collapsible-chevron ${open ? 'open' : ''}">▼</span>
36
+ </button>
37
+ ${open && html`<div class="collapsible-body">${children}</div>`}
38
+ </div>`;
39
+ }
@@ -1,24 +1,55 @@
1
- import { h } from 'preact';
2
- import { useState, useCallback } from 'preact/hooks';
3
- import htm from 'htm';
4
- import { copyToClipboard } from '/js/utils.js';
5
- const html = htm.bind(h);
6
-
7
- /**
8
- * CopyButton button with visual feedback after copying.
9
- * @param {{ text: string, label?: string, className?: string }} props
10
- */
11
- export function CopyButton({ text, label = 'Copy', className = '' }) {
12
- const [copied, setCopied] = useState(false);
13
-
14
- const handleCopy = useCallback(async () => {
15
- await copyToClipboard(text);
16
- setCopied(true);
17
- setTimeout(() => setCopied(false), 2000);
18
- }, [text]);
19
-
20
- return html`
21
- <button class="btn-ghost ${className}" onClick=${handleCopy}>
22
- ${copied ? '✓ Copied' : label}
23
- </button>`;
24
- }
1
+ /**
2
+ * @file CopyButton.js
3
+ * @description Canonical clipboard button — copies `text` and shows a brief
4
+ * "copied" confirmation. Replaces the ~80 hand-rolled clipboard sites; the
5
+ * actual copy is delegated to /js/utils.js copyToClipboard.
6
+ * @structure CopyButton({ text, label?, copiedLabel?, className?, title?, onCopied? })
7
+ * @usage import { CopyButton } from '/components/CopyButton.js';
8
+ * html`<${CopyButton} text=${value} />`
9
+ * html`<${CopyButton} text=${value} label=${t('x.copyUrl')} onCopied=${() => showToast('Copied')} />`
10
+ * @version-history
11
+ * v1.0.0 2026-03 Initial copy button with copied-state feedback
12
+ * v1.1.0 2026-06-02 — i18n the labels (default t('common.copy') / t('common.copied')),
13
+ * add onCopied hook (for sites that also toast), copiedLabel, title, type="button",
14
+ * and a `copied` class in the confirmed state (so bespoke classes like
15
+ * .dv-copy-btn.copied / .copy-btn.copied can style it) — for the #1 sweep.
16
+ * v1.1.1 — 2026-06-02 — Compute the button class as a single interpolated string
17
+ * (className-or-base + optional `copied` modifier) — cleaner than two attribute
18
+ * holes and avoids a trailing space. Browser-verified: copied→"…btn-sm copied",
19
+ * default→"btn-ghost". (A stale cached build had briefly masked the copied class
20
+ * during testing — htm itself handles multi-hole class attributes fine.)
21
+ */
22
+ import { h } from 'preact';
23
+ import { useState, useCallback } from 'preact/hooks';
24
+ import htm from 'htm';
25
+ import { copyToClipboard } from '/js/utils.js';
26
+ import { t } from '/js/i18n.js';
27
+ const html = htm.bind(h);
28
+
29
+ /**
30
+ * CopyButton — button with visual feedback after copying.
31
+ * @param {{ text: string, label?: string, copiedLabel?: string, className?: string,
32
+ * title?: string, onCopied?: () => void }} props
33
+ * - label / copiedLabel default to i18n t('common.copy') / t('common.copied')
34
+ * - onCopied: optional callback after a successful copy (e.g. to also show a toast)
35
+ */
36
+ export function CopyButton({ text, label, copiedLabel, className = '', title, onCopied }) {
37
+ const [copied, setCopied] = useState(false);
38
+
39
+ const handleCopy = useCallback(async () => {
40
+ await copyToClipboard(text);
41
+ setCopied(true);
42
+ if (onCopied) onCopied();
43
+ setTimeout(() => setCopied(false), 2000);
44
+ }, [text, onCopied]);
45
+
46
+ // Class as a single computed string: className replaces the btn-ghost base
47
+ // (so callers can pass btn-primary/btn-outline/etc.), plus the `copied` modifier
48
+ // when confirmed (bespoke styles like .hlp-copy-btn.copied hook onto it).
49
+ const cls = `${className || 'btn-ghost'}${copied ? ' copied' : ''}`;
50
+
51
+ return html`
52
+ <button class=${cls} type="button" title=${title} onClick=${handleCopy}>
53
+ ${copied ? (copiedLabel || t('common.copied')) : (label || t('common.copy'))}
54
+ </button>`;
55
+ }
@@ -0,0 +1,57 @@
1
+ import { h } from 'preact';
2
+ import htm from 'htm';
3
+ const html = htm.bind(h);
4
+
5
+ /**
6
+ * @file DataTable.js
7
+ * @description Canonical generic table primitive — renders a plain
8
+ * `<table class="data-table ${className}">` (optionally inside a `.scrollable`
9
+ * wrapper) backed by the shared `.data-table` block in theme.css, so the table
10
+ * look (header row, cell padding, borders, hover) is one tokenized source of
11
+ * truth that flips correctly in dark mode. Unlike the admin `DataTable` (which
12
+ * wraps this in an `.adm-card`), this component renders NO card/container — the
13
+ * caller supplies its own wrapper (`.card`, `.adm-card`, etc.).
14
+ * @structure DataTable({ headers, rows, scroll, className })
15
+ * - headers: array of column header cells (string or VNode)
16
+ * - rows: array of rows; each row is an array of cells. A cell may be:
17
+ * • a primitive/VNode → rendered as plain `<td>`
18
+ * • `{ text, mono?, title?, _html? }` → `<td class="mono"? title=...>`;
19
+ * when `_html: true`, `text` is rendered as raw HTML (see SECURITY).
20
+ * - scroll: when truthy, wraps the table in `<div class="scrollable">`
21
+ * - className: extra class(es) appended to `.data-table` (e.g. for column-width
22
+ * or per-view tweaks)
23
+ * @usage
24
+ * import { DataTable } from '/components/index.js';
25
+ * html`<div class="card"><${DataTable} headers=${['Key','Value']} rows=${rows} /></div>`
26
+ *
27
+ * SECURITY: When a cell object has `_html: true`, `cell.text` is rendered as raw
28
+ * HTML via dangerouslySetInnerHTML. Callers MUST ensure `cell.text` is sanitized
29
+ * (use escHtml() for any user-generated content). Only use `_html` for trusted,
30
+ * server-generated markup like badges.
31
+ *
32
+ * @version-history
33
+ * v1.0.0 — 2026-06-02 — Component unification (#13): created canonical generic
34
+ * DataTable (same _html/mono cell protocol as admin's), backing the shared
35
+ * .data-table CSS. The admin shared.js DataTable now wraps this in .adm-card.
36
+ */
37
+ export function DataTable({ headers, rows, scroll, className }) {
38
+ const cls = `data-table${className ? ` ${className}` : ''}`;
39
+ const table = html`<table class=${cls}>
40
+ <thead><tr>${headers.map(hd => html`<th>${hd}</th>`)}</tr></thead>
41
+ <tbody>
42
+ ${rows.map(row => html`<tr>
43
+ ${row.map(cell => {
44
+ if (cell && typeof cell === 'object' && cell._html) {
45
+ return html`<td class=${cell.mono ? 'mono' : ''} title=${cell.title || ''}
46
+ dangerouslySetInnerHTML=${{ __html: cell.text }}></td>`;
47
+ }
48
+ if (cell && typeof cell === 'object' && cell.mono) {
49
+ return html`<td class="mono" title=${cell.title || ''}>${cell.text}</td>`;
50
+ }
51
+ return html`<td>${cell}</td>`;
52
+ })}
53
+ </tr>`)}
54
+ </tbody>
55
+ </table>`;
56
+ return scroll ? html`<div class="scrollable">${table}</div>` : table;
57
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file EmptyState.js
3
+ * @description Canonical empty-state placeholder — a centered muted message with an
4
+ * optional icon. Replaces the per-view clones (pf-empty / mk-empty / hb-empty /
5
+ * agd-empty / pkg-empty …) and the bare `<div class="empty">` scattered across the
6
+ * frontend. Renders the themed `.empty` class so it flips with dark/light mode.
7
+ * @structure EmptyState({ icon?, text, children? })
8
+ * @usage import { EmptyState } from '/components/EmptyState.js';
9
+ * html`<${EmptyState} text=${t('x.empty')} />`
10
+ * html`<${EmptyState} icon="🎯" text=${t('x.noMatches')} />`
11
+ * @version-history
12
+ * v1.0.0 — 2026-06-02 — Component unification (#9): single empty-state primitive
13
+ * (themed .empty + optional .empty-icon); admin Empty() delegates to it.
14
+ */
15
+ import { h } from 'preact';
16
+ import htm from 'htm';
17
+ const html = htm.bind(h);
18
+
19
+ /**
20
+ * EmptyState — centered muted placeholder.
21
+ * @param {{ icon?: string, text?: any, children?: any }} props
22
+ */
23
+ export function EmptyState({ icon, text, children }) {
24
+ return html`<div class="empty">
25
+ ${icon ? html`<span class="empty-icon">${icon}</span>` : ''}
26
+ ${text != null ? text : children}
27
+ </div>`;
28
+ }