@burdenoff/microfe-crewfoundry 2026.1107.1 → 2026.1107.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crewfoundry/components/WorkforceForecastCard.d.ts +17 -0
- package/dist/crewfoundry/components/WorkforceForecastCard.d.ts.map +1 -0
- package/dist/crewfoundry/components/WorkforceForecastCard.js +222 -0
- package/dist/crewfoundry/components/WorkforceForecastCard.js.map +1 -0
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts +3 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +154 -145
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.d.ts +57 -0
- package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +96 -70
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CrewWorkforceForecast } from '../store/crewfoundryStore';
|
|
2
|
+
|
|
3
|
+
interface WorkforceForecastCardProps {
|
|
4
|
+
forecast: CrewWorkforceForecast | null;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
error: string | null;
|
|
7
|
+
onRetry: () => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* BOFF-10826 — trained attrition model status and the 3/6/12-month headcount
|
|
11
|
+
* and cost forecast. Rendered next to the deterministic BOFF-4208 sections;
|
|
12
|
+
* it has its own loading and error state so a forecast failure never hides
|
|
13
|
+
* the rest of the dashboard.
|
|
14
|
+
*/
|
|
15
|
+
export declare function WorkforceForecastCard({ forecast, loading, error, onRetry, }: WorkforceForecastCardProps): import("react").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=WorkforceForecastCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkforceForecastCard.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/components/WorkforceForecastCard.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAIV,qBAAqB,EACtB,MAAM,2BAA2B,CAAC;AAoHnC,UAAU,0BAA0B;IAClC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,OAAO,EACP,KAAK,EACL,OAAO,GACR,EAAE,0BAA0B,+BAqF5B"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
2
|
+
import { Badge as n, Button as r, Card as i, CardContent as a, CardDescription as o, CardHeader as s, CardTitle as c, ResponsiveTable as l, Spinner as u } from "@burdenoff/fe-libs/ui";
|
|
3
|
+
//#region src/crewfoundry/components/WorkforceForecastCard.tsx
|
|
4
|
+
var d = 5, f = {
|
|
5
|
+
ACTIVE: "Trained model in use",
|
|
6
|
+
HEURISTIC_PREFERRED: "Heuristic in use: model lost the backtest",
|
|
7
|
+
INSUFFICIENT_DATA: "Heuristic in use: not enough history yet"
|
|
8
|
+
}, p = {
|
|
9
|
+
ACTIVE: "success",
|
|
10
|
+
HEURISTIC_PREFERRED: "secondary",
|
|
11
|
+
INSUFFICIENT_DATA: "outline"
|
|
12
|
+
};
|
|
13
|
+
function m(e) {
|
|
14
|
+
let t = e < 0 ? "-" : "", n = Math.abs(e);
|
|
15
|
+
return n >= 1e6 ? `${t}$${(n / 1e6).toFixed(1)}M` : n >= 1e3 ? `${t}$${(n / 1e3).toFixed(0)}K` : `${t}$${Math.round(n)}`;
|
|
16
|
+
}
|
|
17
|
+
function h(e) {
|
|
18
|
+
return Number.isInteger(e) ? String(e) : e.toFixed(1);
|
|
19
|
+
}
|
|
20
|
+
var g = [
|
|
21
|
+
{
|
|
22
|
+
key: "months",
|
|
23
|
+
header: "Horizon",
|
|
24
|
+
priority: "primary",
|
|
25
|
+
cell: (e) => /* @__PURE__ */ t("span", {
|
|
26
|
+
className: "font-medium",
|
|
27
|
+
children: [e.months, " months"]
|
|
28
|
+
})
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
key: "headcount",
|
|
32
|
+
header: "Headcount (90% range)",
|
|
33
|
+
priority: "primary",
|
|
34
|
+
cell: (e) => /* @__PURE__ */ t("span", {
|
|
35
|
+
className: "tabular-nums md:block md:text-right",
|
|
36
|
+
children: [
|
|
37
|
+
h(e.projectedHeadcount),
|
|
38
|
+
" ",
|
|
39
|
+
/* @__PURE__ */ t("span", {
|
|
40
|
+
className: "text-xs text-text-secondary",
|
|
41
|
+
children: [
|
|
42
|
+
"(",
|
|
43
|
+
h(e.low),
|
|
44
|
+
" to ",
|
|
45
|
+
h(e.high),
|
|
46
|
+
")"
|
|
47
|
+
]
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
})
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: "flows",
|
|
54
|
+
header: "Hires / exits",
|
|
55
|
+
priority: "secondary",
|
|
56
|
+
cell: (e) => /* @__PURE__ */ t("span", {
|
|
57
|
+
className: "tabular-nums md:block md:text-right",
|
|
58
|
+
children: [
|
|
59
|
+
"+",
|
|
60
|
+
h(e.expectedHires),
|
|
61
|
+
" / -",
|
|
62
|
+
h(e.expectedExits)
|
|
63
|
+
]
|
|
64
|
+
})
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: "monthly",
|
|
68
|
+
header: "Monthly cost",
|
|
69
|
+
priority: "secondary",
|
|
70
|
+
cell: (t) => /* @__PURE__ */ e("span", {
|
|
71
|
+
className: "tabular-nums md:block md:text-right",
|
|
72
|
+
children: m(t.projectedMonthlyCost)
|
|
73
|
+
})
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
key: "cumulative",
|
|
77
|
+
header: "Cumulative cost",
|
|
78
|
+
priority: "secondary",
|
|
79
|
+
cell: (t) => /* @__PURE__ */ e("span", {
|
|
80
|
+
className: "tabular-nums md:block md:text-right",
|
|
81
|
+
children: m(t.cumulativeCost)
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
], _ = [
|
|
85
|
+
{
|
|
86
|
+
key: "employee",
|
|
87
|
+
header: "Employee",
|
|
88
|
+
priority: "primary",
|
|
89
|
+
cell: (n) => /* @__PURE__ */ t("div", { children: [/* @__PURE__ */ e("p", {
|
|
90
|
+
className: "font-medium",
|
|
91
|
+
children: n.employeeName
|
|
92
|
+
}), /* @__PURE__ */ e("p", {
|
|
93
|
+
className: "text-xs text-text-secondary",
|
|
94
|
+
children: n.department
|
|
95
|
+
})] })
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: "probability",
|
|
99
|
+
header: "Exit probability",
|
|
100
|
+
priority: "primary",
|
|
101
|
+
cell: (t) => /* @__PURE__ */ e("span", {
|
|
102
|
+
className: "tabular-nums md:block md:text-right",
|
|
103
|
+
children: t.predictedExitProbability === null ? "—" : `${Math.round(t.predictedExitProbability * 100)}%`
|
|
104
|
+
})
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
key: "drivers",
|
|
108
|
+
header: "Drivers",
|
|
109
|
+
priority: "secondary",
|
|
110
|
+
cell: (t) => /* @__PURE__ */ e("span", {
|
|
111
|
+
className: "text-sm text-text-secondary",
|
|
112
|
+
children: t.drivers.length > 0 ? t.drivers.join(", ") : "No risk signals"
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
function v({ forecast: v, loading: y, error: b, onRetry: x }) {
|
|
117
|
+
let S = v?.attrition ?? null, C = v?.headcount ?? null, w = S?.model.status === "ACTIVE", T = w ? S.predictions.slice(0, d) : [];
|
|
118
|
+
return /* @__PURE__ */ t(i, {
|
|
119
|
+
"data-testid": "workforce-forecast",
|
|
120
|
+
children: [/* @__PURE__ */ t(s, { children: [/* @__PURE__ */ e(c, { children: "Workforce forecast" }), /* @__PURE__ */ e(o, { children: "Headcount and payroll cost projected from your own hiring velocity and exit rate, and an attrition model trained on this workspace's history only. The model replaces the heuristic only when it beats it on a held-out period." })] }), /* @__PURE__ */ t(a, {
|
|
121
|
+
className: "space-y-5",
|
|
122
|
+
children: [
|
|
123
|
+
b ? /* @__PURE__ */ t("div", {
|
|
124
|
+
className: "flex flex-wrap items-center justify-between gap-3",
|
|
125
|
+
children: [/* @__PURE__ */ e("p", {
|
|
126
|
+
className: "text-sm text-status-error-text",
|
|
127
|
+
children: b
|
|
128
|
+
}), /* @__PURE__ */ e(r, {
|
|
129
|
+
variant: "outline",
|
|
130
|
+
size: "sm",
|
|
131
|
+
onClick: x,
|
|
132
|
+
children: "Try again"
|
|
133
|
+
})]
|
|
134
|
+
}) : null,
|
|
135
|
+
!v && y ? /* @__PURE__ */ e("div", {
|
|
136
|
+
className: "flex min-h-[8rem] items-center justify-center",
|
|
137
|
+
children: /* @__PURE__ */ e(u, { size: "md" })
|
|
138
|
+
}) : null,
|
|
139
|
+
C ? /* @__PURE__ */ t("section", {
|
|
140
|
+
className: "space-y-3",
|
|
141
|
+
"data-testid": "headcount-forecast",
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ t("div", {
|
|
144
|
+
className: "flex flex-wrap items-center gap-2",
|
|
145
|
+
children: [/* @__PURE__ */ e("h3", {
|
|
146
|
+
className: "text-sm font-semibold",
|
|
147
|
+
children: "Headcount and cost"
|
|
148
|
+
}), C.status === "LIMITED_HISTORY" ? /* @__PURE__ */ e(n, {
|
|
149
|
+
variant: "outline",
|
|
150
|
+
children: "Limited history"
|
|
151
|
+
}) : null]
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ t("p", {
|
|
154
|
+
className: "text-sm text-text-secondary",
|
|
155
|
+
children: [
|
|
156
|
+
C.currentHeadcount,
|
|
157
|
+
" active today, ",
|
|
158
|
+
C.hiresPerMonth.toFixed(1),
|
|
159
|
+
" hires a month and a ",
|
|
160
|
+
(C.monthlyExitRate * 100).toFixed(1),
|
|
161
|
+
"% monthly exit rate over the last ",
|
|
162
|
+
h(C.observationMonths),
|
|
163
|
+
" months. Current payroll",
|
|
164
|
+
" ",
|
|
165
|
+
m(C.currentMonthlyCost),
|
|
166
|
+
" a month; ",
|
|
167
|
+
C.openRequisitions,
|
|
168
|
+
" open role",
|
|
169
|
+
C.openRequisitions === 1 ? "" : "s",
|
|
170
|
+
" shown for context."
|
|
171
|
+
]
|
|
172
|
+
}),
|
|
173
|
+
/* @__PURE__ */ e(l, {
|
|
174
|
+
columns: g,
|
|
175
|
+
data: C.horizons,
|
|
176
|
+
rowKey: (e) => String(e.months)
|
|
177
|
+
})
|
|
178
|
+
]
|
|
179
|
+
}) : null,
|
|
180
|
+
S ? /* @__PURE__ */ t("section", {
|
|
181
|
+
className: "space-y-3",
|
|
182
|
+
"data-testid": "attrition-model",
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ t("div", {
|
|
185
|
+
className: "flex flex-wrap items-center gap-2",
|
|
186
|
+
children: [/* @__PURE__ */ e("h3", {
|
|
187
|
+
className: "text-sm font-semibold",
|
|
188
|
+
children: "Attrition model"
|
|
189
|
+
}), /* @__PURE__ */ e(n, {
|
|
190
|
+
variant: p[S.model.status],
|
|
191
|
+
"data-testid": "attrition-model-status",
|
|
192
|
+
children: f[S.model.status]
|
|
193
|
+
})]
|
|
194
|
+
}),
|
|
195
|
+
/* @__PURE__ */ e("p", {
|
|
196
|
+
className: "text-sm text-text-secondary",
|
|
197
|
+
children: S.model.reason
|
|
198
|
+
}),
|
|
199
|
+
w && T.length > 0 ? /* @__PURE__ */ e(l, {
|
|
200
|
+
columns: _,
|
|
201
|
+
data: T,
|
|
202
|
+
rowKey: (e) => e.employeeId
|
|
203
|
+
}) : null,
|
|
204
|
+
/* @__PURE__ */ t("p", {
|
|
205
|
+
className: "text-xs text-text-secondary",
|
|
206
|
+
children: [
|
|
207
|
+
"Probability of leaving within ",
|
|
208
|
+
S.model.horizonDays,
|
|
209
|
+
" days.",
|
|
210
|
+
S.model.excludedFeatures.length > 0 ? ` Never used: ${S.model.excludedFeatures.join("; ")}.` : null
|
|
211
|
+
]
|
|
212
|
+
})
|
|
213
|
+
]
|
|
214
|
+
}) : null
|
|
215
|
+
]
|
|
216
|
+
})]
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
export { v as WorkforceForecastCard };
|
|
221
|
+
|
|
222
|
+
//# sourceMappingURL=WorkforceForecastCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkforceForecastCard.js","names":[],"sources":["../../../src/crewfoundry/components/WorkforceForecastCard.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n ResponsiveTable,\n type ResponsiveTableColumn,\n Spinner,\n} from '@burdenoff/fe-libs/ui';\nimport type {\n CrewAttritionModelStatus,\n CrewAttritionPrediction,\n CrewHeadcountForecastHorizon,\n CrewWorkforceForecast,\n} from '../store/crewfoundryStore';\n\n/** Most at-risk employees listed when the trained model is in use. */\nconst MAX_PREDICTION_ROWS = 5;\n\nconst MODEL_STATUS_LABEL: Record<CrewAttritionModelStatus, string> = {\n ACTIVE: 'Trained model in use',\n HEURISTIC_PREFERRED: 'Heuristic in use: model lost the backtest',\n INSUFFICIENT_DATA: 'Heuristic in use: not enough history yet',\n};\n\nconst MODEL_STATUS_VARIANT: Record<CrewAttritionModelStatus, 'success' | 'secondary' | 'outline'> =\n {\n ACTIVE: 'success',\n HEURISTIC_PREFERRED: 'secondary',\n INSUFFICIENT_DATA: 'outline',\n };\n\nfunction formatMoney(value: number): string {\n const sign = value < 0 ? '-' : '';\n const abs = Math.abs(value);\n if (abs >= 1_000_000) return `${sign}$${(abs / 1_000_000).toFixed(1)}M`;\n if (abs >= 1_000) return `${sign}$${(abs / 1_000).toFixed(0)}K`;\n return `${sign}$${Math.round(abs)}`;\n}\n\nfunction formatCount(value: number): string {\n return Number.isInteger(value) ? String(value) : value.toFixed(1);\n}\n\nconst horizonColumns: ResponsiveTableColumn<CrewHeadcountForecastHorizon>[] = [\n {\n key: 'months',\n header: 'Horizon',\n priority: 'primary',\n cell: (row) => <span className=\"font-medium\">{row.months} months</span>,\n },\n {\n key: 'headcount',\n header: 'Headcount (90% range)',\n priority: 'primary',\n cell: (row) => (\n <span className=\"tabular-nums md:block md:text-right\">\n {formatCount(row.projectedHeadcount)}{' '}\n <span className=\"text-xs text-text-secondary\">\n ({formatCount(row.low)} to {formatCount(row.high)})\n </span>\n </span>\n ),\n },\n {\n key: 'flows',\n header: 'Hires / exits',\n priority: 'secondary',\n cell: (row) => (\n <span className=\"tabular-nums md:block md:text-right\">\n +{formatCount(row.expectedHires)} / -{formatCount(row.expectedExits)}\n </span>\n ),\n },\n {\n key: 'monthly',\n header: 'Monthly cost',\n priority: 'secondary',\n cell: (row) => (\n <span className=\"tabular-nums md:block md:text-right\">\n {formatMoney(row.projectedMonthlyCost)}\n </span>\n ),\n },\n {\n key: 'cumulative',\n header: 'Cumulative cost',\n priority: 'secondary',\n cell: (row) => (\n <span className=\"tabular-nums md:block md:text-right\">{formatMoney(row.cumulativeCost)}</span>\n ),\n },\n];\n\nconst predictionColumns: ResponsiveTableColumn<CrewAttritionPrediction>[] = [\n {\n key: 'employee',\n header: 'Employee',\n priority: 'primary',\n cell: (row) => (\n <div>\n <p className=\"font-medium\">{row.employeeName}</p>\n <p className=\"text-xs text-text-secondary\">{row.department}</p>\n </div>\n ),\n },\n {\n key: 'probability',\n header: 'Exit probability',\n priority: 'primary',\n cell: (row) => (\n <span className=\"tabular-nums md:block md:text-right\">\n {row.predictedExitProbability === null\n ? '—'\n : `${Math.round(row.predictedExitProbability * 100)}%`}\n </span>\n ),\n },\n {\n key: 'drivers',\n header: 'Drivers',\n priority: 'secondary',\n cell: (row) => (\n <span className=\"text-sm text-text-secondary\">\n {row.drivers.length > 0 ? row.drivers.join(', ') : 'No risk signals'}\n </span>\n ),\n },\n];\n\ninterface WorkforceForecastCardProps {\n forecast: CrewWorkforceForecast | null;\n loading: boolean;\n error: string | null;\n onRetry: () => void;\n}\n\n/**\n * BOFF-10826 — trained attrition model status and the 3/6/12-month headcount\n * and cost forecast. Rendered next to the deterministic BOFF-4208 sections;\n * it has its own loading and error state so a forecast failure never hides\n * the rest of the dashboard.\n */\nexport function WorkforceForecastCard({\n forecast,\n loading,\n error,\n onRetry,\n}: WorkforceForecastCardProps) {\n const attrition = forecast?.attrition ?? null;\n const headcount = forecast?.headcount ?? null;\n const modelActive = attrition?.model.status === 'ACTIVE';\n const topPredictions = modelActive ? attrition.predictions.slice(0, MAX_PREDICTION_ROWS) : [];\n\n return (\n <Card data-testid=\"workforce-forecast\">\n <CardHeader>\n <CardTitle>Workforce forecast</CardTitle>\n <CardDescription>\n Headcount and payroll cost projected from your own hiring velocity and exit rate, and an\n attrition model trained on this workspace's history only. The model replaces the\n heuristic only when it beats it on a held-out period.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n {error ? (\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n <Button variant=\"outline\" size=\"sm\" onClick={onRetry}>\n Try again\n </Button>\n </div>\n ) : null}\n\n {!forecast && loading ? (\n <div className=\"flex min-h-[8rem] items-center justify-center\">\n <Spinner size=\"md\" />\n </div>\n ) : null}\n\n {headcount ? (\n <section className=\"space-y-3\" data-testid=\"headcount-forecast\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"text-sm font-semibold\">Headcount and cost</h3>\n {headcount.status === 'LIMITED_HISTORY' ? (\n <Badge variant=\"outline\">Limited history</Badge>\n ) : null}\n </div>\n <p className=\"text-sm text-text-secondary\">\n {headcount.currentHeadcount} active today, {headcount.hiresPerMonth.toFixed(1)} hires\n a month and a {(headcount.monthlyExitRate * 100).toFixed(1)}% monthly exit rate over\n the last {formatCount(headcount.observationMonths)} months. Current payroll{' '}\n {formatMoney(headcount.currentMonthlyCost)} a month; {headcount.openRequisitions} open\n role{headcount.openRequisitions === 1 ? '' : 's'} shown for context.\n </p>\n <ResponsiveTable\n columns={horizonColumns}\n data={headcount.horizons}\n rowKey={(row) => String(row.months)}\n />\n </section>\n ) : null}\n\n {attrition ? (\n <section className=\"space-y-3\" data-testid=\"attrition-model\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"text-sm font-semibold\">Attrition model</h3>\n <Badge\n variant={MODEL_STATUS_VARIANT[attrition.model.status]}\n data-testid=\"attrition-model-status\"\n >\n {MODEL_STATUS_LABEL[attrition.model.status]}\n </Badge>\n </div>\n <p className=\"text-sm text-text-secondary\">{attrition.model.reason}</p>\n {modelActive && topPredictions.length > 0 ? (\n <ResponsiveTable\n columns={predictionColumns}\n data={topPredictions}\n rowKey={(row) => row.employeeId}\n />\n ) : null}\n <p className=\"text-xs text-text-secondary\">\n Probability of leaving within {attrition.model.horizonDays} days.\n {attrition.model.excludedFeatures.length > 0\n ? ` Never used: ${attrition.model.excludedFeatures.join('; ')}.`\n : null}\n </p>\n </section>\n ) : null}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":"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"}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* `crewExecutiveDashboard` rollup, so every figure is computed from the
|
|
5
5
|
* workspace's real rows by one deterministic implementation rather than
|
|
6
6
|
* re-derived in the browser. Project budget and department budget figures
|
|
7
|
-
* still come from the bootstrap store, which already owns those rows.
|
|
7
|
+
* still come from the bootstrap store, which already owns those rows. The
|
|
8
|
+
* workforce forecast card (BOFF-10826) adds the trained attrition model and
|
|
9
|
+
* the 3/6/12-month headcount and cost projection.
|
|
8
10
|
*/
|
|
9
11
|
export declare function DashboardExecutiveDashboardPage(): import("react").JSX.Element;
|
|
10
12
|
//# sourceMappingURL=DashboardExecutiveDashboardPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardExecutiveDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DashboardExecutiveDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx"],"names":[],"mappings":"AAwdA;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,gCAqH9C"}
|