@almadar/ui 6.26.0 → 6.28.0

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.
@@ -32267,6 +32267,247 @@ var init_WizardNavigation = __esm({
32267
32267
  WizardNavigation.displayName = "WizardNavigation";
32268
32268
  }
32269
32269
  });
32270
+ function parseDay(value) {
32271
+ if (value === void 0 || value === null || value === "") return null;
32272
+ const d = value instanceof Date ? new Date(value.getTime()) : new Date(value);
32273
+ if (Number.isNaN(d.getTime())) return null;
32274
+ d.setHours(0, 0, 0, 0);
32275
+ return d;
32276
+ }
32277
+ function Gantt({
32278
+ tasks = [],
32279
+ links = [],
32280
+ titleField = "title",
32281
+ startField = "start",
32282
+ endField = "end",
32283
+ durationField,
32284
+ statusField = "status",
32285
+ groupField = "",
32286
+ rangeStart,
32287
+ rangeEnd,
32288
+ showToday = true,
32289
+ dayWidth = 28,
32290
+ barClickEvent,
32291
+ className,
32292
+ isLoading = false,
32293
+ error = null
32294
+ }) {
32295
+ const { t } = hooks.useTranslate();
32296
+ const placed = React89.useMemo(() => {
32297
+ const rows = Array.isArray(tasks) ? tasks : tasks ? [tasks] : [];
32298
+ const out = [];
32299
+ rows.forEach((row, idx) => {
32300
+ const start = parseDay(core.getNestedValue(row, startField));
32301
+ if (!start) return;
32302
+ let end = parseDay(core.getNestedValue(row, endField));
32303
+ if (!end && durationField) {
32304
+ const days2 = Number(core.getNestedValue(row, durationField));
32305
+ if (Number.isFinite(days2) && days2 > 0) {
32306
+ end = new Date(start.getTime() + days2 * DAY_MS);
32307
+ }
32308
+ }
32309
+ if (!end || end.getTime() < start.getTime()) end = new Date(start.getTime() + DAY_MS);
32310
+ out.push({
32311
+ row,
32312
+ id: String(row.id ?? idx),
32313
+ label: String(core.getNestedValue(row, titleField) ?? ""),
32314
+ status: String(core.getNestedValue(row, statusField) ?? "").toLowerCase(),
32315
+ group: groupField ? String(core.getNestedValue(row, groupField) ?? "") : "",
32316
+ start,
32317
+ end
32318
+ });
32319
+ });
32320
+ return out;
32321
+ }, [tasks, titleField, startField, endField, durationField, statusField, groupField]);
32322
+ const [axisStart, axisEnd] = React89.useMemo(() => {
32323
+ const lo = parseDay(rangeStart) ?? (placed.length ? new Date(Math.min(...placed.map((p) => p.start.getTime())) - 2 * DAY_MS) : new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)));
32324
+ const hi = parseDay(rangeEnd) ?? (placed.length ? new Date(Math.max(...placed.map((p) => p.end.getTime())) + 2 * DAY_MS) : new Date(lo.getTime() + 30 * DAY_MS));
32325
+ return hi.getTime() > lo.getTime() ? [lo, hi] : [lo, new Date(lo.getTime() + DAY_MS)];
32326
+ }, [rangeStart, rangeEnd, placed]);
32327
+ const totalDays = Math.round((axisEnd.getTime() - axisStart.getTime()) / DAY_MS);
32328
+ const chartWidth = totalDays * dayWidth;
32329
+ const dayOffset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
32330
+ const displayItems = React89.useMemo(() => {
32331
+ if (!groupField) return placed.map((task) => ({ kind: "task", task }));
32332
+ const items = [];
32333
+ const seen = /* @__PURE__ */ new Set();
32334
+ for (const task of placed) {
32335
+ if (!seen.has(task.group)) {
32336
+ seen.add(task.group);
32337
+ items.push({ kind: "group", label: task.group || "\u2014" });
32338
+ }
32339
+ items.push({ kind: "task", task });
32340
+ }
32341
+ return items;
32342
+ }, [placed, groupField]);
32343
+ const barGeometry = React89.useMemo(() => {
32344
+ const offset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
32345
+ const map = /* @__PURE__ */ new Map();
32346
+ displayItems.forEach((item, idx) => {
32347
+ if (item.kind !== "task") return;
32348
+ const x0 = offset(item.task.start);
32349
+ const x1 = Math.max(offset(item.task.end), x0 + dayWidth / 2);
32350
+ map.set(item.task.id, { x0, x1, y: HEADER_HEIGHT + idx * ROW_HEIGHT + ROW_HEIGHT / 2 });
32351
+ });
32352
+ return map;
32353
+ }, [displayItems, axisStart, dayWidth]);
32354
+ const days = React89.useMemo(() => {
32355
+ const out = [];
32356
+ for (let i = 0; i < totalDays; i++) out.push(new Date(axisStart.getTime() + i * DAY_MS));
32357
+ return out;
32358
+ }, [axisStart, totalDays]);
32359
+ const todayOffset = React89.useMemo(() => {
32360
+ const today = parseDay(/* @__PURE__ */ new Date());
32361
+ if (!today || today < axisStart || today > axisEnd) return null;
32362
+ return (today.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
32363
+ }, [axisStart, axisEnd, dayWidth]);
32364
+ if (isLoading) {
32365
+ return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
32366
+ }
32367
+ if (error) {
32368
+ return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-4", className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "error", children: error.message }) });
32369
+ }
32370
+ if (placed.length === 0) {
32371
+ return /* @__PURE__ */ jsxRuntime.jsx(
32372
+ EmptyState,
32373
+ {
32374
+ title: t("empty.noData"),
32375
+ className
32376
+ }
32377
+ );
32378
+ }
32379
+ return /* @__PURE__ */ jsxRuntime.jsx(
32380
+ Box,
32381
+ {
32382
+ className: cn("w-full overflow-auto rounded-md border border-border bg-card", className),
32383
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", style: { width: LABEL_WIDTH + chartWidth, minWidth: "100%" }, children: [
32384
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "none", className: "sticky top-0 z-20 bg-card border-b border-border", style: { height: HEADER_HEIGHT }, children: [
32385
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card border-r border-border", style: { width: LABEL_WIDTH, height: HEADER_HEIGHT } }),
32386
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "relative", style: { width: chartWidth, height: HEADER_HEIGHT }, children: days.map((day, i) => /* @__PURE__ */ jsxRuntime.jsx(
32387
+ Box,
32388
+ {
32389
+ className: cn(
32390
+ "absolute top-0 bottom-0 border-l border-border/50 flex items-end justify-center pb-1",
32391
+ day.getDay() === 0 || day.getDay() === 6 ? "bg-muted/40" : void 0
32392
+ ),
32393
+ style: { left: i * dayWidth, width: dayWidth },
32394
+ children: dayWidth >= 20 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: day.getDate() })
32395
+ },
32396
+ i
32397
+ )) })
32398
+ ] }),
32399
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "relative", children: [
32400
+ displayItems.map(
32401
+ (item, idx) => item.kind === "group" ? /* @__PURE__ */ jsxRuntime.jsxs(
32402
+ HStack,
32403
+ {
32404
+ gap: "none",
32405
+ className: "border-b border-border bg-muted/30",
32406
+ style: { height: ROW_HEIGHT },
32407
+ children: [
32408
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-muted/30 px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", weight: "semibold", children: item.label }) }),
32409
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { width: chartWidth, height: ROW_HEIGHT } })
32410
+ ]
32411
+ },
32412
+ `g-${idx}`
32413
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
32414
+ HStack,
32415
+ {
32416
+ gap: "none",
32417
+ className: "border-b border-border/50",
32418
+ style: { height: ROW_HEIGHT },
32419
+ children: [
32420
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "truncate", children: item.task.label }) }),
32421
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "relative", style: { width: chartWidth, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(
32422
+ Box,
32423
+ {
32424
+ className: cn(
32425
+ "absolute top-1/2 -translate-y-1/2 h-4 rounded-sm transition-colors",
32426
+ STATUS_BAR[item.task.status] ?? "bg-primary/80 hover:bg-primary",
32427
+ barClickEvent ? "cursor-pointer" : void 0
32428
+ ),
32429
+ style: {
32430
+ left: dayOffset(item.task.start),
32431
+ width: Math.max(dayOffset(item.task.end) - dayOffset(item.task.start), dayWidth / 2)
32432
+ },
32433
+ action: barClickEvent,
32434
+ actionPayload: { id: item.task.id }
32435
+ }
32436
+ ) })
32437
+ ]
32438
+ },
32439
+ item.task.id
32440
+ )
32441
+ ),
32442
+ links.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
32443
+ "svg",
32444
+ {
32445
+ className: "absolute pointer-events-none",
32446
+ style: { left: LABEL_WIDTH, top: 0 },
32447
+ width: chartWidth,
32448
+ height: HEADER_HEIGHT + displayItems.length * ROW_HEIGHT,
32449
+ children: [
32450
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx("marker", { id: "gantt-arrow", markerWidth: "8", markerHeight: "8", refX: "7", refY: "4", orient: "auto", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0,0 L8,4 L0,8 z", fill: "var(--muted-foreground, currentColor)" }) }) }),
32451
+ links.map((link, i) => {
32452
+ const from = barGeometry.get(link.from);
32453
+ const to = barGeometry.get(link.to);
32454
+ if (!from || !to) return null;
32455
+ const midX = from.x1 + Math.max(8, (to.x0 - from.x1) / 2);
32456
+ return /* @__PURE__ */ jsxRuntime.jsx(
32457
+ "path",
32458
+ {
32459
+ d: `M ${from.x1} ${from.y} L ${midX} ${from.y} L ${midX} ${to.y} L ${to.x0} ${to.y}`,
32460
+ fill: "none",
32461
+ stroke: "var(--muted-foreground, currentColor)",
32462
+ strokeWidth: 1.5,
32463
+ markerEnd: "url(#gantt-arrow)"
32464
+ },
32465
+ i
32466
+ );
32467
+ })
32468
+ ]
32469
+ }
32470
+ ),
32471
+ showToday && todayOffset !== null && /* @__PURE__ */ jsxRuntime.jsx(
32472
+ Box,
32473
+ {
32474
+ className: "absolute top-0 bottom-0 w-0.5 bg-error/70 pointer-events-none",
32475
+ style: { left: LABEL_WIDTH + todayOffset }
32476
+ }
32477
+ )
32478
+ ] })
32479
+ ] })
32480
+ }
32481
+ );
32482
+ }
32483
+ var DAY_MS, ROW_HEIGHT, HEADER_HEIGHT, LABEL_WIDTH, STATUS_BAR;
32484
+ var init_Gantt = __esm({
32485
+ "components/core/molecules/Gantt.tsx"() {
32486
+ "use client";
32487
+ init_cn();
32488
+ init_getNestedValue();
32489
+ init_Box();
32490
+ init_Stack();
32491
+ init_Typography();
32492
+ init_LoadingState();
32493
+ init_EmptyState();
32494
+ DAY_MS = 24 * 60 * 60 * 1e3;
32495
+ ROW_HEIGHT = 36;
32496
+ HEADER_HEIGHT = 44;
32497
+ LABEL_WIDTH = 192;
32498
+ STATUS_BAR = {
32499
+ complete: "bg-success/80 hover:bg-success",
32500
+ done: "bg-success/80 hover:bg-success",
32501
+ active: "bg-primary/80 hover:bg-primary",
32502
+ "in-progress": "bg-primary/80 hover:bg-primary",
32503
+ blocked: "bg-error/80 hover:bg-error",
32504
+ error: "bg-error/80 hover:bg-error",
32505
+ "at-risk": "bg-warning/80 hover:bg-warning",
32506
+ pending: "bg-muted-foreground/50 hover:bg-muted-foreground/70"
32507
+ };
32508
+ Gantt.displayName = "Gantt";
32509
+ }
32510
+ });
32270
32511
  var RepeatableFormSection;
32271
32512
  var init_RepeatableFormSection = __esm({
32272
32513
  "components/core/molecules/RepeatableFormSection.tsx"() {
@@ -51814,6 +52055,7 @@ var init_component_registry_generated = __esm({
51814
52055
  init_GameIcon();
51815
52056
  init_GameMenu();
51816
52057
  init_GameShell();
52058
+ init_Gantt();
51817
52059
  init_GenericAppTemplate();
51818
52060
  init_GeometricPattern();
51819
52061
  init_GradientDivider();
@@ -52093,6 +52335,7 @@ var init_component_registry_generated = __esm({
52093
52335
  "GameIcon": GameIcon,
52094
52336
  "GameMenu": GameMenu,
52095
52337
  "GameShell": GameShell,
52338
+ "Gantt": Gantt,
52096
52339
  "GenericAppTemplate": GenericAppTemplate,
52097
52340
  "GeometricPattern": GeometricPattern,
52098
52341
  "GradientDivider": GradientDivider,
@@ -54647,7 +54890,7 @@ function createHttpTransport(serverUrl, getAccessToken) {
54647
54890
  } catch {
54648
54891
  }
54649
54892
  },
54650
- sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait, results, entityByTrait, behaviorHint) => {
54893
+ sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait, results, entityByTrait, behaviorHint, user) => {
54651
54894
  const traits2 = results?.map((r) => ({ trait: r.traitName, from: r.result.previousState }));
54652
54895
  const body = {
54653
54896
  event,
@@ -54668,7 +54911,8 @@ function createHttpTransport(serverUrl, getAccessToken) {
54668
54911
  // "do nothing" and break every organism's INIT on the stateless path.
54669
54912
  ...results !== void 0 ? { traits: traits2 ?? [] } : {},
54670
54913
  ...entityByTrait ? { entityByTrait } : {},
54671
- ...behaviorHint !== void 0 ? { behavior: behaviorHint } : {}
54914
+ ...behaviorHint !== void 0 ? { behavior: behaviorHint } : {},
54915
+ ...user ? { user } : {}
54672
54916
  };
54673
54917
  const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
54674
54918
  method: "POST",
@@ -54730,7 +54974,7 @@ function ServerBridgeProvider({
54730
54974
  disposedRef.current = true;
54731
54975
  };
54732
54976
  }, []);
54733
- const sendEvent = React89.useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
54977
+ const sendEvent = React89.useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted, results, entityByTrait, user) => {
54734
54978
  const emptyMeta = { success: false, transitioned: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54735
54979
  if (!connected) return { effects: [], meta: emptyMeta };
54736
54980
  if (tick !== void 0) {
@@ -54740,7 +54984,7 @@ function ServerBridgeProvider({
54740
54984
  return commandPump.enqueue(async () => {
54741
54985
  if (disposedRef.current) return { effects: [], meta: emptyMeta };
54742
54986
  try {
54743
- const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait, results, entityByTrait, schema.name);
54987
+ const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait, results, entityByTrait, schema.name, user);
54744
54988
  const effects = [];
54745
54989
  const responseData = result.data || {};
54746
54990
  const dataEntities = {};
@@ -6,7 +6,7 @@ export { a as CurrentPagePathContext, b as CurrentPagePathProvider, c as Current
6
6
  import { b as UserData } from '../UserContext-D566nfWA.cjs';
7
7
  export { U as UserContext, a as UserContextValue, c as UserProvider, d as UserProviderProps, u as useHasPermission, e as useHasRole, f as useUser, g as useUserForEvaluation } from '../UserContext-D566nfWA.cjs';
8
8
  import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.cjs';
9
- export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-CTZw2DbY.cjs';
9
+ export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-C6FgxdfG.cjs';
10
10
  import { i as UseOfflineExecutorResult, U as UseOfflineExecutorOptions } from '../offline-executor-DdV2o0Zu.cjs';
11
11
  export { N as NavigationContextValue, c as NavigationProvider, d as NavigationProviderProps, e as NavigationState, j as comparePathSpecificity, l as extractRouteParams, m as findPageByName, n as findPageByPath, o as getAllPages, p as getDefaultPage, q as matchPath, r as matchPathAmong, s as pathMatches, u as useActivePage, t as useInitPayload, v as useNavigateTo, w as useNavigation, x as useNavigationId, y as useNavigationState } from '../offline-executor-DdV2o0Zu.cjs';
12
12
  import '../verificationRegistry-DTrKDRoa.cjs';
@@ -6,7 +6,7 @@ export { a as CurrentPagePathContext, b as CurrentPagePathProvider, c as Current
6
6
  import { b as UserData } from '../UserContext-D566nfWA.js';
7
7
  export { U as UserContext, a as UserContextValue, c as UserProvider, d as UserProviderProps, u as useHasPermission, e as useHasRole, f as useUser, g as useUserForEvaluation } from '../UserContext-D566nfWA.js';
8
8
  import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.js';
9
- export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-CTZw2DbY.js';
9
+ export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-C6FgxdfG.js';
10
10
  import { i as UseOfflineExecutorResult, U as UseOfflineExecutorOptions } from '../offline-executor-DdV2o0Zu.js';
11
11
  export { N as NavigationContextValue, c as NavigationProvider, d as NavigationProviderProps, e as NavigationState, j as comparePathSpecificity, l as extractRouteParams, m as findPageByName, n as findPageByPath, o as getAllPages, p as getDefaultPage, q as matchPath, r as matchPathAmong, s as pathMatches, u as useActivePage, t as useInitPayload, v as useNavigateTo, w as useNavigation, x as useNavigationId, y as useNavigationState } from '../offline-executor-DdV2o0Zu.js';
12
12
  import '../verificationRegistry-Cwa52VyK.js';
@@ -32193,6 +32193,247 @@ var init_WizardNavigation = __esm({
32193
32193
  WizardNavigation.displayName = "WizardNavigation";
32194
32194
  }
32195
32195
  });
32196
+ function parseDay(value) {
32197
+ if (value === void 0 || value === null || value === "") return null;
32198
+ const d = value instanceof Date ? new Date(value.getTime()) : new Date(value);
32199
+ if (Number.isNaN(d.getTime())) return null;
32200
+ d.setHours(0, 0, 0, 0);
32201
+ return d;
32202
+ }
32203
+ function Gantt({
32204
+ tasks = [],
32205
+ links = [],
32206
+ titleField = "title",
32207
+ startField = "start",
32208
+ endField = "end",
32209
+ durationField,
32210
+ statusField = "status",
32211
+ groupField = "",
32212
+ rangeStart,
32213
+ rangeEnd,
32214
+ showToday = true,
32215
+ dayWidth = 28,
32216
+ barClickEvent,
32217
+ className,
32218
+ isLoading = false,
32219
+ error = null
32220
+ }) {
32221
+ const { t } = useTranslate();
32222
+ const placed = useMemo(() => {
32223
+ const rows = Array.isArray(tasks) ? tasks : tasks ? [tasks] : [];
32224
+ const out = [];
32225
+ rows.forEach((row, idx) => {
32226
+ const start = parseDay(getNestedValue(row, startField));
32227
+ if (!start) return;
32228
+ let end = parseDay(getNestedValue(row, endField));
32229
+ if (!end && durationField) {
32230
+ const days2 = Number(getNestedValue(row, durationField));
32231
+ if (Number.isFinite(days2) && days2 > 0) {
32232
+ end = new Date(start.getTime() + days2 * DAY_MS);
32233
+ }
32234
+ }
32235
+ if (!end || end.getTime() < start.getTime()) end = new Date(start.getTime() + DAY_MS);
32236
+ out.push({
32237
+ row,
32238
+ id: String(row.id ?? idx),
32239
+ label: String(getNestedValue(row, titleField) ?? ""),
32240
+ status: String(getNestedValue(row, statusField) ?? "").toLowerCase(),
32241
+ group: groupField ? String(getNestedValue(row, groupField) ?? "") : "",
32242
+ start,
32243
+ end
32244
+ });
32245
+ });
32246
+ return out;
32247
+ }, [tasks, titleField, startField, endField, durationField, statusField, groupField]);
32248
+ const [axisStart, axisEnd] = useMemo(() => {
32249
+ const lo = parseDay(rangeStart) ?? (placed.length ? new Date(Math.min(...placed.map((p) => p.start.getTime())) - 2 * DAY_MS) : new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)));
32250
+ const hi = parseDay(rangeEnd) ?? (placed.length ? new Date(Math.max(...placed.map((p) => p.end.getTime())) + 2 * DAY_MS) : new Date(lo.getTime() + 30 * DAY_MS));
32251
+ return hi.getTime() > lo.getTime() ? [lo, hi] : [lo, new Date(lo.getTime() + DAY_MS)];
32252
+ }, [rangeStart, rangeEnd, placed]);
32253
+ const totalDays = Math.round((axisEnd.getTime() - axisStart.getTime()) / DAY_MS);
32254
+ const chartWidth = totalDays * dayWidth;
32255
+ const dayOffset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
32256
+ const displayItems = useMemo(() => {
32257
+ if (!groupField) return placed.map((task) => ({ kind: "task", task }));
32258
+ const items = [];
32259
+ const seen = /* @__PURE__ */ new Set();
32260
+ for (const task of placed) {
32261
+ if (!seen.has(task.group)) {
32262
+ seen.add(task.group);
32263
+ items.push({ kind: "group", label: task.group || "\u2014" });
32264
+ }
32265
+ items.push({ kind: "task", task });
32266
+ }
32267
+ return items;
32268
+ }, [placed, groupField]);
32269
+ const barGeometry = useMemo(() => {
32270
+ const offset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
32271
+ const map = /* @__PURE__ */ new Map();
32272
+ displayItems.forEach((item, idx) => {
32273
+ if (item.kind !== "task") return;
32274
+ const x0 = offset(item.task.start);
32275
+ const x1 = Math.max(offset(item.task.end), x0 + dayWidth / 2);
32276
+ map.set(item.task.id, { x0, x1, y: HEADER_HEIGHT + idx * ROW_HEIGHT + ROW_HEIGHT / 2 });
32277
+ });
32278
+ return map;
32279
+ }, [displayItems, axisStart, dayWidth]);
32280
+ const days = useMemo(() => {
32281
+ const out = [];
32282
+ for (let i = 0; i < totalDays; i++) out.push(new Date(axisStart.getTime() + i * DAY_MS));
32283
+ return out;
32284
+ }, [axisStart, totalDays]);
32285
+ const todayOffset = useMemo(() => {
32286
+ const today = parseDay(/* @__PURE__ */ new Date());
32287
+ if (!today || today < axisStart || today > axisEnd) return null;
32288
+ return (today.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
32289
+ }, [axisStart, axisEnd, dayWidth]);
32290
+ if (isLoading) {
32291
+ return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
32292
+ }
32293
+ if (error) {
32294
+ return /* @__PURE__ */ jsx(Box, { className: cn("p-4", className), children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
32295
+ }
32296
+ if (placed.length === 0) {
32297
+ return /* @__PURE__ */ jsx(
32298
+ EmptyState,
32299
+ {
32300
+ title: t("empty.noData"),
32301
+ className
32302
+ }
32303
+ );
32304
+ }
32305
+ return /* @__PURE__ */ jsx(
32306
+ Box,
32307
+ {
32308
+ className: cn("w-full overflow-auto rounded-md border border-border bg-card", className),
32309
+ children: /* @__PURE__ */ jsxs(Box, { className: "relative", style: { width: LABEL_WIDTH + chartWidth, minWidth: "100%" }, children: [
32310
+ /* @__PURE__ */ jsxs(HStack, { gap: "none", className: "sticky top-0 z-20 bg-card border-b border-border", style: { height: HEADER_HEIGHT }, children: [
32311
+ /* @__PURE__ */ jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card border-r border-border", style: { width: LABEL_WIDTH, height: HEADER_HEIGHT } }),
32312
+ /* @__PURE__ */ jsx(Box, { className: "relative", style: { width: chartWidth, height: HEADER_HEIGHT }, children: days.map((day, i) => /* @__PURE__ */ jsx(
32313
+ Box,
32314
+ {
32315
+ className: cn(
32316
+ "absolute top-0 bottom-0 border-l border-border/50 flex items-end justify-center pb-1",
32317
+ day.getDay() === 0 || day.getDay() === 6 ? "bg-muted/40" : void 0
32318
+ ),
32319
+ style: { left: i * dayWidth, width: dayWidth },
32320
+ children: dayWidth >= 20 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: day.getDate() })
32321
+ },
32322
+ i
32323
+ )) })
32324
+ ] }),
32325
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "relative", children: [
32326
+ displayItems.map(
32327
+ (item, idx) => item.kind === "group" ? /* @__PURE__ */ jsxs(
32328
+ HStack,
32329
+ {
32330
+ gap: "none",
32331
+ className: "border-b border-border bg-muted/30",
32332
+ style: { height: ROW_HEIGHT },
32333
+ children: [
32334
+ /* @__PURE__ */ jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-muted/30 px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsx(Typography, { variant: "caption", weight: "semibold", children: item.label }) }),
32335
+ /* @__PURE__ */ jsx(Box, { style: { width: chartWidth, height: ROW_HEIGHT } })
32336
+ ]
32337
+ },
32338
+ `g-${idx}`
32339
+ ) : /* @__PURE__ */ jsxs(
32340
+ HStack,
32341
+ {
32342
+ gap: "none",
32343
+ className: "border-b border-border/50",
32344
+ style: { height: ROW_HEIGHT },
32345
+ children: [
32346
+ /* @__PURE__ */ jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "truncate", children: item.task.label }) }),
32347
+ /* @__PURE__ */ jsx(Box, { className: "relative", style: { width: chartWidth, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsx(
32348
+ Box,
32349
+ {
32350
+ className: cn(
32351
+ "absolute top-1/2 -translate-y-1/2 h-4 rounded-sm transition-colors",
32352
+ STATUS_BAR[item.task.status] ?? "bg-primary/80 hover:bg-primary",
32353
+ barClickEvent ? "cursor-pointer" : void 0
32354
+ ),
32355
+ style: {
32356
+ left: dayOffset(item.task.start),
32357
+ width: Math.max(dayOffset(item.task.end) - dayOffset(item.task.start), dayWidth / 2)
32358
+ },
32359
+ action: barClickEvent,
32360
+ actionPayload: { id: item.task.id }
32361
+ }
32362
+ ) })
32363
+ ]
32364
+ },
32365
+ item.task.id
32366
+ )
32367
+ ),
32368
+ links.length > 0 && /* @__PURE__ */ jsxs(
32369
+ "svg",
32370
+ {
32371
+ className: "absolute pointer-events-none",
32372
+ style: { left: LABEL_WIDTH, top: 0 },
32373
+ width: chartWidth,
32374
+ height: HEADER_HEIGHT + displayItems.length * ROW_HEIGHT,
32375
+ children: [
32376
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("marker", { id: "gantt-arrow", markerWidth: "8", markerHeight: "8", refX: "7", refY: "4", orient: "auto", children: /* @__PURE__ */ jsx("path", { d: "M0,0 L8,4 L0,8 z", fill: "var(--muted-foreground, currentColor)" }) }) }),
32377
+ links.map((link, i) => {
32378
+ const from = barGeometry.get(link.from);
32379
+ const to = barGeometry.get(link.to);
32380
+ if (!from || !to) return null;
32381
+ const midX = from.x1 + Math.max(8, (to.x0 - from.x1) / 2);
32382
+ return /* @__PURE__ */ jsx(
32383
+ "path",
32384
+ {
32385
+ d: `M ${from.x1} ${from.y} L ${midX} ${from.y} L ${midX} ${to.y} L ${to.x0} ${to.y}`,
32386
+ fill: "none",
32387
+ stroke: "var(--muted-foreground, currentColor)",
32388
+ strokeWidth: 1.5,
32389
+ markerEnd: "url(#gantt-arrow)"
32390
+ },
32391
+ i
32392
+ );
32393
+ })
32394
+ ]
32395
+ }
32396
+ ),
32397
+ showToday && todayOffset !== null && /* @__PURE__ */ jsx(
32398
+ Box,
32399
+ {
32400
+ className: "absolute top-0 bottom-0 w-0.5 bg-error/70 pointer-events-none",
32401
+ style: { left: LABEL_WIDTH + todayOffset }
32402
+ }
32403
+ )
32404
+ ] })
32405
+ ] })
32406
+ }
32407
+ );
32408
+ }
32409
+ var DAY_MS, ROW_HEIGHT, HEADER_HEIGHT, LABEL_WIDTH, STATUS_BAR;
32410
+ var init_Gantt = __esm({
32411
+ "components/core/molecules/Gantt.tsx"() {
32412
+ "use client";
32413
+ init_cn();
32414
+ init_getNestedValue();
32415
+ init_Box();
32416
+ init_Stack();
32417
+ init_Typography();
32418
+ init_LoadingState();
32419
+ init_EmptyState();
32420
+ DAY_MS = 24 * 60 * 60 * 1e3;
32421
+ ROW_HEIGHT = 36;
32422
+ HEADER_HEIGHT = 44;
32423
+ LABEL_WIDTH = 192;
32424
+ STATUS_BAR = {
32425
+ complete: "bg-success/80 hover:bg-success",
32426
+ done: "bg-success/80 hover:bg-success",
32427
+ active: "bg-primary/80 hover:bg-primary",
32428
+ "in-progress": "bg-primary/80 hover:bg-primary",
32429
+ blocked: "bg-error/80 hover:bg-error",
32430
+ error: "bg-error/80 hover:bg-error",
32431
+ "at-risk": "bg-warning/80 hover:bg-warning",
32432
+ pending: "bg-muted-foreground/50 hover:bg-muted-foreground/70"
32433
+ };
32434
+ Gantt.displayName = "Gantt";
32435
+ }
32436
+ });
32196
32437
  var RepeatableFormSection;
32197
32438
  var init_RepeatableFormSection = __esm({
32198
32439
  "components/core/molecules/RepeatableFormSection.tsx"() {
@@ -51740,6 +51981,7 @@ var init_component_registry_generated = __esm({
51740
51981
  init_GameIcon();
51741
51982
  init_GameMenu();
51742
51983
  init_GameShell();
51984
+ init_Gantt();
51743
51985
  init_GenericAppTemplate();
51744
51986
  init_GeometricPattern();
51745
51987
  init_GradientDivider();
@@ -52019,6 +52261,7 @@ var init_component_registry_generated = __esm({
52019
52261
  "GameIcon": GameIcon,
52020
52262
  "GameMenu": GameMenu,
52021
52263
  "GameShell": GameShell,
52264
+ "Gantt": Gantt,
52022
52265
  "GenericAppTemplate": GenericAppTemplate,
52023
52266
  "GeometricPattern": GeometricPattern,
52024
52267
  "GradientDivider": GradientDivider,
@@ -54573,7 +54816,7 @@ function createHttpTransport(serverUrl, getAccessToken) {
54573
54816
  } catch {
54574
54817
  }
54575
54818
  },
54576
- sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait, results, entityByTrait, behaviorHint) => {
54819
+ sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait, results, entityByTrait, behaviorHint, user) => {
54577
54820
  const traits2 = results?.map((r) => ({ trait: r.traitName, from: r.result.previousState }));
54578
54821
  const body = {
54579
54822
  event,
@@ -54594,7 +54837,8 @@ function createHttpTransport(serverUrl, getAccessToken) {
54594
54837
  // "do nothing" and break every organism's INIT on the stateless path.
54595
54838
  ...results !== void 0 ? { traits: traits2 ?? [] } : {},
54596
54839
  ...entityByTrait ? { entityByTrait } : {},
54597
- ...behaviorHint !== void 0 ? { behavior: behaviorHint } : {}
54840
+ ...behaviorHint !== void 0 ? { behavior: behaviorHint } : {},
54841
+ ...user ? { user } : {}
54598
54842
  };
54599
54843
  const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
54600
54844
  method: "POST",
@@ -54656,7 +54900,7 @@ function ServerBridgeProvider({
54656
54900
  disposedRef.current = true;
54657
54901
  };
54658
54902
  }, []);
54659
- const sendEvent = useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
54903
+ const sendEvent = useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted, results, entityByTrait, user) => {
54660
54904
  const emptyMeta = { success: false, transitioned: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54661
54905
  if (!connected) return { effects: [], meta: emptyMeta };
54662
54906
  if (tick !== void 0) {
@@ -54666,7 +54910,7 @@ function ServerBridgeProvider({
54666
54910
  return commandPump.enqueue(async () => {
54667
54911
  if (disposedRef.current) return { effects: [], meta: emptyMeta };
54668
54912
  try {
54669
- const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait, results, entityByTrait, schema.name);
54913
+ const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait, results, entityByTrait, schema.name, user);
54670
54914
  const effects = [];
54671
54915
  const responseData = result.data || {};
54672
54916
  const dataEntities = {};