@optifye/dashboard-core 4.1.0 → 4.1.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/index.d.mts +31 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +780 -162
- package/dist/index.mjs +781 -163
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25337,6 +25337,32 @@ var S3ClipsService = class {
|
|
|
25337
25337
|
return null;
|
|
25338
25338
|
}
|
|
25339
25339
|
}
|
|
25340
|
+
/**
|
|
25341
|
+
* Fetches full metadata including timestamps
|
|
25342
|
+
*/
|
|
25343
|
+
async getFullMetadata(playlistUri) {
|
|
25344
|
+
try {
|
|
25345
|
+
const metadataUri = playlistUri.replace(/playlist\.m3u8$/, "metadata.json");
|
|
25346
|
+
const url = new URL(metadataUri);
|
|
25347
|
+
const bucket = url.hostname;
|
|
25348
|
+
const key = url.pathname.substring(1);
|
|
25349
|
+
const command = new clientS3.GetObjectCommand({
|
|
25350
|
+
Bucket: bucket,
|
|
25351
|
+
Key: key
|
|
25352
|
+
});
|
|
25353
|
+
const response = await this.s3Client.send(command);
|
|
25354
|
+
if (!response.Body) {
|
|
25355
|
+
console.warn(`Empty response body for metadata file: ${key}`);
|
|
25356
|
+
return null;
|
|
25357
|
+
}
|
|
25358
|
+
const metadataContent = await response.Body.transformToString();
|
|
25359
|
+
const metadata = JSON.parse(metadataContent);
|
|
25360
|
+
return metadata;
|
|
25361
|
+
} catch (error) {
|
|
25362
|
+
console.error(`Error fetching or parsing metadata:`, error);
|
|
25363
|
+
return null;
|
|
25364
|
+
}
|
|
25365
|
+
}
|
|
25340
25366
|
/**
|
|
25341
25367
|
* Converts S3 URI to CloudFront URL
|
|
25342
25368
|
* Uses streaming proxy for localhost development to handle CORS
|
|
@@ -25349,15 +25375,22 @@ var S3ClipsService = class {
|
|
|
25349
25375
|
/**
|
|
25350
25376
|
* Processes a single video completely
|
|
25351
25377
|
*/
|
|
25352
|
-
async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime) {
|
|
25378
|
+
async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime, includeMetadata = false) {
|
|
25353
25379
|
const parsedInfo = parseS3Uri(uri);
|
|
25354
25380
|
if (!parsedInfo) {
|
|
25355
25381
|
console.warn(`Skipping URI due to parsing failure: ${uri}`);
|
|
25356
25382
|
return null;
|
|
25357
25383
|
}
|
|
25358
25384
|
let cycleTimeSeconds = null;
|
|
25359
|
-
|
|
25360
|
-
|
|
25385
|
+
let creationTimestamp = void 0;
|
|
25386
|
+
if (includeMetadata || includeCycleTime && (parsedInfo.type === "bottleneck" && parsedInfo.description.toLowerCase().includes("cycle time") || parsedInfo.type === "best_cycle_time" || parsedInfo.type === "worst_cycle_time")) {
|
|
25387
|
+
const metadata = await this.getFullMetadata(uri);
|
|
25388
|
+
if (metadata) {
|
|
25389
|
+
if (metadata.original_task_metadata?.cycle_time) {
|
|
25390
|
+
cycleTimeSeconds = metadata.original_task_metadata.cycle_time;
|
|
25391
|
+
}
|
|
25392
|
+
creationTimestamp = metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp || metadata[""];
|
|
25393
|
+
}
|
|
25361
25394
|
}
|
|
25362
25395
|
const cloudfrontPlaylistUrl = this.s3UriToCloudfront(uri);
|
|
25363
25396
|
const { type: videoType, timestamp: videoTimestamp } = parsedInfo;
|
|
@@ -25366,7 +25399,8 @@ var S3ClipsService = class {
|
|
|
25366
25399
|
src: cloudfrontPlaylistUrl,
|
|
25367
25400
|
// Direct CloudFront playlist URL
|
|
25368
25401
|
...parsedInfo,
|
|
25369
|
-
cycle_time_seconds: cycleTimeSeconds || void 0
|
|
25402
|
+
cycle_time_seconds: cycleTimeSeconds || void 0,
|
|
25403
|
+
creation_timestamp: creationTimestamp
|
|
25370
25404
|
};
|
|
25371
25405
|
}
|
|
25372
25406
|
/**
|
|
@@ -25428,7 +25462,7 @@ var S3ClipsService = class {
|
|
|
25428
25462
|
* Main method to fetch clips based on parameters
|
|
25429
25463
|
*/
|
|
25430
25464
|
async fetchClips(params) {
|
|
25431
|
-
const { workspaceId, date: inputDate, shift, category, limit, mode, includeCycleTime } = params;
|
|
25465
|
+
const { workspaceId, date: inputDate, shift, category, limit, mode, includeCycleTime, includeMetadata, timestampStart, timestampEnd } = params;
|
|
25432
25466
|
if (!workspaceId) {
|
|
25433
25467
|
throw new Error("Valid Workspace ID is required");
|
|
25434
25468
|
}
|
|
@@ -25533,7 +25567,7 @@ var S3ClipsService = class {
|
|
|
25533
25567
|
const batch = filteredUris.slice(i, i + concurrencyLimit);
|
|
25534
25568
|
const batchPromises = batch.map(async (uri, batchIndex) => {
|
|
25535
25569
|
const index = i + batchIndex;
|
|
25536
|
-
const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false);
|
|
25570
|
+
const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false, includeMetadata || (!!timestampStart || !!timestampEnd));
|
|
25537
25571
|
processedCount++;
|
|
25538
25572
|
if (processedCount % 10 === 0) {
|
|
25539
25573
|
console.log(`S3ClipsService: Processed ${processedCount}/${filteredUris.length} videos for category '${category || "all"}'...`);
|
|
@@ -25543,7 +25577,26 @@ var S3ClipsService = class {
|
|
|
25543
25577
|
const batchResults = await Promise.all(batchPromises);
|
|
25544
25578
|
videoResults.push(...batchResults);
|
|
25545
25579
|
}
|
|
25546
|
-
|
|
25580
|
+
let videos = videoResults.filter((v) => v !== null);
|
|
25581
|
+
if (timestampStart || timestampEnd) {
|
|
25582
|
+
videos = videos.filter((video) => {
|
|
25583
|
+
if (!video.creation_timestamp) return false;
|
|
25584
|
+
const videoTimestamp = new Date(video.creation_timestamp).getTime();
|
|
25585
|
+
if (timestampStart && timestampEnd) {
|
|
25586
|
+
const start = new Date(timestampStart).getTime();
|
|
25587
|
+
const end = new Date(timestampEnd).getTime();
|
|
25588
|
+
return videoTimestamp >= start && videoTimestamp <= end;
|
|
25589
|
+
} else if (timestampStart) {
|
|
25590
|
+
const start = new Date(timestampStart).getTime();
|
|
25591
|
+
return videoTimestamp >= start;
|
|
25592
|
+
} else if (timestampEnd) {
|
|
25593
|
+
const end = new Date(timestampEnd).getTime();
|
|
25594
|
+
return videoTimestamp <= end;
|
|
25595
|
+
}
|
|
25596
|
+
return true;
|
|
25597
|
+
});
|
|
25598
|
+
console.log(`S3ClipsService: Filtered by timestamp - ${videos.length} videos remain after filtering`);
|
|
25599
|
+
}
|
|
25547
25600
|
console.log(`S3ClipsService: Successfully processed ${videos.length} out of ${filteredUris.length} video clips for category '${category || "all"}' (limit: ${limitPerCategory} per category).`);
|
|
25548
25601
|
const typeCounts = videos.reduce((acc, video) => {
|
|
25549
25602
|
acc[video.type] = (acc[video.type] || 0) + 1;
|
|
@@ -25588,6 +25641,7 @@ var BottlenecksContent = ({
|
|
|
25588
25641
|
const dashboardConfig = useDashboardConfig();
|
|
25589
25642
|
const videoRef = React46.useRef(null);
|
|
25590
25643
|
const fullscreenContainerRef = React46.useRef(null);
|
|
25644
|
+
const timestampFilterRef = React46.useRef(null);
|
|
25591
25645
|
const [isPlaying, setIsPlaying] = React46.useState(false);
|
|
25592
25646
|
const [currentTime, setCurrentTime] = React46.useState(0);
|
|
25593
25647
|
const [duration, setDuration] = React46.useState(0);
|
|
@@ -25597,6 +25651,22 @@ var BottlenecksContent = ({
|
|
|
25597
25651
|
const [allVideos, setAllVideos] = React46.useState([]);
|
|
25598
25652
|
const [isLoading, setIsLoading] = React46.useState(true);
|
|
25599
25653
|
const [error, setError] = React46.useState(null);
|
|
25654
|
+
const [showTimestampFilter, setShowTimestampFilter] = React46.useState(false);
|
|
25655
|
+
const [timestampStart, setTimestampStart] = React46.useState("");
|
|
25656
|
+
const [timestampEnd, setTimestampEnd] = React46.useState("");
|
|
25657
|
+
React46.useEffect(() => {
|
|
25658
|
+
const handleClickOutside = (event) => {
|
|
25659
|
+
if (timestampFilterRef.current && !timestampFilterRef.current.contains(event.target)) {
|
|
25660
|
+
setShowTimestampFilter(false);
|
|
25661
|
+
}
|
|
25662
|
+
};
|
|
25663
|
+
if (showTimestampFilter) {
|
|
25664
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
25665
|
+
}
|
|
25666
|
+
return () => {
|
|
25667
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
25668
|
+
};
|
|
25669
|
+
}, [showTimestampFilter]);
|
|
25600
25670
|
const s3ClipsService = React46.useMemo(() => {
|
|
25601
25671
|
if (!dashboardConfig?.s3Config) {
|
|
25602
25672
|
console.warn("S3 configuration not found in dashboard config");
|
|
@@ -25609,13 +25679,26 @@ var BottlenecksContent = ({
|
|
|
25609
25679
|
setIsLoading(true);
|
|
25610
25680
|
setError(null);
|
|
25611
25681
|
try {
|
|
25682
|
+
const operationalDate = date || getOperationalDate();
|
|
25683
|
+
let timestampStartFull;
|
|
25684
|
+
let timestampEndFull;
|
|
25685
|
+
if (timestampStart) {
|
|
25686
|
+
timestampStartFull = `${operationalDate}T${timestampStart}:00`;
|
|
25687
|
+
}
|
|
25688
|
+
if (timestampEnd) {
|
|
25689
|
+
timestampEndFull = `${operationalDate}T${timestampEnd}:00`;
|
|
25690
|
+
}
|
|
25612
25691
|
const videos = await s3ClipsService.fetchClips({
|
|
25613
25692
|
workspaceId,
|
|
25614
|
-
date:
|
|
25693
|
+
date: operationalDate,
|
|
25615
25694
|
mode: "full",
|
|
25616
25695
|
includeCycleTime: true,
|
|
25617
|
-
|
|
25696
|
+
includeMetadata: true,
|
|
25697
|
+
// Always include metadata for timestamp info
|
|
25698
|
+
limit: 50,
|
|
25618
25699
|
// Reasonable limit for UI performance
|
|
25700
|
+
timestampStart: timestampStartFull,
|
|
25701
|
+
timestampEnd: timestampEndFull
|
|
25619
25702
|
});
|
|
25620
25703
|
if (Array.isArray(videos) && videos.length > 0) {
|
|
25621
25704
|
preloadVideoUrl2(videos[0].src);
|
|
@@ -25643,7 +25726,7 @@ var BottlenecksContent = ({
|
|
|
25643
25726
|
} finally {
|
|
25644
25727
|
setIsLoading(false);
|
|
25645
25728
|
}
|
|
25646
|
-
}, [workspaceId, date, s3ClipsService]);
|
|
25729
|
+
}, [workspaceId, date, s3ClipsService, timestampStart, timestampEnd]);
|
|
25647
25730
|
React46.useEffect(() => {
|
|
25648
25731
|
if (s3ClipsService) {
|
|
25649
25732
|
fetchClips();
|
|
@@ -26012,6 +26095,43 @@ var BottlenecksContent = ({
|
|
|
26012
26095
|
return "Bottleneck";
|
|
26013
26096
|
}
|
|
26014
26097
|
};
|
|
26098
|
+
const formatTimestamp = (timestamp) => {
|
|
26099
|
+
if (!timestamp) return "";
|
|
26100
|
+
try {
|
|
26101
|
+
const date2 = new Date(timestamp);
|
|
26102
|
+
const today = /* @__PURE__ */ new Date();
|
|
26103
|
+
const isToday = date2.toDateString() === today.toDateString();
|
|
26104
|
+
if (isToday) {
|
|
26105
|
+
return date2.toLocaleString("en-US", {
|
|
26106
|
+
hour: "numeric",
|
|
26107
|
+
minute: "2-digit",
|
|
26108
|
+
hour12: true
|
|
26109
|
+
});
|
|
26110
|
+
} else {
|
|
26111
|
+
return date2.toLocaleString("en-US", {
|
|
26112
|
+
month: "short",
|
|
26113
|
+
day: "numeric",
|
|
26114
|
+
hour: "numeric",
|
|
26115
|
+
minute: "2-digit",
|
|
26116
|
+
hour12: true
|
|
26117
|
+
});
|
|
26118
|
+
}
|
|
26119
|
+
} catch {
|
|
26120
|
+
return "";
|
|
26121
|
+
}
|
|
26122
|
+
};
|
|
26123
|
+
const formatTimeOnly = (time2) => {
|
|
26124
|
+
if (!time2) return "";
|
|
26125
|
+
try {
|
|
26126
|
+
const [hours, minutes] = time2.split(":");
|
|
26127
|
+
const hour = parseInt(hours);
|
|
26128
|
+
const ampm = hour >= 12 ? "PM" : "AM";
|
|
26129
|
+
const displayHour = hour % 12 || 12;
|
|
26130
|
+
return `${displayHour}:${minutes} ${ampm}`;
|
|
26131
|
+
} catch {
|
|
26132
|
+
return time2;
|
|
26133
|
+
}
|
|
26134
|
+
};
|
|
26015
26135
|
if (!dashboardConfig?.s3Config) {
|
|
26016
26136
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-4 flex flex-col items-center justify-center h-[calc(100vh-12rem)] text-center", children: [
|
|
26017
26137
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "w-12 h-12 text-red-400 mb-3" }),
|
|
@@ -26120,6 +26240,74 @@ var BottlenecksContent = ({
|
|
|
26120
26240
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
|
|
26121
26241
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-800", children: activeFilter === "low_value" ? `Low Value Moments (${clipCounts.lowValue})` : activeFilter === "best_cycle_time" ? `Best Cycle Times (${clipCounts.bestCycleTimes})` : activeFilter === "worst_cycle_time" ? `Worst Cycle Times (${clipCounts.worstCycleTimes})` : activeFilter === "long_cycle_time" ? `Long Cycle Time (${clipCounts.longCycleTimes})` : `All Clips (${clipCounts.total})` }),
|
|
26122
26242
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
26243
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: timestampFilterRef, children: [
|
|
26244
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26245
|
+
"button",
|
|
26246
|
+
{
|
|
26247
|
+
onClick: () => setShowTimestampFilter(!showTimestampFilter),
|
|
26248
|
+
className: `p-2 rounded-lg transition-all ${timestampStart || timestampEnd ? "bg-blue-50 text-blue-600 hover:bg-blue-100" : "text-gray-600 hover:bg-gray-100"}`,
|
|
26249
|
+
"aria-label": "Filter by time",
|
|
26250
|
+
title: "Filter by time",
|
|
26251
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-5 w-5" })
|
|
26252
|
+
}
|
|
26253
|
+
),
|
|
26254
|
+
showTimestampFilter && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 mt-2 w-80 bg-white rounded-lg shadow-lg border border-gray-200 p-4 z-20", children: [
|
|
26255
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-gray-700 mb-3", children: "Filter by Time" }),
|
|
26256
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
26257
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
26258
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "timestamp-start", className: "block text-xs font-medium text-gray-600 mb-1", children: "Start Time" }),
|
|
26259
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26260
|
+
"input",
|
|
26261
|
+
{
|
|
26262
|
+
id: "timestamp-start",
|
|
26263
|
+
type: "time",
|
|
26264
|
+
value: timestampStart,
|
|
26265
|
+
onChange: (e) => setTimestampStart(e.target.value),
|
|
26266
|
+
className: "w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
26267
|
+
}
|
|
26268
|
+
)
|
|
26269
|
+
] }),
|
|
26270
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
26271
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "timestamp-end", className: "block text-xs font-medium text-gray-600 mb-1", children: "End Time" }),
|
|
26272
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26273
|
+
"input",
|
|
26274
|
+
{
|
|
26275
|
+
id: "timestamp-end",
|
|
26276
|
+
type: "time",
|
|
26277
|
+
value: timestampEnd,
|
|
26278
|
+
onChange: (e) => setTimestampEnd(e.target.value),
|
|
26279
|
+
className: "w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
26280
|
+
}
|
|
26281
|
+
)
|
|
26282
|
+
] }),
|
|
26283
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between pt-2", children: [
|
|
26284
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26285
|
+
"button",
|
|
26286
|
+
{
|
|
26287
|
+
onClick: () => {
|
|
26288
|
+
setTimestampStart("");
|
|
26289
|
+
setTimestampEnd("");
|
|
26290
|
+
setShowTimestampFilter(false);
|
|
26291
|
+
},
|
|
26292
|
+
className: "px-3 py-1.5 text-sm text-gray-600 hover:text-gray-800 transition-colors",
|
|
26293
|
+
children: "Clear"
|
|
26294
|
+
}
|
|
26295
|
+
),
|
|
26296
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26297
|
+
"button",
|
|
26298
|
+
{
|
|
26299
|
+
onClick: () => {
|
|
26300
|
+
setShowTimestampFilter(false);
|
|
26301
|
+
fetchClips();
|
|
26302
|
+
},
|
|
26303
|
+
className: "px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
|
|
26304
|
+
children: "Apply Filter"
|
|
26305
|
+
}
|
|
26306
|
+
)
|
|
26307
|
+
] })
|
|
26308
|
+
] })
|
|
26309
|
+
] })
|
|
26310
|
+
] }),
|
|
26123
26311
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26124
26312
|
"button",
|
|
26125
26313
|
{
|
|
@@ -26143,6 +26331,29 @@ var BottlenecksContent = ({
|
|
|
26143
26331
|
)
|
|
26144
26332
|
] })
|
|
26145
26333
|
] }) }),
|
|
26334
|
+
(timestampStart || timestampEnd) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-2 bg-blue-50 border-b border-blue-100 flex items-center justify-between", children: [
|
|
26335
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2 text-sm text-blue-700", children: [
|
|
26336
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4" }),
|
|
26337
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
26338
|
+
"Filtered by time: ",
|
|
26339
|
+
timestampStart ? formatTimeOnly(timestampStart) : "Any",
|
|
26340
|
+
" - ",
|
|
26341
|
+
timestampEnd ? formatTimeOnly(timestampEnd) : "Any"
|
|
26342
|
+
] })
|
|
26343
|
+
] }),
|
|
26344
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26345
|
+
"button",
|
|
26346
|
+
{
|
|
26347
|
+
onClick: () => {
|
|
26348
|
+
setTimestampStart("");
|
|
26349
|
+
setTimestampEnd("");
|
|
26350
|
+
fetchClips();
|
|
26351
|
+
},
|
|
26352
|
+
className: "text-sm text-blue-600 hover:text-blue-800 transition-colors",
|
|
26353
|
+
children: "Clear filter"
|
|
26354
|
+
}
|
|
26355
|
+
)
|
|
26356
|
+
] }),
|
|
26146
26357
|
isLoading && allVideos.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner2, { size: "md", message: "Loading clips..." }) }) : allVideos.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center p-8", children: [
|
|
26147
26358
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
|
|
26148
26359
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Clips Found" }),
|
|
@@ -26202,6 +26413,7 @@ var BottlenecksContent = ({
|
|
|
26202
26413
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
|
|
26203
26414
|
] }) })
|
|
26204
26415
|
),
|
|
26416
|
+
currentVideo.creation_timestamp && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-3 left-3 z-10 bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-white shadow-sm text-xs", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-80", children: formatTimestamp(currentVideo.creation_timestamp) }) }),
|
|
26205
26417
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 p-3 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-white", children: [
|
|
26206
26418
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26207
26419
|
"button",
|
|
@@ -28122,9 +28334,9 @@ var SideNavBar = React46.memo(({
|
|
|
28122
28334
|
}
|
|
28123
28335
|
)
|
|
28124
28336
|
] }),
|
|
28125
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-auto", children: [
|
|
28126
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-px bg-gray-200 my-
|
|
28127
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "
|
|
28337
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-auto mb-2", children: [
|
|
28338
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-px bg-gray-200 my-3" }),
|
|
28339
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
28128
28340
|
"button",
|
|
28129
28341
|
{
|
|
28130
28342
|
onClick: handleProfileClick,
|
|
@@ -28706,7 +28918,7 @@ var ThreadSidebar = ({
|
|
|
28706
28918
|
if (error) {
|
|
28707
28919
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `p-4 text-red-600 text-sm ${className}`, children: "Failed to load conversations" });
|
|
28708
28920
|
}
|
|
28709
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col h-
|
|
28921
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col h-screen bg-gray-50 border-r border-gray-200 ${className}`, children: [
|
|
28710
28922
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 p-4 border-b border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28711
28923
|
"button",
|
|
28712
28924
|
{
|
|
@@ -28718,7 +28930,7 @@ var ThreadSidebar = ({
|
|
|
28718
28930
|
]
|
|
28719
28931
|
}
|
|
28720
28932
|
) }),
|
|
28721
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center p-8", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner_default, { size: "sm" }) }) : threads.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-gray-500 text-sm", children: "No conversations yet" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2", children: threads.map((thread) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28933
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto min-h-0", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center p-8", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner_default, { size: "sm" }) }) : threads.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-gray-500 text-sm", children: "No conversations yet" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2", children: threads.map((thread) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28722
28934
|
"div",
|
|
28723
28935
|
{
|
|
28724
28936
|
onClick: () => onSelectThread(thread.id),
|
|
@@ -28750,6 +28962,23 @@ var ThreadSidebar = ({
|
|
|
28750
28962
|
] });
|
|
28751
28963
|
};
|
|
28752
28964
|
var axelProfilePng = "/axel-profile.png";
|
|
28965
|
+
var ProfilePicture = React46__namespace.default.memo(({ alt = "Axel", className = "w-12 h-12" }) => {
|
|
28966
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${className} rounded-xl overflow-hidden shadow-sm`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
28967
|
+
"img",
|
|
28968
|
+
{
|
|
28969
|
+
src: axelProfilePng,
|
|
28970
|
+
alt,
|
|
28971
|
+
className: "w-full h-full object-cover",
|
|
28972
|
+
loading: "eager",
|
|
28973
|
+
decoding: "async"
|
|
28974
|
+
}
|
|
28975
|
+
) }) });
|
|
28976
|
+
});
|
|
28977
|
+
ProfilePicture.displayName = "ProfilePicture";
|
|
28978
|
+
var preloadImage = (src) => {
|
|
28979
|
+
const img = new Image();
|
|
28980
|
+
img.src = src;
|
|
28981
|
+
};
|
|
28753
28982
|
var AIAgentView = () => {
|
|
28754
28983
|
const { navigate, pathname } = useNavigation();
|
|
28755
28984
|
const config = useDashboardConfig();
|
|
@@ -28761,16 +28990,92 @@ var AIAgentView = () => {
|
|
|
28761
28990
|
const [lastError, setLastError] = React46.useState(null);
|
|
28762
28991
|
const [copiedMessageId, setCopiedMessageId] = React46.useState(null);
|
|
28763
28992
|
const [activeThreadId, setActiveThreadId] = React46.useState(void 0);
|
|
28764
|
-
const [isSidebarOpen, setIsSidebarOpen] = React46.useState(
|
|
28993
|
+
const [isSidebarOpen, setIsSidebarOpen] = React46.useState(false);
|
|
28765
28994
|
const [streamingStates, setStreamingStates] = React46.useState(/* @__PURE__ */ new Map());
|
|
28766
28995
|
const [userId, setUserId] = React46.useState(null);
|
|
28767
28996
|
const [pendingThreadId, setPendingThreadId] = React46.useState(null);
|
|
28997
|
+
const [isTransitioning, setIsTransitioning] = React46.useState(false);
|
|
28998
|
+
const [typedText, setTypedText] = React46.useState("");
|
|
28999
|
+
const [newChatCount, setNewChatCount] = React46.useState(0);
|
|
29000
|
+
const [hasStartedTyping, setHasStartedTyping] = React46.useState(false);
|
|
29001
|
+
const [typingStartTime, setTypingStartTime] = React46.useState(null);
|
|
29002
|
+
const [lastTypingTime, setLastTypingTime] = React46.useState(null);
|
|
29003
|
+
const [characterCount, setCharacterCount] = React46.useState(0);
|
|
29004
|
+
const typingTimeoutRef = React46.useRef(null);
|
|
28768
29005
|
const isThreadLoading = (threadId) => {
|
|
28769
29006
|
return threadId ? loadingThreads.has(threadId) : false;
|
|
28770
29007
|
};
|
|
28771
29008
|
const getStreamingState = (threadId) => {
|
|
28772
29009
|
return threadId ? streamingStates.get(threadId) || { message: "", reasoning: "" } : { message: "", reasoning: "" };
|
|
28773
29010
|
};
|
|
29011
|
+
const trackTypingStart = () => {
|
|
29012
|
+
if (!hasStartedTyping) {
|
|
29013
|
+
const now2 = Date.now();
|
|
29014
|
+
setHasStartedTyping(true);
|
|
29015
|
+
setTypingStartTime(now2);
|
|
29016
|
+
setLastTypingTime(now2);
|
|
29017
|
+
trackCoreEvent("AI Agent Input Started", {
|
|
29018
|
+
line_id: lineId,
|
|
29019
|
+
company_id: companyId,
|
|
29020
|
+
shift_id: shiftId,
|
|
29021
|
+
active_thread_id: activeThreadId,
|
|
29022
|
+
has_existing_messages: messages.length > 0,
|
|
29023
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
29024
|
+
});
|
|
29025
|
+
}
|
|
29026
|
+
};
|
|
29027
|
+
const trackTypingProgress = (newValue) => {
|
|
29028
|
+
const now2 = Date.now();
|
|
29029
|
+
setLastTypingTime(now2);
|
|
29030
|
+
setCharacterCount(newValue.length);
|
|
29031
|
+
if (typingTimeoutRef.current) {
|
|
29032
|
+
clearTimeout(typingTimeoutRef.current);
|
|
29033
|
+
}
|
|
29034
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
29035
|
+
if (hasStartedTyping && typingStartTime && newValue.length > 0) {
|
|
29036
|
+
const typingDuration = now2 - typingStartTime;
|
|
29037
|
+
trackCoreEvent("AI Agent Input Typing Progress", {
|
|
29038
|
+
line_id: lineId,
|
|
29039
|
+
company_id: companyId,
|
|
29040
|
+
shift_id: shiftId,
|
|
29041
|
+
active_thread_id: activeThreadId,
|
|
29042
|
+
character_count: newValue.length,
|
|
29043
|
+
typing_duration_ms: typingDuration,
|
|
29044
|
+
has_existing_messages: messages.length > 0,
|
|
29045
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
29046
|
+
});
|
|
29047
|
+
}
|
|
29048
|
+
}, 2e3);
|
|
29049
|
+
};
|
|
29050
|
+
const trackMessageSent = (messageContent) => {
|
|
29051
|
+
if (hasStartedTyping && typingStartTime) {
|
|
29052
|
+
const now2 = Date.now();
|
|
29053
|
+
const totalTypingDuration = now2 - typingStartTime;
|
|
29054
|
+
trackCoreEvent("AI Agent Message Sent", {
|
|
29055
|
+
line_id: lineId,
|
|
29056
|
+
company_id: companyId,
|
|
29057
|
+
shift_id: shiftId,
|
|
29058
|
+
active_thread_id: activeThreadId,
|
|
29059
|
+
message_length: messageContent.length,
|
|
29060
|
+
character_count: messageContent.length,
|
|
29061
|
+
typing_duration_ms: totalTypingDuration,
|
|
29062
|
+
has_existing_messages: messages.length > 0,
|
|
29063
|
+
is_new_conversation: !activeThreadId,
|
|
29064
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
29065
|
+
});
|
|
29066
|
+
}
|
|
29067
|
+
resetTypingState();
|
|
29068
|
+
};
|
|
29069
|
+
const resetTypingState = () => {
|
|
29070
|
+
setHasStartedTyping(false);
|
|
29071
|
+
setTypingStartTime(null);
|
|
29072
|
+
setLastTypingTime(null);
|
|
29073
|
+
setCharacterCount(0);
|
|
29074
|
+
if (typingTimeoutRef.current) {
|
|
29075
|
+
clearTimeout(typingTimeoutRef.current);
|
|
29076
|
+
typingTimeoutRef.current = null;
|
|
29077
|
+
}
|
|
29078
|
+
};
|
|
28774
29079
|
const textareaRef = React46.useRef(null);
|
|
28775
29080
|
const messagesEndRef = React46.useRef(null);
|
|
28776
29081
|
const containerRef = React46.useRef(null);
|
|
@@ -28792,6 +29097,41 @@ var AIAgentView = () => {
|
|
|
28792
29097
|
const lineId = getLineIdFromPath();
|
|
28793
29098
|
const { shiftId } = getCurrentShift(dateTimeConfig.defaultTimezone || "Asia/Kolkata", shiftConfig);
|
|
28794
29099
|
const companyId = entityConfig.companyId || "default-company-id";
|
|
29100
|
+
const ACTIVE_THREAD_STORAGE_KEY = `ai-agent-active-thread-${lineId}`;
|
|
29101
|
+
React46.useLayoutEffect(() => {
|
|
29102
|
+
const savedThreadId = localStorage.getItem(ACTIVE_THREAD_STORAGE_KEY);
|
|
29103
|
+
if (savedThreadId && savedThreadId !== "undefined") {
|
|
29104
|
+
setActiveThreadId(savedThreadId);
|
|
29105
|
+
}
|
|
29106
|
+
}, [ACTIVE_THREAD_STORAGE_KEY]);
|
|
29107
|
+
React46.useEffect(() => {
|
|
29108
|
+
if (activeThreadId) {
|
|
29109
|
+
localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
|
|
29110
|
+
} else {
|
|
29111
|
+
localStorage.removeItem(ACTIVE_THREAD_STORAGE_KEY);
|
|
29112
|
+
}
|
|
29113
|
+
}, [activeThreadId, ACTIVE_THREAD_STORAGE_KEY]);
|
|
29114
|
+
React46.useEffect(() => {
|
|
29115
|
+
const handleVisibilityChange = () => {
|
|
29116
|
+
if (document.visibilityState === "hidden" && activeThreadId) {
|
|
29117
|
+
localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
|
|
29118
|
+
}
|
|
29119
|
+
};
|
|
29120
|
+
const handleBeforeUnload = () => {
|
|
29121
|
+
if (activeThreadId) {
|
|
29122
|
+
localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
|
|
29123
|
+
}
|
|
29124
|
+
};
|
|
29125
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
29126
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
29127
|
+
return () => {
|
|
29128
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
29129
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
29130
|
+
if (activeThreadId) {
|
|
29131
|
+
localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
|
|
29132
|
+
}
|
|
29133
|
+
};
|
|
29134
|
+
}, [activeThreadId, ACTIVE_THREAD_STORAGE_KEY]);
|
|
28795
29135
|
React46.useEffect(() => {
|
|
28796
29136
|
if (textareaRef.current) {
|
|
28797
29137
|
textareaRef.current.style.height = "auto";
|
|
@@ -28806,6 +29146,27 @@ var AIAgentView = () => {
|
|
|
28806
29146
|
setTimeout(scrollToBottom, 100);
|
|
28807
29147
|
}
|
|
28808
29148
|
}, [activeThreadId]);
|
|
29149
|
+
React46.useEffect(() => {
|
|
29150
|
+
if (messages.length === 0 && !isTransitioning) {
|
|
29151
|
+
const fullText = "Hi, I'm Axel - Your AI Supervisor";
|
|
29152
|
+
let index = 0;
|
|
29153
|
+
setTypedText("");
|
|
29154
|
+
const typeInterval = setInterval(() => {
|
|
29155
|
+
if (index < fullText.length) {
|
|
29156
|
+
setTypedText(fullText.substring(0, index + 1));
|
|
29157
|
+
index++;
|
|
29158
|
+
} else {
|
|
29159
|
+
clearInterval(typeInterval);
|
|
29160
|
+
}
|
|
29161
|
+
}, 50);
|
|
29162
|
+
return () => clearInterval(typeInterval);
|
|
29163
|
+
}
|
|
29164
|
+
}, [messages.length, isTransitioning]);
|
|
29165
|
+
React46.useEffect(() => {
|
|
29166
|
+
if (isSidebarOpen) {
|
|
29167
|
+
setNewChatCount(0);
|
|
29168
|
+
}
|
|
29169
|
+
}, [isSidebarOpen]);
|
|
28809
29170
|
const copyToClipboard = async (text, messageId) => {
|
|
28810
29171
|
try {
|
|
28811
29172
|
await navigator.clipboard.writeText(text);
|
|
@@ -28820,8 +29181,21 @@ var AIAgentView = () => {
|
|
|
28820
29181
|
setMessages([]);
|
|
28821
29182
|
setInputValue("");
|
|
28822
29183
|
setPendingThreadId(null);
|
|
29184
|
+
setTypedText("");
|
|
29185
|
+
resetTypingState();
|
|
29186
|
+
localStorage.removeItem(ACTIVE_THREAD_STORAGE_KEY);
|
|
28823
29187
|
textareaRef.current?.focus();
|
|
28824
29188
|
};
|
|
29189
|
+
React46.useEffect(() => {
|
|
29190
|
+
preloadImage(axelProfilePng);
|
|
29191
|
+
}, []);
|
|
29192
|
+
React46.useEffect(() => {
|
|
29193
|
+
return () => {
|
|
29194
|
+
if (typingTimeoutRef.current) {
|
|
29195
|
+
clearTimeout(typingTimeoutRef.current);
|
|
29196
|
+
}
|
|
29197
|
+
};
|
|
29198
|
+
}, []);
|
|
28825
29199
|
React46.useEffect(() => {
|
|
28826
29200
|
const checkAuth = async () => {
|
|
28827
29201
|
const supabase2 = _getSupabaseInstance();
|
|
@@ -28852,6 +29226,13 @@ var AIAgentView = () => {
|
|
|
28852
29226
|
let currentThreadId = activeThreadId || `temp-${Date.now()}`;
|
|
28853
29227
|
if (isThreadLoading(currentThreadId)) return;
|
|
28854
29228
|
const userMessage = inputValue.trim();
|
|
29229
|
+
trackMessageSent(userMessage);
|
|
29230
|
+
if (displayMessages.length === 0) {
|
|
29231
|
+
setIsTransitioning(true);
|
|
29232
|
+
setTimeout(() => {
|
|
29233
|
+
setIsTransitioning(false);
|
|
29234
|
+
}, 800);
|
|
29235
|
+
}
|
|
28855
29236
|
setInputValue("");
|
|
28856
29237
|
setLoadingThreads((prev) => new Set(prev).add(currentThreadId));
|
|
28857
29238
|
setLastError(null);
|
|
@@ -28895,6 +29276,9 @@ var AIAgentView = () => {
|
|
|
28895
29276
|
currentThreadId = threadId;
|
|
28896
29277
|
setActiveThreadId(threadId);
|
|
28897
29278
|
setPendingThreadId(null);
|
|
29279
|
+
if (!isSidebarOpen) {
|
|
29280
|
+
setNewChatCount((prev) => prev + 1);
|
|
29281
|
+
}
|
|
28898
29282
|
setLoadingThreads((prev) => {
|
|
28899
29283
|
const newSet = new Set(prev);
|
|
28900
29284
|
if (newSet.has(oldThreadId)) {
|
|
@@ -28993,7 +29377,9 @@ var AIAgentView = () => {
|
|
|
28993
29377
|
const handleKeyDown = (e) => {
|
|
28994
29378
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
28995
29379
|
e.preventDefault();
|
|
28996
|
-
|
|
29380
|
+
if (!isCurrentThreadLoading) {
|
|
29381
|
+
handleSubmit(e);
|
|
29382
|
+
}
|
|
28997
29383
|
}
|
|
28998
29384
|
};
|
|
28999
29385
|
const formatMessage = (content) => {
|
|
@@ -29002,7 +29388,81 @@ var AIAgentView = () => {
|
|
|
29002
29388
|
text = text.replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1.5 py-0.5 rounded text-sm font-mono text-gray-800">$1</code>');
|
|
29003
29389
|
return text;
|
|
29004
29390
|
};
|
|
29005
|
-
const
|
|
29391
|
+
const parseTableFromText = (lines2, startIndex) => {
|
|
29392
|
+
const tableLines = [];
|
|
29393
|
+
let i = startIndex;
|
|
29394
|
+
while (i < lines2.length) {
|
|
29395
|
+
const line = lines2[i].trim();
|
|
29396
|
+
if (!line) {
|
|
29397
|
+
i++;
|
|
29398
|
+
break;
|
|
29399
|
+
}
|
|
29400
|
+
if (line.includes("|") || line.match(/^[-|=\s]+$/)) {
|
|
29401
|
+
tableLines.push(line);
|
|
29402
|
+
i++;
|
|
29403
|
+
} else {
|
|
29404
|
+
break;
|
|
29405
|
+
}
|
|
29406
|
+
}
|
|
29407
|
+
if (tableLines.length === 0) return { html: "", endIndex: startIndex };
|
|
29408
|
+
const dataLines = tableLines.filter((line) => !line.match(/^[-|=\s]+$/));
|
|
29409
|
+
if (dataLines.length === 0) return { html: "", endIndex: i };
|
|
29410
|
+
let headerRow = [];
|
|
29411
|
+
let dataRows = [];
|
|
29412
|
+
const firstLine = dataLines[0];
|
|
29413
|
+
if (firstLine.includes("|")) {
|
|
29414
|
+
const cells = firstLine.split("|").map((cell) => cell.trim()).filter((cell) => cell.length > 0);
|
|
29415
|
+
if (cells.length >= 2) {
|
|
29416
|
+
headerRow = cells;
|
|
29417
|
+
for (let j = 1; j < dataLines.length; j++) {
|
|
29418
|
+
const row = dataLines[j];
|
|
29419
|
+
if (row.includes("|")) {
|
|
29420
|
+
const rowCells = row.split("|").map((cell) => cell.trim()).filter((cell) => cell.length > 0);
|
|
29421
|
+
while (rowCells.length < headerRow.length) rowCells.push("");
|
|
29422
|
+
if (rowCells.length > headerRow.length) rowCells.splice(headerRow.length);
|
|
29423
|
+
dataRows.push(rowCells);
|
|
29424
|
+
}
|
|
29425
|
+
}
|
|
29426
|
+
}
|
|
29427
|
+
}
|
|
29428
|
+
if (headerRow.length === 0) {
|
|
29429
|
+
for (const line of dataLines) {
|
|
29430
|
+
if (line.includes("|")) {
|
|
29431
|
+
const rowCells = line.split("|").map((cell) => cell.trim()).filter((cell) => cell.length > 0);
|
|
29432
|
+
if (rowCells.length >= 2) {
|
|
29433
|
+
dataRows.push(rowCells);
|
|
29434
|
+
}
|
|
29435
|
+
}
|
|
29436
|
+
}
|
|
29437
|
+
if (dataRows.length > 0 && dataRows[0].length > 0) {
|
|
29438
|
+
headerRow = dataRows[0].map((_, index) => `Column ${index + 1}`);
|
|
29439
|
+
}
|
|
29440
|
+
}
|
|
29441
|
+
if (headerRow.length > 0 && dataRows.length > 0) {
|
|
29442
|
+
let tableHtml = '<div class="overflow-x-auto my-4"><table class="min-w-full border-collapse border border-gray-300 rounded-lg shadow-sm">';
|
|
29443
|
+
tableHtml += '<thead class="bg-gray-50">';
|
|
29444
|
+
tableHtml += "<tr>";
|
|
29445
|
+
headerRow.forEach((header) => {
|
|
29446
|
+
tableHtml += `<th class="border border-gray-300 px-4 py-2 text-left font-semibold text-gray-900">${processInlineFormatting(header)}</th>`;
|
|
29447
|
+
});
|
|
29448
|
+
tableHtml += "</tr>";
|
|
29449
|
+
tableHtml += "</thead>";
|
|
29450
|
+
tableHtml += '<tbody class="bg-white">';
|
|
29451
|
+
dataRows.forEach((row, rowIndex) => {
|
|
29452
|
+
tableHtml += `<tr class="${rowIndex % 2 === 0 ? "bg-white" : "bg-gray-50"}">`;
|
|
29453
|
+
row.forEach((cell) => {
|
|
29454
|
+
tableHtml += `<td class="border border-gray-300 px-4 py-2 text-gray-800">${processInlineFormatting(cell)}</td>`;
|
|
29455
|
+
});
|
|
29456
|
+
tableHtml += "</tr>";
|
|
29457
|
+
});
|
|
29458
|
+
tableHtml += "</tbody>";
|
|
29459
|
+
tableHtml += "</table></div>";
|
|
29460
|
+
return { html: tableHtml, endIndex: i };
|
|
29461
|
+
}
|
|
29462
|
+
return { html: "", endIndex: startIndex };
|
|
29463
|
+
};
|
|
29464
|
+
const processedContent = content;
|
|
29465
|
+
const lines = processedContent.split("\n");
|
|
29006
29466
|
const formattedLines = [];
|
|
29007
29467
|
let inList = false;
|
|
29008
29468
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -29016,6 +29476,18 @@ var AIAgentView = () => {
|
|
|
29016
29476
|
formattedLines.push("<br/>");
|
|
29017
29477
|
continue;
|
|
29018
29478
|
}
|
|
29479
|
+
if (trimmedLine.includes("|") && (trimmedLine.match(/\|/g) || []).length >= 1) {
|
|
29480
|
+
if (inList) {
|
|
29481
|
+
formattedLines.push("</ul>");
|
|
29482
|
+
inList = false;
|
|
29483
|
+
}
|
|
29484
|
+
const tableResult = parseTableFromText(lines, i);
|
|
29485
|
+
if (tableResult.html) {
|
|
29486
|
+
formattedLines.push(tableResult.html);
|
|
29487
|
+
i = tableResult.endIndex - 1;
|
|
29488
|
+
continue;
|
|
29489
|
+
}
|
|
29490
|
+
}
|
|
29019
29491
|
if (trimmedLine.startsWith("###")) {
|
|
29020
29492
|
if (inList) {
|
|
29021
29493
|
formattedLines.push("</ul>");
|
|
@@ -29099,100 +29571,200 @@ var AIAgentView = () => {
|
|
|
29099
29571
|
position: messages.length
|
|
29100
29572
|
});
|
|
29101
29573
|
}
|
|
29102
|
-
|
|
29103
|
-
|
|
29104
|
-
|
|
29574
|
+
const renderAssistantContent = (content) => {
|
|
29575
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
29576
|
+
"div",
|
|
29105
29577
|
{
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
onNewThread: handleNewThread,
|
|
29109
|
-
className: "h-full"
|
|
29578
|
+
className: "formatted-content",
|
|
29579
|
+
dangerouslySetInnerHTML: { __html: formatMessage(content) }
|
|
29110
29580
|
}
|
|
29111
|
-
)
|
|
29112
|
-
|
|
29113
|
-
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
{
|
|
29118
|
-
|
|
29119
|
-
|
|
29120
|
-
"aria-label": "Toggle sidebar",
|
|
29121
|
-
children: isSidebarOpen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-5 h-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "w-5 h-5" })
|
|
29581
|
+
);
|
|
29582
|
+
};
|
|
29583
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-screen bg-white", children: [
|
|
29584
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: {
|
|
29585
|
+
__html: `
|
|
29586
|
+
@keyframes slideDown {
|
|
29587
|
+
0% {
|
|
29588
|
+
transform: translateY(-40vh);
|
|
29589
|
+
opacity: 1;
|
|
29122
29590
|
}
|
|
29123
|
-
|
|
29124
|
-
|
|
29125
|
-
|
|
29126
|
-
{
|
|
29127
|
-
onClick: () => navigate("/"),
|
|
29128
|
-
className: "flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors",
|
|
29129
|
-
"aria-label": "Go back",
|
|
29130
|
-
children: [
|
|
29131
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-5 h-5" }),
|
|
29132
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Back" })
|
|
29133
|
-
]
|
|
29591
|
+
100% {
|
|
29592
|
+
transform: translateY(0);
|
|
29593
|
+
opacity: 1;
|
|
29134
29594
|
}
|
|
29135
|
-
|
|
29136
|
-
|
|
29595
|
+
}
|
|
29596
|
+
`
|
|
29597
|
+
} }),
|
|
29598
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex-1 flex flex-col h-screen transition-all duration-300 ${isSidebarOpen ? "mr-80" : "mr-0"}`, children: [
|
|
29599
|
+
/* @__PURE__ */ jsxRuntime.jsx("header", { className: "flex-shrink-0 bg-white border-b border-gray-200 sticky top-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
29600
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29601
|
+
"button",
|
|
29602
|
+
{
|
|
29603
|
+
onClick: () => navigate("/"),
|
|
29604
|
+
className: "flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors",
|
|
29605
|
+
"aria-label": "Go back",
|
|
29606
|
+
children: [
|
|
29607
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-5 h-5" }),
|
|
29608
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Back" })
|
|
29609
|
+
]
|
|
29610
|
+
}
|
|
29611
|
+
) }),
|
|
29137
29612
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
|
|
29138
29613
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
29139
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl sm:text-2xl md:text-3xl font-bold text-gray-800 tracking-tight leading-none", children: "
|
|
29614
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl sm:text-2xl md:text-3xl font-bold text-gray-800 tracking-tight leading-none", children: "Chat with Axel" }),
|
|
29140
29615
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-blue-500 animate-pulse ring-2 ring-blue-500/30" })
|
|
29141
29616
|
] }),
|
|
29142
29617
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center mt-1", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-500", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) })
|
|
29143
29618
|
] }),
|
|
29144
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "
|
|
29619
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29620
|
+
"button",
|
|
29621
|
+
{
|
|
29622
|
+
onClick: () => setIsSidebarOpen(!isSidebarOpen),
|
|
29623
|
+
className: "relative p-2 hover:bg-gray-100 rounded-lg transition-colors",
|
|
29624
|
+
"aria-label": "Toggle sidebar",
|
|
29625
|
+
children: [
|
|
29626
|
+
isSidebarOpen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-5 h-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "w-5 h-5" }),
|
|
29627
|
+
!isSidebarOpen && newChatCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-medium", children: newChatCount })
|
|
29628
|
+
]
|
|
29629
|
+
}
|
|
29630
|
+
) })
|
|
29145
29631
|
] }) }) }),
|
|
29146
29632
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29147
29633
|
"main",
|
|
29148
29634
|
{
|
|
29149
29635
|
ref: containerRef,
|
|
29150
|
-
className:
|
|
29151
|
-
children:
|
|
29152
|
-
|
|
29153
|
-
|
|
29154
|
-
|
|
29155
|
-
{
|
|
29156
|
-
|
|
29157
|
-
|
|
29158
|
-
className: "
|
|
29159
|
-
}
|
|
29160
|
-
|
|
29161
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
29162
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
29163
|
-
|
|
29636
|
+
className: `flex-1 bg-gray-50/50 min-h-0 ${displayMessages.length === 0 && !isTransitioning ? "flex items-center justify-center" : "overflow-y-auto"}`,
|
|
29637
|
+
children: !activeThreadId && displayMessages.length === 0 && !isTransitioning ? (
|
|
29638
|
+
/* Centered welcome and input for new chat */
|
|
29639
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-3xl mx-auto px-4 sm:px-6 flex flex-col items-center justify-center space-y-12 -mt-16", children: [
|
|
29640
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
29641
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center mb-8", children: /* @__PURE__ */ jsxRuntime.jsx(ProfilePicture, { alt: "Axel - AI Manufacturing Expert", className: "w-24 h-24" }) }),
|
|
29642
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-3xl font-semibold text-gray-900", children: [
|
|
29643
|
+
typedText,
|
|
29644
|
+
typedText.length < "Hi, I'm Axel - Your AI Supervisor".length && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-pulse", children: "|" })
|
|
29645
|
+
] })
|
|
29646
|
+
] }),
|
|
29647
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-2xl", children: [
|
|
29648
|
+
activeThreadId && messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29649
|
+
"button",
|
|
29650
|
+
{
|
|
29651
|
+
onClick: handleNewThread,
|
|
29652
|
+
className: "inline-flex items-center gap-2 px-3 py-1.5 text-xs font-medium text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-lg transition-colors",
|
|
29653
|
+
children: [
|
|
29654
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "w-3.5 h-3.5" }),
|
|
29655
|
+
"New conversation"
|
|
29656
|
+
]
|
|
29657
|
+
}
|
|
29658
|
+
) }),
|
|
29659
|
+
/* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
|
|
29660
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative bg-white rounded-3xl shadow-lg border border-gray-200 focus-within:border-gray-300 transition-all duration-200", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-end gap-2 p-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 relative", children: [
|
|
29661
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29662
|
+
"textarea",
|
|
29663
|
+
{
|
|
29664
|
+
ref: textareaRef,
|
|
29665
|
+
value: inputValue,
|
|
29666
|
+
onChange: (e) => {
|
|
29667
|
+
const newValue = e.target.value;
|
|
29668
|
+
setInputValue(newValue);
|
|
29669
|
+
if (newValue.length > 0 && !hasStartedTyping) {
|
|
29670
|
+
trackTypingStart();
|
|
29671
|
+
}
|
|
29672
|
+
if (newValue.length > 0) {
|
|
29673
|
+
trackTypingProgress(newValue);
|
|
29674
|
+
}
|
|
29675
|
+
if (newValue.length === 0) {
|
|
29676
|
+
resetTypingState();
|
|
29677
|
+
}
|
|
29678
|
+
},
|
|
29679
|
+
onKeyDown: handleKeyDown,
|
|
29680
|
+
onFocus: () => {
|
|
29681
|
+
trackCoreEvent("AI Agent Input Focused", {
|
|
29682
|
+
line_id: lineId,
|
|
29683
|
+
company_id: companyId,
|
|
29684
|
+
shift_id: shiftId,
|
|
29685
|
+
active_thread_id: activeThreadId,
|
|
29686
|
+
has_existing_messages: messages.length > 0,
|
|
29687
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
29688
|
+
});
|
|
29689
|
+
},
|
|
29690
|
+
placeholder: "Ask me about production optimization, quality metrics, or any manufacturing challenge...",
|
|
29691
|
+
className: "w-full resize-none bg-transparent px-2 py-2 pr-12 focus:outline-none placeholder-gray-500 text-gray-900 text-sm leading-relaxed",
|
|
29692
|
+
rows: 1,
|
|
29693
|
+
style: { minHeight: "24px", maxHeight: "120px" }
|
|
29694
|
+
}
|
|
29695
|
+
),
|
|
29696
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 bottom-2 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
29697
|
+
"button",
|
|
29698
|
+
{
|
|
29699
|
+
type: "submit",
|
|
29700
|
+
disabled: !inputValue.trim() || isCurrentThreadLoading,
|
|
29701
|
+
className: "inline-flex items-center justify-center w-8 h-8 bg-gray-900 text-white rounded-full hover:bg-gray-800 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-gray-500/20",
|
|
29702
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" })
|
|
29703
|
+
}
|
|
29704
|
+
) })
|
|
29705
|
+
] }) }) }),
|
|
29706
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center mt-2 text-xs text-gray-400", children: [
|
|
29707
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: isCurrentThreadLoading ? "You can type your next message while Axel responds" : "Press Enter to send \u2022 Shift+Enter for new line" }),
|
|
29708
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-4", children: [
|
|
29709
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-1.5 h-1.5 rounded-full ${isCurrentThreadLoading ? "bg-orange-500" : "bg-green-500"}` }),
|
|
29710
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: isCurrentThreadLoading ? "Responding..." : "Connected" })
|
|
29711
|
+
] })
|
|
29712
|
+
] })
|
|
29713
|
+
] })
|
|
29164
29714
|
] })
|
|
29165
|
-
] })
|
|
29166
|
-
|
|
29715
|
+
] })
|
|
29716
|
+
) : isTransitioning ? (
|
|
29717
|
+
/* Transition state - show user message first, then thinking */
|
|
29718
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 py-6 pb-32", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
29167
29719
|
displayMessages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29168
29720
|
"div",
|
|
29169
29721
|
{
|
|
29170
29722
|
className: `flex gap-4 ${message.role === "user" ? "justify-end" : "justify-start"}`,
|
|
29171
29723
|
children: [
|
|
29172
|
-
message.role === "assistant" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
29173
|
-
|
|
29724
|
+
message.role === "assistant" && /* @__PURE__ */ jsxRuntime.jsx(ProfilePicture, {}),
|
|
29725
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `max-w-none w-full group ${message.role === "user" ? "order-1" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
29726
|
+
"div",
|
|
29174
29727
|
{
|
|
29175
|
-
|
|
29176
|
-
|
|
29177
|
-
|
|
29728
|
+
className: `relative px-5 py-4 rounded-2xl shadow-sm ${message.role === "user" ? "bg-blue-600 text-white max-w-[85%] ml-auto" : "bg-white border border-gray-200/80 max-w-full"}`,
|
|
29729
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${message.role === "user" ? "text-white" : "text-gray-800"}`, children: [
|
|
29730
|
+
message.role === "assistant" ? renderAssistantContent(message.content) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap leading-relaxed", children: message.content }),
|
|
29731
|
+
message.id === -1 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-0.5 h-4 bg-gray-400 animate-pulse ml-0.5" })
|
|
29732
|
+
] })
|
|
29178
29733
|
}
|
|
29179
|
-
) })
|
|
29180
|
-
|
|
29734
|
+
) })
|
|
29735
|
+
]
|
|
29736
|
+
},
|
|
29737
|
+
message.id === -1 ? "streaming-message" : `${message.id}-${index}`
|
|
29738
|
+
)),
|
|
29739
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 justify-start", children: [
|
|
29740
|
+
/* @__PURE__ */ jsxRuntime.jsx(ProfilePicture, {}),
|
|
29741
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white border border-gray-200/80 px-5 py-4 rounded-2xl shadow-sm max-w-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
29742
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex space-x-1", children: [
|
|
29743
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce" }),
|
|
29744
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.1s" } }),
|
|
29745
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.2s" } })
|
|
29746
|
+
] }),
|
|
29747
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600 text-sm", children: "Axel is thinking..." })
|
|
29748
|
+
] }) })
|
|
29749
|
+
] })
|
|
29750
|
+
] }) })
|
|
29751
|
+
) : (
|
|
29752
|
+
/* Regular chat view with messages */
|
|
29753
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 py-6 pb-32", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
29754
|
+
displayMessages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29755
|
+
"div",
|
|
29756
|
+
{
|
|
29757
|
+
className: `flex gap-4 ${message.role === "user" ? "justify-end" : "justify-start"}`,
|
|
29758
|
+
children: [
|
|
29759
|
+
message.role === "assistant" && /* @__PURE__ */ jsxRuntime.jsx(ProfilePicture, {}),
|
|
29760
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `max-w-none w-full group ${message.role === "user" ? "order-1" : ""}`, children: [
|
|
29181
29761
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
29182
29762
|
"div",
|
|
29183
29763
|
{
|
|
29184
|
-
className: `relative px-5 py-4 rounded-2xl shadow-sm ${message.role === "user" ? "bg-blue-600 text-white" : "bg-white border border-gray-200/80"}`,
|
|
29764
|
+
className: `relative px-5 py-4 rounded-2xl shadow-sm ${message.role === "user" ? "bg-blue-600 text-white max-w-[85%] ml-auto" : "bg-white border border-gray-200/80 max-w-full"}`,
|
|
29185
29765
|
children: [
|
|
29186
29766
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${message.role === "user" ? "text-white" : "text-gray-800"}`, children: [
|
|
29187
|
-
message.role === "assistant" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
29188
|
-
"div",
|
|
29189
|
-
{
|
|
29190
|
-
className: "formatted-content",
|
|
29191
|
-
dangerouslySetInnerHTML: {
|
|
29192
|
-
__html: formatMessage(message.content)
|
|
29193
|
-
}
|
|
29194
|
-
}
|
|
29195
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap leading-relaxed", children: message.content }),
|
|
29767
|
+
message.role === "assistant" ? renderAssistantContent(message.content) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap leading-relaxed", children: message.content }),
|
|
29196
29768
|
message.id === -1 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-0.5 h-4 bg-gray-400 animate-pulse ml-0.5" })
|
|
29197
29769
|
] }),
|
|
29198
29770
|
message.role === "assistant" && message.id !== -1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -29218,15 +29790,14 @@ var AIAgentView = () => {
|
|
|
29218
29790
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Axel" })
|
|
29219
29791
|
] })
|
|
29220
29792
|
] })
|
|
29221
|
-
] })
|
|
29222
|
-
message.role === "user" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 bg-gray-700 text-white rounded-xl flex items-center justify-center text-sm font-semibold", children: entityConfig.companyId?.charAt(0).toUpperCase() || "U" }) })
|
|
29793
|
+
] })
|
|
29223
29794
|
]
|
|
29224
29795
|
},
|
|
29225
|
-
message.id === -1 ?
|
|
29796
|
+
message.id === -1 ? "streaming-message" : `${message.id}-${index}`
|
|
29226
29797
|
)),
|
|
29227
29798
|
lastError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 justify-start", children: [
|
|
29228
29799
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12 h-12 rounded-xl bg-red-100 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "w-6 h-6 text-red-600" }) }) }),
|
|
29229
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-red-50 border border-red-200 px-5 py-4 rounded-2xl shadow-sm max-w-
|
|
29800
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-red-50 border border-red-200 px-5 py-4 rounded-2xl shadow-sm max-w-full", children: [
|
|
29230
29801
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-red-800 text-sm", children: lastError }),
|
|
29231
29802
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29232
29803
|
"button",
|
|
@@ -29239,29 +29810,22 @@ var AIAgentView = () => {
|
|
|
29239
29810
|
] })
|
|
29240
29811
|
] }),
|
|
29241
29812
|
isCurrentThreadLoading && !currentStreaming.message && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 justify-start", children: [
|
|
29242
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29243
|
-
|
|
29244
|
-
{
|
|
29245
|
-
src: axelProfilePng,
|
|
29246
|
-
alt: "Axel",
|
|
29247
|
-
className: "w-full h-full object-cover"
|
|
29248
|
-
}
|
|
29249
|
-
) }) }),
|
|
29250
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white border border-gray-200/80 px-5 py-4 rounded-2xl shadow-sm max-w-[75%]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
29813
|
+
/* @__PURE__ */ jsxRuntime.jsx(ProfilePicture, {}),
|
|
29814
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white border border-gray-200/80 px-5 py-4 rounded-2xl shadow-sm max-w-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
29251
29815
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex space-x-1", children: [
|
|
29252
29816
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce" }),
|
|
29253
29817
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.1s" } }),
|
|
29254
29818
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.2s" } })
|
|
29255
29819
|
] }),
|
|
29256
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600 text-sm", children: "Axel is
|
|
29820
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600 text-sm", children: "Axel is thinking..." })
|
|
29257
29821
|
] }) })
|
|
29258
29822
|
] }),
|
|
29259
29823
|
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
|
|
29260
|
-
] })
|
|
29261
|
-
|
|
29824
|
+
] }) })
|
|
29825
|
+
)
|
|
29262
29826
|
}
|
|
29263
29827
|
),
|
|
29264
|
-
/* @__PURE__ */ jsxRuntime.jsx("footer", { className: "
|
|
29828
|
+
(displayMessages.length > 0 || isTransitioning) && /* @__PURE__ */ jsxRuntime.jsx("footer", { className: "fixed bottom-0 left-0 right-0 bg-gradient-to-t from-gray-50/50 to-transparent pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-4xl mx-auto p-4 sm:p-6 pointer-events-auto", children: [
|
|
29265
29829
|
activeThreadId && messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29266
29830
|
"button",
|
|
29267
29831
|
{
|
|
@@ -29273,48 +29837,81 @@ var AIAgentView = () => {
|
|
|
29273
29837
|
]
|
|
29274
29838
|
}
|
|
29275
29839
|
) }),
|
|
29276
|
-
/* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit,
|
|
29277
|
-
/* @__PURE__ */ jsxRuntime.
|
|
29278
|
-
|
|
29279
|
-
|
|
29280
|
-
|
|
29281
|
-
|
|
29282
|
-
|
|
29283
|
-
|
|
29284
|
-
|
|
29285
|
-
|
|
29286
|
-
|
|
29287
|
-
|
|
29288
|
-
|
|
29289
|
-
|
|
29290
|
-
|
|
29291
|
-
|
|
29292
|
-
|
|
29293
|
-
|
|
29294
|
-
|
|
29295
|
-
|
|
29296
|
-
|
|
29297
|
-
|
|
29298
|
-
|
|
29299
|
-
|
|
29300
|
-
|
|
29301
|
-
|
|
29302
|
-
|
|
29303
|
-
|
|
29304
|
-
|
|
29305
|
-
|
|
29306
|
-
|
|
29307
|
-
|
|
29308
|
-
|
|
29309
|
-
|
|
29310
|
-
|
|
29311
|
-
|
|
29312
|
-
|
|
29313
|
-
|
|
29840
|
+
/* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
|
|
29841
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29842
|
+
"div",
|
|
29843
|
+
{
|
|
29844
|
+
className: `relative bg-white rounded-3xl shadow-lg border border-gray-200 focus-within:border-gray-300 transition-all duration-200 ${isTransitioning ? "animate-slide-down" : ""}`,
|
|
29845
|
+
style: isTransitioning ? {
|
|
29846
|
+
animation: "slideDown 0.8s cubic-bezier(0.4, 0, 0.2, 1) forwards"
|
|
29847
|
+
} : {},
|
|
29848
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-end gap-2 p-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 relative", children: [
|
|
29849
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29850
|
+
"textarea",
|
|
29851
|
+
{
|
|
29852
|
+
ref: textareaRef,
|
|
29853
|
+
value: inputValue,
|
|
29854
|
+
onChange: (e) => {
|
|
29855
|
+
const newValue = e.target.value;
|
|
29856
|
+
setInputValue(newValue);
|
|
29857
|
+
if (newValue.length > 0 && !hasStartedTyping) {
|
|
29858
|
+
trackTypingStart();
|
|
29859
|
+
}
|
|
29860
|
+
if (newValue.length > 0) {
|
|
29861
|
+
trackTypingProgress(newValue);
|
|
29862
|
+
}
|
|
29863
|
+
if (newValue.length === 0) {
|
|
29864
|
+
resetTypingState();
|
|
29865
|
+
}
|
|
29866
|
+
},
|
|
29867
|
+
onKeyDown: handleKeyDown,
|
|
29868
|
+
onFocus: () => {
|
|
29869
|
+
trackCoreEvent("AI Agent Input Focused", {
|
|
29870
|
+
line_id: lineId,
|
|
29871
|
+
company_id: companyId,
|
|
29872
|
+
shift_id: shiftId,
|
|
29873
|
+
active_thread_id: activeThreadId,
|
|
29874
|
+
has_existing_messages: messages.length > 0,
|
|
29875
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
29876
|
+
});
|
|
29877
|
+
},
|
|
29878
|
+
placeholder: "Ask me about production optimization, quality metrics, or any manufacturing challenge...",
|
|
29879
|
+
className: "w-full resize-none bg-transparent px-2 py-2 pr-12 focus:outline-none placeholder-gray-500 text-gray-900 text-sm leading-relaxed",
|
|
29880
|
+
rows: 1,
|
|
29881
|
+
style: { minHeight: "24px", maxHeight: "120px" }
|
|
29882
|
+
}
|
|
29883
|
+
),
|
|
29884
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 bottom-2 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
29885
|
+
"button",
|
|
29886
|
+
{
|
|
29887
|
+
type: "submit",
|
|
29888
|
+
disabled: !inputValue.trim() || isCurrentThreadLoading,
|
|
29889
|
+
className: "inline-flex items-center justify-center w-8 h-8 bg-gray-900 text-white rounded-full hover:bg-gray-800 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-gray-500/20",
|
|
29890
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" })
|
|
29891
|
+
}
|
|
29892
|
+
) })
|
|
29893
|
+
] }) })
|
|
29894
|
+
}
|
|
29895
|
+
),
|
|
29896
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center mt-2 text-xs text-gray-400", children: [
|
|
29897
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: isCurrentThreadLoading ? "You can type your next message while Axel responds" : "Press Enter to send \u2022 Shift+Enter for new line" }),
|
|
29898
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-4", children: [
|
|
29899
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-1.5 h-1.5 rounded-full ${isCurrentThreadLoading ? "bg-orange-500" : "bg-green-500"}` }),
|
|
29900
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: isCurrentThreadLoading ? "Responding..." : "Connected" })
|
|
29901
|
+
] })
|
|
29314
29902
|
] })
|
|
29315
29903
|
] })
|
|
29316
29904
|
] }) })
|
|
29317
|
-
] })
|
|
29905
|
+
] }),
|
|
29906
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${isSidebarOpen ? "w-80" : "w-0"} transition-all duration-300 overflow-hidden flex-shrink-0 border-l border-gray-200 h-screen fixed right-0 top-0 z-20`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
29907
|
+
ThreadSidebar,
|
|
29908
|
+
{
|
|
29909
|
+
activeThreadId,
|
|
29910
|
+
onSelectThread: setActiveThreadId,
|
|
29911
|
+
onNewThread: handleNewThread,
|
|
29912
|
+
className: "h-full"
|
|
29913
|
+
}
|
|
29914
|
+
) })
|
|
29318
29915
|
] });
|
|
29319
29916
|
};
|
|
29320
29917
|
var AIAgentView_default = AIAgentView;
|
|
@@ -31191,7 +31788,8 @@ var parseBreaksFromDB = (dbBreaks) => {
|
|
|
31191
31788
|
duration: calculateBreakDuration(
|
|
31192
31789
|
breakItem.start || breakItem.startTime || "00:00",
|
|
31193
31790
|
breakItem.end || breakItem.endTime || "00:00"
|
|
31194
|
-
)
|
|
31791
|
+
),
|
|
31792
|
+
remarks: breakItem.remarks || breakItem.name || ""
|
|
31195
31793
|
}));
|
|
31196
31794
|
} else if (dbBreaks.breaks && Array.isArray(dbBreaks.breaks)) {
|
|
31197
31795
|
return dbBreaks.breaks.map((breakItem) => ({
|
|
@@ -31200,7 +31798,8 @@ var parseBreaksFromDB = (dbBreaks) => {
|
|
|
31200
31798
|
duration: calculateBreakDuration(
|
|
31201
31799
|
breakItem.start || breakItem.startTime || "00:00",
|
|
31202
31800
|
breakItem.end || breakItem.endTime || "00:00"
|
|
31203
|
-
)
|
|
31801
|
+
),
|
|
31802
|
+
remarks: breakItem.remarks || breakItem.name || ""
|
|
31204
31803
|
}));
|
|
31205
31804
|
} else {
|
|
31206
31805
|
console.warn("Unexpected breaks format:", dbBreaks);
|
|
@@ -31218,7 +31817,8 @@ var formatBreaks = (breaks) => {
|
|
|
31218
31817
|
return {
|
|
31219
31818
|
breaks: breaks.map((breakItem) => ({
|
|
31220
31819
|
start: breakItem.startTime,
|
|
31221
|
-
end: breakItem.endTime
|
|
31820
|
+
end: breakItem.endTime,
|
|
31821
|
+
remarks: breakItem.remarks || ""
|
|
31222
31822
|
}))
|
|
31223
31823
|
};
|
|
31224
31824
|
};
|
|
@@ -31228,13 +31828,14 @@ var BreakRow = React46.memo(({
|
|
|
31228
31828
|
onRemove,
|
|
31229
31829
|
index
|
|
31230
31830
|
}) => {
|
|
31231
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-
|
|
31831
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 gap-2 sm:gap-4 items-center w-full bg-white hover:bg-gray-50 rounded-md transition-all duration-200 p-2", children: [
|
|
31232
31832
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
31233
31833
|
"input",
|
|
31234
31834
|
{
|
|
31235
31835
|
type: "time",
|
|
31236
31836
|
value: breakItem.startTime,
|
|
31237
31837
|
onChange: (e) => onUpdate(index, "startTime", e.target.value),
|
|
31838
|
+
step: "60",
|
|
31238
31839
|
className: "w-full px-2 sm:px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
31239
31840
|
}
|
|
31240
31841
|
) }),
|
|
@@ -31244,6 +31845,7 @@ var BreakRow = React46.memo(({
|
|
|
31244
31845
|
type: "time",
|
|
31245
31846
|
value: breakItem.endTime,
|
|
31246
31847
|
onChange: (e) => onUpdate(index, "endTime", e.target.value),
|
|
31848
|
+
step: "60",
|
|
31247
31849
|
className: "w-full px-2 sm:px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
31248
31850
|
}
|
|
31249
31851
|
) }),
|
|
@@ -31251,6 +31853,16 @@ var BreakRow = React46.memo(({
|
|
|
31251
31853
|
breakItem.duration,
|
|
31252
31854
|
" min"
|
|
31253
31855
|
] }) }),
|
|
31856
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
31857
|
+
"input",
|
|
31858
|
+
{
|
|
31859
|
+
type: "text",
|
|
31860
|
+
value: breakItem.remarks || "",
|
|
31861
|
+
onChange: (e) => onUpdate(index, "remarks", e.target.value),
|
|
31862
|
+
placeholder: "Break remarks",
|
|
31863
|
+
className: "w-full px-2 sm:px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
31864
|
+
}
|
|
31865
|
+
) }),
|
|
31254
31866
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
31255
31867
|
"button",
|
|
31256
31868
|
{
|
|
@@ -31367,10 +31979,11 @@ var ShiftPanel = React46.memo(({
|
|
|
31367
31979
|
"Breaks"
|
|
31368
31980
|
] }) }),
|
|
31369
31981
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2 mb-4 w-full", children: breaks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31370
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-
|
|
31982
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 gap-2 sm:gap-4 text-xs font-medium text-gray-500 mb-1 w-full px-2", children: [
|
|
31371
31983
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: "Break Start" }),
|
|
31372
31984
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: "Break End" }),
|
|
31373
31985
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: "Duration" }),
|
|
31986
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: "Remarks" }),
|
|
31374
31987
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-1" })
|
|
31375
31988
|
] }),
|
|
31376
31989
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-gray-50/80 p-2 rounded-md", children: breaks.map((breakItem, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -31583,7 +32196,8 @@ var ShiftsView = ({
|
|
|
31583
32196
|
const newBreak = {
|
|
31584
32197
|
startTime: dayShift.startTime,
|
|
31585
32198
|
endTime: dayShift.startTime,
|
|
31586
|
-
duration: 0
|
|
32199
|
+
duration: 0,
|
|
32200
|
+
remarks: ""
|
|
31587
32201
|
};
|
|
31588
32202
|
return {
|
|
31589
32203
|
...typedConfig,
|
|
@@ -31624,14 +32238,16 @@ var ShiftsView = ({
|
|
|
31624
32238
|
const dayShift = { ...typedConfig.dayShift };
|
|
31625
32239
|
const newBreaks = [...dayShift.breaks];
|
|
31626
32240
|
newBreaks[index] = { ...newBreaks[index], [field]: value };
|
|
31627
|
-
|
|
31628
|
-
|
|
31629
|
-
|
|
31630
|
-
|
|
31631
|
-
|
|
31632
|
-
endMinutes
|
|
31633
|
-
|
|
31634
|
-
|
|
32241
|
+
if (field === "startTime" || field === "endTime") {
|
|
32242
|
+
const startParts = newBreaks[index].startTime.split(":").map(Number);
|
|
32243
|
+
const endParts = newBreaks[index].endTime.split(":").map(Number);
|
|
32244
|
+
let startMinutes = startParts[0] * 60 + startParts[1];
|
|
32245
|
+
let endMinutes = endParts[0] * 60 + endParts[1];
|
|
32246
|
+
if (endMinutes < startMinutes) {
|
|
32247
|
+
endMinutes += 24 * 60;
|
|
32248
|
+
}
|
|
32249
|
+
newBreaks[index].duration = endMinutes - startMinutes;
|
|
32250
|
+
}
|
|
31635
32251
|
return {
|
|
31636
32252
|
...typedConfig,
|
|
31637
32253
|
dayShift: {
|
|
@@ -31650,14 +32266,16 @@ var ShiftsView = ({
|
|
|
31650
32266
|
const nightShift = { ...typedConfig.nightShift };
|
|
31651
32267
|
const newBreaks = [...nightShift.breaks];
|
|
31652
32268
|
newBreaks[index] = { ...newBreaks[index], [field]: value };
|
|
31653
|
-
|
|
31654
|
-
|
|
31655
|
-
|
|
31656
|
-
|
|
31657
|
-
|
|
31658
|
-
endMinutes
|
|
31659
|
-
|
|
31660
|
-
|
|
32269
|
+
if (field === "startTime" || field === "endTime") {
|
|
32270
|
+
const startParts = newBreaks[index].startTime.split(":").map(Number);
|
|
32271
|
+
const endParts = newBreaks[index].endTime.split(":").map(Number);
|
|
32272
|
+
let startMinutes = startParts[0] * 60 + startParts[1];
|
|
32273
|
+
let endMinutes = endParts[0] * 60 + endParts[1];
|
|
32274
|
+
if (endMinutes < startMinutes) {
|
|
32275
|
+
endMinutes += 24 * 60;
|
|
32276
|
+
}
|
|
32277
|
+
newBreaks[index].duration = endMinutes - startMinutes;
|
|
32278
|
+
}
|
|
31661
32279
|
return {
|
|
31662
32280
|
...typedConfig,
|
|
31663
32281
|
nightShift: {
|