@oondemand/oon-core-front 0.3.33 → 0.3.35
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.d.ts +29 -4
- package/dist/index.js +314 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -603,11 +603,28 @@ type OonPipelineCreateDef = {
|
|
|
603
603
|
defaultStage?: string;
|
|
604
604
|
defaultValues?: Record<string, unknown>;
|
|
605
605
|
};
|
|
606
|
+
type OonPipelineActionGroup = "approval" | "workStatus" | "custom";
|
|
607
|
+
type OonPipelineActionTone = "success" | "danger" | "warning" | "neutral" | "brand";
|
|
608
|
+
type OonPipelineOperationalKind = "approval" | "work-status" | "business";
|
|
609
|
+
/**
|
|
610
|
+
* Ações padrão da esteira. Quando omitido, aprovação/reprovação e status de
|
|
611
|
+
* trabalho ficam habilitados automaticamente quando os campos necessários
|
|
612
|
+
* existem na metadata do model.
|
|
613
|
+
*/
|
|
614
|
+
type OonPipelineDefaultActionsConfig = {
|
|
615
|
+
approval?: boolean;
|
|
616
|
+
workStatus?: boolean;
|
|
617
|
+
workStatusField?: string;
|
|
618
|
+
excludedStages?: string[];
|
|
619
|
+
};
|
|
620
|
+
type OonPipelineDefaultActionsDef = false | OonPipelineDefaultActionsConfig;
|
|
606
621
|
/**
|
|
607
622
|
* Ações operacionais exibidas no cabeçalho do ticket.
|
|
608
623
|
*
|
|
609
624
|
* - setField/transition atualizam um campo do próprio ticket;
|
|
610
|
-
* - formAction carrega dados opcionais e envia um formulário a um endpoint
|
|
625
|
+
* - formAction carrega dados opcionais e envia um formulário a um endpoint;
|
|
626
|
+
* - group/tone organizam a ação visualmente sem acoplar regra de negócio à UI;
|
|
627
|
+
* - operationalKind cria um contrato estável para telemetria, SLA e produtividade.
|
|
611
628
|
*/
|
|
612
629
|
type OonPipelineActionDef = Omit<OonRowActionDef, "type"> & {
|
|
613
630
|
type: OonRowActionDef["type"] | "setField" | "transition" | "formAction";
|
|
@@ -618,6 +635,9 @@ type OonPipelineActionDef = Omit<OonRowActionDef, "type"> & {
|
|
|
618
635
|
loadEndpoint?: string;
|
|
619
636
|
fields?: OonFormFieldDef[];
|
|
620
637
|
initialValues?: Record<string, unknown>;
|
|
638
|
+
group?: OonPipelineActionGroup;
|
|
639
|
+
tone?: OonPipelineActionTone;
|
|
640
|
+
operationalKind?: OonPipelineOperationalKind;
|
|
621
641
|
};
|
|
622
642
|
/**
|
|
623
643
|
* Extensão pública da view de esteira com filtros, inclusão, lista, ações e
|
|
@@ -642,7 +662,9 @@ type OonPipelineViewDef = PipelineViewDef & {
|
|
|
642
662
|
defaultView?: OonPipelineViewMode;
|
|
643
663
|
/** Colunas e ações da visualização em lista. */
|
|
644
664
|
list?: OonCollectionListConfig;
|
|
645
|
-
/** Ações
|
|
665
|
+
/** Ações padrão do Core; use false para desabilitá-las nesta esteira. */
|
|
666
|
+
defaultActions?: OonPipelineDefaultActionsDef;
|
|
667
|
+
/** Ações adicionais ou overrides exibidos no cabeçalho do ticket aberto. */
|
|
646
668
|
ticketActions?: OonPipelineActionDef[];
|
|
647
669
|
};
|
|
648
670
|
|
|
@@ -712,6 +734,8 @@ interface CentralUiManifest {
|
|
|
712
734
|
viewModes?: OonPipelineViewMode[];
|
|
713
735
|
defaultView?: OonPipelineViewMode;
|
|
714
736
|
list?: OonCollectionListConfig;
|
|
737
|
+
/** Habilitadas por padrão; use false para remover aprovação e status de trabalho. */
|
|
738
|
+
defaultActions?: OonPipelineDefaultActionsDef;
|
|
715
739
|
ticketActions?: OonPipelineActionDef[];
|
|
716
740
|
}>;
|
|
717
741
|
documents?: Array<{
|
|
@@ -817,10 +841,11 @@ interface CorePipelineProps {
|
|
|
817
841
|
viewModes?: OonPipelineViewMode[];
|
|
818
842
|
defaultView?: OonPipelineViewMode;
|
|
819
843
|
list?: OonCollectionListConfig;
|
|
844
|
+
defaultActions?: OonPipelineDefaultActionsDef;
|
|
820
845
|
ticketActions?: OonPipelineActionDef[];
|
|
821
846
|
}
|
|
822
847
|
/** Esteira com quadro/lista, filtros, inclusão e ações operacionais no ticket. */
|
|
823
|
-
declare function CorePipeline({ model, label, endpoint, stageField, stages, titleField, form, relations, ticketModal, filters, create, viewModes, defaultView, list, ticketActions, }: CorePipelineProps): react.JSX.Element;
|
|
848
|
+
declare function CorePipeline({ model, label, endpoint, stageField, stages, titleField, form, relations, ticketModal, filters, create, viewModes, defaultView, list, defaultActions, ticketActions, }: CorePipelineProps): react.JSX.Element;
|
|
824
849
|
|
|
825
850
|
interface CoreIntegrationProps {
|
|
826
851
|
label?: string;
|
|
@@ -1003,4 +1028,4 @@ declare function useCoreMetadata(): _tanstack_react_query.UseQueryResult<NoInfer
|
|
|
1003
1028
|
/** Descrição de uma model específica — base do modo "dynamic". */
|
|
1004
1029
|
declare function useModelSchema(name: string): _tanstack_react_query.UseQueryResult<NoInfer<ModelSummary>, Error>;
|
|
1005
1030
|
|
|
1006
|
-
export { type CentralFormFieldDef, type CentralUiManifest, type CollectionMode, type CollectionViewDef, CoreActions, CoreAssistant, CoreCards, CoreCollection, CoreCurrency, CoreDashboard, CoreDataGrid, CoreDocument, CoreEmptyState, CoreField, CoreForm, CoreIntegration, CoreLoadingState, type CoreMetadata, CorePage, CorePageHeader, CorePipeline, CoreRelationField, CoreToolbar, type DashboardViewDef, type DashboardWidgetDef, type DocumentViewDef, type FieldKind, type FieldMeta, type ListParams, type ManifestRuntime, type ModelSummary, type OonActionDef, type OonApiConfig, type OonAppConfig, type OonAppKind, type OonAuthConfig, type OonAuthMode, type OonBlockDef, type OonColumnDef, type OonComponentRegistry, type OonCoreFrontConfig, type OonError, type OonFormFieldDef, type OonLayoutConfig, type OonMenuItem, type OonModule, type OonNavigationConfig, type OonNavigationMode, type OonPageDef, type OonPipelineTicketModalConfig, type OonPipelineViewDef, type OonRoute, type OonSchemaVersion, type OonSecurityConfig, type OonUiManifest, type OonUser, type OonViewDefinition, type PaginatedResult, type Pagination, PermissionGate, type PipelineViewDef, defineCollectionView, defineDashboard, defineDocumentView, defineOonModule, definePipelineView, manifestToConfig, oonCoreFront, start, startFromManifest, useCoreMetadata, useModelSchema, useOonApi, useOonAuth, useOonResource };
|
|
1031
|
+
export { type CentralFormFieldDef, type CentralUiManifest, type CollectionMode, type CollectionViewDef, CoreActions, CoreAssistant, CoreCards, CoreCollection, CoreCurrency, CoreDashboard, CoreDataGrid, CoreDocument, CoreEmptyState, CoreField, CoreForm, CoreIntegration, CoreLoadingState, type CoreMetadata, CorePage, CorePageHeader, CorePipeline, CoreRelationField, CoreToolbar, type DashboardViewDef, type DashboardWidgetDef, type DocumentViewDef, type FieldKind, type FieldMeta, type ListParams, type ManifestRuntime, type ModelSummary, type OonActionDef, type OonApiConfig, type OonAppConfig, type OonAppKind, type OonAuthConfig, type OonAuthMode, type OonBlockDef, type OonColumnDef, type OonComponentRegistry, type OonCoreFrontConfig, type OonError, type OonFormFieldDef, type OonLayoutConfig, type OonMenuItem, type OonModule, type OonNavigationConfig, type OonNavigationMode, type OonPageDef, type OonPipelineActionDef, type OonPipelineActionGroup, type OonPipelineActionTone, type OonPipelineDefaultActionsConfig, type OonPipelineDefaultActionsDef, type OonPipelineTicketModalConfig, type OonPipelineViewDef, type OonRoute, type OonSchemaVersion, type OonSecurityConfig, type OonUiManifest, type OonUser, type OonViewDefinition, type PaginatedResult, type Pagination, PermissionGate, type PipelineViewDef, defineCollectionView, defineDashboard, defineDocumentView, defineOonModule, definePipelineView, manifestToConfig, oonCoreFront, start, startFromManifest, useCoreMetadata, useModelSchema, useOonApi, useOonAuth, useOonResource };
|
package/dist/index.js
CHANGED
|
@@ -88,11 +88,11 @@ function createRestClient(deps) {
|
|
|
88
88
|
instance.interceptors.response.use(
|
|
89
89
|
(res) => res,
|
|
90
90
|
(error) => {
|
|
91
|
-
const
|
|
91
|
+
const normalized2 = normalizeError(error);
|
|
92
92
|
const requestPath = String(error.config?.url || "").split("?")[0].replace(/\/$/, "");
|
|
93
93
|
const isLogin = requestPath.endsWith("/auth/autenticar");
|
|
94
|
-
if (
|
|
95
|
-
return Promise.reject(
|
|
94
|
+
if (normalized2.status === 401 && !isLogin) onUnauthorized?.();
|
|
95
|
+
return Promise.reject(normalized2);
|
|
96
96
|
}
|
|
97
97
|
);
|
|
98
98
|
return instance;
|
|
@@ -778,8 +778,8 @@ function PlusIcon() {
|
|
|
778
778
|
function renderCell(value, kind) {
|
|
779
779
|
const formatted = formatCell(value, kind);
|
|
780
780
|
if (kind === "enum") {
|
|
781
|
-
const
|
|
782
|
-
const palette = /erro|cancel|inativo|recus|critica/.test(
|
|
781
|
+
const normalized2 = String(value ?? "").toLowerCase();
|
|
782
|
+
const palette = /erro|cancel|inativo|recus|critica/.test(normalized2) ? "red" : /pendente|aguardando|rascunho/.test(normalized2) ? "orange" : /processando|conferencia|integrando|validando/.test(normalized2) ? "blue" : /ativo|sucesso|conclu|aplicada|disponivel|aprov/.test(normalized2) ? "green" : "gray";
|
|
783
783
|
return /* @__PURE__ */ jsx7(Badge, { colorPalette: palette, variant: "subtle", borderRadius: "full", px: "7px", py: "3px", fontSize: "9px", fontWeight: "600", textTransform: "capitalize", children: formatted });
|
|
784
784
|
}
|
|
785
785
|
if (kind === "boolean") {
|
|
@@ -1424,9 +1424,9 @@ function parseCurrencyInitial(value) {
|
|
|
1424
1424
|
return Number.isFinite(parsed) ? String(parsed) : "";
|
|
1425
1425
|
}
|
|
1426
1426
|
function formatCurrency(value) {
|
|
1427
|
-
const
|
|
1428
|
-
if (!
|
|
1429
|
-
const numeric = Number(
|
|
1427
|
+
const normalized2 = parseCurrencyInitial(value);
|
|
1428
|
+
if (!normalized2) return "";
|
|
1429
|
+
const numeric = Number(normalized2);
|
|
1430
1430
|
if (!Number.isFinite(numeric)) return "";
|
|
1431
1431
|
return new Intl.NumberFormat("pt-BR", {
|
|
1432
1432
|
style: "currency",
|
|
@@ -1833,7 +1833,7 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
|
|
|
1833
1833
|
|
|
1834
1834
|
// src/components/internal/CoreDetailModal.tsx
|
|
1835
1835
|
import { useEffect as useEffect6, useMemo as useMemo7, useState as useState9 } from "react";
|
|
1836
|
-
import { Box as Box8, Button as Button8, Flex as Flex7, Heading as Heading3, Text as Text10 } from "@chakra-ui/react";
|
|
1836
|
+
import { Box as Box8, Button as Button8, Flex as Flex7, Heading as Heading3, IconButton, Text as Text10 } from "@chakra-ui/react";
|
|
1837
1837
|
import { useQuery as useQuery6, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
|
|
1838
1838
|
|
|
1839
1839
|
// src/components/internal/CoreTabbedDetail.tsx
|
|
@@ -1980,6 +1980,13 @@ function interpolateEndpoint(endpoint, row, parent) {
|
|
|
1980
1980
|
|
|
1981
1981
|
// src/components/internal/CoreRowAction.tsx
|
|
1982
1982
|
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1983
|
+
var ACTION_TONES = {
|
|
1984
|
+
success: { bg: "#DCFCE7", color: "#166534", border: "#BBF7D0", hover: "#D1FAE5" },
|
|
1985
|
+
danger: { bg: "#FEE2E2", color: "#991B1B", border: "#FECACA", hover: "#FDE2E2" },
|
|
1986
|
+
warning: { bg: "#FEF3C7", color: "#92400E", border: "#FDE68A", hover: "#FDEDB3" },
|
|
1987
|
+
neutral: { bg: "#F1F5F9", color: "#334155", border: "#E2E8F0", hover: "#E8EEF5" },
|
|
1988
|
+
brand: { bg: "#E0F2FE", color: "#075985", border: "#BAE6FD", hover: "#D5EEFC" }
|
|
1989
|
+
};
|
|
1983
1990
|
function messageOf2(error) {
|
|
1984
1991
|
return error instanceof Error ? error.message : typeof error === "string" ? error : "N\xE3o foi poss\xEDvel executar a a\xE7\xE3o.";
|
|
1985
1992
|
}
|
|
@@ -1990,6 +1997,25 @@ function unwrap2(value) {
|
|
|
1990
1997
|
if (data && typeof data === "object") return data;
|
|
1991
1998
|
return record;
|
|
1992
1999
|
}
|
|
2000
|
+
function emitOperationalEvent(action, row, changes) {
|
|
2001
|
+
if (typeof window === "undefined" || typeof window.dispatchEvent !== "function") return;
|
|
2002
|
+
if (!action.operationalKind) return;
|
|
2003
|
+
const field = action.field;
|
|
2004
|
+
window.dispatchEvent(new CustomEvent("oon:pipeline-action", {
|
|
2005
|
+
detail: {
|
|
2006
|
+
actionId: action.id,
|
|
2007
|
+
label: action.label,
|
|
2008
|
+
group: action.group,
|
|
2009
|
+
operationalKind: action.operationalKind,
|
|
2010
|
+
recordId: row._id ?? row.id,
|
|
2011
|
+
field,
|
|
2012
|
+
previousValue: field ? row[field] : void 0,
|
|
2013
|
+
nextValue: field ? changes?.[field] ?? action.value : void 0,
|
|
2014
|
+
changes,
|
|
2015
|
+
occurredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2016
|
+
}
|
|
2017
|
+
}));
|
|
2018
|
+
}
|
|
1993
2019
|
function CoreRowAction({ action, row, parent, onOpenDetail, onRefresh, onUpdate }) {
|
|
1994
2020
|
const { http } = useOonApi();
|
|
1995
2021
|
const [loading, setLoading] = useState6(false);
|
|
@@ -1997,6 +2023,9 @@ function CoreRowAction({ action, row, parent, onOpenDetail, onRefresh, onUpdate
|
|
|
1997
2023
|
const [formOpen, setFormOpen] = useState6(false);
|
|
1998
2024
|
const [formInitialValues, setFormInitialValues] = useState6({});
|
|
1999
2025
|
const pipelineAction = action;
|
|
2026
|
+
const tone = pipelineAction.tone ? ACTION_TONES[pipelineAction.tone] : void 0;
|
|
2027
|
+
const isWorkStatus = pipelineAction.group === "workStatus";
|
|
2028
|
+
const isSelected = isWorkStatus && !!pipelineAction.field && row[pipelineAction.field] === pipelineAction.value;
|
|
2000
2029
|
if (evaluateCondition(action.hiddenWhen, row)) return null;
|
|
2001
2030
|
const disabled = evaluateCondition(action.disabledWhen, row) || loading;
|
|
2002
2031
|
const confirmAction = () => action.confirm ? window.confirm(action.confirm.description ?? action.confirm.title ?? `Executar ${action.label}?`) : true;
|
|
@@ -2030,7 +2059,9 @@ function CoreRowAction({ action, row, parent, onOpenDetail, onRefresh, onUpdate
|
|
|
2030
2059
|
if (!pipelineAction.field || !onUpdate || !confirmAction()) return;
|
|
2031
2060
|
setLoading(true);
|
|
2032
2061
|
try {
|
|
2033
|
-
|
|
2062
|
+
const changes = { [pipelineAction.field]: pipelineAction.value };
|
|
2063
|
+
await onUpdate(changes);
|
|
2064
|
+
emitOperationalEvent(pipelineAction, row, changes);
|
|
2034
2065
|
onRefresh?.(pipelineAction.refresh);
|
|
2035
2066
|
} catch (err) {
|
|
2036
2067
|
setError(err);
|
|
@@ -2044,6 +2075,7 @@ function CoreRowAction({ action, row, parent, onOpenDetail, onRefresh, onUpdate
|
|
|
2044
2075
|
try {
|
|
2045
2076
|
const url = interpolateEndpoint(action.endpoint, row, parent);
|
|
2046
2077
|
await http.request({ url, method: action.method ?? "POST" });
|
|
2078
|
+
emitOperationalEvent(pipelineAction, row);
|
|
2047
2079
|
onRefresh?.(action.refresh);
|
|
2048
2080
|
} catch (err) {
|
|
2049
2081
|
setError(err);
|
|
@@ -2051,8 +2083,35 @@ function CoreRowAction({ action, row, parent, onOpenDetail, onRefresh, onUpdate
|
|
|
2051
2083
|
setLoading(false);
|
|
2052
2084
|
}
|
|
2053
2085
|
};
|
|
2054
|
-
return /* @__PURE__ */ jsxs8("span", { children: [
|
|
2055
|
-
/* @__PURE__ */
|
|
2086
|
+
return /* @__PURE__ */ jsxs8("span", { style: { display: "inline-flex", flexDirection: "column" }, children: [
|
|
2087
|
+
/* @__PURE__ */ jsxs8(
|
|
2088
|
+
Button5,
|
|
2089
|
+
{
|
|
2090
|
+
type: "button",
|
|
2091
|
+
size: "xs",
|
|
2092
|
+
minH: isWorkStatus ? "32px" : "28px",
|
|
2093
|
+
px: isWorkStatus ? "12px" : "9px",
|
|
2094
|
+
borderRadius: isWorkStatus ? "full" : "6px",
|
|
2095
|
+
fontSize: "10px",
|
|
2096
|
+
fontWeight: "700",
|
|
2097
|
+
variant: tone ? "outline" : void 0,
|
|
2098
|
+
bg: isWorkStatus && !isSelected ? "white" : tone?.bg,
|
|
2099
|
+
color: tone?.color,
|
|
2100
|
+
borderColor: isSelected ? tone?.color : tone?.border,
|
|
2101
|
+
borderWidth: isSelected ? "2px" : "1px",
|
|
2102
|
+
boxShadow: isSelected ? `0 0 0 3px ${tone?.border ?? "#E2E8F0"}` : tone ? "none" : void 0,
|
|
2103
|
+
"aria-pressed": isWorkStatus ? isSelected : void 0,
|
|
2104
|
+
loading,
|
|
2105
|
+
disabled,
|
|
2106
|
+
onClick: run,
|
|
2107
|
+
_hover: tone ? { bg: tone.hover, borderColor: tone.border } : void 0,
|
|
2108
|
+
_disabled: tone ? { opacity: isSelected ? 1 : 0.55, cursor: "not-allowed" } : void 0,
|
|
2109
|
+
children: [
|
|
2110
|
+
isWorkStatus ? /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", style: { width: 8, height: 8, display: "inline-block", marginRight: 7, borderRadius: "999px", background: tone?.color ?? "#64748B", boxShadow: isSelected ? "0 0 0 2px rgba(255,255,255,.9)" : "none" } }) : null,
|
|
2111
|
+
action.label
|
|
2112
|
+
]
|
|
2113
|
+
}
|
|
2114
|
+
),
|
|
2056
2115
|
error ? /* @__PURE__ */ jsx12(Text7, { mt: "3px", color: "#B42318", fontSize: "9px", children: messageOf2(error) }) : null,
|
|
2057
2116
|
formOpen && pipelineAction.type === "formAction" ? /* @__PURE__ */ jsx12(
|
|
2058
2117
|
DynamicForm,
|
|
@@ -2070,6 +2129,7 @@ function CoreRowAction({ action, row, parent, onOpenDetail, onRefresh, onUpdate
|
|
|
2070
2129
|
try {
|
|
2071
2130
|
const url = interpolateEndpoint(pipelineAction.endpoint, row, parent);
|
|
2072
2131
|
await http.request({ url, method: pipelineAction.method ?? "POST", data: values });
|
|
2132
|
+
emitOperationalEvent(pipelineAction, row, values);
|
|
2073
2133
|
setFormOpen(false);
|
|
2074
2134
|
onRefresh?.(pipelineAction.refresh);
|
|
2075
2135
|
} catch (err) {
|
|
@@ -2488,7 +2548,9 @@ function InlineParentForm({
|
|
|
2488
2548
|
groups,
|
|
2489
2549
|
parent,
|
|
2490
2550
|
resource,
|
|
2491
|
-
onSaved
|
|
2551
|
+
onSaved,
|
|
2552
|
+
formId,
|
|
2553
|
+
externalSubmit = false
|
|
2492
2554
|
}) {
|
|
2493
2555
|
const fields = rawFields;
|
|
2494
2556
|
const [values, setValues] = useState8({});
|
|
@@ -2552,6 +2614,7 @@ function InlineParentForm({
|
|
|
2552
2614
|
return /* @__PURE__ */ jsx14(
|
|
2553
2615
|
"form",
|
|
2554
2616
|
{
|
|
2617
|
+
id: formId,
|
|
2555
2618
|
noValidate: true,
|
|
2556
2619
|
onSubmit: async (event) => {
|
|
2557
2620
|
event.preventDefault();
|
|
@@ -2580,7 +2643,7 @@ function InlineParentForm({
|
|
|
2580
2643
|
children: /* @__PURE__ */ jsxs10(Stack3, { gap: "16px", children: [
|
|
2581
2644
|
error ? /* @__PURE__ */ jsx14(Box7, { role: "alert", p: "10px 12px", color: "#B42318", bg: "#FEF3F2", borderWidth: "1px", borderColor: "#FECDCA", borderRadius: "7px", fontSize: "11px", children: messageOf3(error) }) : null,
|
|
2582
2645
|
renderFields(),
|
|
2583
|
-
/* @__PURE__ */ jsx14(Flex6, { justify: "flex-end", children: /* @__PURE__ */ jsx14(Button7, { type: "submit", colorPalette: "brand", loading: saving, children: "Salvar dados principais" }) })
|
|
2646
|
+
!externalSubmit ? /* @__PURE__ */ jsx14(Flex6, { justify: "flex-end", children: /* @__PURE__ */ jsx14(Button7, { type: "submit", colorPalette: "brand", loading: saving, children: "Salvar dados principais" }) }) : null
|
|
2584
2647
|
] })
|
|
2585
2648
|
}
|
|
2586
2649
|
);
|
|
@@ -2595,7 +2658,9 @@ function CoreTabbedDetail({
|
|
|
2595
2658
|
relations,
|
|
2596
2659
|
refreshTokens,
|
|
2597
2660
|
onRefresh,
|
|
2598
|
-
onParentSaved
|
|
2661
|
+
onParentSaved,
|
|
2662
|
+
formId,
|
|
2663
|
+
externalSubmit
|
|
2599
2664
|
}) {
|
|
2600
2665
|
const active = tabs.find((tab) => tab.id === activeTab) ?? tabs[0];
|
|
2601
2666
|
return /* @__PURE__ */ jsxs10(Stack3, { gap: 4, children: [
|
|
@@ -2621,7 +2686,9 @@ function CoreTabbedDetail({
|
|
|
2621
2686
|
groups: active.groups,
|
|
2622
2687
|
parent: parent ?? {},
|
|
2623
2688
|
resource,
|
|
2624
|
-
onSaved: onParentSaved
|
|
2689
|
+
onSaved: onParentSaved,
|
|
2690
|
+
formId,
|
|
2691
|
+
externalSubmit
|
|
2625
2692
|
}
|
|
2626
2693
|
) : (active.type === "relatedGrid" || active.type === "readonlyGrid") && parent ? /* @__PURE__ */ jsx14(
|
|
2627
2694
|
CoreRelatedGrid,
|
|
@@ -2650,7 +2717,8 @@ function CoreDetailModal({
|
|
|
2650
2717
|
initialRecord,
|
|
2651
2718
|
initialTab,
|
|
2652
2719
|
relations,
|
|
2653
|
-
|
|
2720
|
+
topActions,
|
|
2721
|
+
bottomActions,
|
|
2654
2722
|
onClose,
|
|
2655
2723
|
onSaved
|
|
2656
2724
|
}) {
|
|
@@ -2695,18 +2763,38 @@ function CoreDetailModal({
|
|
|
2695
2763
|
};
|
|
2696
2764
|
const width = config.size === "full" ? "98vw" : config.size === "md" ? "760px" : config.size === "lg" ? "980px" : "1180px";
|
|
2697
2765
|
const displayTitle = parent?.[config.titleField ?? ""] ? String(parent[config.titleField ?? ""]) : title;
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2766
|
+
const activeIsForm = (config.tabs.find((tab) => tab.id === activeTab) ?? config.tabs[0])?.type === "form";
|
|
2767
|
+
const formId = `oon-detail-form-${model.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
|
|
2768
|
+
return /* @__PURE__ */ jsx15(Flex7, { position: "fixed", inset: 0, zIndex: 1e3, align: "center", justify: "center", p: 4, bg: "rgba(15,23,42,.48)", children: /* @__PURE__ */ jsxs11(Box8, { role: "dialog", "aria-modal": "true", display: "flex", flexDirection: "column", w: `min(${width}, 98vw)`, h: "94vh", maxH: "94vh", overflow: "hidden", bg: "white", borderRadius: "14px", boxShadow: "0 24px 70px rgba(15,23,42,.24)", children: [
|
|
2769
|
+
/* @__PURE__ */ jsxs11(Flex7, { minH: "72px", px: "20px", py: "10px", align: "center", justify: "space-between", gap: 4, borderBottomWidth: "1px", borderColor: "#E5E9ED", children: [
|
|
2770
|
+
/* @__PURE__ */ jsxs11(Box8, { minW: "160px", children: [
|
|
2701
2771
|
/* @__PURE__ */ jsx15(Text10, { color: "#0474AF", fontSize: "10px", fontWeight: "700", textTransform: "uppercase", children: "Detalhe" }),
|
|
2702
2772
|
/* @__PURE__ */ jsx15(Heading3, { size: "md", children: recordId ? displayTitle : `Novo ${title}` })
|
|
2703
2773
|
] }),
|
|
2704
|
-
/* @__PURE__ */ jsxs11(Flex7, { align: "center", justify: "flex-end", gap: "
|
|
2705
|
-
recordId ?
|
|
2706
|
-
/* @__PURE__ */ jsx15(
|
|
2774
|
+
/* @__PURE__ */ jsxs11(Flex7, { flex: "1", align: "center", justify: "flex-end", gap: "8px", wrap: "wrap", children: [
|
|
2775
|
+
recordId ? topActions : null,
|
|
2776
|
+
/* @__PURE__ */ jsx15(
|
|
2777
|
+
IconButton,
|
|
2778
|
+
{
|
|
2779
|
+
"aria-label": "Fechar",
|
|
2780
|
+
title: "Fechar",
|
|
2781
|
+
size: "sm",
|
|
2782
|
+
minW: "32px",
|
|
2783
|
+
h: "32px",
|
|
2784
|
+
borderRadius: "full",
|
|
2785
|
+
variant: "ghost",
|
|
2786
|
+
color: "#475569",
|
|
2787
|
+
fontSize: "21px",
|
|
2788
|
+
fontWeight: "400",
|
|
2789
|
+
lineHeight: "1",
|
|
2790
|
+
onClick: onClose,
|
|
2791
|
+
_hover: { bg: "#F1F5F9", color: "#0F172A" },
|
|
2792
|
+
children: "\xD7"
|
|
2793
|
+
}
|
|
2794
|
+
)
|
|
2707
2795
|
] })
|
|
2708
2796
|
] }),
|
|
2709
|
-
/* @__PURE__ */ jsx15(Box8, {
|
|
2797
|
+
/* @__PURE__ */ jsx15(Box8, { flex: "1", minH: 0, p: "20px", overflowY: "auto", children: schemaQuery.isLoading || parentQuery.isLoading ? /* @__PURE__ */ jsx15(Text10, { children: "Carregando..." }) : /* @__PURE__ */ jsx15(
|
|
2710
2798
|
CoreTabbedDetail,
|
|
2711
2799
|
{
|
|
2712
2800
|
tabs: config.tabs,
|
|
@@ -2718,13 +2806,35 @@ function CoreDetailModal({
|
|
|
2718
2806
|
relations,
|
|
2719
2807
|
refreshTokens,
|
|
2720
2808
|
onRefresh: refresh,
|
|
2809
|
+
formId,
|
|
2810
|
+
externalSubmit: true,
|
|
2721
2811
|
onParentSaved: (saved) => {
|
|
2722
2812
|
setParent(saved);
|
|
2723
2813
|
onSaved?.(saved);
|
|
2724
2814
|
refresh(["parent"]);
|
|
2725
2815
|
}
|
|
2726
2816
|
}
|
|
2727
|
-
) })
|
|
2817
|
+
) }),
|
|
2818
|
+
/* @__PURE__ */ jsxs11(
|
|
2819
|
+
Flex7,
|
|
2820
|
+
{
|
|
2821
|
+
flex: "0 0 auto",
|
|
2822
|
+
minH: "64px",
|
|
2823
|
+
px: "20px",
|
|
2824
|
+
py: "10px",
|
|
2825
|
+
align: "center",
|
|
2826
|
+
justify: "space-between",
|
|
2827
|
+
gap: "12px",
|
|
2828
|
+
bg: "white",
|
|
2829
|
+
borderTopWidth: "1px",
|
|
2830
|
+
borderColor: "#E5E9ED",
|
|
2831
|
+
boxShadow: "0 -8px 24px rgba(15,23,42,.06)",
|
|
2832
|
+
children: [
|
|
2833
|
+
/* @__PURE__ */ jsx15(Box8, { children: recordId ? bottomActions : null }),
|
|
2834
|
+
/* @__PURE__ */ jsx15(Button8, { type: "submit", form: formId, colorPalette: "brand", disabled: !activeIsForm || schemaQuery.isLoading || parentQuery.isLoading, children: "Salvar" })
|
|
2835
|
+
]
|
|
2836
|
+
}
|
|
2837
|
+
)
|
|
2728
2838
|
] }) });
|
|
2729
2839
|
}
|
|
2730
2840
|
|
|
@@ -2872,6 +2982,133 @@ function CoreDocument({ model, label, endpoint, columns, form }) {
|
|
|
2872
2982
|
import { useState as useState11 } from "react";
|
|
2873
2983
|
import { Badge as Badge4, Box as Box10, Button as Button9, Flex as Flex8, Heading as Heading5, Input as Input6, NativeSelect as NativeSelect5, Stack as Stack5, Text as Text12 } from "@chakra-ui/react";
|
|
2874
2984
|
import { useMutation as useMutation3, useQuery as useQuery7, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
|
|
2985
|
+
|
|
2986
|
+
// src/pipelineTicket.ts
|
|
2987
|
+
var DEFAULT_EXCLUDED_STAGES = [
|
|
2988
|
+
"cancelado",
|
|
2989
|
+
"cancelada",
|
|
2990
|
+
"cancelled",
|
|
2991
|
+
"rejeitado",
|
|
2992
|
+
"rejeitada",
|
|
2993
|
+
"rejected"
|
|
2994
|
+
];
|
|
2995
|
+
function normalized(value) {
|
|
2996
|
+
return String(value ?? "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").trim().toLowerCase();
|
|
2997
|
+
}
|
|
2998
|
+
function slug(value) {
|
|
2999
|
+
return normalized(value).replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
3000
|
+
}
|
|
3001
|
+
function approvalTone(action) {
|
|
3002
|
+
const key = normalized(`${action.id ?? ""} ${action.label}`);
|
|
3003
|
+
if (/recusar|reprovar|reject/.test(key)) return "danger";
|
|
3004
|
+
if (/aprovar|approve/.test(key)) return "success";
|
|
3005
|
+
return void 0;
|
|
3006
|
+
}
|
|
3007
|
+
function workStatusPresentation(value) {
|
|
3008
|
+
const key = normalized(value);
|
|
3009
|
+
if (/aguardando.*inicio|nao.*iniciado|waiting/.test(key)) {
|
|
3010
|
+
return { order: 0, label: "Aguardando in\xEDcio", tone: "warning" };
|
|
3011
|
+
}
|
|
3012
|
+
if (/trabalhando|em.*andamento|working/.test(key)) {
|
|
3013
|
+
return { order: 1, label: "Trabalhando", tone: "success" };
|
|
3014
|
+
}
|
|
3015
|
+
if (/revisar|revisao|review/.test(key)) {
|
|
3016
|
+
return { order: 2, label: "Revis\xE3o", tone: "danger" };
|
|
3017
|
+
}
|
|
3018
|
+
return void 0;
|
|
3019
|
+
}
|
|
3020
|
+
function decoratePipelineAction(action, stageField, workStatusField) {
|
|
3021
|
+
const approval = action.type === "transition" && action.field === stageField && approvalTone(action);
|
|
3022
|
+
const workStatus = action.type === "setField" && action.field === workStatusField;
|
|
3023
|
+
const group = action.group ?? (approval ? "approval" : workStatus ? "workStatus" : "custom");
|
|
3024
|
+
const tone = action.tone ?? (approval || (workStatus ? workStatusPresentation(action.value)?.tone : void 0)) ?? (group === "custom" ? "neutral" : void 0);
|
|
3025
|
+
const operationalKind = action.operationalKind ?? (group === "approval" ? "approval" : group === "workStatus" ? "work-status" : "business");
|
|
3026
|
+
return { ...action, group, tone, operationalKind };
|
|
3027
|
+
}
|
|
3028
|
+
function resolvePipelineActions({
|
|
3029
|
+
stageField,
|
|
3030
|
+
stages,
|
|
3031
|
+
workStatusValues = [],
|
|
3032
|
+
ticketActions = [],
|
|
3033
|
+
defaultActions
|
|
3034
|
+
}) {
|
|
3035
|
+
const config = defaultActions === false ? void 0 : defaultActions ?? {};
|
|
3036
|
+
const workStatusField = config?.workStatusField ?? "statusTrabalho";
|
|
3037
|
+
const explicit = ticketActions.map((action) => decoratePipelineAction(action, stageField, workStatusField));
|
|
3038
|
+
if (defaultActions === false) return explicit;
|
|
3039
|
+
const resolved = [];
|
|
3040
|
+
const hasExplicitApproval = explicit.some((action) => action.group === "approval");
|
|
3041
|
+
const hasExplicitWorkStatus = explicit.some((action) => action.group === "workStatus");
|
|
3042
|
+
if (config?.approval !== false && !hasExplicitApproval) {
|
|
3043
|
+
const excluded = /* @__PURE__ */ new Set([
|
|
3044
|
+
...DEFAULT_EXCLUDED_STAGES,
|
|
3045
|
+
...(config?.excludedStages ?? []).map(normalized)
|
|
3046
|
+
]);
|
|
3047
|
+
const approvalStages = stages.filter((stage) => !excluded.has(normalized(stage.id)));
|
|
3048
|
+
approvalStages.forEach((stage, index) => {
|
|
3049
|
+
const next = approvalStages[index + 1];
|
|
3050
|
+
if (next) {
|
|
3051
|
+
resolved.push({
|
|
3052
|
+
id: `core-aprovar-${slug(stage.id)}`,
|
|
3053
|
+
label: "Aprovar",
|
|
3054
|
+
type: "transition",
|
|
3055
|
+
field: stageField,
|
|
3056
|
+
value: next.id,
|
|
3057
|
+
hiddenWhen: { field: stageField, notEquals: stage.id },
|
|
3058
|
+
confirm: { description: `Aprovar este ticket e alterar a etapa para ${next.label}?` },
|
|
3059
|
+
refresh: ["all"],
|
|
3060
|
+
group: "approval",
|
|
3061
|
+
tone: "success",
|
|
3062
|
+
operationalKind: "approval"
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
});
|
|
3066
|
+
approvalStages.forEach((stage, index) => {
|
|
3067
|
+
const previous = approvalStages[index - 1];
|
|
3068
|
+
if (previous) {
|
|
3069
|
+
resolved.push({
|
|
3070
|
+
id: `core-recusar-${slug(stage.id)}`,
|
|
3071
|
+
label: "Recusar",
|
|
3072
|
+
type: "transition",
|
|
3073
|
+
field: stageField,
|
|
3074
|
+
value: previous.id,
|
|
3075
|
+
hiddenWhen: { field: stageField, notEquals: stage.id },
|
|
3076
|
+
confirm: { description: `Recusar este ticket e retornar a etapa para ${previous.label}?` },
|
|
3077
|
+
refresh: ["all"],
|
|
3078
|
+
group: "approval",
|
|
3079
|
+
tone: "danger",
|
|
3080
|
+
operationalKind: "approval"
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
});
|
|
3084
|
+
}
|
|
3085
|
+
if (config?.workStatus !== false && !hasExplicitWorkStatus && workStatusValues.length) {
|
|
3086
|
+
workStatusValues.map((value) => ({ value, presentation: workStatusPresentation(value) })).filter((item) => Boolean(item.presentation)).sort((a, b) => a.presentation.order - b.presentation.order).forEach(({ value, presentation }) => {
|
|
3087
|
+
resolved.push({
|
|
3088
|
+
id: `core-status-trabalho-${slug(value)}`,
|
|
3089
|
+
label: presentation.label,
|
|
3090
|
+
type: "setField",
|
|
3091
|
+
field: workStatusField,
|
|
3092
|
+
value,
|
|
3093
|
+
disabledWhen: { field: workStatusField, equals: value },
|
|
3094
|
+
refresh: ["all"],
|
|
3095
|
+
group: "workStatus",
|
|
3096
|
+
tone: presentation.tone,
|
|
3097
|
+
operationalKind: "work-status"
|
|
3098
|
+
});
|
|
3099
|
+
});
|
|
3100
|
+
}
|
|
3101
|
+
return [...resolved, ...explicit];
|
|
3102
|
+
}
|
|
3103
|
+
function groupPipelineActions(actions) {
|
|
3104
|
+
return {
|
|
3105
|
+
approval: actions.filter((action) => action.group === "approval"),
|
|
3106
|
+
workStatus: actions.filter((action) => action.group === "workStatus"),
|
|
3107
|
+
custom: actions.filter((action) => action.group === "custom")
|
|
3108
|
+
};
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
// src/components/CorePipeline.tsx
|
|
2875
3112
|
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2876
3113
|
function ticketId(row) {
|
|
2877
3114
|
const id = row._id ?? row.id;
|
|
@@ -2887,6 +3124,13 @@ function mergeFormFields2(metadataFields, overrides) {
|
|
|
2887
3124
|
});
|
|
2888
3125
|
return merged;
|
|
2889
3126
|
}
|
|
3127
|
+
function workStatusColor(value) {
|
|
3128
|
+
const normalized2 = String(value ?? "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
|
|
3129
|
+
if (/aguardando.*inicio|nao.*iniciado|waiting/.test(normalized2)) return "#D97706";
|
|
3130
|
+
if (/trabalhando|em.*andamento|working/.test(normalized2)) return "#16A34A";
|
|
3131
|
+
if (/revisar|revisao|review/.test(normalized2)) return "#DC2626";
|
|
3132
|
+
return "#94A3B8";
|
|
3133
|
+
}
|
|
2890
3134
|
function PipelineFilterControl({
|
|
2891
3135
|
filter,
|
|
2892
3136
|
value,
|
|
@@ -2945,6 +3189,7 @@ function CorePipeline({
|
|
|
2945
3189
|
viewModes = ["board"],
|
|
2946
3190
|
defaultView,
|
|
2947
3191
|
list,
|
|
3192
|
+
defaultActions,
|
|
2948
3193
|
ticketActions = []
|
|
2949
3194
|
}) {
|
|
2950
3195
|
const schemaQuery = useModelSchema(model);
|
|
@@ -2993,6 +3238,17 @@ function CorePipeline({
|
|
|
2993
3238
|
if (viewMode === "board" && listQuery.isError) return /* @__PURE__ */ jsx18(ErrorState, { error: listQuery.error });
|
|
2994
3239
|
const stageFieldMeta = schema?.fields.find((field) => field.name === stageField);
|
|
2995
3240
|
const resolvedStages = stages ?? (stageFieldMeta?.options ?? []).map((option) => ({ id: option, label: option }));
|
|
3241
|
+
const defaultActionsConfig = defaultActions === false ? void 0 : defaultActions;
|
|
3242
|
+
const workStatusField = defaultActionsConfig?.workStatusField ?? "statusTrabalho";
|
|
3243
|
+
const workStatusMeta = schema?.fields.find((field) => field.name === workStatusField);
|
|
3244
|
+
const resolvedTicketActions = resolvePipelineActions({
|
|
3245
|
+
stageField,
|
|
3246
|
+
stages: resolvedStages,
|
|
3247
|
+
workStatusValues: workStatusMeta?.options ?? [],
|
|
3248
|
+
ticketActions,
|
|
3249
|
+
defaultActions
|
|
3250
|
+
});
|
|
3251
|
+
const groupedTicketActions = groupPipelineActions(resolvedTicketActions);
|
|
2996
3252
|
const resolvedTitleField = titleField ?? ticketModal?.titleField ?? schema?.fields.find((field) => field.kind === "string")?.name ?? schema?.searchable[0] ?? "_id";
|
|
2997
3253
|
const detailFields = (schema?.fields ?? []).filter((field) => field.name !== stageField && field.name !== resolvedTitleField && field.kind !== "raw").slice(0, 3);
|
|
2998
3254
|
const formFields = mergeFormFields2(formFieldsFromMeta(schema?.fields ?? []), form);
|
|
@@ -3014,7 +3270,7 @@ function CorePipeline({
|
|
|
3014
3270
|
...defaultStage ? { [stageField]: defaultStage } : {}
|
|
3015
3271
|
});
|
|
3016
3272
|
};
|
|
3017
|
-
const
|
|
3273
|
+
const renderModalAction = (action, index) => selectedTicket ? /* @__PURE__ */ jsx18(
|
|
3018
3274
|
CoreRowAction,
|
|
3019
3275
|
{
|
|
3020
3276
|
action,
|
|
@@ -3032,7 +3288,12 @@ function CorePipeline({
|
|
|
3032
3288
|
}
|
|
3033
3289
|
},
|
|
3034
3290
|
action.id ?? `${action.label}-${index}`
|
|
3035
|
-
)
|
|
3291
|
+
) : null;
|
|
3292
|
+
const modalTopActions = selectedTicket && !creating && groupedTicketActions.workStatus.length ? /* @__PURE__ */ jsx18(Flex8, { role: "group", "aria-label": "Status da atividade", gap: "6px", align: "center", wrap: "wrap", children: groupedTicketActions.workStatus.map(renderModalAction) }) : null;
|
|
3293
|
+
const modalBottomActions = selectedTicket && !creating ? /* @__PURE__ */ jsxs13(Flex8, { gap: "8px", align: "center", wrap: "wrap", children: [
|
|
3294
|
+
groupedTicketActions.approval.length ? /* @__PURE__ */ jsx18(Flex8, { role: "group", "aria-label": "Aprova\xE7\xE3o do ticket", gap: "6px", align: "center", wrap: "wrap", children: groupedTicketActions.approval.map(renderModalAction) }) : null,
|
|
3295
|
+
groupedTicketActions.custom.length ? /* @__PURE__ */ jsx18(Flex8, { role: "group", "aria-label": "A\xE7\xF5es do neg\xF3cio", gap: "6px", align: "center", wrap: "wrap", children: groupedTicketActions.custom.map(renderModalAction) }) : null
|
|
3296
|
+
] }) : null;
|
|
3036
3297
|
return /* @__PURE__ */ jsxs13(Stack5, { gap: 5, children: [
|
|
3037
3298
|
/* @__PURE__ */ jsxs13(Flex8, { align: { base: "stretch", md: "flex-end" }, justify: "space-between", gap: 4, direction: { base: "column", md: "row" }, children: [
|
|
3038
3299
|
/* @__PURE__ */ jsxs13(Box10, { children: [
|
|
@@ -3118,7 +3379,24 @@ function CorePipeline({
|
|
|
3118
3379
|
},
|
|
3119
3380
|
_hover: { borderColor: "brand.300", transform: "translateY(-1px)", boxShadow: "0 7px 18px rgba(7, 38, 46, 0.09)" },
|
|
3120
3381
|
children: [
|
|
3121
|
-
/* @__PURE__ */
|
|
3382
|
+
/* @__PURE__ */ jsxs13(Flex8, { align: "flex-start", justify: "space-between", gap: "8px", mb: 2, children: [
|
|
3383
|
+
/* @__PURE__ */ jsx18(Text12, { fontSize: "13px", fontWeight: "700", color: "#24323A", lineClamp: 2, children: ticketTitle }),
|
|
3384
|
+
/* @__PURE__ */ jsx18(
|
|
3385
|
+
Box10,
|
|
3386
|
+
{
|
|
3387
|
+
as: "span",
|
|
3388
|
+
title: `Status da atividade: ${String(row[workStatusField] ?? "N\xE3o informado")}`,
|
|
3389
|
+
"aria-label": `Status da atividade: ${String(row[workStatusField] ?? "N\xE3o informado")}`,
|
|
3390
|
+
flex: "0 0 auto",
|
|
3391
|
+
w: "10px",
|
|
3392
|
+
h: "10px",
|
|
3393
|
+
mt: "4px",
|
|
3394
|
+
borderRadius: "full",
|
|
3395
|
+
bg: workStatusColor(row[workStatusField]),
|
|
3396
|
+
boxShadow: "0 0 0 3px white, 0 0 0 4px #E2E8F0"
|
|
3397
|
+
}
|
|
3398
|
+
)
|
|
3399
|
+
] }),
|
|
3122
3400
|
/* @__PURE__ */ jsx18(Stack5, { gap: 1, children: detailFields.map((field) => /* @__PURE__ */ jsxs13(Flex8, { gap: 2, align: "baseline", justify: "space-between", children: [
|
|
3123
3401
|
/* @__PURE__ */ jsx18(Text12, { fontSize: "10px", color: "gray.500", textTransform: "uppercase", letterSpacing: "0.03em", children: fieldLabel(field) }),
|
|
3124
3402
|
/* @__PURE__ */ jsx18(Text12, { fontSize: "11px", color: "#46545C", fontWeight: "500", textAlign: "right", lineClamp: 1, children: formatCell(row[field.name], field.kind) })
|
|
@@ -3141,7 +3419,8 @@ function CorePipeline({
|
|
|
3141
3419
|
initialRecord: selectedTicket,
|
|
3142
3420
|
initialTab: creating ? create?.initialTab : void 0,
|
|
3143
3421
|
relations,
|
|
3144
|
-
|
|
3422
|
+
topActions: modalTopActions,
|
|
3423
|
+
bottomActions: modalBottomActions,
|
|
3145
3424
|
onClose: () => {
|
|
3146
3425
|
setSelectedTicket(null);
|
|
3147
3426
|
setCreating(false);
|
|
@@ -3254,10 +3533,10 @@ function registryKey(key) {
|
|
|
3254
3533
|
}
|
|
3255
3534
|
function resolveComponent(registry, key, bucket) {
|
|
3256
3535
|
if (!key) return null;
|
|
3257
|
-
const
|
|
3536
|
+
const normalized2 = registryKey(key);
|
|
3258
3537
|
const inferred = key.includes(".") ? PREFIX_BUCKETS[key.split(".")[0]] : void 0;
|
|
3259
3538
|
const targetBucket = bucket ?? inferred ?? "pageComponents";
|
|
3260
|
-
return registry?.[targetBucket]?.[
|
|
3539
|
+
return registry?.[targetBucket]?.[normalized2] ?? registry?.[targetBucket]?.[key] ?? null;
|
|
3261
3540
|
}
|
|
3262
3541
|
function MissingRenderer({ renderer, children }) {
|
|
3263
3542
|
if (import.meta.env?.MODE === "production") return /* @__PURE__ */ jsx21(Fragment4, { children: children ?? null });
|
|
@@ -3371,7 +3650,7 @@ function CorePage2({ page, registry }) {
|
|
|
3371
3650
|
|
|
3372
3651
|
// src/app/moduleRegistry.tsx
|
|
3373
3652
|
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
3374
|
-
function
|
|
3653
|
+
function slug2(value) {
|
|
3375
3654
|
return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3376
3655
|
}
|
|
3377
3656
|
function requiredAccess2(source) {
|
|
@@ -3381,7 +3660,7 @@ function requiredAccess2(source) {
|
|
|
3381
3660
|
function viewId(view) {
|
|
3382
3661
|
if (view.id) return view.id;
|
|
3383
3662
|
if (view.type === "dashboard") return "dashboard";
|
|
3384
|
-
return
|
|
3663
|
+
return slug2(view.model);
|
|
3385
3664
|
}
|
|
3386
3665
|
function viewPath(view) {
|
|
3387
3666
|
if (view.path) return view.path;
|
|
@@ -3436,6 +3715,7 @@ function renderView(view, registry) {
|
|
|
3436
3715
|
viewModes: v.viewModes,
|
|
3437
3716
|
defaultView: v.defaultView,
|
|
3438
3717
|
list: v.list,
|
|
3718
|
+
defaultActions: v.defaultActions,
|
|
3439
3719
|
ticketActions: v.ticketActions
|
|
3440
3720
|
}
|
|
3441
3721
|
);
|
|
@@ -4574,6 +4854,7 @@ function manifestToConfig(manifest, runtime) {
|
|
|
4574
4854
|
viewModes: p.viewModes,
|
|
4575
4855
|
defaultView: p.defaultView,
|
|
4576
4856
|
list: p.list,
|
|
4857
|
+
defaultActions: p.defaultActions,
|
|
4577
4858
|
ticketActions: p.ticketActions
|
|
4578
4859
|
};
|
|
4579
4860
|
views.push(view);
|