@oondemand/oon-core-front 0.3.57 → 0.3.59

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.
package/dist/index.js CHANGED
@@ -4220,10 +4220,21 @@ import { jsx as jsx25 } from "react/jsx-runtime";
4220
4220
  function slug2(value2) {
4221
4221
  return value2.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4222
4222
  }
4223
- function requiredAccess2(source) {
4224
- const values = [...source.permissions ?? [], ...source.capabilities ?? []].filter(Boolean);
4223
+ function requiredPermissions(source) {
4224
+ const values = [...source.permissions ?? []].filter(Boolean);
4225
4225
  return values.length ? values : void 0;
4226
4226
  }
4227
+ function declaredAppCapabilities(config) {
4228
+ const capabilities = config.app.capabilities;
4229
+ return Array.isArray(capabilities) ? capabilities : void 0;
4230
+ }
4231
+ function supportsCapabilities(config, source) {
4232
+ const required = (source.capabilities ?? []).filter(Boolean);
4233
+ if (!required.length) return true;
4234
+ const declared = declaredAppCapabilities(config);
4235
+ if (!declared) return true;
4236
+ return required.every((capability) => declared.includes(capability));
4237
+ }
4227
4238
  function viewId(view) {
4228
4239
  if (view.id) return view.id;
4229
4240
  if (view.type === "dashboard") return "dashboard";
@@ -4299,15 +4310,29 @@ function viewToRoute(view, registry) {
4299
4310
  return {
4300
4311
  path: viewPath(view),
4301
4312
  element: renderView(view, registry),
4302
- permissions: requiredAccess2(view)
4313
+ permissions: requiredPermissions(view),
4314
+ capabilities: "capabilities" in view ? view.capabilities : void 0
4303
4315
  };
4304
4316
  }
4305
4317
  function pageToRoute(page, registry) {
4306
- return { path: page.path, element: /* @__PURE__ */ jsx25(CorePage2, { page, registry }), permissions: requiredAccess2(page) };
4318
+ return {
4319
+ path: page.path,
4320
+ element: /* @__PURE__ */ jsx25(CorePage2, { page, registry }),
4321
+ permissions: requiredPermissions(page),
4322
+ capabilities: page.capabilities
4323
+ };
4307
4324
  }
4308
4325
  function pageToMenu(page) {
4309
4326
  if (page.hidden || !page.label) return null;
4310
- return { label: page.label, href: page.path, icon: page.icon, section: page.section, permissions: requiredAccess2(page), capabilities: page.capabilities, order: page.order };
4327
+ return {
4328
+ label: page.label,
4329
+ href: page.path,
4330
+ icon: page.icon,
4331
+ section: page.section,
4332
+ permissions: requiredPermissions(page),
4333
+ capabilities: page.capabilities,
4334
+ order: page.order
4335
+ };
4311
4336
  }
4312
4337
  function viewToMenu(view) {
4313
4338
  return {
@@ -4315,7 +4340,7 @@ function viewToMenu(view) {
4315
4340
  href: viewPath(view),
4316
4341
  icon: view.icon,
4317
4342
  section: view.section,
4318
- permissions: requiredAccess2(view),
4343
+ permissions: requiredPermissions(view),
4319
4344
  capabilities: "capabilities" in view ? view.capabilities : void 0
4320
4345
  };
4321
4346
  }
@@ -4325,16 +4350,20 @@ function resolveRegistry(config) {
4325
4350
  const seenPaths = /* @__PURE__ */ new Set();
4326
4351
  const componentRegistry = config.registry ?? config.ui?.registry;
4327
4352
  const pushRoute = (route) => {
4328
- if (seenPaths.has(route.path)) return;
4353
+ if (!supportsCapabilities(config, route) || seenPaths.has(route.path)) return;
4329
4354
  seenPaths.add(route.path);
4330
- routes.push(route);
4355
+ routes.push({ ...route, permissions: requiredPermissions(route) });
4356
+ };
4357
+ const pushMenu = (item) => {
4358
+ if (!supportsCapabilities(config, item)) return;
4359
+ menu.push({ ...item, permissions: requiredPermissions(item) });
4331
4360
  };
4332
4361
  for (const mod of config.modules ?? []) {
4333
- for (const route of mod.routes ?? []) pushRoute({ ...route, permissions: requiredAccess2(route) });
4334
- for (const item of mod.menu ?? []) menu.push({ ...item, permissions: requiredAccess2(item) });
4362
+ for (const route of mod.routes ?? []) pushRoute(route);
4363
+ for (const item of mod.menu ?? []) pushMenu(item);
4335
4364
  for (const view of mod.views ?? []) {
4336
4365
  pushRoute(viewToRoute(view, componentRegistry));
4337
- menu.push(viewToMenu(view));
4366
+ pushMenu(viewToMenu(view));
4338
4367
  }
4339
4368
  }
4340
4369
  const navMode = config.ui?.navigation?.mode ?? "auto";
@@ -4343,16 +4372,16 @@ function resolveRegistry(config) {
4343
4372
  if (includeAuto) {
4344
4373
  for (const view of config.ui?.views ?? []) {
4345
4374
  pushRoute(viewToRoute(view, componentRegistry));
4346
- menu.push(viewToMenu(view));
4375
+ pushMenu(viewToMenu(view));
4347
4376
  }
4348
4377
  for (const page of config.ui?.pages ?? []) {
4349
4378
  pushRoute(pageToRoute(page, componentRegistry));
4350
4379
  const item = pageToMenu(page);
4351
- if (item) menu.push(item);
4380
+ if (item) pushMenu(item);
4352
4381
  }
4353
4382
  }
4354
4383
  if (includeManual) {
4355
- for (const item of config.ui?.navigation?.items ?? []) menu.push({ ...item, permissions: requiredAccess2(item) });
4384
+ for (const item of config.ui?.navigation?.items ?? []) pushMenu(item);
4356
4385
  }
4357
4386
  menu.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
4358
4387
  return { routes, menu };
@@ -4366,7 +4395,7 @@ import {
4366
4395
 
4367
4396
  // src/shell/DefaultShell.tsx
4368
4397
  import { Box as Box18, Button as Button11, Flex as Flex11, Spacer as Spacer2, Text as Text19 } from "@chakra-ui/react";
4369
- import { Outlet } from "react-router-dom";
4398
+ import { Outlet, useNavigate } from "react-router-dom";
4370
4399
 
4371
4400
  // src/shell/Sidebar.tsx
4372
4401
  import { Box as Box17, Flex as Flex10, Image, Stack as Stack8, Text as Text18 } from "@chakra-ui/react";
@@ -4473,7 +4502,7 @@ function Sidebar({ app, menu, registry }) {
4473
4502
  // package.json
4474
4503
  var package_default = {
4475
4504
  name: "@oondemand/oon-core-front",
4476
- version: "0.3.57",
4505
+ version: "0.3.59",
4477
4506
  repository: {
4478
4507
  type: "git",
4479
4508
  url: "git+https://github.com/oondemand/oon-platform.git",
@@ -4593,8 +4622,50 @@ function shortCommit(commit) {
4593
4622
 
4594
4623
  // src/shell/DefaultShell.tsx
4595
4624
  import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
4596
- function CoreTopbar({ app }) {
4597
- const { user, logout } = useOonAuth();
4625
+ function SettingsIcon() {
4626
+ return /* @__PURE__ */ jsxs19(
4627
+ "svg",
4628
+ {
4629
+ "aria-hidden": "true",
4630
+ width: "18",
4631
+ height: "18",
4632
+ viewBox: "0 0 24 24",
4633
+ fill: "none",
4634
+ xmlns: "http://www.w3.org/2000/svg",
4635
+ children: [
4636
+ /* @__PURE__ */ jsx27(
4637
+ "path",
4638
+ {
4639
+ d: "M12 15.25a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5Z",
4640
+ stroke: "currentColor",
4641
+ strokeWidth: "1.8"
4642
+ }
4643
+ ),
4644
+ /* @__PURE__ */ jsx27(
4645
+ "path",
4646
+ {
4647
+ d: "M19.43 12.98c.04-.32.07-.65.07-.98s-.03-.66-.08-.98l2.12-1.66-2-3.46-2.5 1a7.64 7.64 0 0 0-1.7-.98L15 3.25h-4l-.35 2.67c-.61.25-1.18.58-1.7.98l-2.5-1-2 3.46 2.12 1.66c-.04.32-.07.65-.07.98s.03.66.08.98l-2.12 1.66 2 3.46 2.5-1c.52.4 1.09.73 1.7.98l.34 2.67h4l.35-2.67a7.64 7.64 0 0 0 1.7-.98l2.5 1 2-3.46-2.12-1.66Z",
4648
+ stroke: "currentColor",
4649
+ strokeWidth: "1.8",
4650
+ strokeLinecap: "round",
4651
+ strokeLinejoin: "round"
4652
+ }
4653
+ )
4654
+ ]
4655
+ }
4656
+ );
4657
+ }
4658
+ function resolveSettingsHref(menu) {
4659
+ const explicit = menu.find((item) => item.action === "settings");
4660
+ if (explicit) return explicit.href;
4661
+ const settingsPage = menu.find((item) => item.href === "/configuracoes");
4662
+ if (settingsPage) return settingsPage.href;
4663
+ const integrationsPage = menu.find((item) => item.href === "/integracoes");
4664
+ return integrationsPage?.href ?? null;
4665
+ }
4666
+ function CoreTopbar({ app, menu }) {
4667
+ const { user, logout, hasPermission } = useOonAuth();
4668
+ const navigate = useNavigate();
4598
4669
  const metadataQuery = useCoreMetadata();
4599
4670
  const runtime = resolveRuntimeVersionInfo(app, metadataQuery.data);
4600
4671
  const centralVersion = runtime.centralVersion ?? "n\xE3o informada";
@@ -4615,6 +4686,9 @@ function CoreTopbar({ app }) {
4615
4686
  runtime.releaseId ? `Release ${runtime.releaseId}` : void 0,
4616
4687
  runtime.startedAt ? `Backend iniciado ${formatRuntimeDate(runtime.startedAt)}` : void 0
4617
4688
  ].filter(Boolean).join(" \xB7 ");
4689
+ const settingsHref = resolveSettingsHref(
4690
+ menu.filter((item) => !item.hidden && hasPermission(item.permissions))
4691
+ );
4618
4692
  return /* @__PURE__ */ jsxs19(
4619
4693
  Flex11,
4620
4694
  {
@@ -4660,6 +4734,21 @@ function CoreTopbar({ app }) {
4660
4734
  /* @__PURE__ */ jsx27(Text19, { fontSize: "sm", fontWeight: "600", color: "#24323A", children: user.nome }),
4661
4735
  user.email ? /* @__PURE__ */ jsx27(Text19, { fontSize: "xs", color: "gray.500", children: user.email }) : null
4662
4736
  ] }),
4737
+ settingsHref ? /* @__PURE__ */ jsx27(
4738
+ Button11,
4739
+ {
4740
+ size: "sm",
4741
+ variant: "outline",
4742
+ colorPalette: "brand",
4743
+ borderRadius: "8px",
4744
+ minW: "36px",
4745
+ px: 2,
4746
+ "aria-label": "Abrir configura\xE7\xF5es",
4747
+ title: "Configura\xE7\xF5es",
4748
+ onClick: () => navigate(settingsHref),
4749
+ children: /* @__PURE__ */ jsx27(SettingsIcon, {})
4750
+ }
4751
+ ) : null,
4663
4752
  /* @__PURE__ */ jsx27(
4664
4753
  Button11,
4665
4754
  {
@@ -4689,7 +4778,7 @@ function Slot({
4689
4778
  return Component ? /* @__PURE__ */ jsx27(Component, { app, menu }) : /* @__PURE__ */ jsx27(MissingRenderer, { renderer: slot });
4690
4779
  }
4691
4780
  if (name === "sidebar") return /* @__PURE__ */ jsx27(Sidebar, { app, menu, registry });
4692
- if (name === "topbar") return /* @__PURE__ */ jsx27(CoreTopbar, { app });
4781
+ if (name === "topbar") return /* @__PURE__ */ jsx27(CoreTopbar, { app, menu });
4693
4782
  if (name === "footer" && slot === "core") {
4694
4783
  return /* @__PURE__ */ jsx27(Box18, { as: "footer", px: 6, py: 4, color: "gray.500", fontSize: "xs", borderTopWidth: "1px", children: "OonCore" });
4695
4784
  }
@@ -4757,11 +4846,11 @@ function AuthenticatedLayout({ app, menu, layout, registry }) {
4757
4846
 
4758
4847
  // src/security/AccessDeniedPage.tsx
4759
4848
  import { Box as Box19, Button as Button12, Flex as Flex12, Heading as Heading9, Text as Text20, VStack } from "@chakra-ui/react";
4760
- import { useNavigate } from "react-router-dom";
4849
+ import { useNavigate as useNavigate2 } from "react-router-dom";
4761
4850
  import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
4762
4851
  function AccessDeniedPage({ app }) {
4763
4852
  const { logout } = useOonAuth();
4764
- const navigate = useNavigate();
4853
+ const navigate = useNavigate2();
4765
4854
  function useAnotherAccount() {
4766
4855
  logout();
4767
4856
  navigate("/login", { replace: true });
@@ -5763,8 +5852,12 @@ function startFromManifest(manifest, runtime) {
5763
5852
  start(manifestToConfig(manifest, runtime));
5764
5853
  }
5765
5854
 
5855
+ // src/modules/integrations.tsx
5856
+ import { Stack as Stack11 } from "@chakra-ui/react";
5857
+
5766
5858
  // src/components/CoreIntegration.tsx
5767
- import { Badge as Badge5, Box as Box22, Button as Button15, Flex as Flex14, Heading as Heading12, Stack as Stack9, Text as Text23 } from "@chakra-ui/react";
5859
+ import { useEffect as useEffect9, useState as useState14 } from "react";
5860
+ import { Badge as Badge5, Box as Box22, Button as Button15, Flex as Flex14, Heading as Heading12, Input as Input8, Stack as Stack9, Text as Text23 } from "@chakra-ui/react";
5768
5861
  import { useMutation as useMutation4, useQuery as useQuery8 } from "@tanstack/react-query";
5769
5862
  import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
5770
5863
  function dateTime(value2) {
@@ -5774,15 +5867,242 @@ function dateTime(value2) {
5774
5867
  }
5775
5868
  function statusPalette(status) {
5776
5869
  const normalized2 = String(status || "").toLowerCase();
5777
- if (normalized2.includes("erro") || normalized2.includes("inativo")) return "red";
5778
- if (normalized2.includes("process") || normalized2.includes("tempor\xE1rio")) return "yellow";
5779
- if (normalized2.includes("conclu\xEDdo") || normalized2.includes("ativo")) return "green";
5870
+ if (normalized2.includes("erro") || normalized2.includes("error") || normalized2.includes("inativo")) return "red";
5871
+ if (normalized2.includes("process") || normalized2.includes("tempor\xE1rio") || normalized2.includes("not-tested")) return "yellow";
5872
+ if (normalized2.includes("conclu\xEDdo") || normalized2.includes("ativo") || normalized2 === "ok") return "green";
5780
5873
  return "gray";
5781
5874
  }
5782
5875
  function countActive(values) {
5783
5876
  if (!values) return 0;
5784
5877
  return Object.entries(values).filter(([status]) => !["Conclu\xEDdo", "Arquivado"].includes(status)).reduce((sum, [, count]) => sum + Number(count || 0), 0);
5785
5878
  }
5879
+ function ProviderConfigurationPanel({ provider }) {
5880
+ const { http } = useOonApi();
5881
+ const [draft, setDraft] = useState14({
5882
+ instanceId: "default",
5883
+ label: provider.label,
5884
+ active: true,
5885
+ environment: "production",
5886
+ baseUrl: "",
5887
+ appKey: "",
5888
+ appSecret: "",
5889
+ webhookToken: ""
5890
+ });
5891
+ const configuration = useQuery8({
5892
+ queryKey: ["core-integrations", provider.key, "configuration"],
5893
+ queryFn: async () => (await http.get(`/integrations/providers/${provider.key}/configuration`)).data?.instances ?? []
5894
+ });
5895
+ const mappings = useQuery8({
5896
+ queryKey: ["core-integrations", provider.key, "mappings"],
5897
+ queryFn: async () => (await http.get(`/integrations/providers/${provider.key}/mappings`)).data
5898
+ });
5899
+ const selected = (configuration.data ?? []).find((item) => item.instanceId === draft.instanceId);
5900
+ useEffect9(() => {
5901
+ if (!selected) return;
5902
+ setDraft((current) => ({
5903
+ ...current,
5904
+ instanceId: selected.instanceId || "default",
5905
+ label: selected.label || provider.label,
5906
+ active: selected.active !== false,
5907
+ environment: selected.environment || "production",
5908
+ baseUrl: selected.baseUrl || "",
5909
+ appKey: "",
5910
+ appSecret: "",
5911
+ webhookToken: ""
5912
+ }));
5913
+ }, [provider.label, selected?.instanceId, selected?.updatedAt]);
5914
+ const save = useMutation4({
5915
+ mutationFn: async () => http.put(
5916
+ `/integrations/providers/${provider.key}/configuration/${draft.instanceId}`,
5917
+ {
5918
+ label: draft.label,
5919
+ active: draft.active,
5920
+ environment: draft.environment,
5921
+ baseUrl: draft.baseUrl,
5922
+ ...draft.appKey ? { appKey: draft.appKey } : {},
5923
+ ...draft.appSecret ? { appSecret: draft.appSecret } : {},
5924
+ ...draft.webhookToken ? { webhookToken: draft.webhookToken } : {}
5925
+ },
5926
+ { headers: { "x-oon-origin": "integration" } }
5927
+ ),
5928
+ onSuccess: async () => {
5929
+ setDraft((current) => ({ ...current, appKey: "", appSecret: "", webhookToken: "" }));
5930
+ await configuration.refetch();
5931
+ }
5932
+ });
5933
+ const testConnection = useMutation4({
5934
+ mutationFn: async () => http.post(
5935
+ `/integrations/providers/${provider.key}/configuration/${draft.instanceId}/test`,
5936
+ {},
5937
+ { headers: { "x-oon-origin": "integration" } }
5938
+ ),
5939
+ onSuccess: () => configuration.refetch()
5940
+ });
5941
+ const error = configuration.error || mappings.error || save.error || testConnection.error;
5942
+ const mappingCounts = {
5943
+ chamadas: mappings.data?.calls?.length ?? 0,
5944
+ listas: mappings.data?.lists?.length ?? 0,
5945
+ webhooks: mappings.data?.webhooks?.length ?? 0
5946
+ };
5947
+ return /* @__PURE__ */ jsx38(Box22, { borderTopWidth: "1px", borderColor: "gray.100", pt: 4, children: /* @__PURE__ */ jsxs23(Stack9, { gap: 3, children: [
5948
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 3, wrap: "wrap", children: [
5949
+ /* @__PURE__ */ jsxs23(Box22, { children: [
5950
+ /* @__PURE__ */ jsx38(Text23, { fontWeight: "semibold", children: "Configura\xE7\xE3o" }),
5951
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "gray.500", children: "Credenciais protegidas por inst\xE2ncia. Segredos gravados nunca s\xE3o devolvidos ao navegador." })
5952
+ ] }),
5953
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 2, wrap: "wrap", children: [
5954
+ /* @__PURE__ */ jsxs23(Badge5, { variant: "outline", children: [
5955
+ mappingCounts.chamadas,
5956
+ " chamadas"
5957
+ ] }),
5958
+ /* @__PURE__ */ jsxs23(Badge5, { variant: "outline", children: [
5959
+ mappingCounts.listas,
5960
+ " listas"
5961
+ ] }),
5962
+ /* @__PURE__ */ jsxs23(Badge5, { variant: "outline", children: [
5963
+ mappingCounts.webhooks,
5964
+ " webhooks"
5965
+ ] })
5966
+ ] })
5967
+ ] }),
5968
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 3, wrap: "wrap", children: [
5969
+ /* @__PURE__ */ jsxs23(Box22, { minW: "180px", flex: "1", children: [
5970
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Inst\xE2ncia" }),
5971
+ /* @__PURE__ */ jsx38(
5972
+ Input8,
5973
+ {
5974
+ size: "sm",
5975
+ value: draft.instanceId,
5976
+ onChange: (event) => setDraft((current) => ({ ...current, instanceId: event.target.value })),
5977
+ placeholder: "default"
5978
+ }
5979
+ )
5980
+ ] }),
5981
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "2", children: [
5982
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Nome" }),
5983
+ /* @__PURE__ */ jsx38(
5984
+ Input8,
5985
+ {
5986
+ size: "sm",
5987
+ value: draft.label,
5988
+ onChange: (event) => setDraft((current) => ({ ...current, label: event.target.value }))
5989
+ }
5990
+ )
5991
+ ] }),
5992
+ /* @__PURE__ */ jsxs23(Box22, { minW: "180px", flex: "1", children: [
5993
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Ambiente" }),
5994
+ /* @__PURE__ */ jsxs23(
5995
+ "select",
5996
+ {
5997
+ style: {
5998
+ width: "100%",
5999
+ height: "32px",
6000
+ border: "1px solid #e2e8f0",
6001
+ borderRadius: "6px",
6002
+ padding: "0 8px",
6003
+ background: "white"
6004
+ },
6005
+ value: draft.environment,
6006
+ onChange: (event) => setDraft((current) => ({
6007
+ ...current,
6008
+ environment: event.currentTarget.value
6009
+ })),
6010
+ children: [
6011
+ /* @__PURE__ */ jsx38("option", { value: "production", children: "Produ\xE7\xE3o" }),
6012
+ /* @__PURE__ */ jsx38("option", { value: "homologation", children: "Homologa\xE7\xE3o" })
6013
+ ]
6014
+ }
6015
+ )
6016
+ ] })
6017
+ ] }),
6018
+ /* @__PURE__ */ jsxs23(Box22, { children: [
6019
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "URL base" }),
6020
+ /* @__PURE__ */ jsx38(
6021
+ Input8,
6022
+ {
6023
+ size: "sm",
6024
+ value: draft.baseUrl,
6025
+ onChange: (event) => setDraft((current) => ({ ...current, baseUrl: event.target.value })),
6026
+ placeholder: "https://app.omie.com.br/api/v1"
6027
+ }
6028
+ )
6029
+ ] }),
6030
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 3, wrap: "wrap", children: [
6031
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "1", children: [
6032
+ /* @__PURE__ */ jsxs23(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: [
6033
+ "App Key ",
6034
+ selected?.appKeyMasked ? `(${selected.appKeyMasked})` : ""
6035
+ ] }),
6036
+ /* @__PURE__ */ jsx38(
6037
+ Input8,
6038
+ {
6039
+ size: "sm",
6040
+ type: "password",
6041
+ value: draft.appKey,
6042
+ onChange: (event) => setDraft((current) => ({ ...current, appKey: event.target.value })),
6043
+ placeholder: selected?.credentialsConfigured ? "Manter valor atual" : "Informe a App Key"
6044
+ }
6045
+ )
6046
+ ] }),
6047
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "1", children: [
6048
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "App Secret" }),
6049
+ /* @__PURE__ */ jsx38(
6050
+ Input8,
6051
+ {
6052
+ size: "sm",
6053
+ type: "password",
6054
+ value: draft.appSecret,
6055
+ onChange: (event) => setDraft((current) => ({ ...current, appSecret: event.target.value })),
6056
+ placeholder: selected?.credentialsConfigured ? "Manter valor atual" : "Informe o App Secret"
6057
+ }
6058
+ )
6059
+ ] }),
6060
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "1", children: [
6061
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Token do webhook" }),
6062
+ /* @__PURE__ */ jsx38(
6063
+ Input8,
6064
+ {
6065
+ size: "sm",
6066
+ type: "password",
6067
+ value: draft.webhookToken,
6068
+ onChange: (event) => setDraft((current) => ({ ...current, webhookToken: event.target.value })),
6069
+ placeholder: "Manter ou definir token"
6070
+ }
6071
+ )
6072
+ ] })
6073
+ ] }),
6074
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 3, wrap: "wrap", children: [
6075
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", gap: 2, wrap: "wrap", children: [
6076
+ /* @__PURE__ */ jsxs23("label", { children: [
6077
+ /* @__PURE__ */ jsx38(
6078
+ "input",
6079
+ {
6080
+ type: "checkbox",
6081
+ checked: draft.active,
6082
+ onChange: (event) => setDraft((current) => ({ ...current, active: event.target.checked }))
6083
+ }
6084
+ ),
6085
+ " ",
6086
+ "Integra\xE7\xE3o ativa"
6087
+ ] }),
6088
+ /* @__PURE__ */ jsxs23(Badge5, { colorPalette: statusPalette(selected?.connectionStatus), children: [
6089
+ "Conex\xE3o: ",
6090
+ selected?.connectionStatus ?? "n\xE3o testada"
6091
+ ] }),
6092
+ /* @__PURE__ */ jsxs23(Text23, { fontSize: "xs", color: "gray.500", children: [
6093
+ "\xDAltimo teste: ",
6094
+ dateTime(selected?.lastConnectionTestAt)
6095
+ ] })
6096
+ ] }),
6097
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 2, children: [
6098
+ /* @__PURE__ */ jsx38(Button15, { size: "xs", variant: "outline", loading: testConnection.isPending, onClick: () => testConnection.mutate(), children: "Testar conex\xE3o" }),
6099
+ /* @__PURE__ */ jsx38(Button15, { size: "xs", loading: save.isPending, onClick: () => save.mutate(), children: "Salvar configura\xE7\xE3o" })
6100
+ ] })
6101
+ ] }),
6102
+ selected?.lastConnectionError ? /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "red.600", children: selected.lastConnectionError }) : null,
6103
+ error ? /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "red.600", children: "N\xE3o foi poss\xEDvel operar a configura\xE7\xE3o do provedor." }) : null
6104
+ ] }) });
6105
+ }
5786
6106
  function CoreIntegration({ label = "Integra\xE7\xF5es" }) {
5787
6107
  const { http } = useOonApi();
5788
6108
  const providers = useQuery8({
@@ -5816,6 +6136,14 @@ function CoreIntegration({ label = "Integra\xE7\xF5es" }) {
5816
6136
  ),
5817
6137
  onSuccess: refresh
5818
6138
  });
6139
+ const syncResource = useMutation4({
6140
+ mutationFn: ({ provider, resource }) => http.post(
6141
+ `/integrations/providers/${provider}/resources/${resource}/sync`,
6142
+ {},
6143
+ { headers: { "x-oon-origin": "integration" } }
6144
+ ),
6145
+ onSuccess: refresh
6146
+ });
5819
6147
  const reprocess = useMutation4({
5820
6148
  mutationFn: (id) => http.post(
5821
6149
  `/integrations/queue/${id}/reprocess`,
@@ -5839,7 +6167,7 @@ function CoreIntegration({ label = "Integra\xE7\xF5es" }) {
5839
6167
  /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 4, wrap: "wrap", children: [
5840
6168
  /* @__PURE__ */ jsxs23(Box22, { children: [
5841
6169
  /* @__PURE__ */ jsx38(Heading12, { size: "lg", children: label }),
5842
- /* @__PURE__ */ jsx38(Text23, { color: "gray.500", children: "Sa\xFAde, filas, eventos e diagn\xF3stico sanitizado por provedor." })
6170
+ /* @__PURE__ */ jsx38(Text23, { color: "gray.500", children: "Configura\xE7\xE3o, sa\xFAde, filas, eventos e diagn\xF3stico sanitizado por provedor." })
5843
6171
  ] }),
5844
6172
  /* @__PURE__ */ jsx38(Button15, { size: "sm", variant: "outline", loading: process.isPending, onClick: () => process.mutate(), children: "Processar pend\xEAncias" })
5845
6173
  ] }),
@@ -5872,7 +6200,18 @@ function CoreIntegration({ label = "Integra\xE7\xF5es" }) {
5872
6200
  "Pend\xEAncia mais antiga: ",
5873
6201
  dateTime(provider.oldestPendingAt)
5874
6202
  ] }),
5875
- /* @__PURE__ */ jsx38(Flex14, { gap: 2, wrap: "wrap", children: (provider.resources ?? []).map((resource) => /* @__PURE__ */ jsx38(Badge5, { variant: "outline", colorPalette: "blue", children: resource.label }, resource.key)) })
6203
+ /* @__PURE__ */ jsx38(Flex14, { gap: 2, wrap: "wrap", children: (provider.resources ?? []).map((resource) => /* @__PURE__ */ jsx38(
6204
+ Button15,
6205
+ {
6206
+ size: "xs",
6207
+ variant: "outline",
6208
+ loading: syncResource.isPending,
6209
+ onClick: () => syncResource.mutate({ provider: provider.key, resource: resource.key }),
6210
+ children: resource.label
6211
+ },
6212
+ resource.key
6213
+ )) }),
6214
+ provider.configuration?.enabled ? /* @__PURE__ */ jsx38(ProviderConfigurationPanel, { provider }) : null
5876
6215
  ] }) }, provider.key)) }),
5877
6216
  /* @__PURE__ */ jsxs23(Box22, { children: [
5878
6217
  /* @__PURE__ */ jsx38(Heading12, { size: "md", mb: 3, children: "Fila recente" }),
@@ -5921,8 +6260,93 @@ function CoreIntegration({ label = "Integra\xE7\xF5es" }) {
5921
6260
  ] });
5922
6261
  }
5923
6262
 
6263
+ // src/components/CoreIntegrationMappings.tsx
6264
+ import { Badge as Badge6, Box as Box23, Flex as Flex15, Heading as Heading13, Stack as Stack10, Text as Text24 } from "@chakra-ui/react";
6265
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
6266
+ import { jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
6267
+ function dateTime2(value2) {
6268
+ if (!value2) return "sem execu\xE7\xE3o";
6269
+ const date = new Date(value2);
6270
+ return Number.isNaN(date.getTime()) ? value2 : date.toLocaleString("pt-BR");
6271
+ }
6272
+ function CoreIntegrationMappings() {
6273
+ const { http } = useOonApi();
6274
+ const providers = useQuery9({
6275
+ queryKey: ["core-integrations", "providers"],
6276
+ queryFn: async () => (await http.get("/integrations/providers")).data?.results ?? []
6277
+ });
6278
+ const providerKeys = (providers.data ?? []).map((provider) => provider.key).join(",");
6279
+ const summaries = useQuery9({
6280
+ queryKey: ["core-integrations", "mapping-summaries", providerKeys],
6281
+ enabled: providers.isSuccess && providerKeys.length > 0,
6282
+ queryFn: async () => Promise.all((providers.data ?? []).map(async (provider) => ({
6283
+ provider,
6284
+ mappings: (await http.get(`/integrations/providers/${provider.key}/mappings`)).data
6285
+ })))
6286
+ });
6287
+ if (providers.isLoading || summaries.isLoading) {
6288
+ return /* @__PURE__ */ jsx39(Text24, { color: "gray.500", children: "Carregando contratos declarados\u2026" });
6289
+ }
6290
+ if (providers.error || summaries.error) {
6291
+ return /* @__PURE__ */ jsx39(Text24, { color: "red.600", children: "N\xE3o foi poss\xEDvel carregar os contratos declarados." });
6292
+ }
6293
+ if (!(summaries.data ?? []).length) return null;
6294
+ return /* @__PURE__ */ jsxs24(Box23, { children: [
6295
+ /* @__PURE__ */ jsx39(Heading13, { size: "md", mb: 1, children: "Contratos declarados" }),
6296
+ /* @__PURE__ */ jsx39(Text24, { color: "gray.500", mb: 3, children: "Chamadas, listas e mappings pertencem \xE0 Central; o Core exibe somente metadados sanitizados." }),
6297
+ /* @__PURE__ */ jsx39(Stack10, { gap: 3, children: summaries.data?.map(({ provider, mappings }) => /* @__PURE__ */ jsx39(Box23, { borderWidth: "1px", borderRadius: "md", bg: "white", p: 4, children: /* @__PURE__ */ jsxs24(Stack10, { gap: 4, children: [
6298
+ /* @__PURE__ */ jsx39(Heading13, { size: "sm", children: provider.label }),
6299
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6300
+ /* @__PURE__ */ jsx39(Text24, { fontWeight: "semibold", mb: 2, children: "Chamadas Omie" }),
6301
+ /* @__PURE__ */ jsx39(Flex15, { gap: 2, wrap: "wrap", children: (mappings.calls ?? []).length ? mappings.calls?.map((call) => /* @__PURE__ */ jsxs24(Badge6, { variant: "outline", children: [
6302
+ call.label || call.key,
6303
+ " \xB7 ",
6304
+ call.call || "opera\xE7\xE3o",
6305
+ call.paginated ? " \xB7 paginada" : ""
6306
+ ] }, call.key)) : /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", color: "gray.400", children: "Nenhuma chamada declarada." }) })
6307
+ ] }),
6308
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6309
+ /* @__PURE__ */ jsx39(Text24, { fontWeight: "semibold", mb: 2, children: "Listas Omie" }),
6310
+ /* @__PURE__ */ jsx39(Stack10, { gap: 2, children: (mappings.lists ?? []).length ? mappings.lists?.map((list) => {
6311
+ const latest = list.executions?.[0];
6312
+ return /* @__PURE__ */ jsx39(Box23, { borderWidth: "1px", borderColor: "gray.100", borderRadius: "md", p: 3, children: /* @__PURE__ */ jsxs24(Flex15, { align: "center", justify: "space-between", gap: 2, wrap: "wrap", children: [
6313
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6314
+ /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", fontWeight: "medium", children: list.label || list.key }),
6315
+ /* @__PURE__ */ jsxs24(Text24, { fontSize: "xs", color: "gray.500", children: [
6316
+ list.mode || "modo padr\xE3o",
6317
+ " \xB7 ",
6318
+ list.direction || "dire\xE7\xE3o padr\xE3o",
6319
+ " \xB7 ",
6320
+ list.targetModel || "destino declarado"
6321
+ ] })
6322
+ ] }),
6323
+ /* @__PURE__ */ jsxs24(Flex15, { gap: 2, wrap: "wrap", children: [
6324
+ /* @__PURE__ */ jsx39(Badge6, { variant: "outline", children: latest?.status || "n\xE3o executada" }),
6325
+ /* @__PURE__ */ jsx39(Badge6, { variant: "outline", children: dateTime2(latest?.lastCompletedAt) })
6326
+ ] })
6327
+ ] }) }, list.key);
6328
+ }) : /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", color: "gray.400", children: "Nenhuma lista declarada." }) })
6329
+ ] }),
6330
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6331
+ /* @__PURE__ */ jsx39(Text24, { fontWeight: "semibold", mb: 2, children: "Mappings de webhook" }),
6332
+ /* @__PURE__ */ jsx39(Stack10, { gap: 1, children: (mappings.webhooks ?? []).length ? mappings.webhooks?.map((webhook) => /* @__PURE__ */ jsxs24(Text24, { fontSize: "sm", color: "gray.600", children: [
6333
+ webhook.eventType,
6334
+ " \u2192 ",
6335
+ (webhook.actions ?? []).map((action) => action.handler).filter(Boolean).join(", ") || "sem a\xE7\xE3o declarada"
6336
+ ] }, `${webhook.eventType}:${webhook.resource || ""}`)) : /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", color: "gray.400", children: "Nenhum mapping de webhook declarado." }) })
6337
+ ] })
6338
+ ] }) }, provider.key)) })
6339
+ ] });
6340
+ }
6341
+
5924
6342
  // src/modules/integrations.tsx
5925
- import { jsx as jsx39 } from "react/jsx-runtime";
6343
+ import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
6344
+ function CoreIntegrationPage() {
6345
+ return /* @__PURE__ */ jsxs25(Stack11, { gap: 8, children: [
6346
+ /* @__PURE__ */ jsx40(CoreIntegration, {}),
6347
+ /* @__PURE__ */ jsx40(CoreIntegrationMappings, {})
6348
+ ] });
6349
+ }
5926
6350
  function createIntegrationModule() {
5927
6351
  return {
5928
6352
  id: "core.integrations",
@@ -5930,7 +6354,7 @@ function createIntegrationModule() {
5930
6354
  routes: [
5931
6355
  {
5932
6356
  path: "/integracoes",
5933
- element: /* @__PURE__ */ jsx39(CoreIntegration, {}),
6357
+ element: /* @__PURE__ */ jsx40(CoreIntegrationPage, {}),
5934
6358
  capabilities: ["core.integrations"]
5935
6359
  }
5936
6360
  ],
@@ -5992,9 +6416,9 @@ function defineOonModule(mod) {
5992
6416
  }
5993
6417
 
5994
6418
  // src/components/CoreCurrency.tsx
5995
- import { Button as Button16, Flex as Flex15, Heading as Heading13, Stack as Stack10, Text as Text24 } from "@chakra-ui/react";
6419
+ import { Button as Button16, Flex as Flex16, Heading as Heading14, Stack as Stack12, Text as Text25 } from "@chakra-ui/react";
5996
6420
  import { useMutation as useMutation5, useQueryClient as useQueryClient5 } from "@tanstack/react-query";
5997
- import { jsx as jsx40, jsxs as jsxs24 } from "react/jsx-runtime";
6421
+ import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
5998
6422
  function CoreCurrency({ model = "Moeda", label = "Multi-moedas", endpoint = "/moedas", columns }) {
5999
6423
  const { http } = useOonApi();
6000
6424
  const queryClient = useQueryClient5();
@@ -6002,25 +6426,25 @@ function CoreCurrency({ model = "Moeda", label = "Multi-moedas", endpoint = "/mo
6002
6426
  mutationFn: () => http.post(`${endpoint}/actions/update-rates`, {}, { headers: { "x-oon-origin": "integration" } }),
6003
6427
  onSuccess: () => queryClient.invalidateQueries({ queryKey: ["oon", "list", endpoint] })
6004
6428
  });
6005
- return /* @__PURE__ */ jsxs24(Stack10, { gap: 6, children: [
6006
- /* @__PURE__ */ jsxs24(Flex15, { align: "center", justify: "space-between", children: [
6007
- /* @__PURE__ */ jsx40(Heading13, { size: "lg", children: label }),
6008
- /* @__PURE__ */ jsx40(Button16, { size: "sm", colorPalette: "blue", loading: updateRates.isPending, onClick: () => updateRates.mutate(), children: "Atualizar cota\xE7\xF5es" })
6429
+ return /* @__PURE__ */ jsxs26(Stack12, { gap: 6, children: [
6430
+ /* @__PURE__ */ jsxs26(Flex16, { align: "center", justify: "space-between", children: [
6431
+ /* @__PURE__ */ jsx41(Heading14, { size: "lg", children: label }),
6432
+ /* @__PURE__ */ jsx41(Button16, { size: "sm", colorPalette: "blue", loading: updateRates.isPending, onClick: () => updateRates.mutate(), children: "Atualizar cota\xE7\xF5es" })
6009
6433
  ] }),
6010
- updateRates.isError ? /* @__PURE__ */ jsx40(Text24, { fontSize: "sm", color: "red.600", children: updateRates.error?.message }) : null,
6011
- /* @__PURE__ */ jsx40(CoreCollection, { model, label: "", mode: columns ? "full" : "dynamic", endpoint, columns })
6434
+ updateRates.isError ? /* @__PURE__ */ jsx41(Text25, { fontSize: "sm", color: "red.600", children: updateRates.error?.message }) : null,
6435
+ /* @__PURE__ */ jsx41(CoreCollection, { model, label: "", mode: columns ? "full" : "dynamic", endpoint, columns })
6012
6436
  ] });
6013
6437
  }
6014
6438
 
6015
6439
  // src/components/CoreAssistant.tsx
6016
- import { useState as useState14 } from "react";
6017
- import { Box as Box23, Button as Button17, Flex as Flex16, Heading as Heading14, Input as Input8, Stack as Stack11, Text as Text25 } from "@chakra-ui/react";
6440
+ import { useState as useState15 } from "react";
6441
+ import { Box as Box24, Button as Button17, Flex as Flex17, Heading as Heading15, Input as Input9, Stack as Stack13, Text as Text26 } from "@chakra-ui/react";
6018
6442
  import { useMutation as useMutation6 } from "@tanstack/react-query";
6019
- import { jsx as jsx41, jsxs as jsxs25 } from "react/jsx-runtime";
6443
+ import { jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
6020
6444
  function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint = "/assistant-runs" }) {
6021
6445
  const { http } = useOonApi();
6022
- const [messages, setMessages] = useState14([]);
6023
- const [input, setInput] = useState14("");
6446
+ const [messages, setMessages] = useState15([]);
6447
+ const [input, setInput] = useState15("");
6024
6448
  const ask = useMutation6({
6025
6449
  mutationFn: async (message) => {
6026
6450
  const { data } = await http.post(
@@ -6045,11 +6469,11 @@ function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint =
6045
6469
  setInput("");
6046
6470
  ask.mutate(text);
6047
6471
  };
6048
- return /* @__PURE__ */ jsxs25(Stack11, { gap: 4, maxW: "560px", children: [
6049
- /* @__PURE__ */ jsx41(Heading14, { size: "md", children: label }),
6050
- /* @__PURE__ */ jsx41(Box23, { borderWidth: "1px", borderColor: "gray.200", borderRadius: "md", bg: "white", p: 4, minH: "240px", children: /* @__PURE__ */ jsxs25(Stack11, { gap: 3, children: [
6051
- messages.length === 0 ? /* @__PURE__ */ jsx41(Text25, { color: "gray.400", fontSize: "sm", children: "Fa\xE7a uma pergunta ao assistente." }) : messages.map((m, idx) => /* @__PURE__ */ jsx41(Flex16, { justify: m.role === "user" ? "flex-end" : "flex-start", children: /* @__PURE__ */ jsx41(
6052
- Box23,
6472
+ return /* @__PURE__ */ jsxs27(Stack13, { gap: 4, maxW: "560px", children: [
6473
+ /* @__PURE__ */ jsx42(Heading15, { size: "md", children: label }),
6474
+ /* @__PURE__ */ jsx42(Box24, { borderWidth: "1px", borderColor: "gray.200", borderRadius: "md", bg: "white", p: 4, minH: "240px", children: /* @__PURE__ */ jsxs27(Stack13, { gap: 3, children: [
6475
+ messages.length === 0 ? /* @__PURE__ */ jsx42(Text26, { color: "gray.400", fontSize: "sm", children: "Fa\xE7a uma pergunta ao assistente." }) : messages.map((m, idx) => /* @__PURE__ */ jsx42(Flex17, { justify: m.role === "user" ? "flex-end" : "flex-start", children: /* @__PURE__ */ jsx42(
6476
+ Box24,
6053
6477
  {
6054
6478
  bg: m.role === "user" ? "brand.500" : "gray.100",
6055
6479
  color: m.role === "user" ? "white" : "gray.800",
@@ -6061,12 +6485,12 @@ function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint =
6061
6485
  children: m.content
6062
6486
  }
6063
6487
  ) }, idx)),
6064
- ask.isPending ? /* @__PURE__ */ jsx41(Text25, { color: "gray.400", fontSize: "sm", children: "Pensando\u2026" }) : null,
6065
- ask.isError ? /* @__PURE__ */ jsx41(Text25, { color: "red.600", fontSize: "sm", children: ask.error?.message }) : null
6488
+ ask.isPending ? /* @__PURE__ */ jsx42(Text26, { color: "gray.400", fontSize: "sm", children: "Pensando\u2026" }) : null,
6489
+ ask.isError ? /* @__PURE__ */ jsx42(Text26, { color: "red.600", fontSize: "sm", children: ask.error?.message }) : null
6066
6490
  ] }) }),
6067
- /* @__PURE__ */ jsxs25(Flex16, { gap: 2, children: [
6068
- /* @__PURE__ */ jsx41(
6069
- Input8,
6491
+ /* @__PURE__ */ jsxs27(Flex17, { gap: 2, children: [
6492
+ /* @__PURE__ */ jsx42(
6493
+ Input9,
6070
6494
  {
6071
6495
  size: "sm",
6072
6496
  value: input,
@@ -6077,7 +6501,7 @@ function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint =
6077
6501
  }
6078
6502
  }
6079
6503
  ),
6080
- /* @__PURE__ */ jsx41(Button17, { size: "sm", colorPalette: "blue", onClick: send, loading: ask.isPending, children: "Enviar" })
6504
+ /* @__PURE__ */ jsx42(Button17, { size: "sm", colorPalette: "blue", onClick: send, loading: ask.isPending, children: "Enviar" })
6081
6505
  ] })
6082
6506
  ] });
6083
6507
  }