@burdenoff/microfe-channel 2026.830.1 → 2026.830.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/channel/ChannelRoot.d.ts.map +1 -1
  2. package/dist/channel/ChannelRoot.js +32 -35
  3. package/dist/channel/ChannelRoot.js.map +1 -1
  4. package/dist/channel/components/AdapterCredentialsForm.d.ts.map +1 -1
  5. package/dist/channel/components/AdapterCredentialsForm.js +52 -58
  6. package/dist/channel/components/AdapterCredentialsForm.js.map +1 -1
  7. package/dist/channel/components/FeatureNotEnabled.d.ts.map +1 -1
  8. package/dist/channel/components/FeatureNotEnabled.js +27 -22
  9. package/dist/channel/components/FeatureNotEnabled.js.map +1 -1
  10. package/dist/channel/components/MarkdownEditor.d.ts.map +1 -1
  11. package/dist/channel/components/MarkdownEditor.js +78 -77
  12. package/dist/channel/components/MarkdownEditor.js.map +1 -1
  13. package/dist/channel/components/PermissionGuard.d.ts.map +1 -1
  14. package/dist/channel/components/PermissionGuard.js +6 -9
  15. package/dist/channel/components/PermissionGuard.js.map +1 -1
  16. package/dist/channel/hooks/useTr.d.ts +17 -0
  17. package/dist/channel/hooks/useTr.d.ts.map +1 -0
  18. package/dist/channel/hooks/useTr.js +14 -0
  19. package/dist/channel/hooks/useTr.js.map +1 -0
  20. package/dist/channel/modules/channels/i18n.js +24 -24
  21. package/dist/channel/modules/channels/i18n.js.map +1 -1
  22. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js +2 -2
  23. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -1
  24. package/dist/channel/modules/channels/pages/ChannelSettingsPage.d.ts.map +1 -1
  25. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +232 -226
  26. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
  27. package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts.map +1 -1
  28. package/dist/channel/modules/channels/pages/ChannelUsersPage.js +152 -146
  29. package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
  30. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.d.ts.map +1 -1
  31. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +112 -114
  32. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
  33. package/dist/channel/modules/channels/pages/CreateChannelPage.d.ts.map +1 -1
  34. package/dist/channel/modules/channels/pages/CreateChannelPage.js +300 -269
  35. package/dist/channel/modules/channels/pages/CreateChannelPage.js.map +1 -1
  36. package/dist/channel/modules/channels/pages/CreateConnectionPage.d.ts.map +1 -1
  37. package/dist/channel/modules/channels/pages/CreateConnectionPage.js +108 -102
  38. package/dist/channel/modules/channels/pages/CreateConnectionPage.js.map +1 -1
  39. package/dist/channel/modules/channels/pages/EditChannelPage.d.ts.map +1 -1
  40. package/dist/channel/modules/channels/pages/EditChannelPage.js +384 -343
  41. package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
  42. package/dist/channel/modules/channels/pages/SendMessagePage.d.ts.map +1 -1
  43. package/dist/channel/modules/channels/pages/SendMessagePage.js +170 -156
  44. package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -1
  45. package/dist/channel/pages/ChannelLandingPage.d.ts.map +1 -1
  46. package/dist/channel/pages/ChannelLandingPage.js +47 -50
  47. package/dist/channel/pages/ChannelLandingPage.js.map +1 -1
  48. package/dist/translations/en.d.ts +271 -4
  49. package/dist/translations/en.d.ts.map +1 -1
  50. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ChannelRoot.d.ts","sourceRoot":"","sources":["../../src/channel/ChannelRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,OAAO,KAAK,EAAW,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGzD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA+F5C,CAAC"}
1
+ {"version":3,"file":"ChannelRoot.d.ts","sourceRoot":"","sources":["../../src/channel/ChannelRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,OAAO,KAAK,EAAW,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGzD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAwF5C,CAAC"}
@@ -1,75 +1,72 @@
1
- import { ChannelProvider as e } from "./providers/ChannelProvider.js";
2
- import { ChannelRoutes as t } from "./ChannelRoutes.js";
3
- import { useCallback as n, useEffect as r } from "react";
1
+ import { useTr as e } from "./hooks/useTr.js";
2
+ import { ChannelProvider as t } from "./providers/ChannelProvider.js";
3
+ import { ChannelRoutes as n } from "./ChannelRoutes.js";
4
+ import { useEffect as r } from "react";
4
5
  import { ErrorBoundary as i } from "@burdenoff/fe-libs/shared/components";
5
- import { useI18n as a } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
- import { Cable as o, Radio as s, Send as c, Settings as l } from "lucide-react";
7
- import { jsx as u } from "react/jsx-runtime";
6
+ import { Cable as a, Radio as o, Send as s, Settings as c } from "lucide-react";
7
+ import { jsx as l } from "react/jsx-runtime";
8
8
  //#region src/channel/ChannelRoot.tsx
9
- var d = (d) => {
10
- let { registerNavItems: f, registerFooterItems: p, basePath: m = "/" } = d, { t: h } = a(), g = n((e, t) => {
11
- let n = h(e);
12
- return n === e ? t : n;
13
- }, [h]), _ = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
9
+ var u = (u) => {
10
+ let { registerNavItems: d, registerFooterItems: f, basePath: p = "/" } = u, m = e(), h = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
14
11
  return r(() => {
15
- if (f) return f([
12
+ if (d) return d([
16
13
  {
17
14
  id: "channel-channels",
18
- label: g("channel.channels", "Channels"),
19
- path: m === "/" ? "/" : _(m, "list"),
20
- icon: /* @__PURE__ */ u(s, { size: 20 }),
15
+ label: m("channel.channels", "Channels"),
16
+ path: p === "/" ? "/" : h(p, "list"),
17
+ icon: /* @__PURE__ */ l(o, { size: 20 }),
21
18
  order: 100,
22
19
  group: "channel"
23
20
  },
24
21
  {
25
22
  id: "channel-connections",
26
- label: g("channel.connections", "Connections"),
27
- path: _(m, "connections"),
28
- icon: /* @__PURE__ */ u(o, { size: 20 }),
23
+ label: m("channel.connections", "Connections"),
24
+ path: h(p, "connections"),
25
+ icon: /* @__PURE__ */ l(a, { size: 20 }),
29
26
  order: 110,
30
27
  group: "channel"
31
28
  },
32
29
  {
33
30
  id: "channel-send",
34
- label: g("channel.sendMessage", "Send Message"),
35
- path: _(m, "send"),
36
- icon: /* @__PURE__ */ u(c, { size: 20 }),
31
+ label: m("channel.sendMessage", "Send Message"),
32
+ path: h(p, "send"),
33
+ icon: /* @__PURE__ */ l(s, { size: 20 }),
37
34
  order: 120,
38
35
  group: "channel"
39
36
  },
40
37
  {
41
38
  id: "channel-settings",
42
- label: g("channel.settings", "Settings"),
43
- path: _(m, "settings"),
44
- icon: /* @__PURE__ */ u(l, { size: 20 }),
39
+ label: m("channel.settings", "Settings"),
40
+ path: h(p, "settings"),
41
+ icon: /* @__PURE__ */ l(c, { size: 20 }),
45
42
  order: 130,
46
43
  group: "channel"
47
44
  }
48
45
  ]);
49
46
  }, [
50
- f,
51
- m,
52
- g
47
+ d,
48
+ p,
49
+ m
53
50
  ]), r(() => {
54
- if (p) return p([{
51
+ if (f) return f([{
55
52
  id: "channel-status",
56
- label: g("channel.channelsReady", "Channels Ready"),
53
+ label: m("channel.channelsReady", "Channels Ready"),
57
54
  type: "status",
58
55
  order: 10,
59
56
  section: "left"
60
57
  }]);
61
- }, [p, g]), /* @__PURE__ */ u(i, {
62
- fallback: /* @__PURE__ */ u("div", {
58
+ }, [f, m]), /* @__PURE__ */ l(i, {
59
+ fallback: /* @__PURE__ */ l("div", {
63
60
  className: "p-6 text-center text-text-secondary",
64
61
  children: "Something went wrong loading this module. Please refresh the page."
65
62
  }),
66
- children: /* @__PURE__ */ u(e, {
67
- ...d,
68
- children: /* @__PURE__ */ u(t, {})
63
+ children: /* @__PURE__ */ l(t, {
64
+ ...u,
65
+ children: /* @__PURE__ */ l(n, {})
69
66
  })
70
67
  });
71
68
  };
72
69
  //#endregion
73
- export { d as ChannelRoot };
70
+ export { u as ChannelRoot };
74
71
 
75
72
  //# sourceMappingURL=ChannelRoot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChannelRoot.js","names":[],"sources":["../../src/channel/ChannelRoot.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useEffect, useCallback } from 'react';\nimport { ErrorBoundary } from '@burdenoff/fe-libs/shared/components';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Radio, Cable, Send, Settings } from 'lucide-react';\nimport { ChannelProvider } from './providers/ChannelProvider';\nimport type { NavItem, ChannelRootProps } from './types';\nimport { ChannelRoutes } from './ChannelRoutes';\n\n/**\n * Root component for the Channel microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { ChannelRoot, type ChannelRootProps } from '@burdenoff/microfe-channel';\n *\n * function App() {\n * const props: ChannelRootProps = {\n * basePath: '/channels',\n * navigate: (path) => router.push(path),\n * currentUser: { id: '1', email: 'user@example.com', firstName: 'John', lastName: 'Doe' },\n * workspaceId: 'ws-123',\n * organizationId: 'org-123',\n * apiGatewayUrl: 'https://api.example.com/workspaces/graphql',\n * authToken: 'token',\n * registerNavItems: (items) => { return () => {}; },\n * };\n *\n * return <ChannelRoot {...props} />;\n * }\n * ```\n */\nexport const ChannelRoot: FC<ChannelRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'channel-channels',\n label: tr('channel.channels', 'Channels'),\n path: basePath === '/' ? '/' : joinPath(basePath, 'list'),\n icon: <Radio size={20} />,\n order: 100,\n group: 'channel',\n },\n {\n id: 'channel-connections',\n label: tr('channel.connections', 'Connections'),\n path: joinPath(basePath, 'connections'),\n icon: <Cable size={20} />,\n order: 110,\n group: 'channel',\n },\n {\n id: 'channel-send',\n label: tr('channel.sendMessage', 'Send Message'),\n path: joinPath(basePath, 'send'),\n icon: <Send size={20} />,\n order: 120,\n group: 'channel',\n },\n {\n id: 'channel-settings',\n label: tr('channel.settings', 'Settings'),\n path: joinPath(basePath, 'settings'),\n icon: <Settings size={20} />,\n order: 130,\n group: 'channel',\n },\n ];\n\n // Register and get cleanup function\n const cleanup = registerNavItems(navItems);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, tr]);\n\n // Register footer items (example: Channel status indicator in left section)\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'channel-status',\n label: tr('channel.channelsReady', 'Channels Ready'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n Something went wrong loading this module. Please refresh the page.\n </div>\n }\n >\n <ChannelProvider {...props}>\n <ChannelRoutes />\n </ChannelProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;AAoCA,IAAa,KAAqC,MAAU;CAC1D,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,QAAQ,GAC5D,EAAE,SAAM,GAAS,EACjB,IAAK,GACR,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAE,CACJ,EAGK,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AAoEtD,QA/DA,QAAgB;AACT,QAyCL,QAHgB,EApCY;GAC1B;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,WAAW;IACzC,MAAM,MAAa,MAAM,MAAM,EAAS,GAAU,OAAO;IACzD,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,uBAAuB,cAAc;IAC/C,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,uBAAuB,eAAe;IAChD,MAAM,EAAS,GAAU,OAAO;IAChC,MAAM,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IACxB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,WAAW;IACzC,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACF,CAGyC;IAIzC;EAAC;EAAkB;EAAU;EAAG,CAAC,EAGpC,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO,EAAG,yBAAyB,iBAAiB;GACpD,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAG,CAAC,EAG3B,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aAAsC;GAE/C,CAAA;YAGR,kBAAC,GAAD;GAAiB,GAAI;aACnB,kBAAC,GAAD,EAAiB,CAAA;GACD,CAAA;EACJ,CAAA"}
1
+ {"version":3,"file":"ChannelRoot.js","names":[],"sources":["../../src/channel/ChannelRoot.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useEffect, useCallback } from 'react';\nimport { ErrorBoundary } from '@burdenoff/fe-libs/shared/components';\nimport { useTr } from './hooks/useTr';\nimport { Radio, Cable, Send, Settings } from 'lucide-react';\nimport { ChannelProvider } from './providers/ChannelProvider';\nimport type { NavItem, ChannelRootProps } from './types';\nimport { ChannelRoutes } from './ChannelRoutes';\n\n/**\n * Root component for the Channel microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { ChannelRoot, type ChannelRootProps } from '@burdenoff/microfe-channel';\n *\n * function App() {\n * const props: ChannelRootProps = {\n * basePath: '/channels',\n * navigate: (path) => router.push(path),\n * currentUser: { id: '1', email: 'user@example.com', firstName: 'John', lastName: 'Doe' },\n * workspaceId: 'ws-123',\n * organizationId: 'org-123',\n * apiGatewayUrl: 'https://api.example.com/workspaces/graphql',\n * authToken: 'token',\n * registerNavItems: (items) => { return () => {}; },\n * };\n *\n * return <ChannelRoot {...props} />;\n * }\n * ```\n */\nexport const ChannelRoot: FC<ChannelRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const tr = useTr();\n\n // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'channel-channels',\n label: tr('channel.channels', 'Channels'),\n path: basePath === '/' ? '/' : joinPath(basePath, 'list'),\n icon: <Radio size={20} />,\n order: 100,\n group: 'channel',\n },\n {\n id: 'channel-connections',\n label: tr('channel.connections', 'Connections'),\n path: joinPath(basePath, 'connections'),\n icon: <Cable size={20} />,\n order: 110,\n group: 'channel',\n },\n {\n id: 'channel-send',\n label: tr('channel.sendMessage', 'Send Message'),\n path: joinPath(basePath, 'send'),\n icon: <Send size={20} />,\n order: 120,\n group: 'channel',\n },\n {\n id: 'channel-settings',\n label: tr('channel.settings', 'Settings'),\n path: joinPath(basePath, 'settings'),\n icon: <Settings size={20} />,\n order: 130,\n group: 'channel',\n },\n ];\n\n // Register and get cleanup function\n const cleanup = registerNavItems(navItems);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, tr]);\n\n // Register footer items (example: Channel status indicator in left section)\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'channel-status',\n label: tr('channel.channelsReady', 'Channels Ready'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n Something went wrong loading this module. Please refresh the page.\n </div>\n }\n >\n <ChannelProvider {...props}>\n <ChannelRoutes />\n </ChannelProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;AAoCA,IAAa,KAAqC,MAAU;CAC1D,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,QAAQ,GAC5D,IAAK,GAAO,EAGZ,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AAoEtD,QA/DA,QAAgB;AACT,QAyCL,QAHgB,EApCY;GAC1B;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,WAAW;IACzC,MAAM,MAAa,MAAM,MAAM,EAAS,GAAU,OAAO;IACzD,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,uBAAuB,cAAc;IAC/C,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,uBAAuB,eAAe;IAChD,MAAM,EAAS,GAAU,OAAO;IAChC,MAAM,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IACxB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,WAAW;IACzC,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACF,CAGyC;IAIzC;EAAC;EAAkB;EAAU;EAAG,CAAC,EAGpC,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO,EAAG,yBAAyB,iBAAiB;GACpD,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAG,CAAC,EAG3B,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aAAsC;GAE/C,CAAA;YAGR,kBAAC,GAAD;GAAiB,GAAI;aACnB,kBAAC,GAAD,EAAiB,CAAA;GACD,CAAA;EACJ,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"AdapterCredentialsForm.d.ts","sourceRoot":"","sources":["../../../src/channel/components/AdapterCredentialsForm.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAQxD,UAAU,2BAA2B;IACnC,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACzD,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAgB,sBAAsB,CAAC,EACrC,WAAW,EACX,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,QAAgB,EAChB,oBAA2B,GAC5B,EAAE,2BAA2B,+BAwP7B;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,WAAW,EACX,WAAW,GACZ,EAAE;IACD,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,sCA8BA"}
1
+ {"version":3,"file":"AdapterCredentialsForm.d.ts","sourceRoot":"","sources":["../../../src/channel/components/AdapterCredentialsForm.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAQxD,UAAU,2BAA2B;IACnC,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACzD,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAgB,sBAAsB,CAAC,EACrC,WAAW,EACX,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,QAAgB,EAChB,oBAA2B,GAC5B,EAAE,2BAA2B,+BAsP7B;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,WAAW,EACX,WAAW,GACZ,EAAE;IACD,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,sCA0BA"}
@@ -1,25 +1,22 @@
1
- import { getAdapterCredentialSchema as e, getDefaultCredentials as t, validateCredentials as n } from "../config/adapterCredentials.js";
2
- import { useEffect as r, useState as i } from "react";
3
- import { useI18n as a } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
1
+ import { useTr as e } from "../hooks/useTr.js";
2
+ import { getAdapterCredentialSchema as t, getDefaultCredentials as n, validateCredentials as r } from "../config/adapterCredentials.js";
3
+ import { useEffect as i, useState as a } from "react";
4
4
  import { AlertCircle as o, CheckCircle2 as s, ExternalLink as c, Eye as l, EyeOff as u } from "lucide-react";
5
5
  import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
6
6
  //#region src/channel/components/AdapterCredentialsForm.tsx
7
7
  function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g, disabled: _ = !1, showPlatformMetadata: v = !0 }) {
8
- let { t: y } = a(), b = (e, t) => {
9
- let n = y(e);
10
- return n === e ? t : n;
11
- }, [x, S] = i({}), [C, w] = i({}), T = e(s);
12
- if (r(() => {
8
+ let y = e(), [b, x] = a({}), [S, C] = a({}), w = t(s);
9
+ if (i(() => {
13
10
  if (s) {
14
11
  let e = {
15
- ...t(s),
12
+ ...n(s),
16
13
  ...m
17
14
  };
18
15
  JSON.stringify(e) !== JSON.stringify(m) && h(e);
19
16
  }
20
- }, [s]), r(() => {
17
+ }, [s]), i(() => {
21
18
  if (g && s) {
22
- let { valid: e, errors: t } = n(s, m);
19
+ let { valid: e, errors: t } = r(s, m);
23
20
  g(e, t);
24
21
  }
25
22
  }, [
@@ -30,10 +27,10 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
30
27
  className: "text-center py-6 text-text-secondary",
31
28
  children: /* @__PURE__ */ f("p", {
32
29
  className: "text-sm",
33
- children: b("channel.selectAdapterType", "Select an adapter type to configure credentials")
30
+ children: y("channel.selectAdapterType", "Select an adapter type to configure credentials")
34
31
  })
35
32
  });
36
- if (!T) return /* @__PURE__ */ f("div", {
33
+ if (!w) return /* @__PURE__ */ f("div", {
37
34
  className: "p-4 bg-status-warning-bg-subtle border border-warning-300 rounded-lg",
38
35
  children: /* @__PURE__ */ p("div", {
39
36
  className: "flex items-start gap-2",
@@ -43,33 +40,33 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
43
40
  }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ p("p", {
44
41
  className: "text-sm font-medium text-warning-700",
45
42
  children: [
46
- b("channel.noCredentialSchema", "No credential schema defined for"),
43
+ y("channel.noCredentialSchema", "No credential schema defined for"),
47
44
  " ",
48
45
  s
49
46
  ]
50
47
  }), /* @__PURE__ */ f("p", {
51
48
  className: "text-xs text-warning-600 mt-1",
52
- children: b("channel.enterCredentialsAsJson", "You can still enter credentials as JSON in the raw format below.")
49
+ children: y("channel.enterCredentialsAsJson", "You can still enter credentials as JSON in the raw format below.")
53
50
  })] })]
54
51
  })
55
52
  });
56
- let E = (e, t) => {
53
+ let T = (e, t) => {
57
54
  h({
58
55
  ...m,
59
56
  [e]: t
60
57
  });
61
- }, D = (e) => {
62
- w((t) => ({
58
+ }, E = (e) => {
59
+ C((t) => ({
63
60
  ...t,
64
61
  [e]: !0
65
62
  }));
66
- }, O = (e) => {
67
- S((t) => ({
63
+ }, D = (e) => {
64
+ x((t) => ({
68
65
  ...t,
69
66
  [e]: !t[e]
70
67
  }));
71
- }, k = (e) => {
72
- let t = m[e.key], n = C[e.key] && e.required && !t, r = `w-full px-3 py-2 text-sm bg-surface border rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-primary disabled:opacity-50 disabled:cursor-not-allowed ${n ? "border-status-error-border" : "border-border-subtle"}`, i = `adapter-cred-${e.key}`;
68
+ }, O = (e) => {
69
+ let t = m[e.key], n = S[e.key] && e.required && !t, r = `w-full px-3 py-2 text-sm bg-surface border rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-primary disabled:opacity-50 disabled:cursor-not-allowed ${n ? "border-status-error-border" : "border-border-subtle"}`, i = `adapter-cred-${e.key}`;
73
70
  return /* @__PURE__ */ p("div", { children: [
74
71
  /* @__PURE__ */ p("label", {
75
72
  htmlFor: i,
@@ -84,8 +81,8 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
84
81
  "aria-label": e.displayName,
85
82
  type: "text",
86
83
  value: t || "",
87
- onChange: (t) => E(e.key, t.target.value),
88
- onBlur: () => D(e.key),
84
+ onChange: (t) => T(e.key, t.target.value),
85
+ onBlur: () => E(e.key),
89
86
  disabled: _,
90
87
  placeholder: e.placeholder,
91
88
  className: r
@@ -95,28 +92,28 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
95
92
  children: [/* @__PURE__ */ f("input", {
96
93
  id: i,
97
94
  "aria-label": e.displayName,
98
- type: x[e.key] ? "text" : "password",
95
+ type: b[e.key] ? "text" : "password",
99
96
  value: t || "",
100
- onChange: (t) => E(e.key, t.target.value),
101
- onBlur: () => D(e.key),
97
+ onChange: (t) => T(e.key, t.target.value),
98
+ onBlur: () => E(e.key),
102
99
  disabled: _,
103
100
  placeholder: e.placeholder,
104
101
  className: `${r} pr-10`
105
102
  }), /* @__PURE__ */ f("button", {
106
103
  type: "button",
107
- onClick: () => O(e.key),
108
- "aria-label": x[e.key] ? `Hide ${e.displayName}` : `Show ${e.displayName}`,
104
+ onClick: () => D(e.key),
105
+ "aria-label": b[e.key] ? y("channel.hideField", "Hide {{field}}", { field: e.displayName }) : y("channel.showField", "Show {{field}}", { field: e.displayName }),
109
106
  className: "absolute right-2 top-1/2 -translate-y-1/2 p-1 text-text-secondary hover:text-text-primary",
110
107
  tabIndex: -1,
111
- children: x[e.key] ? /* @__PURE__ */ f(u, { size: 16 }) : /* @__PURE__ */ f(l, { size: 16 })
108
+ children: b[e.key] ? /* @__PURE__ */ f(u, { size: 16 }) : /* @__PURE__ */ f(l, { size: 16 })
112
109
  })]
113
110
  }),
114
111
  e.type === "textarea" && /* @__PURE__ */ f("textarea", {
115
112
  id: i,
116
113
  "aria-label": e.displayName,
117
114
  value: t || "",
118
- onChange: (t) => E(e.key, t.target.value),
119
- onBlur: () => D(e.key),
115
+ onChange: (t) => T(e.key, t.target.value),
116
+ onBlur: () => E(e.key),
120
117
  disabled: _,
121
118
  placeholder: e.placeholder,
122
119
  rows: 4,
@@ -127,8 +124,8 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
127
124
  "aria-label": e.displayName,
128
125
  type: "number",
129
126
  value: t ?? e.defaultValue ?? "",
130
- onChange: (t) => E(e.key, t.target.value ? Number(t.target.value) : void 0),
131
- onBlur: () => D(e.key),
127
+ onChange: (t) => T(e.key, t.target.value ? Number(t.target.value) : void 0),
128
+ onBlur: () => E(e.key),
132
129
  disabled: _,
133
130
  placeholder: e.placeholder,
134
131
  className: r
@@ -138,7 +135,7 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
138
135
  children: [/* @__PURE__ */ f("input", {
139
136
  type: "checkbox",
140
137
  checked: t ?? e.defaultValue ?? !1,
141
- onChange: (t) => E(e.key, t.target.checked),
138
+ onChange: (t) => T(e.key, t.target.checked),
142
139
  disabled: _,
143
140
  className: "size-4 rounded border-border-subtle text-accent-primary focus:ring-accent-primary"
144
141
  }), /* @__PURE__ */ f("span", {
@@ -150,14 +147,14 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
150
147
  id: i,
151
148
  "aria-label": e.displayName,
152
149
  value: t ?? e.defaultValue ?? "",
153
- onChange: (t) => E(e.key, t.target.value),
154
- onBlur: () => D(e.key),
150
+ onChange: (t) => T(e.key, t.target.value),
151
+ onBlur: () => E(e.key),
155
152
  disabled: _,
156
153
  className: `${r} bg-bg-surface`,
157
154
  children: [/* @__PURE__ */ p("option", {
158
155
  value: "",
159
156
  children: [
160
- b("channel.select", "Select"),
157
+ y("channel.select", "Select"),
161
158
  " ",
162
159
  e.displayName.toLowerCase()
163
160
  ]
@@ -172,7 +169,7 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
172
169
  }),
173
170
  n && /* @__PURE__ */ f("p", {
174
171
  className: "mt-1 text-xs text-status-error-text",
175
- children: b("channel.fieldRequired", "This field is required")
172
+ children: y("channel.fieldRequired", "This field is required")
176
173
  })
177
174
  ] }, e.key);
178
175
  };
@@ -182,43 +179,40 @@ function m({ adapterType: s, credentials: m, onChange: h, onValidationChange: g,
182
179
  className: "flex items-start justify-between",
183
180
  children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("h3", {
184
181
  className: "text-sm font-semibold text-text-primary",
185
- children: T.displayName
182
+ children: w.displayName
186
183
  }), /* @__PURE__ */ f("p", {
187
184
  className: "text-xs text-text-secondary mt-0.5",
188
- children: T.description
189
- })] }), T.docUrl && /* @__PURE__ */ p("a", {
190
- href: T.docUrl,
185
+ children: w.description
186
+ })] }), w.docUrl && /* @__PURE__ */ p("a", {
187
+ href: w.docUrl,
191
188
  target: "_blank",
192
189
  rel: "noopener noreferrer",
193
190
  className: "flex items-center gap-1 text-xs text-accent-primary hover:text-accent-primary-hover",
194
- children: [/* @__PURE__ */ f("span", { children: b("channel.docs", "Docs") }), /* @__PURE__ */ f(c, { size: 12 })]
191
+ children: [/* @__PURE__ */ f("span", { children: y("channel.docs", "Docs") }), /* @__PURE__ */ f(c, { size: 12 })]
195
192
  })]
196
193
  }), /* @__PURE__ */ p("div", {
197
194
  className: "space-y-4",
198
- children: [T.credentials.length > 0 && /* @__PURE__ */ f("div", {
195
+ children: [w.credentials.length > 0 && /* @__PURE__ */ f("div", {
199
196
  className: "space-y-4",
200
- children: T.credentials.map(k)
201
- }), v && T.platformMetadata && T.platformMetadata.length > 0 && /* @__PURE__ */ f(d, { children: /* @__PURE__ */ p("div", {
197
+ children: w.credentials.map(O)
198
+ }), v && w.platformMetadata && w.platformMetadata.length > 0 && /* @__PURE__ */ f(d, { children: /* @__PURE__ */ p("div", {
202
199
  className: "border-t border-border-subtle pt-4 mt-4",
203
200
  children: [/* @__PURE__ */ f("p", {
204
201
  className: "text-xs font-medium text-text-secondary mb-3",
205
- children: b("channel.optionalSettings", "Optional Settings")
202
+ children: y("channel.optionalSettings", "Optional Settings")
206
203
  }), /* @__PURE__ */ f("div", {
207
204
  className: "space-y-4",
208
- children: T.platformMetadata.map(k)
205
+ children: w.platformMetadata.map(O)
209
206
  })]
210
207
  }) })]
211
208
  })]
212
209
  });
213
210
  }
214
- function h({ adapterType: e, credentials: t }) {
215
- let { t: r } = a(), i = (e, t) => {
216
- let n = r(e);
217
- return n === e ? t : n;
218
- };
219
- if (!e) return null;
220
- let { valid: c, errors: l } = n(e, t);
221
- return c ? /* @__PURE__ */ p("div", {
211
+ function h({ adapterType: t, credentials: n }) {
212
+ let i = e();
213
+ if (!t) return null;
214
+ let { valid: a, errors: c } = r(t, n);
215
+ return a ? /* @__PURE__ */ p("div", {
222
216
  className: "flex items-center gap-1.5 text-status-success-text",
223
217
  children: [/* @__PURE__ */ f(s, { size: 14 }), /* @__PURE__ */ f("span", {
224
218
  className: "text-xs",
@@ -229,7 +223,7 @@ function h({ adapterType: e, credentials: t }) {
229
223
  children: [/* @__PURE__ */ f(o, { size: 14 }), /* @__PURE__ */ p("span", {
230
224
  className: "text-xs",
231
225
  children: [
232
- l.length,
226
+ c.length,
233
227
  " ",
234
228
  i("channel.fieldsNeedAttention", "field(s) need attention")
235
229
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"AdapterCredentialsForm.js","names":[],"sources":["../../../src/channel/components/AdapterCredentialsForm.tsx"],"sourcesContent":["/**\n * Adapter Credentials Form\n *\n * Dynamic form that renders credential fields based on the selected adapter type.\n * Field names match exactly what the backend adapters expect.\n */\n\nimport { useState, useEffect } from 'react';\nimport { ExternalLink, Eye, EyeOff, AlertCircle, CheckCircle2 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { AdapterType } from '../hooks/useChannels';\nimport {\n getAdapterCredentialSchema,\n getDefaultCredentials,\n validateCredentials,\n type CredentialField,\n} from '../config/adapterCredentials';\n\ninterface AdapterCredentialsFormProps {\n adapterType: AdapterType | undefined;\n credentials: Record<string, unknown>;\n onChange: (credentials: Record<string, unknown>) => void;\n onValidationChange?: (isValid: boolean, errors: string[]) => void;\n disabled?: boolean;\n showPlatformMetadata?: boolean;\n}\n\nexport function AdapterCredentialsForm({\n adapterType,\n credentials,\n onChange,\n onValidationChange,\n disabled = false,\n showPlatformMetadata = true,\n}: AdapterCredentialsFormProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [showPasswords, setShowPasswords] = useState<Record<string, boolean>>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n const schema = getAdapterCredentialSchema(adapterType);\n\n // Initialize with default values when adapter type changes\n useEffect(() => {\n if (adapterType) {\n const defaults = getDefaultCredentials(adapterType);\n const merged = { ...defaults, ...credentials };\n if (JSON.stringify(merged) !== JSON.stringify(credentials)) {\n onChange(merged);\n }\n }\n }, [adapterType]);\n\n // Validate on change\n useEffect(() => {\n if (onValidationChange && adapterType) {\n const { valid, errors } = validateCredentials(adapterType, credentials);\n onValidationChange(valid, errors);\n }\n }, [credentials, adapterType, onValidationChange]);\n\n if (!adapterType) {\n return (\n <div className=\"text-center py-6 text-text-secondary\">\n <p className=\"text-sm\">\n {tr('channel.selectAdapterType', 'Select an adapter type to configure credentials')}\n </p>\n </div>\n );\n }\n\n if (!schema) {\n return (\n <div className=\"p-4 bg-status-warning-bg-subtle border border-warning-300 rounded-lg\">\n <div className=\"flex items-start gap-2\">\n <AlertCircle size={16} className=\"text-status-warning-text mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-warning-700\">\n {tr('channel.noCredentialSchema', 'No credential schema defined for')} {adapterType}\n </p>\n <p className=\"text-xs text-warning-600 mt-1\">\n {tr(\n 'channel.enterCredentialsAsJson',\n 'You can still enter credentials as JSON in the raw format below.'\n )}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n const handleFieldChange = (key: string, value: unknown) => {\n onChange({ ...credentials, [key]: value });\n };\n\n const handleFieldBlur = (key: string) => {\n setTouched((prev) => ({ ...prev, [key]: true }));\n };\n\n const togglePasswordVisibility = (key: string) => {\n setShowPasswords((prev) => ({ ...prev, [key]: !prev[key] }));\n };\n\n const renderField = (field: CredentialField) => {\n const value = credentials[field.key];\n const fieldError = touched[field.key] && field.required && !value;\n\n const commonInputClasses = `w-full px-3 py-2 text-sm bg-surface border rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-primary disabled:opacity-50 disabled:cursor-not-allowed ${\n fieldError ? 'border-status-error-border' : 'border-border-subtle'\n }`;\n\n const fieldId = `adapter-cred-${field.key}`;\n return (\n <div key={field.key}>\n <label htmlFor={fieldId} className=\"block text-sm font-medium text-text-primary mb-1.5\">\n {field.displayName}\n {field.required && <span className=\"text-status-error-text ml-1\">*</span>}\n </label>\n\n {field.type === 'text' && (\n <input\n id={fieldId}\n aria-label={field.displayName}\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n className={commonInputClasses}\n />\n )}\n\n {field.type === 'password' && (\n <div className=\"relative\">\n <input\n id={fieldId}\n aria-label={field.displayName}\n type={showPasswords[field.key] ? 'text' : 'password'}\n value={(value as string) || ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n className={`${commonInputClasses} pr-10`}\n />\n <button\n type=\"button\"\n onClick={() => togglePasswordVisibility(field.key)}\n aria-label={\n showPasswords[field.key] ? `Hide ${field.displayName}` : `Show ${field.displayName}`\n }\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 text-text-secondary hover:text-text-primary\"\n tabIndex={-1}\n >\n {showPasswords[field.key] ? <EyeOff size={16} /> : <Eye size={16} />}\n </button>\n </div>\n )}\n\n {field.type === 'textarea' && (\n <textarea\n id={fieldId}\n aria-label={field.displayName}\n value={(value as string) || ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n rows={4}\n className={`${commonInputClasses} resize-none font-mono text-xs`}\n />\n )}\n\n {field.type === 'number' && (\n <input\n id={fieldId}\n aria-label={field.displayName}\n type=\"number\"\n value={(value as number) ?? field.defaultValue ?? ''}\n onChange={(e) =>\n handleFieldChange(field.key, e.target.value ? Number(e.target.value) : undefined)\n }\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n className={commonInputClasses}\n />\n )}\n\n {field.type === 'boolean' && (\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={(value as boolean) ?? field.defaultValue ?? false}\n onChange={(e) => handleFieldChange(field.key, e.target.checked)}\n disabled={disabled}\n className=\"size-4 rounded border-border-subtle text-accent-primary focus:ring-accent-primary\"\n />\n <span className=\"text-sm text-text-secondary\">{field.description}</span>\n </label>\n )}\n\n {field.type === 'select' && field.options && (\n <select\n id={fieldId}\n aria-label={field.displayName}\n value={(value as string) ?? field.defaultValue ?? ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n className={`${commonInputClasses} bg-bg-surface`}\n >\n <option value=\"\">\n {tr('channel.select', 'Select')} {field.displayName.toLowerCase()}\n </option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n )}\n\n {field.type !== 'boolean' && (\n <p className=\"mt-1 text-xs text-text-secondary\">{field.description}</p>\n )}\n\n {fieldError && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n {tr('channel.fieldRequired', 'This field is required')}\n </p>\n )}\n </div>\n );\n };\n\n return (\n <div className=\"space-y-5\">\n {/* Header with adapter info */}\n <div className=\"flex items-start justify-between\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">{schema.displayName}</h3>\n <p className=\"text-xs text-text-secondary mt-0.5\">{schema.description}</p>\n </div>\n {schema.docUrl && (\n <a\n href={schema.docUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 text-xs text-accent-primary hover:text-accent-primary-hover\"\n >\n <span>{tr('channel.docs', 'Docs')}</span>\n <ExternalLink size={12} />\n </a>\n )}\n </div>\n\n {/* Credential fields */}\n <div className=\"space-y-4\">\n {schema.credentials.length > 0 && (\n <div className=\"space-y-4\">{schema.credentials.map(renderField)}</div>\n )}\n\n {/* Platform metadata fields (optional settings) */}\n {showPlatformMetadata && schema.platformMetadata && schema.platformMetadata.length > 0 && (\n <>\n <div className=\"border-t border-border-subtle pt-4 mt-4\">\n <p className=\"text-xs font-medium text-text-secondary mb-3\">\n {tr('channel.optionalSettings', 'Optional Settings')}\n </p>\n <div className=\"space-y-4\">{schema.platformMetadata.map(renderField)}</div>\n </div>\n </>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Compact validation status indicator\n */\nexport function CredentialValidationStatus({\n adapterType,\n credentials,\n}: {\n adapterType: AdapterType | undefined;\n credentials: Record<string, unknown>;\n}) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n if (!adapterType) return null;\n\n const { valid, errors } = validateCredentials(adapterType, credentials);\n\n if (valid) {\n return (\n <div className=\"flex items-center gap-1.5 text-status-success-text\">\n <CheckCircle2 size={14} />\n <span className=\"text-xs\">\n {tr('channel.allRequiredFieldsFilled', 'All required fields filled')}\n </span>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center gap-1.5 text-status-warning-text\">\n <AlertCircle size={14} />\n <span className=\"text-xs\">\n {errors.length} {tr('channel.fieldsNeedAttention', 'field(s) need attention')}\n </span>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdapterCredentialsForm.js","names":[],"sources":["../../../src/channel/components/AdapterCredentialsForm.tsx"],"sourcesContent":["/**\n * Adapter Credentials Form\n *\n * Dynamic form that renders credential fields based on the selected adapter type.\n * Field names match exactly what the backend adapters expect.\n */\n\nimport { useState, useEffect } from 'react';\nimport { ExternalLink, Eye, EyeOff, AlertCircle, CheckCircle2 } from 'lucide-react';\nimport { useTr } from '../hooks/useTr';\nimport type { AdapterType } from '../hooks/useChannels';\nimport {\n getAdapterCredentialSchema,\n getDefaultCredentials,\n validateCredentials,\n type CredentialField,\n} from '../config/adapterCredentials';\n\ninterface AdapterCredentialsFormProps {\n adapterType: AdapterType | undefined;\n credentials: Record<string, unknown>;\n onChange: (credentials: Record<string, unknown>) => void;\n onValidationChange?: (isValid: boolean, errors: string[]) => void;\n disabled?: boolean;\n showPlatformMetadata?: boolean;\n}\n\nexport function AdapterCredentialsForm({\n adapterType,\n credentials,\n onChange,\n onValidationChange,\n disabled = false,\n showPlatformMetadata = true,\n}: AdapterCredentialsFormProps) {\n const tr = useTr();\n const [showPasswords, setShowPasswords] = useState<Record<string, boolean>>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n const schema = getAdapterCredentialSchema(adapterType);\n\n // Initialize with default values when adapter type changes\n useEffect(() => {\n if (adapterType) {\n const defaults = getDefaultCredentials(adapterType);\n const merged = { ...defaults, ...credentials };\n if (JSON.stringify(merged) !== JSON.stringify(credentials)) {\n onChange(merged);\n }\n }\n }, [adapterType]);\n\n // Validate on change\n useEffect(() => {\n if (onValidationChange && adapterType) {\n const { valid, errors } = validateCredentials(adapterType, credentials);\n onValidationChange(valid, errors);\n }\n }, [credentials, adapterType, onValidationChange]);\n\n if (!adapterType) {\n return (\n <div className=\"text-center py-6 text-text-secondary\">\n <p className=\"text-sm\">\n {tr('channel.selectAdapterType', 'Select an adapter type to configure credentials')}\n </p>\n </div>\n );\n }\n\n if (!schema) {\n return (\n <div className=\"p-4 bg-status-warning-bg-subtle border border-warning-300 rounded-lg\">\n <div className=\"flex items-start gap-2\">\n <AlertCircle size={16} className=\"text-status-warning-text mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-warning-700\">\n {tr('channel.noCredentialSchema', 'No credential schema defined for')} {adapterType}\n </p>\n <p className=\"text-xs text-warning-600 mt-1\">\n {tr(\n 'channel.enterCredentialsAsJson',\n 'You can still enter credentials as JSON in the raw format below.'\n )}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n const handleFieldChange = (key: string, value: unknown) => {\n onChange({ ...credentials, [key]: value });\n };\n\n const handleFieldBlur = (key: string) => {\n setTouched((prev) => ({ ...prev, [key]: true }));\n };\n\n const togglePasswordVisibility = (key: string) => {\n setShowPasswords((prev) => ({ ...prev, [key]: !prev[key] }));\n };\n\n const renderField = (field: CredentialField) => {\n const value = credentials[field.key];\n const fieldError = touched[field.key] && field.required && !value;\n\n const commonInputClasses = `w-full px-3 py-2 text-sm bg-surface border rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-primary disabled:opacity-50 disabled:cursor-not-allowed ${\n fieldError ? 'border-status-error-border' : 'border-border-subtle'\n }`;\n\n const fieldId = `adapter-cred-${field.key}`;\n return (\n <div key={field.key}>\n <label htmlFor={fieldId} className=\"block text-sm font-medium text-text-primary mb-1.5\">\n {field.displayName}\n {field.required && <span className=\"text-status-error-text ml-1\">*</span>}\n </label>\n\n {field.type === 'text' && (\n <input\n id={fieldId}\n aria-label={field.displayName}\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n className={commonInputClasses}\n />\n )}\n\n {field.type === 'password' && (\n <div className=\"relative\">\n <input\n id={fieldId}\n aria-label={field.displayName}\n type={showPasswords[field.key] ? 'text' : 'password'}\n value={(value as string) || ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n className={`${commonInputClasses} pr-10`}\n />\n <button\n type=\"button\"\n onClick={() => togglePasswordVisibility(field.key)}\n aria-label={\n showPasswords[field.key]\n ? tr('channel.hideField', 'Hide {{field}}', { field: field.displayName })\n : tr('channel.showField', 'Show {{field}}', { field: field.displayName })\n }\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 text-text-secondary hover:text-text-primary\"\n tabIndex={-1}\n >\n {showPasswords[field.key] ? <EyeOff size={16} /> : <Eye size={16} />}\n </button>\n </div>\n )}\n\n {field.type === 'textarea' && (\n <textarea\n id={fieldId}\n aria-label={field.displayName}\n value={(value as string) || ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n rows={4}\n className={`${commonInputClasses} resize-none font-mono text-xs`}\n />\n )}\n\n {field.type === 'number' && (\n <input\n id={fieldId}\n aria-label={field.displayName}\n type=\"number\"\n value={(value as number) ?? field.defaultValue ?? ''}\n onChange={(e) =>\n handleFieldChange(field.key, e.target.value ? Number(e.target.value) : undefined)\n }\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n placeholder={field.placeholder}\n className={commonInputClasses}\n />\n )}\n\n {field.type === 'boolean' && (\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={(value as boolean) ?? field.defaultValue ?? false}\n onChange={(e) => handleFieldChange(field.key, e.target.checked)}\n disabled={disabled}\n className=\"size-4 rounded border-border-subtle text-accent-primary focus:ring-accent-primary\"\n />\n <span className=\"text-sm text-text-secondary\">{field.description}</span>\n </label>\n )}\n\n {field.type === 'select' && field.options && (\n <select\n id={fieldId}\n aria-label={field.displayName}\n value={(value as string) ?? field.defaultValue ?? ''}\n onChange={(e) => handleFieldChange(field.key, e.target.value)}\n onBlur={() => handleFieldBlur(field.key)}\n disabled={disabled}\n className={`${commonInputClasses} bg-bg-surface`}\n >\n <option value=\"\">\n {tr('channel.select', 'Select')} {field.displayName.toLowerCase()}\n </option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n )}\n\n {field.type !== 'boolean' && (\n <p className=\"mt-1 text-xs text-text-secondary\">{field.description}</p>\n )}\n\n {fieldError && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n {tr('channel.fieldRequired', 'This field is required')}\n </p>\n )}\n </div>\n );\n };\n\n return (\n <div className=\"space-y-5\">\n {/* Header with adapter info */}\n <div className=\"flex items-start justify-between\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">{schema.displayName}</h3>\n <p className=\"text-xs text-text-secondary mt-0.5\">{schema.description}</p>\n </div>\n {schema.docUrl && (\n <a\n href={schema.docUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 text-xs text-accent-primary hover:text-accent-primary-hover\"\n >\n <span>{tr('channel.docs', 'Docs')}</span>\n <ExternalLink size={12} />\n </a>\n )}\n </div>\n\n {/* Credential fields */}\n <div className=\"space-y-4\">\n {schema.credentials.length > 0 && (\n <div className=\"space-y-4\">{schema.credentials.map(renderField)}</div>\n )}\n\n {/* Platform metadata fields (optional settings) */}\n {showPlatformMetadata && schema.platformMetadata && schema.platformMetadata.length > 0 && (\n <>\n <div className=\"border-t border-border-subtle pt-4 mt-4\">\n <p className=\"text-xs font-medium text-text-secondary mb-3\">\n {tr('channel.optionalSettings', 'Optional Settings')}\n </p>\n <div className=\"space-y-4\">{schema.platformMetadata.map(renderField)}</div>\n </div>\n </>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Compact validation status indicator\n */\nexport function CredentialValidationStatus({\n adapterType,\n credentials,\n}: {\n adapterType: AdapterType | undefined;\n credentials: Record<string, unknown>;\n}) {\n const tr = useTr();\n\n if (!adapterType) return null;\n\n const { valid, errors } = validateCredentials(adapterType, credentials);\n\n if (valid) {\n return (\n <div className=\"flex items-center gap-1.5 text-status-success-text\">\n <CheckCircle2 size={14} />\n <span className=\"text-xs\">\n {tr('channel.allRequiredFieldsFilled', 'All required fields filled')}\n </span>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center gap-1.5 text-status-warning-text\">\n <AlertCircle size={14} />\n <span className=\"text-xs\">\n {errors.length} {tr('channel.fieldsNeedAttention', 'field(s) need attention')}\n </span>\n </div>\n );\n}\n"],"mappings":";;;;;;AA2BA,SAAgB,EAAuB,EACrC,gBACA,gBACA,aACA,uBACA,cAAW,IACX,0BAAuB,MACO;CAC9B,IAAM,IAAK,GAAO,EACZ,CAAC,GAAe,KAAoB,EAAkC,EAAE,CAAC,EACzE,CAAC,GAAS,KAAc,EAAkC,EAAE,CAAC,EAE7D,IAAS,EAA2B,EAAY;AAqBtD,KAlBA,QAAgB;AACd,MAAI,GAAa;GAEf,IAAM,IAAS;IAAE,GADA,EAAsB,EAAY;IACrB,GAAG;IAAa;AAC9C,GAAI,KAAK,UAAU,EAAO,KAAK,KAAK,UAAU,EAAY,IACxD,EAAS,EAAO;;IAGnB,CAAC,EAAY,CAAC,EAGjB,QAAgB;AACd,MAAI,KAAsB,GAAa;GACrC,IAAM,EAAE,UAAO,cAAW,EAAoB,GAAa,EAAY;AACvE,KAAmB,GAAO,EAAO;;IAElC;EAAC;EAAa;EAAa;EAAmB,CAAC,EAE9C,CAAC,EACH,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,KAAD;GAAG,WAAU;aACV,EAAG,6BAA6B,kDAAkD;GACjF,CAAA;EACA,CAAA;AAIV,KAAI,CAAC,EACH,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAa,MAAM;IAAI,WAAU;IAAoC,CAAA,EACrE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,EAAG,8BAA8B,mCAAmC;KAAC;KAAE;KACtE;OACJ,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,kCACA,mEACD;IACC,CAAA,CACA,EAAA,CAAA,CACF;;EACF,CAAA;CAIV,IAAM,KAAqB,GAAa,MAAmB;AACzD,IAAS;GAAE,GAAG;IAAc,IAAM;GAAO,CAAC;IAGtC,KAAmB,MAAgB;AACvC,KAAY,OAAU;GAAE,GAAG;IAAO,IAAM;GAAM,EAAE;IAG5C,KAA4B,MAAgB;AAChD,KAAkB,OAAU;GAAE,GAAG;IAAO,IAAM,CAAC,EAAK;GAAM,EAAE;IAGxD,KAAe,MAA2B;EAC9C,IAAM,IAAQ,EAAY,EAAM,MAC1B,IAAa,EAAQ,EAAM,QAAQ,EAAM,YAAY,CAAC,GAEtD,IAAqB,mKACzB,IAAa,+BAA+B,0BAGxC,IAAU,gBAAgB,EAAM;AACtC,SACE,kBAAC,OAAD,EAAA,UAAA;GACE,kBAAC,SAAD;IAAO,SAAS;IAAS,WAAU;cAAnC,CACG,EAAM,aACN,EAAM,YAAY,kBAAC,QAAD;KAAM,WAAU;eAA8B;KAAQ,CAAA,CACnE;;GAEP,EAAM,SAAS,UACd,kBAAC,SAAD;IACE,IAAI;IACJ,cAAY,EAAM;IAClB,MAAK;IACL,OAAQ,KAAoB;IAC5B,WAAW,MAAM,EAAkB,EAAM,KAAK,EAAE,OAAO,MAAM;IAC7D,cAAc,EAAgB,EAAM,IAAI;IAC9B;IACV,aAAa,EAAM;IACnB,WAAW;IACX,CAAA;GAGH,EAAM,SAAS,cACd,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KACE,IAAI;KACJ,cAAY,EAAM;KAClB,MAAM,EAAc,EAAM,OAAO,SAAS;KAC1C,OAAQ,KAAoB;KAC5B,WAAW,MAAM,EAAkB,EAAM,KAAK,EAAE,OAAO,MAAM;KAC7D,cAAc,EAAgB,EAAM,IAAI;KAC9B;KACV,aAAa,EAAM;KACnB,WAAW,GAAG,EAAmB;KACjC,CAAA,EACF,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAyB,EAAM,IAAI;KAClD,cACE,EAAc,EAAM,OAChB,EAAG,qBAAqB,kBAAkB,EAAE,OAAO,EAAM,aAAa,CAAC,GACvE,EAAG,qBAAqB,kBAAkB,EAAE,OAAO,EAAM,aAAa,CAAC;KAE7E,WAAU;KACV,UAAU;eAET,EAAc,EAAM,OAAO,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA,GAAG,kBAAC,GAAD,EAAK,MAAM,IAAM,CAAA;KAC7D,CAAA,CACL;;GAGP,EAAM,SAAS,cACd,kBAAC,YAAD;IACE,IAAI;IACJ,cAAY,EAAM;IAClB,OAAQ,KAAoB;IAC5B,WAAW,MAAM,EAAkB,EAAM,KAAK,EAAE,OAAO,MAAM;IAC7D,cAAc,EAAgB,EAAM,IAAI;IAC9B;IACV,aAAa,EAAM;IACnB,MAAM;IACN,WAAW,GAAG,EAAmB;IACjC,CAAA;GAGH,EAAM,SAAS,YACd,kBAAC,SAAD;IACE,IAAI;IACJ,cAAY,EAAM;IAClB,MAAK;IACL,OAAQ,KAAoB,EAAM,gBAAgB;IAClD,WAAW,MACT,EAAkB,EAAM,KAAK,EAAE,OAAO,QAAQ,OAAO,EAAE,OAAO,MAAM,GAAG,KAAA,EAAU;IAEnF,cAAc,EAAgB,EAAM,IAAI;IAC9B;IACV,aAAa,EAAM;IACnB,WAAW;IACX,CAAA;GAGH,EAAM,SAAS,aACd,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD;KACE,MAAK;KACL,SAAU,KAAqB,EAAM,gBAAgB;KACrD,WAAW,MAAM,EAAkB,EAAM,KAAK,EAAE,OAAO,QAAQ;KACrD;KACV,WAAU;KACV,CAAA,EACF,kBAAC,QAAD;KAAM,WAAU;eAA+B,EAAM;KAAmB,CAAA,CAClE;;GAGT,EAAM,SAAS,YAAY,EAAM,WAChC,kBAAC,UAAD;IACE,IAAI;IACJ,cAAY,EAAM;IAClB,OAAQ,KAAoB,EAAM,gBAAgB;IAClD,WAAW,MAAM,EAAkB,EAAM,KAAK,EAAE,OAAO,MAAM;IAC7D,cAAc,EAAgB,EAAM,IAAI;IAC9B;IACV,WAAW,GAAG,EAAmB;cAPnC,CASE,kBAAC,UAAD;KAAQ,OAAM;eAAd;MACG,EAAG,kBAAkB,SAAS;MAAC;MAAE,EAAM,YAAY,aAAa;MAC1D;QACR,EAAM,QAAQ,KAAK,MAClB,kBAAC,UAAD;KAAwB,OAAO,EAAI;eAChC,EAAI;KACE,EAFI,EAAI,MAER,CACT,CACK;;GAGV,EAAM,SAAS,aACd,kBAAC,KAAD;IAAG,WAAU;cAAoC,EAAM;IAAgB,CAAA;GAGxE,KACC,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,yBAAyB,yBAAyB;IACpD,CAAA;GAEF,EAAA,EA1HI,EAAM,IA0HV;;AAIV,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CAEE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAA2C,EAAO;IAAiB,CAAA,EACjF,kBAAC,KAAD;IAAG,WAAU;cAAsC,EAAO;IAAgB,CAAA,CACtE,EAAA,CAAA,EACL,EAAO,UACN,kBAAC,KAAD;IACE,MAAM,EAAO;IACb,QAAO;IACP,KAAI;IACJ,WAAU;cAJZ,CAME,kBAAC,QAAD,EAAA,UAAO,EAAG,gBAAgB,OAAO,EAAQ,CAAA,EACzC,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA,CACxB;MAEF;MAGN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAO,YAAY,SAAS,KAC3B,kBAAC,OAAD;IAAK,WAAU;cAAa,EAAO,YAAY,IAAI,EAAY;IAAO,CAAA,EAIvE,KAAwB,EAAO,oBAAoB,EAAO,iBAAiB,SAAS,KACnF,kBAAA,GAAA,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,4BAA4B,oBAAoB;KAClD,CAAA,EACJ,kBAAC,OAAD;KAAK,WAAU;eAAa,EAAO,iBAAiB,IAAI,EAAY;KAAO,CAAA,CACvE;OACL,CAAA,CAED;KACF;;;AAOV,SAAgB,EAA2B,EACzC,gBACA,kBAIC;CACD,IAAM,IAAK,GAAO;AAElB,KAAI,CAAC,EAAa,QAAO;CAEzB,IAAM,EAAE,UAAO,cAAW,EAAoB,GAAa,EAAY;AAavE,QAXI,IAEA,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA,EAC1B,kBAAC,QAAD;GAAM,WAAU;aACb,EAAG,mCAAmC,6BAA6B;GAC/D,CAAA,CACH;MAKR,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD,EAAa,MAAM,IAAM,CAAA,EACzB,kBAAC,QAAD;GAAM,WAAU;aAAhB;IACG,EAAO;IAAO;IAAE,EAAG,+BAA+B,0BAA0B;IACxE;KACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"FeatureNotEnabled.d.ts","sourceRoot":"","sources":["../../../src/channel/components/FeatureNotEnabled.tsx"],"names":[],"mappings":"AAGA,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,sBAAsB,+BAkCjE"}
1
+ {"version":3,"file":"FeatureNotEnabled.d.ts","sourceRoot":"","sources":["../../../src/channel/components/FeatureNotEnabled.tsx"],"names":[],"mappings":"AAIA,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,sBAAsB,+BA+CjE"}
@@ -1,50 +1,55 @@
1
- import { Lock as e } from "lucide-react";
2
- import { usePermissions as t } from "@burdenoff/fe-libs/shared/providers/shell";
3
- import { jsx as n, jsxs as r } from "react/jsx-runtime";
1
+ import { useTr as e } from "../hooks/useTr.js";
2
+ import { Lock as t } from "lucide-react";
3
+ import { usePermissions as n } from "@burdenoff/fe-libs/shared/providers/shell";
4
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
5
  //#region src/channel/components/FeatureNotEnabled.tsx
5
- function i({ flag: i }) {
6
- let { hasRole: a } = t(), o = a("SUPER_ADMIN");
7
- return /* @__PURE__ */ r("div", {
6
+ function a({ flag: a }) {
7
+ let { hasRole: o } = n(), s = o("SUPER_ADMIN"), c = e();
8
+ return /* @__PURE__ */ i("div", {
8
9
  className: "flex flex-col items-center justify-center min-h-[400px] gap-4 text-center p-6",
9
- children: [/* @__PURE__ */ n("div", {
10
+ children: [/* @__PURE__ */ r("div", {
10
11
  className: "p-3 rounded-full bg-bg-elevated",
11
- children: /* @__PURE__ */ n(e, { className: "size-8 text-fg-muted" })
12
- }), /* @__PURE__ */ r("div", {
12
+ children: /* @__PURE__ */ r(t, { className: "size-8 text-fg-muted" })
13
+ }), /* @__PURE__ */ i("div", {
13
14
  className: "space-y-2 max-w-md",
14
15
  children: [
15
- /* @__PURE__ */ n("h3", {
16
+ /* @__PURE__ */ r("h3", {
16
17
  className: "text-lg font-semibold text-fg",
17
- children: "Feature not enabled"
18
+ children: c("channel.featureNotEnabled.title", "Feature not enabled")
18
19
  }),
19
- /* @__PURE__ */ n("p", {
20
+ /* @__PURE__ */ r("p", {
20
21
  className: "text-sm text-fg-muted",
21
- children: "This feature is currently disabled for your workspace."
22
+ children: c("channel.featureNotEnabled.description", "This feature is currently disabled for your workspace.")
22
23
  }),
23
- o ? /* @__PURE__ */ r("p", {
24
+ s ? /* @__PURE__ */ i("p", {
24
25
  className: "text-sm text-fg-muted",
25
26
  children: [
26
- "You can enable it in",
27
+ c("channel.featureNotEnabled.adminPrefix", "You can enable it in"),
27
28
  " ",
28
- /* @__PURE__ */ n("a", {
29
+ /* @__PURE__ */ r("a", {
29
30
  href: "/feature-previews",
30
31
  className: "text-action-primary-text underline underline-offset-2 hover:text-action-primary-text-hover",
31
- children: "Feature Previews"
32
+ children: c("channel.featureNotEnabled.featurePreviews", "Feature Previews")
32
33
  }),
33
34
  "."
34
35
  ]
35
- }) : /* @__PURE__ */ n("p", {
36
+ }) : /* @__PURE__ */ r("p", {
36
37
  className: "text-sm text-fg-muted",
37
- children: "Contact your administrator if you believe this is in error."
38
+ children: c("channel.featureNotEnabled.contactAdmin", "Contact your administrator if you believe this is in error.")
38
39
  }),
39
- o && /* @__PURE__ */ r("p", {
40
+ s && /* @__PURE__ */ i("p", {
40
41
  className: "text-xs text-fg-subtle font-mono mt-1",
41
- children: ["flag: ", i]
42
+ children: [
43
+ c("channel.featureNotEnabled.flagLabel", "flag"),
44
+ ": ",
45
+ a
46
+ ]
42
47
  })
43
48
  ]
44
49
  })]
45
50
  });
46
51
  }
47
52
  //#endregion
48
- export { i as FeatureNotEnabled };
53
+ export { a as FeatureNotEnabled };
49
54
 
50
55
  //# sourceMappingURL=FeatureNotEnabled.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeatureNotEnabled.js","names":[],"sources":["../../../src/channel/components/FeatureNotEnabled.tsx"],"sourcesContent":["import { Lock } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\n\ninterface FeatureNotEnabledProps {\n flag: string;\n}\n\n/**\n * Default fallback rendered when a feature flag is disabled. Behaves as a\n * \"404-style\" panel — never throws, never crashes the route.\n *\n * - The flag key is only shown to super admins (developer-facing detail).\n * - The CTA links to Feature Previews so admins can enable the flag directly.\n */\nexport function FeatureNotEnabled({ flag }: FeatureNotEnabledProps) {\n const { hasRole } = usePermissions();\n const isSuperAdmin = hasRole('SUPER_ADMIN');\n\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[400px] gap-4 text-center p-6\">\n <div className=\"p-3 rounded-full bg-bg-elevated\">\n <Lock className=\"size-8 text-fg-muted\" />\n </div>\n <div className=\"space-y-2 max-w-md\">\n <h3 className=\"text-lg font-semibold text-fg\">Feature not enabled</h3>\n <p className=\"text-sm text-fg-muted\">\n This feature is currently disabled for your workspace.\n </p>\n {isSuperAdmin ? (\n <p className=\"text-sm text-fg-muted\">\n You can enable it in{' '}\n <a\n href=\"/feature-previews\"\n className=\"text-action-primary-text underline underline-offset-2 hover:text-action-primary-text-hover\"\n >\n Feature Previews\n </a>\n .\n </p>\n ) : (\n <p className=\"text-sm text-fg-muted\">\n Contact your administrator if you believe this is in error.\n </p>\n )}\n {isSuperAdmin && <p className=\"text-xs text-fg-subtle font-mono mt-1\">flag: {flag}</p>}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AAcA,SAAgB,EAAkB,EAAE,WAAgC;CAClE,IAAM,EAAE,eAAY,GAAgB,EAC9B,IAAe,EAAQ,cAAc;AAE3C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAM,WAAU,wBAAyB,CAAA;GACrC,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eAAgC;KAAwB,CAAA;IACtE,kBAAC,KAAD;KAAG,WAAU;eAAwB;KAEjC,CAAA;IACH,IACC,kBAAC,KAAD;KAAG,WAAU;eAAb;MAAqC;MACd;MACrB,kBAAC,KAAD;OACE,MAAK;OACL,WAAU;iBACX;OAEG,CAAA;;MAEF;SAEJ,kBAAC,KAAD;KAAG,WAAU;eAAwB;KAEjC,CAAA;IAEL,KAAgB,kBAAC,KAAD;KAAG,WAAU;eAAb,CAAqD,UAAO,EAAS;;IAClF;KACF"}
1
+ {"version":3,"file":"FeatureNotEnabled.js","names":[],"sources":["../../../src/channel/components/FeatureNotEnabled.tsx"],"sourcesContent":["import { Lock } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useTr } from '../hooks/useTr';\n\ninterface FeatureNotEnabledProps {\n flag: string;\n}\n\n/**\n * Default fallback rendered when a feature flag is disabled. Behaves as a\n * \"404-style\" panel — never throws, never crashes the route.\n *\n * - The flag key is only shown to super admins (developer-facing detail).\n * - The CTA links to Feature Previews so admins can enable the flag directly.\n */\nexport function FeatureNotEnabled({ flag }: FeatureNotEnabledProps) {\n const { hasRole } = usePermissions();\n const isSuperAdmin = hasRole('SUPER_ADMIN');\n const tr = useTr();\n\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[400px] gap-4 text-center p-6\">\n <div className=\"p-3 rounded-full bg-bg-elevated\">\n <Lock className=\"size-8 text-fg-muted\" />\n </div>\n <div className=\"space-y-2 max-w-md\">\n <h3 className=\"text-lg font-semibold text-fg\">\n {tr('channel.featureNotEnabled.title', 'Feature not enabled')}\n </h3>\n <p className=\"text-sm text-fg-muted\">\n {tr(\n 'channel.featureNotEnabled.description',\n 'This feature is currently disabled for your workspace.'\n )}\n </p>\n {isSuperAdmin ? (\n <p className=\"text-sm text-fg-muted\">\n {tr('channel.featureNotEnabled.adminPrefix', 'You can enable it in')}{' '}\n <a\n href=\"/feature-previews\"\n className=\"text-action-primary-text underline underline-offset-2 hover:text-action-primary-text-hover\"\n >\n {tr('channel.featureNotEnabled.featurePreviews', 'Feature Previews')}\n </a>\n .\n </p>\n ) : (\n <p className=\"text-sm text-fg-muted\">\n {tr(\n 'channel.featureNotEnabled.contactAdmin',\n 'Contact your administrator if you believe this is in error.'\n )}\n </p>\n )}\n {isSuperAdmin && (\n <p className=\"text-xs text-fg-subtle font-mono mt-1\">\n {tr('channel.featureNotEnabled.flagLabel', 'flag')}: {flag}\n </p>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAeA,SAAgB,EAAkB,EAAE,WAAgC;CAClE,IAAM,EAAE,eAAY,GAAgB,EAC9B,IAAe,EAAQ,cAAc,EACrC,IAAK,GAAO;AAElB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAM,WAAU,wBAAyB,CAAA;GACrC,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,mCAAmC,sBAAsB;KAC1D,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,yCACA,yDACD;KACC,CAAA;IACH,IACC,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,EAAG,yCAAyC,uBAAuB;MAAE;MACtE,kBAAC,KAAD;OACE,MAAK;OACL,WAAU;iBAET,EAAG,6CAA6C,mBAAmB;OAClE,CAAA;;MAEF;SAEJ,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,0CACA,8DACD;KACC,CAAA;IAEL,KACC,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,EAAG,uCAAuC,OAAO;MAAC;MAAG;MACpD;;IAEF;KACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownEditor.d.ts","sourceRoot":"","sources":["../../../src/channel/components/MarkdownEditor.tsx"],"names":[],"mappings":"AAQA,UAAU,mBAAmB;IAC3B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAkED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAW,EACX,IAAQ,EACR,YAAY,EAAE,SAAS,EACvB,SAAc,EACd,iBAAsB,EACtB,EAAE,GACH,EAAE,mBAAmB,+BAgKrB"}
1
+ {"version":3,"file":"MarkdownEditor.d.ts","sourceRoot":"","sources":["../../../src/channel/components/MarkdownEditor.tsx"],"names":[],"mappings":"AASA,UAAU,mBAAmB;IAC3B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAkED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAW,EACX,IAAQ,EACR,YAAY,EAAE,SAAS,EACvB,SAAc,EACd,iBAAsB,EACtB,EAAE,GACH,EAAE,mBAAmB,+BAsKrB"}