@oondemand/oon-core-front 0.3.56 → 0.3.58

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
@@ -4473,7 +4473,7 @@ function Sidebar({ app, menu, registry }) {
4473
4473
  // package.json
4474
4474
  var package_default = {
4475
4475
  name: "@oondemand/oon-core-front",
4476
- version: "0.3.56",
4476
+ version: "0.3.58",
4477
4477
  repository: {
4478
4478
  type: "git",
4479
4479
  url: "git+https://github.com/oondemand/oon-platform.git",
@@ -5763,6 +5763,524 @@ function startFromManifest(manifest, runtime) {
5763
5763
  start(manifestToConfig(manifest, runtime));
5764
5764
  }
5765
5765
 
5766
+ // src/modules/integrations.tsx
5767
+ import { Stack as Stack11 } from "@chakra-ui/react";
5768
+
5769
+ // src/components/CoreIntegration.tsx
5770
+ import { useEffect as useEffect9, useState as useState14 } from "react";
5771
+ 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";
5772
+ import { useMutation as useMutation4, useQuery as useQuery8 } from "@tanstack/react-query";
5773
+ import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
5774
+ function dateTime(value2) {
5775
+ if (!value2) return "\u2014";
5776
+ const date = new Date(value2);
5777
+ return Number.isNaN(date.getTime()) ? value2 : date.toLocaleString("pt-BR");
5778
+ }
5779
+ function statusPalette(status) {
5780
+ const normalized2 = String(status || "").toLowerCase();
5781
+ if (normalized2.includes("erro") || normalized2.includes("error") || normalized2.includes("inativo")) return "red";
5782
+ if (normalized2.includes("process") || normalized2.includes("tempor\xE1rio") || normalized2.includes("not-tested")) return "yellow";
5783
+ if (normalized2.includes("conclu\xEDdo") || normalized2.includes("ativo") || normalized2 === "ok") return "green";
5784
+ return "gray";
5785
+ }
5786
+ function countActive(values) {
5787
+ if (!values) return 0;
5788
+ return Object.entries(values).filter(([status]) => !["Conclu\xEDdo", "Arquivado"].includes(status)).reduce((sum, [, count]) => sum + Number(count || 0), 0);
5789
+ }
5790
+ function ProviderConfigurationPanel({ provider }) {
5791
+ const { http } = useOonApi();
5792
+ const [draft, setDraft] = useState14({
5793
+ instanceId: "default",
5794
+ label: provider.label,
5795
+ active: true,
5796
+ environment: "production",
5797
+ baseUrl: "",
5798
+ appKey: "",
5799
+ appSecret: "",
5800
+ webhookToken: ""
5801
+ });
5802
+ const configuration = useQuery8({
5803
+ queryKey: ["core-integrations", provider.key, "configuration"],
5804
+ queryFn: async () => (await http.get(`/integrations/providers/${provider.key}/configuration`)).data?.instances ?? []
5805
+ });
5806
+ const mappings = useQuery8({
5807
+ queryKey: ["core-integrations", provider.key, "mappings"],
5808
+ queryFn: async () => (await http.get(`/integrations/providers/${provider.key}/mappings`)).data
5809
+ });
5810
+ const selected = (configuration.data ?? []).find((item) => item.instanceId === draft.instanceId);
5811
+ useEffect9(() => {
5812
+ if (!selected) return;
5813
+ setDraft((current) => ({
5814
+ ...current,
5815
+ instanceId: selected.instanceId || "default",
5816
+ label: selected.label || provider.label,
5817
+ active: selected.active !== false,
5818
+ environment: selected.environment || "production",
5819
+ baseUrl: selected.baseUrl || "",
5820
+ appKey: "",
5821
+ appSecret: "",
5822
+ webhookToken: ""
5823
+ }));
5824
+ }, [provider.label, selected?.instanceId, selected?.updatedAt]);
5825
+ const save = useMutation4({
5826
+ mutationFn: async () => http.put(
5827
+ `/integrations/providers/${provider.key}/configuration/${draft.instanceId}`,
5828
+ {
5829
+ label: draft.label,
5830
+ active: draft.active,
5831
+ environment: draft.environment,
5832
+ baseUrl: draft.baseUrl,
5833
+ ...draft.appKey ? { appKey: draft.appKey } : {},
5834
+ ...draft.appSecret ? { appSecret: draft.appSecret } : {},
5835
+ ...draft.webhookToken ? { webhookToken: draft.webhookToken } : {}
5836
+ },
5837
+ { headers: { "x-oon-origin": "integration" } }
5838
+ ),
5839
+ onSuccess: async () => {
5840
+ setDraft((current) => ({ ...current, appKey: "", appSecret: "", webhookToken: "" }));
5841
+ await configuration.refetch();
5842
+ }
5843
+ });
5844
+ const testConnection = useMutation4({
5845
+ mutationFn: async () => http.post(
5846
+ `/integrations/providers/${provider.key}/configuration/${draft.instanceId}/test`,
5847
+ {},
5848
+ { headers: { "x-oon-origin": "integration" } }
5849
+ ),
5850
+ onSuccess: () => configuration.refetch()
5851
+ });
5852
+ const error = configuration.error || mappings.error || save.error || testConnection.error;
5853
+ const mappingCounts = {
5854
+ chamadas: mappings.data?.calls?.length ?? 0,
5855
+ listas: mappings.data?.lists?.length ?? 0,
5856
+ webhooks: mappings.data?.webhooks?.length ?? 0
5857
+ };
5858
+ return /* @__PURE__ */ jsx38(Box22, { borderTopWidth: "1px", borderColor: "gray.100", pt: 4, children: /* @__PURE__ */ jsxs23(Stack9, { gap: 3, children: [
5859
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 3, wrap: "wrap", children: [
5860
+ /* @__PURE__ */ jsxs23(Box22, { children: [
5861
+ /* @__PURE__ */ jsx38(Text23, { fontWeight: "semibold", children: "Configura\xE7\xE3o" }),
5862
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "gray.500", children: "Credenciais protegidas por inst\xE2ncia. Segredos gravados nunca s\xE3o devolvidos ao navegador." })
5863
+ ] }),
5864
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 2, wrap: "wrap", children: [
5865
+ /* @__PURE__ */ jsxs23(Badge5, { variant: "outline", children: [
5866
+ mappingCounts.chamadas,
5867
+ " chamadas"
5868
+ ] }),
5869
+ /* @__PURE__ */ jsxs23(Badge5, { variant: "outline", children: [
5870
+ mappingCounts.listas,
5871
+ " listas"
5872
+ ] }),
5873
+ /* @__PURE__ */ jsxs23(Badge5, { variant: "outline", children: [
5874
+ mappingCounts.webhooks,
5875
+ " webhooks"
5876
+ ] })
5877
+ ] })
5878
+ ] }),
5879
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 3, wrap: "wrap", children: [
5880
+ /* @__PURE__ */ jsxs23(Box22, { minW: "180px", flex: "1", children: [
5881
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Inst\xE2ncia" }),
5882
+ /* @__PURE__ */ jsx38(
5883
+ Input8,
5884
+ {
5885
+ size: "sm",
5886
+ value: draft.instanceId,
5887
+ onChange: (event) => setDraft((current) => ({ ...current, instanceId: event.target.value })),
5888
+ placeholder: "default"
5889
+ }
5890
+ )
5891
+ ] }),
5892
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "2", children: [
5893
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Nome" }),
5894
+ /* @__PURE__ */ jsx38(
5895
+ Input8,
5896
+ {
5897
+ size: "sm",
5898
+ value: draft.label,
5899
+ onChange: (event) => setDraft((current) => ({ ...current, label: event.target.value }))
5900
+ }
5901
+ )
5902
+ ] }),
5903
+ /* @__PURE__ */ jsxs23(Box22, { minW: "180px", flex: "1", children: [
5904
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Ambiente" }),
5905
+ /* @__PURE__ */ jsxs23(
5906
+ "select",
5907
+ {
5908
+ style: {
5909
+ width: "100%",
5910
+ height: "32px",
5911
+ border: "1px solid #e2e8f0",
5912
+ borderRadius: "6px",
5913
+ padding: "0 8px",
5914
+ background: "white"
5915
+ },
5916
+ value: draft.environment,
5917
+ onChange: (event) => setDraft((current) => ({
5918
+ ...current,
5919
+ environment: event.currentTarget.value
5920
+ })),
5921
+ children: [
5922
+ /* @__PURE__ */ jsx38("option", { value: "production", children: "Produ\xE7\xE3o" }),
5923
+ /* @__PURE__ */ jsx38("option", { value: "homologation", children: "Homologa\xE7\xE3o" })
5924
+ ]
5925
+ }
5926
+ )
5927
+ ] })
5928
+ ] }),
5929
+ /* @__PURE__ */ jsxs23(Box22, { children: [
5930
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "URL base" }),
5931
+ /* @__PURE__ */ jsx38(
5932
+ Input8,
5933
+ {
5934
+ size: "sm",
5935
+ value: draft.baseUrl,
5936
+ onChange: (event) => setDraft((current) => ({ ...current, baseUrl: event.target.value })),
5937
+ placeholder: "https://app.omie.com.br/api/v1"
5938
+ }
5939
+ )
5940
+ ] }),
5941
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 3, wrap: "wrap", children: [
5942
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "1", children: [
5943
+ /* @__PURE__ */ jsxs23(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: [
5944
+ "App Key ",
5945
+ selected?.appKeyMasked ? `(${selected.appKeyMasked})` : ""
5946
+ ] }),
5947
+ /* @__PURE__ */ jsx38(
5948
+ Input8,
5949
+ {
5950
+ size: "sm",
5951
+ type: "password",
5952
+ value: draft.appKey,
5953
+ onChange: (event) => setDraft((current) => ({ ...current, appKey: event.target.value })),
5954
+ placeholder: selected?.credentialsConfigured ? "Manter valor atual" : "Informe a App Key"
5955
+ }
5956
+ )
5957
+ ] }),
5958
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "1", children: [
5959
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "App Secret" }),
5960
+ /* @__PURE__ */ jsx38(
5961
+ Input8,
5962
+ {
5963
+ size: "sm",
5964
+ type: "password",
5965
+ value: draft.appSecret,
5966
+ onChange: (event) => setDraft((current) => ({ ...current, appSecret: event.target.value })),
5967
+ placeholder: selected?.credentialsConfigured ? "Manter valor atual" : "Informe o App Secret"
5968
+ }
5969
+ )
5970
+ ] }),
5971
+ /* @__PURE__ */ jsxs23(Box22, { minW: "220px", flex: "1", children: [
5972
+ /* @__PURE__ */ jsx38(Text23, { fontSize: "xs", color: "gray.500", mb: 1, children: "Token do webhook" }),
5973
+ /* @__PURE__ */ jsx38(
5974
+ Input8,
5975
+ {
5976
+ size: "sm",
5977
+ type: "password",
5978
+ value: draft.webhookToken,
5979
+ onChange: (event) => setDraft((current) => ({ ...current, webhookToken: event.target.value })),
5980
+ placeholder: "Manter ou definir token"
5981
+ }
5982
+ )
5983
+ ] })
5984
+ ] }),
5985
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 3, wrap: "wrap", children: [
5986
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", gap: 2, wrap: "wrap", children: [
5987
+ /* @__PURE__ */ jsxs23("label", { children: [
5988
+ /* @__PURE__ */ jsx38(
5989
+ "input",
5990
+ {
5991
+ type: "checkbox",
5992
+ checked: draft.active,
5993
+ onChange: (event) => setDraft((current) => ({ ...current, active: event.target.checked }))
5994
+ }
5995
+ ),
5996
+ " ",
5997
+ "Integra\xE7\xE3o ativa"
5998
+ ] }),
5999
+ /* @__PURE__ */ jsxs23(Badge5, { colorPalette: statusPalette(selected?.connectionStatus), children: [
6000
+ "Conex\xE3o: ",
6001
+ selected?.connectionStatus ?? "n\xE3o testada"
6002
+ ] }),
6003
+ /* @__PURE__ */ jsxs23(Text23, { fontSize: "xs", color: "gray.500", children: [
6004
+ "\xDAltimo teste: ",
6005
+ dateTime(selected?.lastConnectionTestAt)
6006
+ ] })
6007
+ ] }),
6008
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 2, children: [
6009
+ /* @__PURE__ */ jsx38(Button15, { size: "xs", variant: "outline", loading: testConnection.isPending, onClick: () => testConnection.mutate(), children: "Testar conex\xE3o" }),
6010
+ /* @__PURE__ */ jsx38(Button15, { size: "xs", loading: save.isPending, onClick: () => save.mutate(), children: "Salvar configura\xE7\xE3o" })
6011
+ ] })
6012
+ ] }),
6013
+ selected?.lastConnectionError ? /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "red.600", children: selected.lastConnectionError }) : null,
6014
+ error ? /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "red.600", children: "N\xE3o foi poss\xEDvel operar a configura\xE7\xE3o do provedor." }) : null
6015
+ ] }) });
6016
+ }
6017
+ function CoreIntegration({ label = "Integra\xE7\xF5es" }) {
6018
+ const { http } = useOonApi();
6019
+ const providers = useQuery8({
6020
+ queryKey: ["core-integrations", "health"],
6021
+ queryFn: async () => (await http.get("/integrations/health")).data?.results ?? []
6022
+ });
6023
+ const queue = useQuery8({
6024
+ queryKey: ["core-integrations", "queue"],
6025
+ queryFn: async () => (await http.get("/integrations/queue", { params: { limit: 20 } })).data?.results ?? []
6026
+ });
6027
+ const history = useQuery8({
6028
+ queryKey: ["core-integrations", "history"],
6029
+ queryFn: async () => (await http.get("/integrations/history", { params: { limit: 10 } })).data?.results ?? []
6030
+ });
6031
+ const refresh = async () => {
6032
+ await Promise.all([providers.refetch(), queue.refetch(), history.refetch()]);
6033
+ };
6034
+ const process = useMutation4({
6035
+ mutationFn: () => http.post(
6036
+ "/integrations/actions/process-active",
6037
+ {},
6038
+ { headers: { "x-oon-origin": "integration" } }
6039
+ ),
6040
+ onSuccess: refresh
6041
+ });
6042
+ const syncAll = useMutation4({
6043
+ mutationFn: (provider) => http.post(
6044
+ `/integrations/providers/${provider}/sync-all`,
6045
+ {},
6046
+ { headers: { "x-oon-origin": "integration" } }
6047
+ ),
6048
+ onSuccess: refresh
6049
+ });
6050
+ const syncResource = useMutation4({
6051
+ mutationFn: ({ provider, resource }) => http.post(
6052
+ `/integrations/providers/${provider}/resources/${resource}/sync`,
6053
+ {},
6054
+ { headers: { "x-oon-origin": "integration" } }
6055
+ ),
6056
+ onSuccess: refresh
6057
+ });
6058
+ const reprocess = useMutation4({
6059
+ mutationFn: (id) => http.post(
6060
+ `/integrations/queue/${id}/reprocess`,
6061
+ {},
6062
+ { headers: { "x-oon-origin": "integration" } }
6063
+ ),
6064
+ onSuccess: refresh
6065
+ });
6066
+ const archive = useMutation4({
6067
+ mutationFn: (id) => http.post(
6068
+ `/integrations/queue/${id}/archive`,
6069
+ {},
6070
+ { headers: { "x-oon-origin": "integration" } }
6071
+ ),
6072
+ onSuccess: refresh
6073
+ });
6074
+ if (providers.isLoading || queue.isLoading || history.isLoading) return /* @__PURE__ */ jsx38(LoadingScreen, {});
6075
+ const error = providers.error || queue.error || history.error;
6076
+ if (error) return /* @__PURE__ */ jsx38(ErrorState, { error });
6077
+ return /* @__PURE__ */ jsxs23(Stack9, { gap: 6, children: [
6078
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 4, wrap: "wrap", children: [
6079
+ /* @__PURE__ */ jsxs23(Box22, { children: [
6080
+ /* @__PURE__ */ jsx38(Heading12, { size: "lg", children: label }),
6081
+ /* @__PURE__ */ jsx38(Text23, { color: "gray.500", children: "Configura\xE7\xE3o, sa\xFAde, filas, eventos e diagn\xF3stico sanitizado por provedor." })
6082
+ ] }),
6083
+ /* @__PURE__ */ jsx38(Button15, { size: "sm", variant: "outline", loading: process.isPending, onClick: () => process.mutate(), children: "Processar pend\xEAncias" })
6084
+ ] }),
6085
+ /* @__PURE__ */ jsx38(Stack9, { gap: 3, children: (providers.data ?? []).length === 0 ? /* @__PURE__ */ jsx38(Text23, { color: "gray.400", children: "Nenhum provedor registrado." }) : providers.data?.map((provider) => /* @__PURE__ */ jsx38(Box22, { borderWidth: "1px", borderColor: "gray.200", borderRadius: "md", bg: "white", p: 4, children: /* @__PURE__ */ jsxs23(Stack9, { gap: 3, children: [
6086
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 3, wrap: "wrap", children: [
6087
+ /* @__PURE__ */ jsxs23(Box22, { children: [
6088
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", gap: 2, children: [
6089
+ /* @__PURE__ */ jsx38(Text23, { fontWeight: "semibold", children: provider.label }),
6090
+ /* @__PURE__ */ jsx38(Badge5, { colorPalette: statusPalette(provider.status), children: provider.status ?? "\u2014" })
6091
+ ] }),
6092
+ provider.description ? /* @__PURE__ */ jsx38(Text23, { color: "gray.500", fontSize: "sm", children: provider.description }) : null
6093
+ ] }),
6094
+ /* @__PURE__ */ jsx38(Button15, { size: "xs", variant: "outline", loading: syncAll.isPending, onClick: () => syncAll.mutate(provider.key), children: "Sincronizar tudo" })
6095
+ ] }),
6096
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 3, wrap: "wrap", children: [
6097
+ /* @__PURE__ */ jsxs23(Badge5, { colorPalette: countActive(provider.queue) ? "yellow" : "green", children: [
6098
+ "Fila ativa: ",
6099
+ countActive(provider.queue)
6100
+ ] }),
6101
+ /* @__PURE__ */ jsxs23(Badge5, { colorPalette: countActive(provider.inbox) ? "yellow" : "green", children: [
6102
+ "Eventos ativos: ",
6103
+ countActive(provider.inbox)
6104
+ ] }),
6105
+ /* @__PURE__ */ jsxs23(Badge5, { colorPalette: statusPalette(provider.lastExecution?.status), children: [
6106
+ "\xDAltima execu\xE7\xE3o: ",
6107
+ provider.lastExecution?.status ?? "sem hist\xF3rico"
6108
+ ] })
6109
+ ] }),
6110
+ /* @__PURE__ */ jsxs23(Text23, { fontSize: "sm", color: "gray.500", children: [
6111
+ "Pend\xEAncia mais antiga: ",
6112
+ dateTime(provider.oldestPendingAt)
6113
+ ] }),
6114
+ /* @__PURE__ */ jsx38(Flex14, { gap: 2, wrap: "wrap", children: (provider.resources ?? []).map((resource) => /* @__PURE__ */ jsx38(
6115
+ Button15,
6116
+ {
6117
+ size: "xs",
6118
+ variant: "outline",
6119
+ loading: syncResource.isPending,
6120
+ onClick: () => syncResource.mutate({ provider: provider.key, resource: resource.key }),
6121
+ children: resource.label
6122
+ },
6123
+ resource.key
6124
+ )) }),
6125
+ provider.configuration?.enabled ? /* @__PURE__ */ jsx38(ProviderConfigurationPanel, { provider }) : null
6126
+ ] }) }, provider.key)) }),
6127
+ /* @__PURE__ */ jsxs23(Box22, { children: [
6128
+ /* @__PURE__ */ jsx38(Heading12, { size: "md", mb: 3, children: "Fila recente" }),
6129
+ /* @__PURE__ */ jsx38(Stack9, { gap: 2, children: (queue.data ?? []).length === 0 ? /* @__PURE__ */ jsx38(Text23, { color: "gray.400", children: "Nenhum ticket de integra\xE7\xE3o." }) : queue.data?.map((ticket) => /* @__PURE__ */ jsx38(Box22, { borderWidth: "1px", borderRadius: "md", p: 3, bg: "white", children: /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 3, wrap: "wrap", children: [
6130
+ /* @__PURE__ */ jsxs23(Box22, { children: [
6131
+ /* @__PURE__ */ jsxs23(Flex14, { align: "center", gap: 2, wrap: "wrap", children: [
6132
+ /* @__PURE__ */ jsx38(Text23, { fontWeight: "medium", children: ticket.handler }),
6133
+ /* @__PURE__ */ jsx38(Badge5, { colorPalette: statusPalette(ticket.status), children: ticket.status }),
6134
+ /* @__PURE__ */ jsx38(Badge5, { variant: "outline", children: ticket.provider })
6135
+ ] }),
6136
+ /* @__PURE__ */ jsxs23(Text23, { fontSize: "sm", color: "gray.500", children: [
6137
+ ticket.resource || "sem recurso",
6138
+ " \xB7 tentativas ",
6139
+ ticket.attempts,
6140
+ " \xB7 pr\xF3xima ",
6141
+ dateTime(ticket.nextAttemptAt)
6142
+ ] }),
6143
+ ticket.lastError?.message ? /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "red.600", children: ticket.lastError.message }) : null
6144
+ ] }),
6145
+ /* @__PURE__ */ jsxs23(Flex14, { gap: 2, children: [
6146
+ ["Erro tempor\xE1rio", "Erro definitivo", "Arquivado"].includes(ticket.status) ? /* @__PURE__ */ jsx38(Button15, { size: "xs", variant: "outline", loading: reprocess.isPending, onClick: () => reprocess.mutate(ticket._id), children: "Reprocessar" }) : null,
6147
+ ["Erro tempor\xE1rio", "Erro definitivo"].includes(ticket.status) ? /* @__PURE__ */ jsx38(Button15, { size: "xs", variant: "outline", loading: archive.isPending, onClick: () => archive.mutate(ticket._id), children: "Arquivar" }) : null
6148
+ ] })
6149
+ ] }) }, ticket._id)) })
6150
+ ] }),
6151
+ /* @__PURE__ */ jsxs23(Box22, { children: [
6152
+ /* @__PURE__ */ jsx38(Heading12, { size: "md", mb: 3, children: "Hist\xF3rico" }),
6153
+ /* @__PURE__ */ jsx38(Stack9, { gap: 2, children: (history.data ?? []).length === 0 ? /* @__PURE__ */ jsx38(Text23, { color: "gray.400", children: "Nenhuma execu\xE7\xE3o registrada." }) : history.data?.map((execution) => /* @__PURE__ */ jsx38(Box22, { borderWidth: "1px", borderRadius: "md", p: 3, bg: "white", children: /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", gap: 3, wrap: "wrap", children: [
6154
+ /* @__PURE__ */ jsxs23(Box22, { children: [
6155
+ /* @__PURE__ */ jsx38(Text23, { fontWeight: "medium", children: execution.title }),
6156
+ /* @__PURE__ */ jsxs23(Text23, { fontSize: "sm", color: "gray.500", children: [
6157
+ execution.provider,
6158
+ " \xB7 ",
6159
+ execution.resource || "sem recurso",
6160
+ " \xB7 ",
6161
+ dateTime(execution.startedAt),
6162
+ " \xB7 ",
6163
+ execution.durationMs ?? 0,
6164
+ " ms"
6165
+ ] }),
6166
+ execution.error?.message ? /* @__PURE__ */ jsx38(Text23, { fontSize: "sm", color: "red.600", children: execution.error.message }) : null
6167
+ ] }),
6168
+ /* @__PURE__ */ jsx38(Badge5, { colorPalette: statusPalette(execution.status), children: execution.status })
6169
+ ] }) }, execution._id)) })
6170
+ ] })
6171
+ ] });
6172
+ }
6173
+
6174
+ // src/components/CoreIntegrationMappings.tsx
6175
+ import { Badge as Badge6, Box as Box23, Flex as Flex15, Heading as Heading13, Stack as Stack10, Text as Text24 } from "@chakra-ui/react";
6176
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
6177
+ import { jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
6178
+ function dateTime2(value2) {
6179
+ if (!value2) return "sem execu\xE7\xE3o";
6180
+ const date = new Date(value2);
6181
+ return Number.isNaN(date.getTime()) ? value2 : date.toLocaleString("pt-BR");
6182
+ }
6183
+ function CoreIntegrationMappings() {
6184
+ const { http } = useOonApi();
6185
+ const providers = useQuery9({
6186
+ queryKey: ["core-integrations", "providers"],
6187
+ queryFn: async () => (await http.get("/integrations/providers")).data?.results ?? []
6188
+ });
6189
+ const providerKeys = (providers.data ?? []).map((provider) => provider.key).join(",");
6190
+ const summaries = useQuery9({
6191
+ queryKey: ["core-integrations", "mapping-summaries", providerKeys],
6192
+ enabled: providers.isSuccess && providerKeys.length > 0,
6193
+ queryFn: async () => Promise.all((providers.data ?? []).map(async (provider) => ({
6194
+ provider,
6195
+ mappings: (await http.get(`/integrations/providers/${provider.key}/mappings`)).data
6196
+ })))
6197
+ });
6198
+ if (providers.isLoading || summaries.isLoading) {
6199
+ return /* @__PURE__ */ jsx39(Text24, { color: "gray.500", children: "Carregando contratos declarados\u2026" });
6200
+ }
6201
+ if (providers.error || summaries.error) {
6202
+ return /* @__PURE__ */ jsx39(Text24, { color: "red.600", children: "N\xE3o foi poss\xEDvel carregar os contratos declarados." });
6203
+ }
6204
+ if (!(summaries.data ?? []).length) return null;
6205
+ return /* @__PURE__ */ jsxs24(Box23, { children: [
6206
+ /* @__PURE__ */ jsx39(Heading13, { size: "md", mb: 1, children: "Contratos declarados" }),
6207
+ /* @__PURE__ */ jsx39(Text24, { color: "gray.500", mb: 3, children: "Chamadas, listas e mappings pertencem \xE0 Central; o Core exibe somente metadados sanitizados." }),
6208
+ /* @__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: [
6209
+ /* @__PURE__ */ jsx39(Heading13, { size: "sm", children: provider.label }),
6210
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6211
+ /* @__PURE__ */ jsx39(Text24, { fontWeight: "semibold", mb: 2, children: "Chamadas Omie" }),
6212
+ /* @__PURE__ */ jsx39(Flex15, { gap: 2, wrap: "wrap", children: (mappings.calls ?? []).length ? mappings.calls?.map((call) => /* @__PURE__ */ jsxs24(Badge6, { variant: "outline", children: [
6213
+ call.label || call.key,
6214
+ " \xB7 ",
6215
+ call.call || "opera\xE7\xE3o",
6216
+ call.paginated ? " \xB7 paginada" : ""
6217
+ ] }, call.key)) : /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", color: "gray.400", children: "Nenhuma chamada declarada." }) })
6218
+ ] }),
6219
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6220
+ /* @__PURE__ */ jsx39(Text24, { fontWeight: "semibold", mb: 2, children: "Listas Omie" }),
6221
+ /* @__PURE__ */ jsx39(Stack10, { gap: 2, children: (mappings.lists ?? []).length ? mappings.lists?.map((list) => {
6222
+ const latest = list.executions?.[0];
6223
+ 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: [
6224
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6225
+ /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", fontWeight: "medium", children: list.label || list.key }),
6226
+ /* @__PURE__ */ jsxs24(Text24, { fontSize: "xs", color: "gray.500", children: [
6227
+ list.mode || "modo padr\xE3o",
6228
+ " \xB7 ",
6229
+ list.direction || "dire\xE7\xE3o padr\xE3o",
6230
+ " \xB7 ",
6231
+ list.targetModel || "destino declarado"
6232
+ ] })
6233
+ ] }),
6234
+ /* @__PURE__ */ jsxs24(Flex15, { gap: 2, wrap: "wrap", children: [
6235
+ /* @__PURE__ */ jsx39(Badge6, { variant: "outline", children: latest?.status || "n\xE3o executada" }),
6236
+ /* @__PURE__ */ jsx39(Badge6, { variant: "outline", children: dateTime2(latest?.lastCompletedAt) })
6237
+ ] })
6238
+ ] }) }, list.key);
6239
+ }) : /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", color: "gray.400", children: "Nenhuma lista declarada." }) })
6240
+ ] }),
6241
+ /* @__PURE__ */ jsxs24(Box23, { children: [
6242
+ /* @__PURE__ */ jsx39(Text24, { fontWeight: "semibold", mb: 2, children: "Mappings de webhook" }),
6243
+ /* @__PURE__ */ jsx39(Stack10, { gap: 1, children: (mappings.webhooks ?? []).length ? mappings.webhooks?.map((webhook) => /* @__PURE__ */ jsxs24(Text24, { fontSize: "sm", color: "gray.600", children: [
6244
+ webhook.eventType,
6245
+ " \u2192 ",
6246
+ (webhook.actions ?? []).map((action) => action.handler).filter(Boolean).join(", ") || "sem a\xE7\xE3o declarada"
6247
+ ] }, `${webhook.eventType}:${webhook.resource || ""}`)) : /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", color: "gray.400", children: "Nenhum mapping de webhook declarado." }) })
6248
+ ] })
6249
+ ] }) }, provider.key)) })
6250
+ ] });
6251
+ }
6252
+
6253
+ // src/modules/integrations.tsx
6254
+ import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
6255
+ function CoreIntegrationPage() {
6256
+ return /* @__PURE__ */ jsxs25(Stack11, { gap: 8, children: [
6257
+ /* @__PURE__ */ jsx40(CoreIntegration, {}),
6258
+ /* @__PURE__ */ jsx40(CoreIntegrationMappings, {})
6259
+ ] });
6260
+ }
6261
+ function createIntegrationModule() {
6262
+ return {
6263
+ id: "core.integrations",
6264
+ label: "Integra\xE7\xF5es",
6265
+ routes: [
6266
+ {
6267
+ path: "/integracoes",
6268
+ element: /* @__PURE__ */ jsx40(CoreIntegrationPage, {}),
6269
+ capabilities: ["core.integrations"]
6270
+ }
6271
+ ],
6272
+ menu: [
6273
+ {
6274
+ label: "Integra\xE7\xF5es",
6275
+ href: "/integracoes",
6276
+ section: "Integra\xE7\xF5es",
6277
+ order: 800,
6278
+ capabilities: ["core.integrations"]
6279
+ }
6280
+ ]
6281
+ };
6282
+ }
6283
+
5766
6284
  // src/appManifest.ts
5767
6285
  function startCentralFromManifest(manifest, runtime) {
5768
6286
  const legacyCompatibleUi = {
@@ -5772,6 +6290,9 @@ function startCentralFromManifest(manifest, runtime) {
5772
6290
  appKind: manifest.app.appKind
5773
6291
  };
5774
6292
  const config = manifestToConfig(legacyCompatibleUi, runtime);
6293
+ if (manifest.app.modules.integrations) {
6294
+ config.modules = [...config.modules ?? [], createIntegrationModule()];
6295
+ }
5775
6296
  config.app = {
5776
6297
  ...config.app,
5777
6298
  id: manifest.app.id,
@@ -5805,46 +6326,10 @@ function defineOonModule(mod) {
5805
6326
  return mod;
5806
6327
  }
5807
6328
 
5808
- // src/components/CoreIntegration.tsx
5809
- 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";
5810
- import { useMutation as useMutation4 } from "@tanstack/react-query";
5811
- import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
5812
- function CoreIntegration({ label = "Integra\xE7\xF5es" }) {
5813
- const { http } = useOonApi();
5814
- const metadata = useCoreMetadata();
5815
- const reprocess = useMutation4({
5816
- mutationFn: () => http.post("/integrations/actions/process-active", {}, { headers: { "x-oon-origin": "integration" } })
5817
- });
5818
- if (metadata.isLoading) return /* @__PURE__ */ jsx38(LoadingScreen, {});
5819
- if (metadata.isError) return /* @__PURE__ */ jsx38(ErrorState, { error: metadata.error });
5820
- const integrations = metadata.data?.integrations ?? [];
5821
- return /* @__PURE__ */ jsxs23(Stack9, { gap: 6, children: [
5822
- /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", children: [
5823
- /* @__PURE__ */ jsx38(Heading12, { size: "lg", children: label }),
5824
- /* @__PURE__ */ jsx38(Button15, { size: "sm", variant: "outline", loading: reprocess.isPending, onClick: () => reprocess.mutate(), children: "Reprocessar ativos" })
5825
- ] }),
5826
- /* @__PURE__ */ jsx38(Stack9, { gap: 3, children: integrations.length === 0 ? /* @__PURE__ */ jsx38(Text23, { color: "gray.400", children: "Nenhuma integra\xE7\xE3o declarada." }) : integrations.map((it, idx) => /* @__PURE__ */ jsx38(
5827
- Box22,
5828
- {
5829
- borderWidth: "1px",
5830
- borderColor: "gray.200",
5831
- borderRadius: "md",
5832
- bg: "white",
5833
- p: 4,
5834
- children: /* @__PURE__ */ jsxs23(Flex14, { align: "center", justify: "space-between", children: [
5835
- /* @__PURE__ */ jsx38(Text23, { fontWeight: "medium", children: it.label ?? it.name ?? "Integra\xE7\xE3o" }),
5836
- /* @__PURE__ */ jsx38(Badge5, { colorPalette: it.status === "erro" ? "red" : it.status === "ativo" ? "green" : "gray", children: it.status ?? "\u2014" })
5837
- ] })
5838
- },
5839
- it.id ?? it.name ?? idx
5840
- )) })
5841
- ] });
5842
- }
5843
-
5844
6329
  // src/components/CoreCurrency.tsx
5845
- import { Button as Button16, Flex as Flex15, Heading as Heading13, Stack as Stack10, Text as Text24 } from "@chakra-ui/react";
6330
+ import { Button as Button16, Flex as Flex16, Heading as Heading14, Stack as Stack12, Text as Text25 } from "@chakra-ui/react";
5846
6331
  import { useMutation as useMutation5, useQueryClient as useQueryClient5 } from "@tanstack/react-query";
5847
- import { jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
6332
+ import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
5848
6333
  function CoreCurrency({ model = "Moeda", label = "Multi-moedas", endpoint = "/moedas", columns }) {
5849
6334
  const { http } = useOonApi();
5850
6335
  const queryClient = useQueryClient5();
@@ -5852,25 +6337,25 @@ function CoreCurrency({ model = "Moeda", label = "Multi-moedas", endpoint = "/mo
5852
6337
  mutationFn: () => http.post(`${endpoint}/actions/update-rates`, {}, { headers: { "x-oon-origin": "integration" } }),
5853
6338
  onSuccess: () => queryClient.invalidateQueries({ queryKey: ["oon", "list", endpoint] })
5854
6339
  });
5855
- return /* @__PURE__ */ jsxs24(Stack10, { gap: 6, children: [
5856
- /* @__PURE__ */ jsxs24(Flex15, { align: "center", justify: "space-between", children: [
5857
- /* @__PURE__ */ jsx39(Heading13, { size: "lg", children: label }),
5858
- /* @__PURE__ */ jsx39(Button16, { size: "sm", colorPalette: "blue", loading: updateRates.isPending, onClick: () => updateRates.mutate(), children: "Atualizar cota\xE7\xF5es" })
6340
+ return /* @__PURE__ */ jsxs26(Stack12, { gap: 6, children: [
6341
+ /* @__PURE__ */ jsxs26(Flex16, { align: "center", justify: "space-between", children: [
6342
+ /* @__PURE__ */ jsx41(Heading14, { size: "lg", children: label }),
6343
+ /* @__PURE__ */ jsx41(Button16, { size: "sm", colorPalette: "blue", loading: updateRates.isPending, onClick: () => updateRates.mutate(), children: "Atualizar cota\xE7\xF5es" })
5859
6344
  ] }),
5860
- updateRates.isError ? /* @__PURE__ */ jsx39(Text24, { fontSize: "sm", color: "red.600", children: updateRates.error?.message }) : null,
5861
- /* @__PURE__ */ jsx39(CoreCollection, { model, label: "", mode: columns ? "full" : "dynamic", endpoint, columns })
6345
+ updateRates.isError ? /* @__PURE__ */ jsx41(Text25, { fontSize: "sm", color: "red.600", children: updateRates.error?.message }) : null,
6346
+ /* @__PURE__ */ jsx41(CoreCollection, { model, label: "", mode: columns ? "full" : "dynamic", endpoint, columns })
5862
6347
  ] });
5863
6348
  }
5864
6349
 
5865
6350
  // src/components/CoreAssistant.tsx
5866
- import { useState as useState14 } from "react";
5867
- 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";
6351
+ import { useState as useState15 } from "react";
6352
+ 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";
5868
6353
  import { useMutation as useMutation6 } from "@tanstack/react-query";
5869
- import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
6354
+ import { jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
5870
6355
  function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint = "/assistant-runs" }) {
5871
6356
  const { http } = useOonApi();
5872
- const [messages, setMessages] = useState14([]);
5873
- const [input, setInput] = useState14("");
6357
+ const [messages, setMessages] = useState15([]);
6358
+ const [input, setInput] = useState15("");
5874
6359
  const ask = useMutation6({
5875
6360
  mutationFn: async (message) => {
5876
6361
  const { data } = await http.post(
@@ -5895,11 +6380,11 @@ function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint =
5895
6380
  setInput("");
5896
6381
  ask.mutate(text);
5897
6382
  };
5898
- return /* @__PURE__ */ jsxs25(Stack11, { gap: 4, maxW: "560px", children: [
5899
- /* @__PURE__ */ jsx40(Heading14, { size: "md", children: label }),
5900
- /* @__PURE__ */ jsx40(Box23, { borderWidth: "1px", borderColor: "gray.200", borderRadius: "md", bg: "white", p: 4, minH: "240px", children: /* @__PURE__ */ jsxs25(Stack11, { gap: 3, children: [
5901
- messages.length === 0 ? /* @__PURE__ */ jsx40(Text25, { color: "gray.400", fontSize: "sm", children: "Fa\xE7a uma pergunta ao assistente." }) : messages.map((m, idx) => /* @__PURE__ */ jsx40(Flex16, { justify: m.role === "user" ? "flex-end" : "flex-start", children: /* @__PURE__ */ jsx40(
5902
- Box23,
6383
+ return /* @__PURE__ */ jsxs27(Stack13, { gap: 4, maxW: "560px", children: [
6384
+ /* @__PURE__ */ jsx42(Heading15, { size: "md", children: label }),
6385
+ /* @__PURE__ */ jsx42(Box24, { borderWidth: "1px", borderColor: "gray.200", borderRadius: "md", bg: "white", p: 4, minH: "240px", children: /* @__PURE__ */ jsxs27(Stack13, { gap: 3, children: [
6386
+ 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(
6387
+ Box24,
5903
6388
  {
5904
6389
  bg: m.role === "user" ? "brand.500" : "gray.100",
5905
6390
  color: m.role === "user" ? "white" : "gray.800",
@@ -5911,12 +6396,12 @@ function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint =
5911
6396
  children: m.content
5912
6397
  }
5913
6398
  ) }, idx)),
5914
- ask.isPending ? /* @__PURE__ */ jsx40(Text25, { color: "gray.400", fontSize: "sm", children: "Pensando\u2026" }) : null,
5915
- ask.isError ? /* @__PURE__ */ jsx40(Text25, { color: "red.600", fontSize: "sm", children: ask.error?.message }) : null
6399
+ ask.isPending ? /* @__PURE__ */ jsx42(Text26, { color: "gray.400", fontSize: "sm", children: "Pensando\u2026" }) : null,
6400
+ ask.isError ? /* @__PURE__ */ jsx42(Text26, { color: "red.600", fontSize: "sm", children: ask.error?.message }) : null
5916
6401
  ] }) }),
5917
- /* @__PURE__ */ jsxs25(Flex16, { gap: 2, children: [
5918
- /* @__PURE__ */ jsx40(
5919
- Input8,
6402
+ /* @__PURE__ */ jsxs27(Flex17, { gap: 2, children: [
6403
+ /* @__PURE__ */ jsx42(
6404
+ Input9,
5920
6405
  {
5921
6406
  size: "sm",
5922
6407
  value: input,
@@ -5927,7 +6412,7 @@ function CoreAssistant({ assistantCode, label = "Assistente", entity, endpoint =
5927
6412
  }
5928
6413
  }
5929
6414
  ),
5930
- /* @__PURE__ */ jsx40(Button17, { size: "sm", colorPalette: "blue", onClick: send, loading: ask.isPending, children: "Enviar" })
6415
+ /* @__PURE__ */ jsx42(Button17, { size: "sm", colorPalette: "blue", onClick: send, loading: ask.isPending, children: "Enviar" })
5931
6416
  ] })
5932
6417
  ] });
5933
6418
  }
@@ -5955,6 +6440,7 @@ export {
5955
6440
  applyReactiveFormulas,
5956
6441
  buildDomainMutationPayload,
5957
6442
  coerceDomainFormValue,
6443
+ createIntegrationModule,
5958
6444
  defineCollectionView,
5959
6445
  defineDashboard,
5960
6446
  defineDocumentView,