@optifye/dashboard-core 6.6.6 → 6.6.7

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.mjs CHANGED
@@ -3568,329 +3568,10 @@ var useAudioService = () => {
3568
3568
  };
3569
3569
 
3570
3570
  // src/lib/utils/dateShiftUtils.ts
3571
- function isValidDateFormat(date) {
3572
- return /^\d{4}-\d{2}-\d{2}$/.test(date);
3573
- }
3574
3571
  function isValidShiftId(shiftId) {
3575
3572
  const id3 = typeof shiftId === "string" ? parseInt(shiftId, 10) : shiftId;
3576
3573
  return id3 === 0 || id3 === 1;
3577
3574
  }
3578
-
3579
- // src/lib/api/s3-clips-parser.ts
3580
- function parseS3Uri(s3Uri, sopCategories) {
3581
- const path = new URL(s3Uri).pathname;
3582
- const parts = path.split("/").filter((p) => p);
3583
- if (s3Uri.includes("missed_qchecks")) {
3584
- console.warn(`Skipping missed_qchecks URI in parseS3Uri: ${s3Uri}`);
3585
- return null;
3586
- }
3587
- if (parts.length < 8) {
3588
- console.warn(`Invalid S3 path structure: ${s3Uri} - Too few parts: ${parts.length}, expected at least 8`);
3589
- return null;
3590
- }
3591
- try {
3592
- const datePart = parts[2];
3593
- const shiftPart = parts[3];
3594
- const violationType = parts[4];
3595
- let folderName = "";
3596
- let timestamp = "";
3597
- for (let i = 5; i < parts.length; i++) {
3598
- const part = parts[i];
3599
- if (part && part.includes("_") && /\d{8}_\d{6}/.test(part)) {
3600
- folderName = part;
3601
- const timeMatch = folderName.match(/_(\d{8})_(\d{6})_/);
3602
- if (timeMatch) {
3603
- timestamp = `${timeMatch[2].substring(0, 2)}:${timeMatch[2].substring(2, 4)}:${timeMatch[2].substring(4, 6)}`;
3604
- break;
3605
- }
3606
- }
3607
- }
3608
- if (!timestamp) {
3609
- console.warn(`Couldn't extract timestamp from any part: ${parts.join("/")}`);
3610
- timestamp = "00:00:00";
3611
- }
3612
- let severity = "low";
3613
- let type = "bottleneck";
3614
- let description = "Analysis Clip";
3615
- const normalizedViolationType = violationType.toLowerCase().trim();
3616
- if (sopCategories && sopCategories.length > 0) {
3617
- const matchedCategory = sopCategories.find((category) => {
3618
- const categoryId = category.id.toLowerCase();
3619
- const s3FolderName = (category.s3FolderName || category.id).toLowerCase();
3620
- return categoryId === normalizedViolationType || s3FolderName === normalizedViolationType || // Also check for partial matches for flexibility
3621
- normalizedViolationType.includes(categoryId) || normalizedViolationType.includes(s3FolderName);
3622
- });
3623
- if (matchedCategory) {
3624
- type = matchedCategory.id;
3625
- description = matchedCategory.description || matchedCategory.label;
3626
- if (matchedCategory.color.includes("red")) {
3627
- severity = "high";
3628
- } else if (matchedCategory.color.includes("yellow") || matchedCategory.color.includes("orange")) {
3629
- severity = "medium";
3630
- } else {
3631
- severity = "low";
3632
- }
3633
- console.log(`Matched SOP category: ${matchedCategory.id} for violation type: ${violationType}`);
3634
- return { timestamp, severity, description, type, originalUri: s3Uri };
3635
- }
3636
- }
3637
- switch (normalizedViolationType) {
3638
- case "idle_time":
3639
- case "idle":
3640
- case "low_value":
3641
- case "low value":
3642
- case "low_value_moment":
3643
- case "low_value_moments":
3644
- case "low value moment":
3645
- case "low value moments":
3646
- type = "low_value";
3647
- severity = "low";
3648
- description = "Idle Time Detected";
3649
- break;
3650
- case "sop_deviation":
3651
- type = "missing_quality_check";
3652
- severity = "high";
3653
- description = "SOP Deviations";
3654
- break;
3655
- case "long_cycle_time":
3656
- severity = "high";
3657
- type = "long_cycle_time";
3658
- description = "Long Cycle Time Detected";
3659
- break;
3660
- case "best_cycle_time":
3661
- type = "best_cycle_time";
3662
- severity = "low";
3663
- description = "Best Cycle Time Performance";
3664
- break;
3665
- case "worst_cycle_time":
3666
- type = "worst_cycle_time";
3667
- severity = "high";
3668
- description = "Worst Cycle Time Performance";
3669
- break;
3670
- case "cycle_completion":
3671
- case "completed_cycles":
3672
- case "completed_cycle":
3673
- type = "cycle_completion";
3674
- severity = "low";
3675
- description = "Cycle Completion";
3676
- break;
3677
- case "running_cycle":
3678
- case "active_cycle":
3679
- case "production_cycle":
3680
- type = "running_cycle";
3681
- severity = "low";
3682
- description = "Active Production Cycle";
3683
- break;
3684
- case "setup_state":
3685
- case "machine_setup":
3686
- case "line_setup":
3687
- type = "setup_state";
3688
- severity = "medium";
3689
- description = "Machine Setup Activity";
3690
- break;
3691
- case "medium_bottleneck":
3692
- severity = "medium";
3693
- description = "Medium Bottleneck Identified";
3694
- break;
3695
- case "minor_bottleneck":
3696
- case "mild_bottleneck":
3697
- severity = "low";
3698
- description = "Minor Bottleneck Identified";
3699
- break;
3700
- default:
3701
- if (normalizedViolationType.includes("sop") && normalizedViolationType.includes("deviation")) {
3702
- type = "missing_quality_check";
3703
- severity = "high";
3704
- description = "SOP Deviations";
3705
- } else if (normalizedViolationType.includes("worst") && normalizedViolationType.includes("cycle")) {
3706
- type = "worst_cycle_time";
3707
- severity = "high";
3708
- description = "Worst Cycle Time Performance";
3709
- } else if (normalizedViolationType.includes("best") && normalizedViolationType.includes("cycle")) {
3710
- type = "best_cycle_time";
3711
- severity = "low";
3712
- description = "Best Cycle Time Performance";
3713
- } else if (normalizedViolationType.includes("long") && normalizedViolationType.includes("cycle")) {
3714
- type = "long_cycle_time";
3715
- severity = "high";
3716
- description = "Long Cycle Time Detected";
3717
- } else if (normalizedViolationType.includes("cycle") && (normalizedViolationType.includes("completion") || normalizedViolationType.includes("complete"))) {
3718
- type = "cycle_completion";
3719
- severity = "low";
3720
- description = "Cycle Completion";
3721
- } else if (normalizedViolationType.includes("running") && normalizedViolationType.includes("cycle")) {
3722
- type = "running_cycle";
3723
- severity = "low";
3724
- description = "Active Production Cycle";
3725
- } else if (normalizedViolationType.includes("setup") || normalizedViolationType.includes("machine") && normalizedViolationType.includes("setup")) {
3726
- type = "setup_state";
3727
- severity = "medium";
3728
- description = "Machine Setup Activity";
3729
- } else {
3730
- description = `Clip type: ${violationType.replace(/_/g, " ")}`;
3731
- console.log(`Detected unknown violation type: ${violationType} in URI: ${s3Uri}`);
3732
- }
3733
- break;
3734
- }
3735
- return { timestamp, severity, description, type, originalUri: s3Uri };
3736
- } catch (error) {
3737
- console.error(`Error parsing S3 URI: ${s3Uri}`, error);
3738
- return null;
3739
- }
3740
- }
3741
- function shuffleArray(array) {
3742
- const shuffled = [...array];
3743
- for (let i = shuffled.length - 1; i > 0; i--) {
3744
- const j = Math.floor(Math.random() * (i + 1));
3745
- [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
3746
- }
3747
- return shuffled;
3748
- }
3749
- var SmartVideoCache = class extends EventEmitter {
3750
- constructor() {
3751
- super();
3752
- this.metrics = {
3753
- hits: 0,
3754
- misses: 0,
3755
- evictions: 0,
3756
- totalSize: 0,
3757
- entryCount: 0,
3758
- hitRate: 0
3759
- };
3760
- this.setMaxListeners(50);
3761
- }
3762
- /**
3763
- * DISABLED - Always returns null
3764
- */
3765
- async getSummary(key) {
3766
- this.metrics.misses++;
3767
- this.updateHitRate();
3768
- return null;
3769
- }
3770
- /**
3771
- * DISABLED - Does nothing
3772
- */
3773
- async setSummary(key, summary) {
3774
- }
3775
- /**
3776
- * DISABLED - Always returns null
3777
- */
3778
- async getVideos(key) {
3779
- this.metrics.misses++;
3780
- this.updateHitRate();
3781
- return null;
3782
- }
3783
- /**
3784
- * DISABLED - Does nothing
3785
- */
3786
- async setVideos(key, videos) {
3787
- }
3788
- /**
3789
- * DISABLED - Always returns null
3790
- */
3791
- async getClipCounts(key) {
3792
- console.log("[SmartVideoCache] DISABLED - Returning null for clip counts");
3793
- this.metrics.misses++;
3794
- this.updateHitRate();
3795
- return null;
3796
- }
3797
- /**
3798
- * DISABLED - Does nothing
3799
- */
3800
- async setClipCounts(key, clipCountsWithIndex, ttlMinutes) {
3801
- console.log("[SmartVideoCache] DISABLED - Not caching clip counts");
3802
- }
3803
- /**
3804
- * DISABLED - Does nothing
3805
- */
3806
- setPrefetchStatus(key, status) {
3807
- }
3808
- /**
3809
- * DISABLED - Always returns NONE
3810
- */
3811
- getPrefetchStatus(key) {
3812
- return "none" /* NONE */;
3813
- }
3814
- /**
3815
- * DISABLED - Always returns false
3816
- */
3817
- isPrefetchReady(key) {
3818
- return false;
3819
- }
3820
- /**
3821
- * DISABLED - Returns empty cleanup function
3822
- */
3823
- subscribeToPrefetchStatus(key, callback) {
3824
- return () => {
3825
- };
3826
- }
3827
- /**
3828
- * DISABLED - Always returns null
3829
- */
3830
- getSignedUrl(s3Uri) {
3831
- this.metrics.misses++;
3832
- this.updateHitRate();
3833
- return null;
3834
- }
3835
- /**
3836
- * DISABLED - Does nothing
3837
- */
3838
- setSignedUrl(s3Uri, url, ttlSeconds = 3600) {
3839
- }
3840
- /**
3841
- * DISABLED - Always returns empty array
3842
- */
3843
- async getVideosByWorkspace(workspaceId) {
3844
- return [];
3845
- }
3846
- /**
3847
- * DISABLED - Does nothing
3848
- */
3849
- async warmup(entries) {
3850
- }
3851
- /**
3852
- * Get cache statistics (mostly zeros since cache is disabled)
3853
- */
3854
- getStats() {
3855
- return {
3856
- ...this.metrics,
3857
- summaryStats: { hits: 0, misses: this.metrics.misses, evictions: 0, totalSize: 0 },
3858
- videoStats: { hits: 0, misses: this.metrics.misses, evictions: 0, totalSize: 0 },
3859
- clipCountsStats: { hits: 0, misses: this.metrics.misses, evictions: 0, totalSize: 0 },
3860
- urlCacheSize: 0
3861
- };
3862
- }
3863
- /**
3864
- * DISABLED - Does nothing
3865
- */
3866
- clear(type) {
3867
- this.removeAllListeners();
3868
- }
3869
- /**
3870
- * Update hit rate metric
3871
- */
3872
- updateHitRate() {
3873
- const total = this.metrics.hits + this.metrics.misses;
3874
- this.metrics.hitRate = total > 0 ? this.metrics.hits / total : 0;
3875
- }
3876
- /**
3877
- * Export cache state for debugging (returns empty state)
3878
- */
3879
- exportState() {
3880
- return {
3881
- summaries: [],
3882
- videos: [],
3883
- urls: [],
3884
- metrics: this.getStats()
3885
- };
3886
- }
3887
- };
3888
- var smartVideoCache = new SmartVideoCache();
3889
- if (typeof window !== "undefined") {
3890
- window.addEventListener("beforeunload", () => {
3891
- console.log("[SmartVideoCache] Cache disabled - no cleanup needed");
3892
- });
3893
- }
3894
3575
  var getSupabaseClient = () => {
3895
3576
  const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
3896
3577
  const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
@@ -3903,616 +3584,6 @@ var getAuthToken = async () => {
3903
3584
  try {
3904
3585
  const supabase = getSupabaseClient();
3905
3586
  const { data: { session } } = await supabase.auth.getSession();
3906
- return session?.access_token || null;
3907
- } catch (error) {
3908
- console.error("[S3ClipsAPIClient] Error getting auth token:", error);
3909
- return null;
3910
- }
3911
- };
3912
- var S3ClipsAPIClient = class {
3913
- constructor(sopCategories) {
3914
- this.baseUrl = "/api/clips";
3915
- this.requestCache = /* @__PURE__ */ new Map();
3916
- this.sopCategories = sopCategories;
3917
- console.log("[S3ClipsAPIClient] \u2705 Initialized - Using secure API routes (no direct S3 access)");
3918
- }
3919
- /**
3920
- * Fetch with authentication and error handling
3921
- */
3922
- async fetchWithAuth(endpoint, body) {
3923
- const token = await getAuthToken();
3924
- if (!token) {
3925
- throw new Error("Authentication required");
3926
- }
3927
- const response = await fetch(endpoint, {
3928
- method: "POST",
3929
- headers: {
3930
- "Authorization": `Bearer ${token}`,
3931
- "Content-Type": "application/json"
3932
- },
3933
- body: JSON.stringify(body)
3934
- });
3935
- if (!response.ok) {
3936
- const error = await response.json().catch(() => ({ error: "Request failed" }));
3937
- throw new Error(error.error || `API error: ${response.status}`);
3938
- }
3939
- return response.json();
3940
- }
3941
- /**
3942
- * Deduplicate requests to prevent multiple API calls
3943
- */
3944
- async deduplicate(key, factory) {
3945
- if (this.requestCache.has(key)) {
3946
- console.log(`[S3ClipsAPIClient] Deduplicating request: ${key}`);
3947
- return this.requestCache.get(key);
3948
- }
3949
- const promise = factory().finally(() => {
3950
- this.requestCache.delete(key);
3951
- });
3952
- this.requestCache.set(key, promise);
3953
- return promise;
3954
- }
3955
- /**
3956
- * List S3 clips
3957
- */
3958
- async listS3Clips(params) {
3959
- const cacheKey = `list:${JSON.stringify(params)}`;
3960
- return this.deduplicate(cacheKey, async () => {
3961
- const response = await this.fetchWithAuth(this.baseUrl, {
3962
- action: "list",
3963
- workspaceId: params.workspaceId,
3964
- date: params.date,
3965
- shift: params.shiftId,
3966
- maxKeys: params.maxKeys
3967
- });
3968
- return response.clips.map((clip) => clip.originalUri);
3969
- });
3970
- }
3971
- /**
3972
- * Get clip counts
3973
- */
3974
- async getClipCounts(workspaceId, date, shiftId) {
3975
- const cacheKey = `counts:${workspaceId}:${date}:${shiftId}`;
3976
- return this.deduplicate(cacheKey, async () => {
3977
- const response = await this.fetchWithAuth(this.baseUrl, {
3978
- action: "count",
3979
- workspaceId,
3980
- date,
3981
- shift: shiftId.toString()
3982
- });
3983
- return response.counts;
3984
- });
3985
- }
3986
- /**
3987
- * Get clip counts with index (for compatibility)
3988
- */
3989
- async getClipCountsWithIndex(workspaceId, date, shiftId) {
3990
- const counts = await this.getClipCounts(workspaceId, date, shiftId.toString());
3991
- const videoIndex = {
3992
- byCategory: /* @__PURE__ */ new Map(),
3993
- allVideos: [],
3994
- counts,
3995
- workspaceId,
3996
- date,
3997
- shiftId: shiftId.toString(),
3998
- lastUpdated: /* @__PURE__ */ new Date()
3999
- };
4000
- return { counts, videoIndex };
4001
- }
4002
- /**
4003
- * Get metadata for a video
4004
- */
4005
- async getMetadata(playlistUri) {
4006
- const cacheKey = `metadata:${playlistUri}`;
4007
- return this.deduplicate(cacheKey, async () => {
4008
- const response = await this.fetchWithAuth(this.baseUrl, {
4009
- action: "metadata",
4010
- playlistUri
4011
- });
4012
- return response.metadata;
4013
- });
4014
- }
4015
- /**
4016
- * Get metadata cycle time
4017
- */
4018
- async getMetadataCycleTime(playlistUri) {
4019
- const metadata = await this.getMetadata(playlistUri);
4020
- return metadata?.cycle_time_seconds || null;
4021
- }
4022
- /**
4023
- * Get first clip for category
4024
- */
4025
- async getFirstClipForCategory(workspaceId, date, shiftId, category) {
4026
- const cacheKey = `first:${workspaceId}:${date}:${shiftId}:${category}`;
4027
- return this.deduplicate(cacheKey, async () => {
4028
- const response = await this.fetchWithAuth(this.baseUrl, {
4029
- action: "first",
4030
- workspaceId,
4031
- date,
4032
- shift: shiftId.toString(),
4033
- category,
4034
- sopCategories: this.sopCategories
4035
- });
4036
- return response.video;
4037
- });
4038
- }
4039
- /**
4040
- * Get clip by index
4041
- */
4042
- async getClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
4043
- const cacheKey = `by-index:${workspaceId}:${date}:${shiftId}:${category}:${index}`;
4044
- return this.deduplicate(cacheKey, async () => {
4045
- const response = await this.fetchWithAuth(this.baseUrl, {
4046
- action: "by-index",
4047
- workspaceId,
4048
- date,
4049
- shift: shiftId.toString(),
4050
- category,
4051
- index,
4052
- sopCategories: this.sopCategories
4053
- });
4054
- const video = response.video;
4055
- if (video && includeMetadata && video.originalUri) {
4056
- try {
4057
- const metadata = await this.getMetadata(video.originalUri);
4058
- if (metadata) {
4059
- video.cycle_time_seconds = metadata.cycle_time_seconds;
4060
- video.creation_timestamp = metadata.creation_timestamp;
4061
- }
4062
- } catch (error) {
4063
- console.warn("[S3ClipsAPIClient] Failed to fetch metadata:", error);
4064
- }
4065
- }
4066
- return video;
4067
- });
4068
- }
4069
- /**
4070
- * Get videos page with pagination
4071
- */
4072
- async getVideosPage(workspaceId, date, shiftId, category, pageSize = 5, startAfter) {
4073
- const cacheKey = `page:${workspaceId}:${date}:${shiftId}:${category}:${pageSize}:${startAfter || "first"}`;
4074
- return this.deduplicate(cacheKey, async () => {
4075
- const response = await this.fetchWithAuth(this.baseUrl, {
4076
- action: "page",
4077
- workspaceId,
4078
- date,
4079
- shift: shiftId.toString(),
4080
- category,
4081
- pageSize,
4082
- startAfter,
4083
- sopCategories: this.sopCategories
4084
- });
4085
- return {
4086
- videos: response.videos,
4087
- nextToken: response.nextToken,
4088
- hasMore: response.hasMore
4089
- };
4090
- });
4091
- }
4092
- /**
4093
- * Batch fetch multiple videos in parallel
4094
- */
4095
- async batchFetchVideos(workspaceId, date, shiftId, requests) {
4096
- const batchKey = `batch:${workspaceId}:${date}:${shiftId}:${requests.length}`;
4097
- return this.deduplicate(batchKey, async () => {
4098
- const response = await this.fetchWithAuth("/api/clips/batch", {
4099
- workspaceId,
4100
- date,
4101
- shift: shiftId.toString(),
4102
- requests,
4103
- sopCategories: this.sopCategories
4104
- });
4105
- console.log(`[S3ClipsAPIClient] Batch fetched ${response.videos.length} videos in ${response.performance.duration}ms`);
4106
- return response.videos;
4107
- });
4108
- }
4109
- /**
4110
- * Convert S3 URI to CloudFront URL
4111
- * In the API client, URLs are already signed from the server
4112
- */
4113
- s3UriToCloudfront(s3Uri) {
4114
- return s3Uri;
4115
- }
4116
- /**
4117
- * Clean up resources
4118
- */
4119
- dispose() {
4120
- this.requestCache.clear();
4121
- }
4122
- /**
4123
- * Get service statistics
4124
- */
4125
- getStats() {
4126
- return {
4127
- requestCache: {
4128
- pendingCount: this.requestCache.size,
4129
- maxSize: 1e3
4130
- }
4131
- };
4132
- }
4133
- };
4134
-
4135
- // src/lib/api/s3-clips-secure.ts
4136
- var S3ClipsService = class {
4137
- constructor(config) {
4138
- // Flags for compatibility
4139
- this.isIndexBuilding = false;
4140
- this.isPrefetching = false;
4141
- this.currentMetadataFetches = 0;
4142
- this.MAX_CONCURRENT_METADATA = 3;
4143
- this.config = config;
4144
- if (!config.s3Config) {
4145
- throw new Error("S3 configuration is required");
4146
- }
4147
- const sopCategories = config.s3Config.sopCategories?.default;
4148
- this.apiClient = new S3ClipsAPIClient(sopCategories);
4149
- const processing = config.s3Config.processing || {};
4150
- this.defaultLimitPerCategory = processing.defaultLimitPerCategory || 30;
4151
- this.maxLimitPerCategory = processing.maxLimitPerCategory || 1e3;
4152
- this.concurrencyLimit = processing.concurrencyLimit || 10;
4153
- this.maxInitialFetch = processing.maxInitialFetch || 60;
4154
- console.log("[S3ClipsService] \u2705 Initialized with secure API client - AWS credentials are now server-side only!");
4155
- }
4156
- /**
4157
- * Lists S3 clips using API
4158
- */
4159
- async listS3Clips(params) {
4160
- const { workspaceId, date, shiftId } = params;
4161
- if (!isValidShiftId(shiftId)) {
4162
- console.error(`[S3ClipsService] Invalid shift ID: ${shiftId}`);
4163
- return [];
4164
- }
4165
- console.log(`[S3ClipsService] Listing clips via API for workspace: ${workspaceId}`);
4166
- try {
4167
- return await this.apiClient.listS3Clips(params);
4168
- } catch (error) {
4169
- console.error("[S3ClipsService] Error listing clips:", error);
4170
- return [];
4171
- }
4172
- }
4173
- /**
4174
- * Get metadata cycle time
4175
- */
4176
- async getMetadataCycleTime(playlistUri) {
4177
- try {
4178
- return await this.apiClient.getMetadataCycleTime(playlistUri);
4179
- } catch (error) {
4180
- console.error("[S3ClipsService] Error fetching metadata cycle time:", error);
4181
- return null;
4182
- }
4183
- }
4184
- /**
4185
- * Control prefetch mode
4186
- */
4187
- setPrefetchMode(enabled) {
4188
- this.isPrefetching = enabled;
4189
- console.log(`[S3ClipsService] Prefetch mode ${enabled ? "enabled" : "disabled"}`);
4190
- }
4191
- /**
4192
- * Get full metadata
4193
- */
4194
- async getFullMetadata(playlistUri) {
4195
- if (this.isIndexBuilding || this.isPrefetching) {
4196
- console.warn("[S3ClipsService] Skipping metadata - operation in progress");
4197
- return null;
4198
- }
4199
- if (this.currentMetadataFetches >= this.MAX_CONCURRENT_METADATA) {
4200
- console.warn("[S3ClipsService] Skipping metadata - max concurrent fetches reached");
4201
- return null;
4202
- }
4203
- this.currentMetadataFetches++;
4204
- try {
4205
- return await this.apiClient.getMetadata(playlistUri);
4206
- } catch (error) {
4207
- console.error("[S3ClipsService] Error fetching metadata:", error);
4208
- return null;
4209
- } finally {
4210
- this.currentMetadataFetches--;
4211
- }
4212
- }
4213
- /**
4214
- * Convert S3 URI to CloudFront URL
4215
- * URLs from API are already signed
4216
- */
4217
- s3UriToCloudfront(s3Uri) {
4218
- if (s3Uri.startsWith("http")) {
4219
- return s3Uri;
4220
- }
4221
- console.warn("[S3ClipsService] Unexpected S3 URI in secure mode:", s3Uri);
4222
- return s3Uri;
4223
- }
4224
- /**
4225
- * Get SOP categories for workspace
4226
- */
4227
- getSOPCategories(workspaceId) {
4228
- const sopConfig = this.config.s3Config?.sopCategories;
4229
- if (!sopConfig) return void 0;
4230
- if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
4231
- return sopConfig.workspaceOverrides[workspaceId];
4232
- }
4233
- return sopConfig.default;
4234
- }
4235
- async getClipCounts(workspaceId, date, shiftId, buildIndex) {
4236
- if (!isValidShiftId(shiftId)) {
4237
- console.error(`[S3ClipsService] Invalid shift ID: ${shiftId}`);
4238
- return buildIndex ? { counts: {}, videoIndex: this.createEmptyVideoIndex(workspaceId, date, shiftId.toString()) } : {};
4239
- }
4240
- try {
4241
- if (buildIndex) {
4242
- const result = await this.apiClient.getClipCountsWithIndex(workspaceId, date, shiftId);
4243
- const cacheKey = `clip-counts:${workspaceId}:${date}:${shiftId}`;
4244
- await smartVideoCache.setClipCounts(cacheKey, result);
4245
- return result;
4246
- } else {
4247
- const counts = await this.apiClient.getClipCounts(workspaceId, date, shiftId);
4248
- return counts;
4249
- }
4250
- } catch (error) {
4251
- console.error("[S3ClipsService] Error fetching clip counts:", error);
4252
- return buildIndex ? { counts: {}, videoIndex: this.createEmptyVideoIndex(workspaceId, date, shiftId.toString()) } : {};
4253
- }
4254
- }
4255
- async getClipCountsCacheFirst(workspaceId, date, shiftId, buildIndex) {
4256
- const cacheKey = `clip-counts:${workspaceId}:${date}:${shiftId}`;
4257
- const cachedResult = await smartVideoCache.getClipCounts(cacheKey);
4258
- if (cachedResult) {
4259
- console.log("[S3ClipsService] Using cached clip counts");
4260
- return buildIndex ? cachedResult : cachedResult.counts;
4261
- }
4262
- console.log("[S3ClipsService] Cache miss - fetching from API");
4263
- return buildIndex ? this.getClipCounts(workspaceId, date, shiftId, true) : this.getClipCounts(workspaceId, date, shiftId);
4264
- }
4265
- /**
4266
- * Get first clip for category
4267
- */
4268
- async getFirstClipForCategory(workspaceId, date, shiftId, category) {
4269
- if (!isValidShiftId(shiftId)) {
4270
- console.error(`[S3ClipsService] Invalid shift ID: ${shiftId}`);
4271
- return null;
4272
- }
4273
- try {
4274
- return await this.apiClient.getFirstClipForCategory(workspaceId, date, shiftId, category);
4275
- } catch (error) {
4276
- console.error("[S3ClipsService] Error fetching first clip:", error);
4277
- return null;
4278
- }
4279
- }
4280
- /**
4281
- * Get video from index (for compatibility)
4282
- */
4283
- async getVideoFromIndex(videoIndex, category, index, includeCycleTime = true, includeMetadata = true) {
4284
- const { workspaceId, date, shiftId } = videoIndex;
4285
- return this.getClipByIndex(
4286
- workspaceId,
4287
- date,
4288
- shiftId,
4289
- category,
4290
- index,
4291
- includeCycleTime,
4292
- includeMetadata
4293
- );
4294
- }
4295
- /**
4296
- * Get clip by index
4297
- */
4298
- async getClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
4299
- try {
4300
- return await this.apiClient.getClipByIndex(
4301
- workspaceId,
4302
- date,
4303
- shiftId,
4304
- category,
4305
- index,
4306
- includeCycleTime,
4307
- includeMetadata
4308
- );
4309
- } catch (error) {
4310
- console.error("[S3ClipsService] Error fetching clip by index:", error);
4311
- return null;
4312
- }
4313
- }
4314
- /**
4315
- * Process full video (for compatibility)
4316
- */
4317
- async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime, includeMetadata = false) {
4318
- const sopCategories = this.getSOPCategories(workspaceId);
4319
- const parsedInfo = parseS3Uri(uri, sopCategories);
4320
- if (!parsedInfo) {
4321
- console.warn(`Skipping URI due to parsing failure: ${uri}`);
4322
- return null;
4323
- }
4324
- const video = {
4325
- id: `${workspaceId}-${date}-${shiftId}-${index}`,
4326
- src: uri,
4327
- // Already signed from API
4328
- ...parsedInfo,
4329
- originalUri: uri
4330
- };
4331
- if (includeMetadata) {
4332
- const metadata = await this.getFullMetadata(uri);
4333
- if (metadata) {
4334
- video.cycle_time_seconds = metadata.original_task_metadata?.cycle_time;
4335
- video.creation_timestamp = metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp;
4336
- }
4337
- }
4338
- return video;
4339
- }
4340
- /**
4341
- * Fetch clips (main method for compatibility)
4342
- */
4343
- async fetchClips(params) {
4344
- const {
4345
- workspaceId,
4346
- date: inputDate,
4347
- shift,
4348
- category,
4349
- limit,
4350
- offset = 0,
4351
- mode
4352
- } = params;
4353
- if (!workspaceId) {
4354
- throw new Error("Valid Workspace ID is required");
4355
- }
4356
- const date = inputDate || getOperationalDate(
4357
- this.config.dateTimeConfig?.defaultTimezone || "Asia/Kolkata",
4358
- /* @__PURE__ */ new Date(),
4359
- this.config.shiftConfig?.dayShift?.startTime || "06:00"
4360
- );
4361
- if (!isValidDateFormat(date)) {
4362
- throw new Error("Invalid date format. Use YYYY-MM-DD.");
4363
- }
4364
- let shiftId;
4365
- if (shift !== void 0) {
4366
- if (!isValidShiftId(shift)) {
4367
- throw new Error("Invalid shift value. Must be 0 (day) or 1 (night).");
4368
- }
4369
- shiftId = parseInt(shift, 10);
4370
- } else {
4371
- const { shiftId: currentShiftId } = getCurrentShift(
4372
- this.config.dateTimeConfig?.defaultTimezone || "Asia/Kolkata",
4373
- this.config.shiftConfig
4374
- );
4375
- shiftId = currentShiftId;
4376
- }
4377
- console.log(`[S3ClipsService] Fetching clips for workspace ${workspaceId}`);
4378
- if (mode === "summary") {
4379
- const counts = await this.getClipCounts(workspaceId, date, shiftId.toString());
4380
- return { counts, samples: {} };
4381
- }
4382
- const effectiveLimit = limit || this.defaultLimitPerCategory;
4383
- const result = await this.getVideosPage(
4384
- workspaceId,
4385
- date,
4386
- shiftId,
4387
- category || "all",
4388
- effectiveLimit
4389
- );
4390
- return result.videos;
4391
- }
4392
- /**
4393
- * Batch fetch multiple videos in parallel
4394
- */
4395
- async batchFetchVideos(workspaceId, date, shiftId, requests) {
4396
- try {
4397
- const results = await this.apiClient.batchFetchVideos(
4398
- workspaceId,
4399
- date,
4400
- shiftId,
4401
- requests
4402
- );
4403
- return results.map((r2) => r2.video).filter((v) => v !== null);
4404
- } catch (error) {
4405
- console.error("[S3ClipsService] Error batch fetching videos:", error);
4406
- return [];
4407
- }
4408
- }
4409
- /**
4410
- * Get videos page using pagination API
4411
- */
4412
- async getVideosPage(workspaceId, date, shiftId, category, pageSize = 5, startAfter) {
4413
- try {
4414
- return await this.apiClient.getVideosPage(
4415
- workspaceId,
4416
- date,
4417
- shiftId,
4418
- category,
4419
- pageSize,
4420
- startAfter
4421
- );
4422
- } catch (error) {
4423
- console.error("[S3ClipsService] Error fetching videos page:", error);
4424
- return { videos: [], hasMore: false };
4425
- }
4426
- }
4427
- /**
4428
- * Create empty video index for compatibility
4429
- */
4430
- createEmptyVideoIndex(workspaceId, date, shiftId) {
4431
- return {
4432
- byCategory: /* @__PURE__ */ new Map(),
4433
- allVideos: [],
4434
- counts: {},
4435
- workspaceId,
4436
- date,
4437
- shiftId,
4438
- lastUpdated: /* @__PURE__ */ new Date(),
4439
- _debugId: `empty_${Date.now()}`
4440
- };
4441
- }
4442
- /**
4443
- * Get clip by ID
4444
- */
4445
- async getClipById(clipId, sopCategories) {
4446
- console.log(`[S3ClipsService] Getting clip by ID: ${clipId} (Note: This is a fallback implementation)`);
4447
- try {
4448
- const parts = clipId.split("-");
4449
- if (parts.length >= 5) {
4450
- const workspaceId = parts[0];
4451
- const date = parts[1];
4452
- const shift = parts[2];
4453
- const category = parts[3];
4454
- const index = parseInt(parts[4], 10);
4455
- if (!isNaN(index)) {
4456
- return await this.getClipByIndex(workspaceId, date, shift, category, index, true, false);
4457
- }
4458
- }
4459
- console.warn(`[S3ClipsService] Could not parse clipId: ${clipId}`);
4460
- return null;
4461
- } catch (error) {
4462
- console.error("[S3ClipsService] Error getting clip by ID:", error);
4463
- return null;
4464
- }
4465
- }
4466
- /**
4467
- * Get neighboring clips
4468
- */
4469
- async getNeighboringClips(workspaceId, date, shiftId, category, currentClipId, sopCategories) {
4470
- console.log(`[S3ClipsService] Getting neighboring clips for ID: ${currentClipId} (Note: This is a fallback implementation)`);
4471
- try {
4472
- const parts = currentClipId.split("-");
4473
- if (parts.length >= 5) {
4474
- const index = parseInt(parts[4], 10);
4475
- if (!isNaN(index)) {
4476
- const [previous, next] = await Promise.all([
4477
- index > 0 ? this.getClipByIndex(workspaceId, date, shiftId, category, index - 1, true, false) : null,
4478
- this.getClipByIndex(workspaceId, date, shiftId, category, index + 1, true, false)
4479
- ]);
4480
- return { previous, next };
4481
- }
4482
- }
4483
- console.warn(`[S3ClipsService] Could not parse currentClipId: ${currentClipId}`);
4484
- return { previous: null, next: null };
4485
- } catch (error) {
4486
- console.error("[S3ClipsService] Error getting neighboring clips:", error);
4487
- return { previous: null, next: null };
4488
- }
4489
- }
4490
- /**
4491
- * Cleanup
4492
- */
4493
- dispose() {
4494
- console.log("[S3ClipsService] Disposing service");
4495
- this.apiClient.dispose();
4496
- }
4497
- /**
4498
- * Get statistics
4499
- */
4500
- getStats() {
4501
- return this.apiClient.getStats();
4502
- }
4503
- };
4504
- var getSupabaseClient2 = () => {
4505
- const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
4506
- const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
4507
- if (!url || !key) {
4508
- throw new Error("Supabase configuration missing");
4509
- }
4510
- return createClient(url, key);
4511
- };
4512
- var getAuthToken2 = async () => {
4513
- try {
4514
- const supabase = getSupabaseClient2();
4515
- const { data: { session } } = await supabase.auth.getSession();
4516
3587
  console.log("[S3ClipsSupabase] Auth session exists:", !!session, "has token:", !!session?.access_token);
4517
3588
  return session?.access_token || null;
4518
3589
  } catch (error) {
@@ -4543,7 +3614,7 @@ var S3ClipsSupabaseService = class {
4543
3614
  * Fetch with authentication and error handling
4544
3615
  */
4545
3616
  async fetchWithAuth(endpoint, body) {
4546
- const token = await getAuthToken2();
3617
+ const token = await getAuthToken();
4547
3618
  if (!token) {
4548
3619
  throw new Error("Authentication required");
4549
3620
  }
@@ -5006,7 +4077,8 @@ var S3ClipsSupabaseService = class {
5006
4077
  return descriptions[clipType] || "Analysis Clip";
5007
4078
  }
5008
4079
  };
5009
- var S3ClipsService2 = S3ClipsSupabaseService ;
4080
+
4081
+ // src/lib/services/videoPrefetchManager.ts
5010
4082
  var VideoPrefetchManager = class extends EventEmitter {
5011
4083
  constructor() {
5012
4084
  super();
@@ -5020,7 +4092,7 @@ var VideoPrefetchManager = class extends EventEmitter {
5020
4092
  getS3Service(dashboardConfig) {
5021
4093
  const configKey = JSON.stringify(dashboardConfig.s3Config);
5022
4094
  if (!this.s3Services.has(configKey)) {
5023
- this.s3Services.set(configKey, new S3ClipsService2(dashboardConfig));
4095
+ this.s3Services.set(configKey, new S3ClipsSupabaseService(dashboardConfig));
5024
4096
  }
5025
4097
  return this.s3Services.get(configKey);
5026
4098
  }
@@ -22805,32 +21877,10 @@ var VideoGridView = React20__default.memo(({
22805
21877
  observerRef.current?.disconnect();
22806
21878
  };
22807
21879
  }, [filteredWorkspaces]);
22808
- const prefetchCacheRef = useRef({});
21880
+ useRef({});
22809
21881
  const handleWorkspaceClick = useCallback((workspace) => {
22810
21882
  const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
22811
- if (dashboardConfig?.s3Config && workspaceId) {
22812
- const operationalDate = getOperationalDate(dashboardConfig.dateTimeConfig?.defaultTimezone);
22813
- const fullKey = `${workspaceId}-${operationalDate}-all-all-meta-1000--`;
22814
- if (!prefetchCacheRef.current[fullKey]?.status) {
22815
- const clipsService = new S3ClipsService(dashboardConfig);
22816
- const fullPromise = clipsService.fetchClips({
22817
- workspaceId,
22818
- date: operationalDate,
22819
- mode: "full",
22820
- includeCycleTime: true,
22821
- includeMetadata: true,
22822
- limit: 1e3
22823
- });
22824
- prefetchCacheRef.current[fullKey] = { status: "pending", promise: fullPromise };
22825
- fullPromise.then((data) => {
22826
- prefetchCacheRef.current[fullKey] = { status: "resolved", data };
22827
- console.log(`Prefetched full clips data for workspace ${workspaceId}`);
22828
- }).catch((error) => {
22829
- prefetchCacheRef.current[fullKey] = { status: "rejected", error };
22830
- console.warn(`Failed to prefetch full clips for workspace ${workspaceId}:`, error);
22831
- });
22832
- }
22833
- }
21883
+ console.log(`[VideoGridView] Prefetching disabled for workspace ${workspaceId}`);
22834
21884
  trackCoreEvent("Workspace Detail Clicked", {
22835
21885
  workspace_name: workspace.workspace_name,
22836
21886
  workspace_id: workspaceId,
@@ -28887,7 +27937,7 @@ var NewClipsNotification = ({
28887
27937
  }
28888
27938
  );
28889
27939
  };
28890
- var getSupabaseClient3 = () => {
27940
+ var getSupabaseClient2 = () => {
28891
27941
  const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
28892
27942
  const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
28893
27943
  if (!url || !key) {
@@ -28895,9 +27945,9 @@ var getSupabaseClient3 = () => {
28895
27945
  }
28896
27946
  return createClient(url, key);
28897
27947
  };
28898
- var getAuthToken3 = async () => {
27948
+ var getAuthToken2 = async () => {
28899
27949
  try {
28900
- const supabase = getSupabaseClient3();
27950
+ const supabase = getSupabaseClient2();
28901
27951
  const { data: { session } } = await supabase.auth.getSession();
28902
27952
  return session?.access_token || null;
28903
27953
  } catch (error) {
@@ -28918,7 +27968,7 @@ function useWorkspaceCrop(workspaceId) {
28918
27968
  setIsLoading(true);
28919
27969
  setError(null);
28920
27970
  try {
28921
- const token = await getAuthToken3();
27971
+ const token = await getAuthToken2();
28922
27972
  if (!token) {
28923
27973
  throw new Error("Authentication required");
28924
27974
  }
@@ -29071,7 +28121,7 @@ var FileManagerFilters = ({
29071
28121
  method: "POST",
29072
28122
  headers: {
29073
28123
  "Content-Type": "application/json",
29074
- "Authorization": `Bearer ${await getAuthToken4()}`
28124
+ "Authorization": `Bearer ${await getAuthToken3()}`
29075
28125
  },
29076
28126
  body: JSON.stringify({
29077
28127
  action: "clip-metadata",
@@ -29104,10 +28154,10 @@ var FileManagerFilters = ({
29104
28154
  });
29105
28155
  }
29106
28156
  }, [workspaceId, date, shift]);
29107
- const getAuthToken4 = async () => {
28157
+ const getAuthToken3 = async () => {
29108
28158
  try {
29109
- const { createClient: createClient5 } = await import('@supabase/supabase-js');
29110
- const supabase = createClient5(
28159
+ const { createClient: createClient4 } = await import('@supabase/supabase-js');
28160
+ const supabase = createClient4(
29111
28161
  process.env.NEXT_PUBLIC_SUPABASE_URL || "",
29112
28162
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ""
29113
28163
  );
@@ -29130,7 +28180,7 @@ var FileManagerFilters = ({
29130
28180
  method: "POST",
29131
28181
  headers: {
29132
28182
  "Content-Type": "application/json",
29133
- "Authorization": `Bearer ${await getAuthToken4()}`
28183
+ "Authorization": `Bearer ${await getAuthToken3()}`
29134
28184
  },
29135
28185
  body: JSON.stringify({
29136
28186
  action: "percentile-clips",
@@ -29873,8 +28923,6 @@ function useClipsRealtimeUpdates({
29873
28923
  hasNewClips: newClipsNotification !== null && newClipsNotification.count > 0
29874
28924
  };
29875
28925
  }
29876
- var USE_SUPABASE_CLIPS2 = true;
29877
- var S3ClipsService3 = S3ClipsSupabaseService ;
29878
28926
  var BottlenecksContent = ({
29879
28927
  workspaceId,
29880
28928
  workspaceName,
@@ -29932,8 +28980,8 @@ var BottlenecksContent = ({
29932
28980
  workspaceId,
29933
28981
  date: date || getOperationalDate(),
29934
28982
  shiftId: effectiveShift,
29935
- enabled: USE_SUPABASE_CLIPS2,
29936
- // Only enable for Supabase implementation
28983
+ enabled: true,
28984
+ // Supabase implementation
29937
28985
  onNewClips: (notification) => {
29938
28986
  console.log(`[BottlenecksContent] New clips detected:`, notification);
29939
28987
  if (notification.clips.length > 0) {
@@ -29958,7 +29006,7 @@ var BottlenecksContent = ({
29958
29006
  console.warn("S3 configuration not found in dashboard config");
29959
29007
  return null;
29960
29008
  }
29961
- return new S3ClipsService3(dashboardConfig);
29009
+ return new S3ClipsSupabaseService(dashboardConfig);
29962
29010
  }, [dashboardConfig]);
29963
29011
  const {
29964
29012
  clipTypes,
@@ -29979,8 +29027,7 @@ var BottlenecksContent = ({
29979
29027
  dynamicCounts,
29980
29028
  workspaceId,
29981
29029
  date: date || getOperationalDate(),
29982
- shift: shift || "0",
29983
- USE_SUPABASE_CLIPS: USE_SUPABASE_CLIPS2
29030
+ shift: shift || "0"
29984
29031
  });
29985
29032
  useEffect(() => {
29986
29033
  if (clipTypes.length > 0 && !initialFilter) {
@@ -30088,12 +29135,8 @@ var BottlenecksContent = ({
30088
29135
  operationalDate,
30089
29136
  shiftStr,
30090
29137
  targetCategory,
30091
- 0,
29138
+ 0
30092
29139
  // First video (index 0)
30093
- true,
30094
- // includeCycleTime
30095
- true
30096
- // includeMetadata
30097
29140
  );
30098
29141
  if (firstVideo && isMountedRef.current) {
30099
29142
  console.log(`[BottlenecksContent] Successfully loaded first video via index`);
@@ -30237,8 +29280,8 @@ var BottlenecksContent = ({
30237
29280
  if (isPercentileCategory(categoryId)) {
30238
29281
  console.log(`[BottlenecksContent] Loading percentile category: ${categoryId}`);
30239
29282
  const percentileType = categoryId === "fast-cycles" ? "fast-cycles" : categoryId === "slow-cycles" ? "slow-cycles" : "idle-times";
30240
- const { createClient: createClient5 } = await import('@supabase/supabase-js');
30241
- const supabase = createClient5(
29283
+ const { createClient: createClient4 } = await import('@supabase/supabase-js');
29284
+ const supabase = createClient4(
30242
29285
  process.env.NEXT_PUBLIC_SUPABASE_URL || "",
30243
29286
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ""
30244
29287
  );
@@ -30310,9 +29353,7 @@ var BottlenecksContent = ({
30310
29353
  operationalDate,
30311
29354
  shiftStr,
30312
29355
  categoryId,
30313
- clipIndex,
30314
- true,
30315
- true
29356
+ clipIndex
30316
29357
  );
30317
29358
  if (video?.id) {
30318
29359
  await loadAndPlayClipById(video.id, categoryId);
@@ -44476,4 +43517,175 @@ var streamProxyConfig = {
44476
43517
  }
44477
43518
  };
44478
43519
 
44479
- export { ACTION_NAMES, AIAgentView_default as AIAgentView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedWorkspaceHealthView, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TimeDisplay_default as TimeDisplay, TimePickerDropdown, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useAllWorkspaceMetrics, useAnalyticsConfig, useAudioService, useAuth, useAuthConfig, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useTicketHistory, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealth, useWorkspaceHealthById, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, workspaceHealthService, workspaceService };
43520
+ // src/lib/api/s3-clips-parser.ts
43521
+ function parseS3Uri(s3Uri, sopCategories) {
43522
+ const path = new URL(s3Uri).pathname;
43523
+ const parts = path.split("/").filter((p) => p);
43524
+ if (s3Uri.includes("missed_qchecks")) {
43525
+ console.warn(`Skipping missed_qchecks URI in parseS3Uri: ${s3Uri}`);
43526
+ return null;
43527
+ }
43528
+ if (parts.length < 8) {
43529
+ console.warn(`Invalid S3 path structure: ${s3Uri} - Too few parts: ${parts.length}, expected at least 8`);
43530
+ return null;
43531
+ }
43532
+ try {
43533
+ const datePart = parts[2];
43534
+ const shiftPart = parts[3];
43535
+ const violationType = parts[4];
43536
+ let folderName = "";
43537
+ let timestamp = "";
43538
+ for (let i = 5; i < parts.length; i++) {
43539
+ const part = parts[i];
43540
+ if (part && part.includes("_") && /\d{8}_\d{6}/.test(part)) {
43541
+ folderName = part;
43542
+ const timeMatch = folderName.match(/_(\d{8})_(\d{6})_/);
43543
+ if (timeMatch) {
43544
+ timestamp = `${timeMatch[2].substring(0, 2)}:${timeMatch[2].substring(2, 4)}:${timeMatch[2].substring(4, 6)}`;
43545
+ break;
43546
+ }
43547
+ }
43548
+ }
43549
+ if (!timestamp) {
43550
+ console.warn(`Couldn't extract timestamp from any part: ${parts.join("/")}`);
43551
+ timestamp = "00:00:00";
43552
+ }
43553
+ let severity = "low";
43554
+ let type = "bottleneck";
43555
+ let description = "Analysis Clip";
43556
+ const normalizedViolationType = violationType.toLowerCase().trim();
43557
+ if (sopCategories && sopCategories.length > 0) {
43558
+ const matchedCategory = sopCategories.find((category) => {
43559
+ const categoryId = category.id.toLowerCase();
43560
+ const s3FolderName = (category.s3FolderName || category.id).toLowerCase();
43561
+ return categoryId === normalizedViolationType || s3FolderName === normalizedViolationType || // Also check for partial matches for flexibility
43562
+ normalizedViolationType.includes(categoryId) || normalizedViolationType.includes(s3FolderName);
43563
+ });
43564
+ if (matchedCategory) {
43565
+ type = matchedCategory.id;
43566
+ description = matchedCategory.description || matchedCategory.label;
43567
+ if (matchedCategory.color.includes("red")) {
43568
+ severity = "high";
43569
+ } else if (matchedCategory.color.includes("yellow") || matchedCategory.color.includes("orange")) {
43570
+ severity = "medium";
43571
+ } else {
43572
+ severity = "low";
43573
+ }
43574
+ console.log(`Matched SOP category: ${matchedCategory.id} for violation type: ${violationType}`);
43575
+ return { timestamp, severity, description, type, originalUri: s3Uri };
43576
+ }
43577
+ }
43578
+ switch (normalizedViolationType) {
43579
+ case "idle_time":
43580
+ case "idle":
43581
+ case "low_value":
43582
+ case "low value":
43583
+ case "low_value_moment":
43584
+ case "low_value_moments":
43585
+ case "low value moment":
43586
+ case "low value moments":
43587
+ type = "low_value";
43588
+ severity = "low";
43589
+ description = "Idle Time Detected";
43590
+ break;
43591
+ case "sop_deviation":
43592
+ type = "missing_quality_check";
43593
+ severity = "high";
43594
+ description = "SOP Deviations";
43595
+ break;
43596
+ case "long_cycle_time":
43597
+ severity = "high";
43598
+ type = "long_cycle_time";
43599
+ description = "Long Cycle Time Detected";
43600
+ break;
43601
+ case "best_cycle_time":
43602
+ type = "best_cycle_time";
43603
+ severity = "low";
43604
+ description = "Best Cycle Time Performance";
43605
+ break;
43606
+ case "worst_cycle_time":
43607
+ type = "worst_cycle_time";
43608
+ severity = "high";
43609
+ description = "Worst Cycle Time Performance";
43610
+ break;
43611
+ case "cycle_completion":
43612
+ case "completed_cycles":
43613
+ case "completed_cycle":
43614
+ type = "cycle_completion";
43615
+ severity = "low";
43616
+ description = "Cycle Completion";
43617
+ break;
43618
+ case "running_cycle":
43619
+ case "active_cycle":
43620
+ case "production_cycle":
43621
+ type = "running_cycle";
43622
+ severity = "low";
43623
+ description = "Active Production Cycle";
43624
+ break;
43625
+ case "setup_state":
43626
+ case "machine_setup":
43627
+ case "line_setup":
43628
+ type = "setup_state";
43629
+ severity = "medium";
43630
+ description = "Machine Setup Activity";
43631
+ break;
43632
+ case "medium_bottleneck":
43633
+ severity = "medium";
43634
+ description = "Medium Bottleneck Identified";
43635
+ break;
43636
+ case "minor_bottleneck":
43637
+ case "mild_bottleneck":
43638
+ severity = "low";
43639
+ description = "Minor Bottleneck Identified";
43640
+ break;
43641
+ default:
43642
+ if (normalizedViolationType.includes("sop") && normalizedViolationType.includes("deviation")) {
43643
+ type = "missing_quality_check";
43644
+ severity = "high";
43645
+ description = "SOP Deviations";
43646
+ } else if (normalizedViolationType.includes("worst") && normalizedViolationType.includes("cycle")) {
43647
+ type = "worst_cycle_time";
43648
+ severity = "high";
43649
+ description = "Worst Cycle Time Performance";
43650
+ } else if (normalizedViolationType.includes("best") && normalizedViolationType.includes("cycle")) {
43651
+ type = "best_cycle_time";
43652
+ severity = "low";
43653
+ description = "Best Cycle Time Performance";
43654
+ } else if (normalizedViolationType.includes("long") && normalizedViolationType.includes("cycle")) {
43655
+ type = "long_cycle_time";
43656
+ severity = "high";
43657
+ description = "Long Cycle Time Detected";
43658
+ } else if (normalizedViolationType.includes("cycle") && (normalizedViolationType.includes("completion") || normalizedViolationType.includes("complete"))) {
43659
+ type = "cycle_completion";
43660
+ severity = "low";
43661
+ description = "Cycle Completion";
43662
+ } else if (normalizedViolationType.includes("running") && normalizedViolationType.includes("cycle")) {
43663
+ type = "running_cycle";
43664
+ severity = "low";
43665
+ description = "Active Production Cycle";
43666
+ } else if (normalizedViolationType.includes("setup") || normalizedViolationType.includes("machine") && normalizedViolationType.includes("setup")) {
43667
+ type = "setup_state";
43668
+ severity = "medium";
43669
+ description = "Machine Setup Activity";
43670
+ } else {
43671
+ description = `Clip type: ${violationType.replace(/_/g, " ")}`;
43672
+ console.log(`Detected unknown violation type: ${violationType} in URI: ${s3Uri}`);
43673
+ }
43674
+ break;
43675
+ }
43676
+ return { timestamp, severity, description, type, originalUri: s3Uri };
43677
+ } catch (error) {
43678
+ console.error(`Error parsing S3 URI: ${s3Uri}`, error);
43679
+ return null;
43680
+ }
43681
+ }
43682
+ function shuffleArray(array) {
43683
+ const shuffled = [...array];
43684
+ for (let i = shuffled.length - 1; i > 0; i--) {
43685
+ const j = Math.floor(Math.random() * (i + 1));
43686
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
43687
+ }
43688
+ return shuffled;
43689
+ }
43690
+
43691
+ export { ACTION_NAMES, AIAgentView_default as AIAgentView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedWorkspaceHealthView, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TimeDisplay_default as TimeDisplay, TimePickerDropdown, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useAllWorkspaceMetrics, useAnalyticsConfig, useAudioService, useAuth, useAuthConfig, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useTicketHistory, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealth, useWorkspaceHealthById, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, workspaceHealthService, workspaceService };