lightning-pose-app 1.8.1a2__py3-none-any.whl → 1.8.1a4__py3-none-any.whl

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.
Files changed (28) hide show
  1. lightning_pose_app-1.8.1a4.dist-info/METADATA +20 -0
  2. lightning_pose_app-1.8.1a4.dist-info/RECORD +29 -0
  3. litpose_app/config.py +22 -0
  4. litpose_app/deps.py +77 -0
  5. litpose_app/main.py +46 -188
  6. litpose_app/ngdist/ng_app/3rdpartylicenses.txt +11 -11
  7. litpose_app/ngdist/ng_app/index.html +3 -2
  8. litpose_app/ngdist/ng_app/{main-WFYIUX2C.js → main-VCJFCLFP.js} +184 -61
  9. litpose_app/ngdist/ng_app/main-VCJFCLFP.js.map +1 -0
  10. litpose_app/ngdist/ng_app/{styles-AJ6NQDUD.css → styles-ZM27COY6.css} +37 -7
  11. litpose_app/ngdist/ng_app/styles-ZM27COY6.css.map +7 -0
  12. litpose_app/ngdist/ng_app/video-tile.component-RDL4BSJ4.css.map +7 -0
  13. litpose_app/{run_ffprobe.py → routes/ffprobe.py} +34 -2
  14. litpose_app/{super_rglob.py → routes/files.py} +60 -0
  15. litpose_app/routes/project.py +72 -0
  16. litpose_app/routes/transcode.py +67 -0
  17. litpose_app/tasks/__init__.py +0 -0
  18. litpose_app/tasks/management.py +2 -0
  19. litpose_app/tasks/transcode_fine.py +7 -0
  20. litpose_app/transcode_fine.py +175 -0
  21. lightning_pose_app-1.8.1a2.dist-info/METADATA +0 -15
  22. lightning_pose_app-1.8.1a2.dist-info/RECORD +0 -20
  23. litpose_app/ngdist/ng_app/main-WFYIUX2C.js.map +0 -1
  24. litpose_app/ngdist/ng_app/styles-AJ6NQDUD.css.map +0 -7
  25. {lightning_pose_app-1.8.1a2.dist-info → lightning_pose_app-1.8.1a4.dist-info}/WHEEL +0 -0
  26. /litpose_app/ngdist/ng_app/{app.component-IZ5OUDH2.css.map → app.component-UAQUAGNZ.css.map} +0 -0
  27. /litpose_app/ngdist/ng_app/{project-settings.component-BXKZMYM3.css.map → project-settings.component-HKHIVUJR.css.map} +0 -0
  28. /litpose_app/ngdist/ng_app/{viewer-page.component-KIYG73MW.css.map → viewer-page.component-KDHT6XH5.css.map} +0 -0
@@ -40016,10 +40016,18 @@ var ProjectInfoService = class _ProjectInfoService {
40016
40016
  // undefined means not yet requested
40017
40017
  // null means requested and not present
40018
40018
  _projectInfo = void 0;
40019
+ // The directory that we are storing fine videos in.
40020
+ fineVideoDir = "";
40019
40021
  async loadProjectInfo() {
40020
- const response = await this.rpc.call("getProjectInfo");
40021
- this._projectInfo = response.projectInfo ? new ProjectInfo(response.projectInfo) : null;
40022
- this.setAllViews(this._projectInfo?.views ?? []);
40022
+ const promises = [];
40023
+ promises.push(this.rpc.call("getProjectInfo").then((response) => {
40024
+ this._projectInfo = response.projectInfo ? new ProjectInfo(response.projectInfo) : null;
40025
+ this.setAllViews(this._projectInfo?.views ?? []);
40026
+ }));
40027
+ promises.push(this.rpc.call("getFineVideoDir").then((response) => {
40028
+ this.fineVideoDir = response.path;
40029
+ }));
40030
+ return Promise.allSettled(promises);
40023
40031
  }
40024
40032
  get projectInfo() {
40025
40033
  return this._projectInfo;
@@ -40182,6 +40190,32 @@ var CsvParserService = class _CsvParserService {
40182
40190
  }], null, null);
40183
40191
  })();
40184
40192
 
40193
+ // src/app/utils/comparators.ts
40194
+ var compareStringArraysOrdered = (prev, curr) => {
40195
+ if (prev.length !== curr.length) {
40196
+ return false;
40197
+ }
40198
+ for (let i = 0; i < prev.length; i++) {
40199
+ if (prev[i] !== curr[i]) {
40200
+ return false;
40201
+ }
40202
+ }
40203
+ return true;
40204
+ };
40205
+ var createSessionViewComparator = (allViewsOrder) => {
40206
+ return (a, b) => {
40207
+ const indexA = allViewsOrder.indexOf(a.viewName);
40208
+ const indexB = allViewsOrder.indexOf(b.viewName);
40209
+ if (indexA === -1 && indexB === -1)
40210
+ return 0;
40211
+ if (indexA === -1)
40212
+ return 1;
40213
+ if (indexB === -1)
40214
+ return -1;
40215
+ return indexA - indexB;
40216
+ };
40217
+ };
40218
+
40185
40219
  // src/app/session.service.ts
40186
40220
  var SessionService = class _SessionService {
40187
40221
  rpc = inject(RpcService);
@@ -40196,7 +40230,7 @@ var SessionService = class _SessionService {
40196
40230
  const projectInfo = this.projectInfoService.projectInfo;
40197
40231
  const response = await this.rpc.call("rglob", {
40198
40232
  baseDir: projectInfo.data_dir,
40199
- pattern: "**/*.fine.mp4",
40233
+ pattern: "**/*.mp4",
40200
40234
  //temporary
40201
40235
  noDirs: true
40202
40236
  });
@@ -40260,7 +40294,7 @@ var SessionService = class _SessionService {
40260
40294
  this.projectInfoService.setAllKeypoints(allKeypoints);
40261
40295
  }
40262
40296
  getPredictionFilesForSession(sessionKey) {
40263
- const predictionFiles = this.predictionFiles.filter((p) => p.sessionKey === sessionKey || p.sessionKey === sessionKey.replace(/\.fine$/, ""));
40297
+ const predictionFiles = this.predictionFiles.filter((p) => p.sessionKey === sessionKey);
40264
40298
  return predictionFiles;
40265
40299
  }
40266
40300
  async getPredictionFile(pfile) {
@@ -40296,9 +40330,10 @@ var SessionService = class _SessionService {
40296
40330
  videoPath: projectInfo.data_dir + "/" + filename
40297
40331
  });
40298
40332
  }
40333
+ const cmp = createSessionViewComparator(this.projectInfoService.allViews());
40299
40334
  return Array.from(sessionKeyToItsViewFiles.entries()).map(([key, sessionViews]) => ({
40300
40335
  key: key.replace(/\.mp4$/, ""),
40301
- views: sessionViews
40336
+ views: [...sessionViews].sort(cmp)
40302
40337
  }));
40303
40338
  }
40304
40339
  static \u0275fac = function SessionService_Factory(__ngFactoryType__) {
@@ -54406,19 +54441,19 @@ var ViewerSessionsPanelComponent = class _ViewerSessionsPanelComponent {
54406
54441
  // src/app/view-settings.model.ts
54407
54442
  var ViewSettings = class _ViewSettings {
54408
54443
  _viewsShown = new BehaviorSubject([]);
54409
- viewsShown$ = this._viewsShown.asObservable().pipe(distinctUntilChanged());
54444
+ viewsShown$ = this._viewsShown.asObservable().pipe(distinctUntilChanged(compareStringArraysOrdered));
54410
54445
  viewsShown = toSignal(this.viewsShown$, { requireSync: true });
54411
54446
  setViewsShown(selected) {
54412
54447
  this._viewsShown.next(selected);
54413
54448
  }
54414
54449
  _keypointsShown = new BehaviorSubject([]);
54415
- keypointsShown$ = this._keypointsShown.asObservable().pipe(distinctUntilChanged());
54450
+ keypointsShown$ = this._keypointsShown.asObservable().pipe(distinctUntilChanged(compareStringArraysOrdered));
54416
54451
  keypointsShown = toSignal(this.keypointsShown$, { requireSync: true });
54417
54452
  setKeypointsShown(selected) {
54418
54453
  this._keypointsShown.next(selected);
54419
54454
  }
54420
54455
  _modelsShown = new BehaviorSubject([]);
54421
- modelsShown$ = this._modelsShown.asObservable().pipe(distinctUntilChanged());
54456
+ modelsShown$ = this._modelsShown.asObservable().pipe(distinctUntilChanged(compareStringArraysOrdered));
54422
54457
  modelsShown = toSignal(this.modelsShown$, { requireSync: true });
54423
54458
  setModelsShown(selected) {
54424
54459
  this._modelsShown.next(selected);
@@ -54650,17 +54685,27 @@ var VideoPlayerControlsComponent = class _VideoPlayerControlsComponent {
54650
54685
  // src/app/components/video-player/video-tile/video-tile.component.ts
54651
54686
  var _c04 = ["videoEl"];
54652
54687
  var _c13 = ["*"];
54688
+ var videoErrorMessages = {
54689
+ [MediaError.MEDIA_ERR_ABORTED]: "Error: aborted.",
54690
+ [MediaError.MEDIA_ERR_NETWORK]: "Error: network error.",
54691
+ [MediaError.MEDIA_ERR_DECODE]: "Error: decoding error.",
54692
+ [MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED]: "Error: 404 or unsupported video format."
54693
+ };
54653
54694
  var VideoTileComponent = class _VideoTileComponent {
54654
- elementRef;
54695
+ host;
54655
54696
  videoElement = null;
54656
54697
  src = input("");
54657
54698
  // Current time of the video element, for displaying for debug info.
54658
54699
  localCurrentTime = signal(0);
54700
+ videoErrorMessage = linkedSignal(() => {
54701
+ this.src();
54702
+ return "";
54703
+ });
54659
54704
  // the main state, injected from parent so it can be easily shared across video players
54660
54705
  videoPlayerState = inject(VideoPlayerState);
54661
54706
  contentEnd = new EventEmitter();
54662
- constructor(elementRef) {
54663
- this.elementRef = elementRef;
54707
+ constructor(host) {
54708
+ this.host = host;
54664
54709
  this.videoPlayerState.registerVideoPlayer(this);
54665
54710
  combineLatest([
54666
54711
  this.videoPlayerState.currentTime,
@@ -54669,6 +54714,12 @@ var VideoTileComponent = class _VideoTileComponent {
54669
54714
  this.updateLocalCurrentTime();
54670
54715
  });
54671
54716
  }
54717
+ ngOnInit() {
54718
+ const observer = new ResizeObserver(() => {
54719
+ this.updateScaleFactorSignal();
54720
+ });
54721
+ observer.observe(this.host.nativeElement);
54722
+ }
54672
54723
  ngOnDestroy() {
54673
54724
  this.videoPlayerState.unregisterVideoPlayer(this);
54674
54725
  }
@@ -54680,15 +54731,23 @@ var VideoTileComponent = class _VideoTileComponent {
54680
54731
  scaleFactor = signal(1);
54681
54732
  // signal to hide content until video inited
54682
54733
  showProjectedContent = signal(false);
54734
+ onVideoTagError() {
54735
+ const code = this.videoElement?.nativeElement.error?.code;
54736
+ const videoErrorMessage = code ? videoErrorMessages[code] : "Unknown error, check dev logs.";
54737
+ this.videoErrorMessage.set(videoErrorMessage);
54738
+ }
54683
54739
  onLoadedMetadata() {
54684
54740
  this.videoMetadata.next({
54685
54741
  height: this.videoElement?.nativeElement.videoHeight ?? 1,
54686
54742
  width: this.videoElement?.nativeElement.videoWidth ?? 1,
54687
54743
  duration: this.videoElement?.nativeElement.duration ?? 0
54688
54744
  });
54689
- this.scaleFactor.set(this.elementRef.nativeElement.clientWidth / this.videoMetadata.value.width);
54745
+ this.updateScaleFactorSignal();
54690
54746
  this.showProjectedContent.set(true);
54691
54747
  }
54748
+ updateScaleFactorSignal() {
54749
+ this.scaleFactor.set(this.host.nativeElement.clientWidth / this.videoMetadata.value.width);
54750
+ }
54692
54751
  updateLocalCurrentTime() {
54693
54752
  this.localCurrentTime.set(this.videoElement?.nativeElement.currentTime ?? 0);
54694
54753
  }
@@ -54707,7 +54766,7 @@ var VideoTileComponent = class _VideoTileComponent {
54707
54766
  let _t;
54708
54767
  \u0275\u0275queryRefresh(_t = \u0275\u0275loadQuery()) && (ctx.videoElement = _t.first);
54709
54768
  }
54710
- }, inputs: { src: [1, "src"] }, outputs: { contentEnd: "contentEnd" }, ngContentSelectors: _c13, decls: 6, vars: 3, consts: [["videoEl", ""], [1, "relative", "shadow-lg", "shadow-black/20", "bg-base-200"], ["preload", "auto", "muted", "", 1, "w-full", 3, "loadedmetadata", "timeupdate", "ended"], ["type", "video/mp4", 3, "src"]], template: function VideoTileComponent_Template(rf, ctx) {
54769
+ }, inputs: { src: [1, "src"] }, outputs: { contentEnd: "contentEnd" }, ngContentSelectors: _c13, decls: 10, vars: 7, consts: [["videoEl", ""], [1, "relative", "shadow-lg", "shadow-black/20", "bg-base-200"], ["preload", "auto", "muted", "", 3, "loadedmetadata", "timeupdate", "ended", "error", "src"], [1, "absolute", "inset-0", "overflow-auto", "p-2"], [1, "text-sm", "text-gray-400", "mt-2"]], template: function VideoTileComponent_Template(rf, ctx) {
54711
54770
  if (rf & 1) {
54712
54771
  const _r1 = \u0275\u0275getCurrentView();
54713
54772
  \u0275\u0275projectionDef();
@@ -54721,25 +54780,39 @@ var VideoTileComponent = class _VideoTileComponent {
54721
54780
  })("ended", function VideoTileComponent_Template_video_ended_1_listener() {
54722
54781
  \u0275\u0275restoreView(_r1);
54723
54782
  return \u0275\u0275resetView(ctx.onEnd());
54783
+ })("error", function VideoTileComponent_Template_video_error_1_listener() {
54784
+ \u0275\u0275restoreView(_r1);
54785
+ return \u0275\u0275resetView(ctx.onVideoTagError());
54724
54786
  });
54725
- \u0275\u0275element(3, "source", 3);
54787
+ \u0275\u0275text(3, " Your browser does not support the video tag. ");
54726
54788
  \u0275\u0275elementEnd();
54727
54789
  \u0275\u0275elementStart(4, "div");
54728
54790
  \u0275\u0275projection(5);
54729
- \u0275\u0275elementEnd()();
54791
+ \u0275\u0275elementEnd();
54792
+ \u0275\u0275elementStart(6, "div", 3);
54793
+ \u0275\u0275text(7);
54794
+ \u0275\u0275elementStart(8, "p", 4);
54795
+ \u0275\u0275text(9);
54796
+ \u0275\u0275elementEnd()()();
54730
54797
  }
54731
54798
  if (rf & 2) {
54732
- \u0275\u0275advance(3);
54733
- \u0275\u0275property("src", ctx.src(), \u0275\u0275sanitizeUrl);
54734
54799
  \u0275\u0275advance();
54800
+ \u0275\u0275property("src", ctx.src(), \u0275\u0275sanitizeUrl);
54801
+ \u0275\u0275advance(3);
54735
54802
  \u0275\u0275classProp("invisible", !ctx.showProjectedContent());
54803
+ \u0275\u0275advance(2);
54804
+ \u0275\u0275classProp("invisible", !ctx.videoErrorMessage());
54805
+ \u0275\u0275advance();
54806
+ \u0275\u0275textInterpolate1(" ", ctx.videoErrorMessage(), " ");
54807
+ \u0275\u0275advance(2);
54808
+ \u0275\u0275textInterpolate1("Source: ", ctx.src(), "");
54736
54809
  }
54737
- }, encapsulation: 2, changeDetection: 0 });
54810
+ }, styles: ["\n\n[_nghost-%COMP%] {\n display: block;\n}\n/*# sourceMappingURL=/static/video-tile.component-RDL4BSJ4.css.map */"], changeDetection: 0 });
54738
54811
  };
54739
54812
  (() => {
54740
54813
  (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(VideoTileComponent, [{
54741
54814
  type: Component,
54742
- args: [{ selector: "app-video-tile", imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: '<div class="relative shadow-lg shadow-black/20 bg-base-200">\n <!-- bg is visible during loading state -->\n <!-- wrapper to contain video + keypoints -->\n <video\n #videoEl\n preload="auto"\n (loadedmetadata)="onLoadedMetadata()"\n muted\n class="w-full"\n (timeupdate)="updateLocalCurrentTime()"\n (ended)="onEnd()"\n >\n <source [src]="src()" type="video/mp4" />\n </video>\n <div [class.invisible]="!showProjectedContent()">\n <!-- wrapper to hide content until video inited -->\n <ng-content></ng-content>\n </div>\n</div>\n<!--<p>T: {{ localCurrentTime() }}</p>-->\n' }]
54815
+ args: [{ selector: "app-video-tile", imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: '<style>\n :host {\n /* Display for angular elements is inline by default.\n This is a problem when querying the host height, because it ends up being just 0.\n */\n display: block;\n }\n</style>\n\n<div class="relative shadow-lg shadow-black/20 bg-base-200">\n <!-- bg is visible during loading state -->\n <!-- wrapper to contain video + keypoints -->\n <video\n #videoEl\n preload="auto"\n (loadedmetadata)="onLoadedMetadata()"\n muted\n (timeupdate)="updateLocalCurrentTime()"\n (ended)="onEnd()"\n (error)="onVideoTagError()"\n [src]="src()"\n >\n Your browser does not support the video tag.\n </video>\n <div [class.invisible]="!showProjectedContent()">\n <!-- wrapper to hide content until video inited -->\n <ng-content></ng-content>\n </div>\n\n <div\n class="absolute inset-0 overflow-auto p-2"\n [class.invisible]="!videoErrorMessage()"\n >\n {{ videoErrorMessage() }}\n <p class="text-sm text-gray-400 mt-2">Source: {{ src() }}</p>\n </div>\n</div>\n<!--<p>T: {{ localCurrentTime() }}</p>-->\n', styles: ["/* angular:styles/component:css;cca0ce7e24de60b661844ed36e56ee3734a21f5d38966246b6b69d25889a81d9;/home/ksikka/work/lightning-pose-app/web_ui/src/app/components/video-player/video-tile/video-tile.component.html */\n:host {\n display: block;\n}\n/*# sourceMappingURL=/static/video-tile.component-RDL4BSJ4.css.map */\n"] }]
54743
54816
  }], () => [{ type: ElementRef }], { videoElement: [{
54744
54817
  type: ViewChild,
54745
54818
  args: ["videoEl", { static: true }]
@@ -54748,7 +54821,7 @@ var VideoTileComponent = class _VideoTileComponent {
54748
54821
  }] });
54749
54822
  })();
54750
54823
  (() => {
54751
- (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(VideoTileComponent, { className: "VideoTileComponent", filePath: "src/app/components/video-player/video-tile/video-tile.component.ts", lineNumber: 39 });
54824
+ (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(VideoTileComponent, { className: "VideoTileComponent", filePath: "src/app/components/video-player/video-tile/video-tile.component.ts", lineNumber: 49 });
54752
54825
  })();
54753
54826
 
54754
54827
  // node_modules/@angular/cdk/fesm2022/drag-drop.mjs
@@ -58977,19 +59050,58 @@ var Pair = class _Pair {
58977
59050
  }
58978
59051
  };
58979
59052
 
59053
+ // src/app/utils/fine-video.service.ts
59054
+ var FineVideoService = class _FineVideoService {
59055
+ projectInfoService = inject(ProjectInfoService);
59056
+ fineVideoPath(videoPath) {
59057
+ if (!this.projectInfoService.fineVideoDir) {
59058
+ throw new Error("ProjectInfoService.fineVideoDir called but not yet initialized");
59059
+ }
59060
+ const filename = videoPath.split("/").pop();
59061
+ return "/app/v0/files/" + this.projectInfoService.fineVideoDir + "/" + filename;
59062
+ }
59063
+ static \u0275fac = function FineVideoService_Factory(__ngFactoryType__) {
59064
+ return new (__ngFactoryType__ || _FineVideoService)();
59065
+ };
59066
+ static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _FineVideoService, factory: _FineVideoService.\u0275fac, providedIn: "root" });
59067
+ };
59068
+ (() => {
59069
+ (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(FineVideoService, [{
59070
+ type: Injectable,
59071
+ args: [{
59072
+ providedIn: "root"
59073
+ }]
59074
+ }], null, null);
59075
+ })();
59076
+
58980
59077
  // src/app/viewer/viewer-center-panel/viewer-center-panel.component.ts
58981
59078
  var _forTrack03 = ($index, $item) => $item.videoSrc;
58982
59079
  function ViewerCenterPanelComponent_For_3_Template(rf, ctx) {
58983
59080
  if (rf & 1) {
58984
- \u0275\u0275elementStart(0, "app-video-tile", 2);
58985
- \u0275\u0275element(1, "app-keypoint-container", 3);
59081
+ const _r1 = \u0275\u0275getCurrentView();
59082
+ \u0275\u0275elementStart(0, "div", 2)(1, "div", 3)(2, "h3");
59083
+ \u0275\u0275text(3);
58986
59084
  \u0275\u0275elementEnd();
59085
+ \u0275\u0275elementStart(4, "span", 4);
59086
+ \u0275\u0275listener("click", function ViewerCenterPanelComponent_For_3_Template_span_click_4_listener() {
59087
+ const w_r2 = \u0275\u0275restoreView(_r1).$implicit;
59088
+ const ctx_r2 = \u0275\u0275nextContext();
59089
+ return \u0275\u0275resetView(ctx_r2.onWidgetCloseClick(w_r2));
59090
+ });
59091
+ \u0275\u0275text(5, "close");
59092
+ \u0275\u0275elementEnd()();
59093
+ \u0275\u0275elementStart(6, "app-video-tile", 5);
59094
+ \u0275\u0275element(7, "app-keypoint-container", 6);
59095
+ \u0275\u0275elementEnd()();
58987
59096
  }
58988
59097
  if (rf & 2) {
58989
- const w_r1 = ctx.$implicit;
58990
- \u0275\u0275property("src", w_r1.videoSrc);
59098
+ const w_r2 = ctx.$implicit;
59099
+ \u0275\u0275advance(3);
59100
+ \u0275\u0275textInterpolate(w_r2.id);
59101
+ \u0275\u0275advance(3);
59102
+ \u0275\u0275property("src", w_r2.videoSrc);
58991
59103
  \u0275\u0275advance();
58992
- \u0275\u0275property("labelerMode", false)("keypointModels", w_r1.keypoints());
59104
+ \u0275\u0275property("labelerMode", false)("keypointModels", w_r2.keypoints());
58993
59105
  }
58994
59106
  }
58995
59107
  var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
@@ -58997,6 +59109,7 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
58997
59109
  csvParser = inject(CsvParserService);
58998
59110
  projectInfoService = inject(ProjectInfoService);
58999
59111
  loadingService = inject(LoadingService);
59112
+ fineVideoService = inject(FineVideoService);
59000
59113
  get currentFrame() {
59001
59114
  return this.videoPlayerState.currentFrameSignal;
59002
59115
  }
@@ -59038,7 +59151,7 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
59038
59151
  });
59039
59152
  return {
59040
59153
  id: sessionView.viewName,
59041
- videoSrc: this.getVideoSrc(sessionView),
59154
+ videoSrc: this.fineVideoService.fineVideoPath(sessionView.videoPath),
59042
59155
  keypoints: filteredKeypoints
59043
59156
  };
59044
59157
  }
@@ -59075,9 +59188,6 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
59075
59188
  const dataDir = this.projectInfoService.projectInfo?.data_dir;
59076
59189
  return dataDir + "/" + sessionKey.replace(/\*/g, view) + ".mp4";
59077
59190
  }
59078
- getVideoSrc(sessionView) {
59079
- return "/app/v0/files/" + sessionView.videoPath;
59080
- }
59081
59191
  async loadSession(sessionKey) {
59082
59192
  this.sessionKey.set(sessionKey);
59083
59193
  this.widgetModels.set([]);
@@ -59125,13 +59235,17 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
59125
59235
  this.videoPlayerState.duration.set(data.duration);
59126
59236
  this.videoPlayerState.fps.set(data.fps);
59127
59237
  }
59238
+ onWidgetCloseClick(w) {
59239
+ const nextViewsShown = this.viewSettings.viewsShown().filter((v) => v != w.id);
59240
+ this.viewSettings.setViewsShown(nextViewsShown);
59241
+ }
59128
59242
  static \u0275fac = function ViewerCenterPanelComponent_Factory(__ngFactoryType__) {
59129
59243
  return new (__ngFactoryType__ || _ViewerCenterPanelComponent)();
59130
59244
  };
59131
- static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _ViewerCenterPanelComponent, selectors: [["app-viewer-center-panel"]], inputs: { viewSettings: "viewSettings" }, decls: 5, vars: 0, consts: [[1, "flex", "flex-col", "h-full"], [1, "video-tile", "w-full", "grow", "flex", "flex-wrap", "overflow-y-auto", "gap-4", "*:grow", "*:shrink-0", "*:max-w-xs", "justify-start", "content-start", "p-4"], [3, "src"], [3, "labelerMode", "keypointModels"]], template: function ViewerCenterPanelComponent_Template(rf, ctx) {
59245
+ static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _ViewerCenterPanelComponent, selectors: [["app-viewer-center-panel"]], inputs: { viewSettings: "viewSettings" }, decls: 5, vars: 0, consts: [[1, "flex", "flex-col", "h-full"], [1, "w-full", "grow", "flex", "flex-wrap", "overflow-y-auto", "gap-4", "*:max-w-xs", "justify-start", "items-start", "content-start", "p-4"], [1, "panel", "!border-none"], [1, "px-2", "py-1", "text-sm", "flex", "justify-between"], [1, "btn", "btn-circle", "btn-xs", "material-icons", "!text-sm", 3, "click"], [1, "w-auto", 3, "src"], [3, "labelerMode", "keypointModels"]], template: function ViewerCenterPanelComponent_Template(rf, ctx) {
59132
59246
  if (rf & 1) {
59133
59247
  \u0275\u0275elementStart(0, "div", 0)(1, "div", 1);
59134
- \u0275\u0275repeaterCreate(2, ViewerCenterPanelComponent_For_3_Template, 2, 3, "app-video-tile", 2, _forTrack03);
59248
+ \u0275\u0275repeaterCreate(2, ViewerCenterPanelComponent_For_3_Template, 8, 4, "div", 2, _forTrack03);
59135
59249
  \u0275\u0275elementEnd();
59136
59250
  \u0275\u0275element(4, "app-video-player-controls");
59137
59251
  \u0275\u0275elementEnd();
@@ -59153,7 +59267,7 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
59153
59267
  VideoPlayerControlsComponent,
59154
59268
  VideoTileComponent,
59155
59269
  KeypointContainerComponent
59156
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: '<div class="flex flex-col h-full">\n <!-- Video content area -->\n <div\n class="video-tile w-full grow flex flex-wrap overflow-y-auto gap-4 *:grow *:shrink-0 *:max-w-xs justify-start content-start p-4"\n >\n <!-- `track videosrc` makes the widget component get\n destroyed and recreated if videoSrc changes. Reactively\n changing videoSrc of an existing video does not work unfortunately. -->\n @for (w of filteredWidgetModels(); track w.videoSrc) {\n <!--@if (viewSettings.viewsShown().indexOf(w.id) >= 0) {-->\n <app-video-tile [src]="w.videoSrc">\n <app-keypoint-container\n [labelerMode]="false"\n [keypointModels]="w.keypoints()"\n ></app-keypoint-container>\n </app-video-tile>\n }\n </div>\n\n <app-video-player-controls></app-video-player-controls>\n</div>\n' }]
59270
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: '<div class="flex flex-col h-full">\n <!-- Video content area -->\n <div\n class="w-full grow flex flex-wrap overflow-y-auto gap-4 *:max-w-xs justify-start items-start content-start p-4"\n >\n <!-- `track videosrc` makes the widget component get\n destroyed and recreated if videoSrc changes. Reactively\n changing videoSrc of an existing video does not work unfortunately. -->\n @for (w of filteredWidgetModels(); track w.videoSrc) {\n <div class="panel !border-none">\n <div class="px-2 py-1 text-sm flex justify-between">\n <h3>{{ w.id }}</h3>\n <span\n class="btn btn-circle btn-xs material-icons !text-sm"\n (click)="onWidgetCloseClick(w)"\n >close</span\n >\n </div>\n <app-video-tile [src]="w.videoSrc" class="w-auto">\n <app-keypoint-container\n [labelerMode]="false"\n [keypointModels]="w.keypoints()"\n ></app-keypoint-container>\n </app-video-tile>\n </div>\n }\n </div>\n\n <app-video-player-controls></app-video-player-controls>\n</div>\n' }]
59157
59271
  }], null, { viewSettings: [{
59158
59272
  type: Input
59159
59273
  }] });
@@ -59205,10 +59319,10 @@ var _c05 = (a0) => [a0];
59205
59319
  function ViewerPageComponent_Conditional_0_For_14_Template(rf, ctx) {
59206
59320
  if (rf & 1) {
59207
59321
  const _r1 = \u0275\u0275getCurrentView();
59208
- \u0275\u0275elementStart(0, "li", 10)(1, "span");
59322
+ \u0275\u0275elementStart(0, "li", 9)(1, "span");
59209
59323
  \u0275\u0275text(2);
59210
59324
  \u0275\u0275elementEnd();
59211
- \u0275\u0275elementStart(3, "input", 13);
59325
+ \u0275\u0275elementStart(3, "input", 12);
59212
59326
  \u0275\u0275listener("change", function ViewerPageComponent_Conditional_0_For_14_Template_input_change_3_listener($event) {
59213
59327
  const cam_r2 = \u0275\u0275restoreView(_r1).$implicit;
59214
59328
  const ctx_r2 = \u0275\u0275nextContext(2);
@@ -59228,10 +59342,10 @@ function ViewerPageComponent_Conditional_0_For_14_Template(rf, ctx) {
59228
59342
  function ViewerPageComponent_Conditional_0_For_22_Template(rf, ctx) {
59229
59343
  if (rf & 1) {
59230
59344
  const _r4 = \u0275\u0275getCurrentView();
59231
- \u0275\u0275elementStart(0, "li", 10)(1, "span");
59345
+ \u0275\u0275elementStart(0, "li", 9)(1, "span");
59232
59346
  \u0275\u0275text(2);
59233
59347
  \u0275\u0275elementEnd();
59234
- \u0275\u0275elementStart(3, "input", 13);
59348
+ \u0275\u0275elementStart(3, "input", 12);
59235
59349
  \u0275\u0275listener("change", function ViewerPageComponent_Conditional_0_For_22_Template_input_change_3_listener($event) {
59236
59350
  const kp_r5 = \u0275\u0275restoreView(_r4).$implicit;
59237
59351
  const ctx_r2 = \u0275\u0275nextContext(2);
@@ -59250,7 +59364,7 @@ function ViewerPageComponent_Conditional_0_For_22_Template(rf, ctx) {
59250
59364
  }
59251
59365
  function ViewerPageComponent_Conditional_0_For_31_For_5_Template(rf, ctx) {
59252
59366
  if (rf & 1) {
59253
- \u0275\u0275elementStart(0, "option", 15);
59367
+ \u0275\u0275elementStart(0, "option", 14);
59254
59368
  \u0275\u0275text(1);
59255
59369
  \u0275\u0275elementEnd();
59256
59370
  }
@@ -59266,7 +59380,7 @@ function ViewerPageComponent_Conditional_0_For_31_Template(rf, ctx) {
59266
59380
  if (rf & 1) {
59267
59381
  const _r6 = \u0275\u0275getCurrentView();
59268
59382
  \u0275\u0275declareLet(0);
59269
- \u0275\u0275elementStart(1, "li", 12)(2, "select", 14);
59383
+ \u0275\u0275elementStart(1, "li", 11)(2, "select", 13);
59270
59384
  \u0275\u0275listener("change", function ViewerPageComponent_Conditional_0_For_31_Template_select_change_2_listener($event) {
59271
59385
  \u0275\u0275restoreView(_r6);
59272
59386
  const modelIndex_r7 = \u0275\u0275readContextLet(0);
@@ -59274,7 +59388,7 @@ function ViewerPageComponent_Conditional_0_For_31_Template(rf, ctx) {
59274
59388
  return \u0275\u0275resetView(ctx_r2.onModelDropdownItemClick(modelIndex_r7, $event));
59275
59389
  });
59276
59390
  \u0275\u0275declareLet(3);
59277
- \u0275\u0275repeaterCreate(4, ViewerPageComponent_Conditional_0_For_31_For_5_Template, 2, 2, "option", 15, \u0275\u0275repeaterTrackByIdentity);
59391
+ \u0275\u0275repeaterCreate(4, ViewerPageComponent_Conditional_0_For_31_For_5_Template, 2, 2, "option", 14, \u0275\u0275repeaterTrackByIdentity);
59278
59392
  \u0275\u0275elementEnd()();
59279
59393
  }
59280
59394
  if (rf & 2) {
@@ -59296,24 +59410,24 @@ function ViewerPageComponent_Conditional_0_Template(rf, ctx) {
59296
59410
  \u0275\u0275element(4, "app-loading-bar", 3);
59297
59411
  \u0275\u0275elementEnd();
59298
59412
  \u0275\u0275element(5, "app-viewer-center-panel", 4);
59299
- \u0275\u0275elementStart(6, "div", 5)(7, "div", 6)(8, "div", 7)(9, "h1", 8);
59413
+ \u0275\u0275elementStart(6, "div", 5)(7, "div", 6)(8, "div")(9, "h1", 7);
59300
59414
  \u0275\u0275text(10, "Views");
59301
59415
  \u0275\u0275elementEnd()();
59302
- \u0275\u0275elementStart(11, "div", 9)(12, "ul");
59303
- \u0275\u0275repeaterCreate(13, ViewerPageComponent_Conditional_0_For_14_Template, 4, 2, "li", 10, \u0275\u0275repeaterTrackByIdentity);
59416
+ \u0275\u0275elementStart(11, "div", 8)(12, "ul");
59417
+ \u0275\u0275repeaterCreate(13, ViewerPageComponent_Conditional_0_For_14_Template, 4, 2, "li", 9, \u0275\u0275repeaterTrackByIdentity);
59304
59418
  \u0275\u0275elementEnd()()();
59305
- \u0275\u0275elementStart(15, "div", 6)(16, "div", 7)(17, "h1", 8);
59419
+ \u0275\u0275elementStart(15, "div", 6)(16, "div")(17, "h1", 7);
59306
59420
  \u0275\u0275text(18, "Keypoints");
59307
59421
  \u0275\u0275elementEnd()();
59308
- \u0275\u0275elementStart(19, "div", 9)(20, "ul");
59309
- \u0275\u0275repeaterCreate(21, ViewerPageComponent_Conditional_0_For_22_Template, 4, 2, "li", 10, \u0275\u0275repeaterTrackByIdentity);
59422
+ \u0275\u0275elementStart(19, "div", 8)(20, "ul");
59423
+ \u0275\u0275repeaterCreate(21, ViewerPageComponent_Conditional_0_For_22_Template, 4, 2, "li", 9, \u0275\u0275repeaterTrackByIdentity);
59310
59424
  \u0275\u0275elementEnd()()();
59311
- \u0275\u0275elementStart(23, "div", 6)(24, "div", 7)(25, "h1", 8);
59425
+ \u0275\u0275elementStart(23, "div", 6)(24, "div")(25, "h1", 7);
59312
59426
  \u0275\u0275text(26, "Models");
59313
59427
  \u0275\u0275elementEnd()();
59314
- \u0275\u0275elementStart(27, "div", 11)(28, "ul");
59428
+ \u0275\u0275elementStart(27, "div", 10)(28, "ul");
59315
59429
  \u0275\u0275declareLet(29);
59316
- \u0275\u0275repeaterCreate(30, ViewerPageComponent_Conditional_0_For_31_Template, 6, 7, "li", 12, \u0275\u0275repeaterTrackByIndex);
59430
+ \u0275\u0275repeaterCreate(30, ViewerPageComponent_Conditional_0_For_31_Template, 6, 7, "li", 11, \u0275\u0275repeaterTrackByIndex);
59317
59431
  \u0275\u0275elementEnd()()()()();
59318
59432
  }
59319
59433
  if (rf & 2) {
@@ -59391,9 +59505,15 @@ var ViewerPageComponent = class _ViewerPageComponent {
59391
59505
  this.viewSelectionModel.changed.asObservable().pipe(takeUntilDestroyed()).subscribe(() => {
59392
59506
  this.viewSettings.setViewsShown(this.viewSelectionModel.selected);
59393
59507
  });
59508
+ this.viewSettings.viewsShown$.pipe(takeUntilDestroyed()).subscribe((viewsShown) => {
59509
+ this.viewSelectionModel.setSelection(...viewsShown);
59510
+ });
59394
59511
  this.keypointSelectionModel.changed.asObservable().pipe(takeUntilDestroyed()).subscribe(() => {
59395
59512
  this.viewSettings.setKeypointsShown(this.keypointSelectionModel.selected);
59396
59513
  });
59514
+ this.viewSettings.keypointsShown$.pipe(takeUntilDestroyed()).subscribe((keypointsShown) => {
59515
+ this.keypointSelectionModel.setSelection(...keypointsShown);
59516
+ });
59397
59517
  }
59398
59518
  onKeypointCheckboxChange(event, keypointName) {
59399
59519
  const target = event.target;
@@ -59433,7 +59553,7 @@ var ViewerPageComponent = class _ViewerPageComponent {
59433
59553
  if (rf & 2) {
59434
59554
  \u0275\u0275queryAdvance();
59435
59555
  }
59436
- }, inputs: { sessionKey: "sessionKey" }, features: [\u0275\u0275ProvidersFeature([VideoPlayerState, ViewSettings])], decls: 1, vars: 1, consts: [[1, "grow", "flex", "flex-row", "items-stretch"], [1, "bg-base-200", "w-60", "xl:w-80", "flex", "flex-col", "justify-between", "shadow-lg"], [1, "p-4"], [1, "h-20", "p-4"], [1, "grow", "z-30", 3, "viewSettings"], [1, "shrink-0", "w-40", "xl:w-60", "h-full"], [1, "panel", "m-4"], [1, "panel-header"], [1, "px-2", "mb-1"], [1, "panel-content", "max-h-60", "overflow-y-auto"], [1, "p-1", "flex", "justify-between", "items-center"], [1, "panel-content", "max-h-60", "overflow-y-visible"], [1, "p-1", "w-full"], ["type", "checkbox", 1, "checkbox", "checkbox-xs", 3, "change", "checked"], [1, "select", "select-sm", "w-full", "flex-grow", 3, "change"], [3, "selected"]], template: function ViewerPageComponent_Template(rf, ctx) {
59556
+ }, inputs: { sessionKey: "sessionKey" }, features: [\u0275\u0275ProvidersFeature([VideoPlayerState, ViewSettings])], decls: 1, vars: 1, consts: [[1, "grow", "flex", "flex-row", "items-stretch"], [1, "bg-base-200", "w-60", "xl:w-80", "flex", "flex-col", "justify-between", "shadow-lg"], [1, "p-4"], [1, "h-20", "p-4"], [1, "grow", "z-30", 3, "viewSettings"], [1, "shrink-0", "w-40", "xl:w-60", "h-full"], [1, "panel", "m-4"], [1, "px-2", "mb-1"], [1, "panel-content", "max-h-60", "overflow-y-auto"], [1, "p-1", "flex", "justify-between", "items-center"], [1, "panel-content", "max-h-60", "overflow-y-visible"], [1, "p-1", "w-full"], ["type", "checkbox", 1, "checkbox", "checkbox-xs", 3, "change", "checked"], [1, "select", "select-sm", "w-full", "flex-grow", 3, "change"], [3, "selected"]], template: function ViewerPageComponent_Template(rf, ctx) {
59437
59557
  if (rf & 1) {
59438
59558
  \u0275\u0275template(0, ViewerPageComponent_Conditional_0_Template, 32, 3, "div", 0);
59439
59559
  }
@@ -59444,7 +59564,7 @@ var ViewerPageComponent = class _ViewerPageComponent {
59444
59564
  ViewerSessionsPanelComponent,
59445
59565
  ViewerCenterPanelComponent,
59446
59566
  LoadingBarComponent
59447
- ], styles: ["\n\n[_nghost-%COMP%] {\n flex-grow: 1;\n display: flex;\n}\n/*# sourceMappingURL=/static/viewer-page.component-KIYG73MW.css.map */"], changeDetection: 0 });
59567
+ ], styles: ["\n\n[_nghost-%COMP%] {\n flex-grow: 1;\n display: flex;\n}\n/*# sourceMappingURL=/static/viewer-page.component-KDHT6XH5.css.map */"], changeDetection: 0 });
59448
59568
  };
59449
59569
  (() => {
59450
59570
  (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ViewerPageComponent, [{
@@ -59481,7 +59601,8 @@ var ViewerPageComponent = class _ViewerPageComponent {
59481
59601
  <!-- Right pane -->
59482
59602
  <div class="shrink-0 w-40 xl:w-60 h-full">
59483
59603
  <div class="panel m-4">
59484
- <div class="panel-header">
59604
+ <div>
59605
+ <!-- panel header -->
59485
59606
  <h1 class="px-2 mb-1">Views</h1>
59486
59607
  </div>
59487
59608
  <div class="panel-content max-h-60 overflow-y-auto">
@@ -59502,7 +59623,8 @@ var ViewerPageComponent = class _ViewerPageComponent {
59502
59623
  </div>
59503
59624
 
59504
59625
  <div class="panel m-4">
59505
- <div class="panel-header">
59626
+ <div>
59627
+ <!-- panel header -->
59506
59628
  <h1 class="px-2 mb-1">Keypoints</h1>
59507
59629
  </div>
59508
59630
  <div class="panel-content max-h-60 overflow-y-auto">
@@ -59523,7 +59645,8 @@ var ViewerPageComponent = class _ViewerPageComponent {
59523
59645
  </div>
59524
59646
 
59525
59647
  <div class="panel m-4">
59526
- <div class="panel-header">
59648
+ <div>
59649
+ <!-- panel header -->
59527
59650
  <h1 class="px-2 mb-1">Models</h1>
59528
59651
  </div>
59529
59652
  <div class="panel-content max-h-60 overflow-y-visible">
@@ -59559,13 +59682,13 @@ var ViewerPageComponent = class _ViewerPageComponent {
59559
59682
  </div>
59560
59683
  </div>
59561
59684
  }
59562
- `, styles: ["/* angular:styles/component:css;1fa15f7a0ae1b0259233282b2d49fb361834bf7fd726c58584c186240f9d8f04;/home/ksikka/lightning-pose/app/web_ui/src/app/viewer/viewer-page/viewer-page.component.html */\n:host {\n flex-grow: 1;\n display: flex;\n}\n/*# sourceMappingURL=/static/viewer-page.component-KIYG73MW.css.map */\n"] }]
59685
+ `, styles: ["/* angular:styles/component:css;1fa15f7a0ae1b0259233282b2d49fb361834bf7fd726c58584c186240f9d8f04;/home/ksikka/work/lightning-pose-app/web_ui/src/app/viewer/viewer-page/viewer-page.component.html */\n:host {\n flex-grow: 1;\n display: flex;\n}\n/*# sourceMappingURL=/static/viewer-page.component-KDHT6XH5.css.map */\n"] }]
59563
59686
  }], () => [], { sessionKey: [{
59564
59687
  type: Input
59565
59688
  }] });
59566
59689
  })();
59567
59690
  (() => {
59568
- (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(ViewerPageComponent, { className: "ViewerPageComponent", filePath: "src/app/viewer/viewer-page/viewer-page.component.ts", lineNumber: 37 });
59691
+ (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(ViewerPageComponent, { className: "ViewerPageComponent", filePath: "src/app/viewer/viewer-page/viewer-page.component.ts", lineNumber: 35 });
59569
59692
  })();
59570
59693
 
59571
59694
  // src/app/labeler/labeler-page.component.ts
@@ -66127,7 +66250,7 @@ view2
66127
66250
  \u0275\u0275advance();
66128
66251
  \u0275\u0275property("disabled", !ctx.projectInfoForm.dirty);
66129
66252
  }
66130
- }, dependencies: [ReactiveFormsModule, \u0275NgNoValidate, DefaultValueAccessor, NgControlStatus, NgControlStatusGroup, FormGroupDirective, FormControlName], styles: ["\n\n[_ngcontent-%COMP%]::placeholder {\n color: color-mix(in oklch, currentColor 50%, #0000) !important;\n}\n/*# sourceMappingURL=/static/project-settings.component-BXKZMYM3.css.map */"], changeDetection: 0 });
66253
+ }, dependencies: [ReactiveFormsModule, \u0275NgNoValidate, DefaultValueAccessor, NgControlStatus, NgControlStatusGroup, FormGroupDirective, FormControlName], styles: ["\n\n[_ngcontent-%COMP%]::placeholder {\n color: color-mix(in oklch, currentColor 50%, #0000) !important;\n}\n/*# sourceMappingURL=/static/project-settings.component-HKHIVUJR.css.map */"], changeDetection: 0 });
66131
66254
  };
66132
66255
  (() => {
66133
66256
  (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ProjectSettingsComponent, [{
@@ -66211,7 +66334,7 @@ view2
66211
66334
  </button>
66212
66335
  </div>
66213
66336
  </form>
66214
- `, styles: ["/* angular:styles/component:css;5c3484fa86afc1ad339d983c727d8801928706c064dd49a4001f42c8eac3d364;/home/ksikka/lightning-pose/app/web_ui/src/app/project-settings/project-settings.component.html */\n::placeholder {\n color: color-mix(in oklch, currentColor 50%, #0000) !important;\n}\n/*# sourceMappingURL=/static/project-settings.component-BXKZMYM3.css.map */\n"] }]
66337
+ `, styles: ["/* angular:styles/component:css;5c3484fa86afc1ad339d983c727d8801928706c064dd49a4001f42c8eac3d364;/home/ksikka/work/lightning-pose-app/web_ui/src/app/project-settings/project-settings.component.html */\n::placeholder {\n color: color-mix(in oklch, currentColor 50%, #0000) !important;\n}\n/*# sourceMappingURL=/static/project-settings.component-HKHIVUJR.css.map */\n"] }]
66215
66338
  }], () => [], null);
66216
66339
  })();
66217
66340
  (() => {
@@ -66336,7 +66459,7 @@ var AppComponent = class _AppComponent {
66336
66459
  RouterLink,
66337
66460
  RouterLinkActive,
66338
66461
  ProjectSettingsComponent
66339
- ], styles: ["\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n.navbar[_ngcontent-%COMP%] {\n min-height: 3rem;\n}\n/*# sourceMappingURL=/static/app.component-IZ5OUDH2.css.map */"], changeDetection: 0 });
66462
+ ], styles: ["\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n.navbar[_ngcontent-%COMP%] {\n min-height: 3rem;\n}\n/*# sourceMappingURL=/static/app.component-UAQUAGNZ.css.map */"], changeDetection: 0 });
66340
66463
  };
66341
66464
  (() => {
66342
66465
  (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(AppComponent, [{
@@ -66346,7 +66469,7 @@ var AppComponent = class _AppComponent {
66346
66469
  RouterLink,
66347
66470
  RouterLinkActive,
66348
66471
  ProjectSettingsComponent
66349
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: '<style>\n :host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n }\n .navbar {\n min-height: 3rem; /* reduce from default of 4rem */\n }\n</style>\n<header>\n <nav class="navbar bg-base-200 shadow-lg">\n <div class="navbar-start">\n <span class="text-lg font-semibold">Lightning Pose</span>\n </div>\n\n <div class="navbar-center">\n <ul class="menu menu-horizontal p-0">\n <li>\n <a\n routerLink="/viewer"\n routerLinkActive="menu-active"\n ariaCurrentWhenActive="page"\n >Viewer</a\n >\n </li>\n <li>\n <a\n routerLink="/labeler"\n routerLinkActive="menu-active"\n ariaCurrentWhenActive="page"\n >Labeler</a\n >\n </li>\n </ul>\n </div>\n\n <div class="navbar-end">\n <button\n class="btn btn-ghost"\n tabindex="0"\n (click)="settingsDialogOpen.set(true)"\n (keydown.enter)="settingsDialogOpen.set(true)"\n >\n <span class="material-icons">settings</span>\n </button>\n </div>\n </nav>\n</header>\n\n<!-- Set min-height: 0 to allow it to shrink if its content is too large.\n Default min-height for flex items is auto. -->\n<main class="flex-grow flex min-h-0" [class.justify-center]="!hasBeenSetup()">\n @if (hasBeenSetup()) {\n <router-outlet />\n } @else {\n <app-project-settings\n [setupMode]="true"\n class="w-lg mt-8"\n ></app-project-settings>\n }\n</main>\n\n<!-- Settings dialog -->\n<dialog #settingsDialog class="modal">\n @if (settingsDialogOpen()) {\n <app-project-settings\n class="modal-box"\n (done)="settingsDialogOpen.set(false)"\n ></app-project-settings>\n\n <!-- Makes the dialog close when clicked from outside. -->\n <div class="modal-backdrop">\n <button (click)="settingsDialogOpen.set(false)">close</button>\n </div>\n }\n</dialog>\n', styles: ["/* angular:styles/component:css;22d8514f1dd5b50f33b3fb93fdb69668f78eeb349bd672e238e3ac9acfbbda19;/home/ksikka/lightning-pose/app/web_ui/src/app/app.component.html */\n:host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n.navbar {\n min-height: 3rem;\n}\n/*# sourceMappingURL=/static/app.component-IZ5OUDH2.css.map */\n"] }]
66472
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: '<style>\n :host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n }\n .navbar {\n min-height: 3rem; /* reduce from default of 4rem */\n }\n</style>\n<header>\n <nav class="navbar bg-base-200 shadow-lg">\n <div class="navbar-start">\n <span class="text-lg font-semibold">Lightning Pose</span>\n </div>\n\n <div class="navbar-center">\n <ul class="menu menu-horizontal p-0">\n <li>\n <a\n routerLink="/viewer"\n routerLinkActive="menu-active"\n ariaCurrentWhenActive="page"\n >Viewer</a\n >\n </li>\n <li>\n <a\n routerLink="/labeler"\n routerLinkActive="menu-active"\n ariaCurrentWhenActive="page"\n >Labeler</a\n >\n </li>\n </ul>\n </div>\n\n <div class="navbar-end">\n <button\n class="btn btn-ghost"\n tabindex="0"\n (click)="settingsDialogOpen.set(true)"\n (keydown.enter)="settingsDialogOpen.set(true)"\n >\n <span class="material-icons">settings</span>\n </button>\n </div>\n </nav>\n</header>\n\n<!-- Set min-height: 0 to allow it to shrink if its content is too large.\n Default min-height for flex items is auto. -->\n<main class="flex-grow flex min-h-0" [class.justify-center]="!hasBeenSetup()">\n @if (hasBeenSetup()) {\n <router-outlet />\n } @else {\n <app-project-settings\n [setupMode]="true"\n class="w-lg mt-8"\n ></app-project-settings>\n }\n</main>\n\n<!-- Settings dialog -->\n<dialog #settingsDialog class="modal">\n @if (settingsDialogOpen()) {\n <app-project-settings\n class="modal-box"\n (done)="settingsDialogOpen.set(false)"\n ></app-project-settings>\n\n <!-- Makes the dialog close when clicked from outside. -->\n <div class="modal-backdrop">\n <button (click)="settingsDialogOpen.set(false)">close</button>\n </div>\n }\n</dialog>\n', styles: ["/* angular:styles/component:css;22d8514f1dd5b50f33b3fb93fdb69668f78eeb349bd672e238e3ac9acfbbda19;/home/ksikka/work/lightning-pose-app/web_ui/src/app/app.component.html */\n:host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n.navbar {\n min-height: 3rem;\n}\n/*# sourceMappingURL=/static/app.component-UAQUAGNZ.css.map */\n"] }]
66350
66473
  }], () => [], null);
66351
66474
  })();
66352
66475
  (() => {
@@ -66355,4 +66478,4 @@ var AppComponent = class _AppComponent {
66355
66478
 
66356
66479
  // src/main.ts
66357
66480
  bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
66358
- //# sourceMappingURL=main-WFYIUX2C.js.map
66481
+ //# sourceMappingURL=main-VCJFCLFP.js.map