@servicemind.tis/tis-image-and-file-upload-and-view 1.2.33 → 1.2.34

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.
@@ -869,19 +869,33 @@ class TisRemoteUploadService {
869
869
  this.stopHealthCheck();
870
870
  const mobileDeviceId = this.mobileConnection$.value?.mobileDeviceId;
871
871
  if (!mobileDeviceId || !this.deviceId) {
872
- console.warn(`[${TisRemoteUploadService.COMPONENT}] Cannot start health check - missing device IDs`);
872
+ console.warn(`[${TisRemoteUploadService.COMPONENT}] Cannot start health check - missing device IDs`, {
873
+ mobileDeviceId,
874
+ desktopDeviceId: this.deviceId
875
+ });
876
+ return;
877
+ }
878
+ if (!this.socketAdapter?.callApiViaSocket) {
879
+ console.error(`[${TisRemoteUploadService.COMPONENT}] Cannot start health check - socketAdapter.callApiViaSocket not available`);
873
880
  return;
874
881
  }
875
- console.log(`[${TisRemoteUploadService.COMPONENT}] Starting health check (every ${HEALTH_CHECK_INTERVAL / 1000}s)`);
882
+ console.log(`[${TisRemoteUploadService.COMPONENT}] Starting health check (every ${HEALTH_CHECK_INTERVAL / 1000}s)`, {
883
+ mobileDeviceId,
884
+ desktopDeviceId: this.deviceId
885
+ });
876
886
  // Set initial checking state (blinking)
877
887
  this.isCheckingStatus$.next(true);
878
888
  // Run first check immediately
879
- this.checkDevicesOnline();
889
+ this.checkDevicesOnline().catch(err => {
890
+ console.error(`[${TisRemoteUploadService.COMPONENT}] Initial health check failed:`, err);
891
+ });
880
892
  // Then run periodically
881
893
  this.healthCheckSubscription = interval(HEALTH_CHECK_INTERVAL)
882
894
  .pipe(takeUntil(this.destroy$))
883
895
  .subscribe(() => {
884
- this.checkDevicesOnline();
896
+ this.checkDevicesOnline().catch(err => {
897
+ console.error(`[${TisRemoteUploadService.COMPONENT}] Periodic health check failed:`, err);
898
+ });
885
899
  });
886
900
  }
887
901
  /**
@@ -901,14 +915,22 @@ class TisRemoteUploadService {
901
915
  async checkDevicesOnline() {
902
916
  const mobileDeviceId = this.mobileConnection$.value?.mobileDeviceId;
903
917
  if (!mobileDeviceId || !this.deviceId) {
904
- console.warn(`[${TisRemoteUploadService.COMPONENT}] Cannot check devices - missing device IDs`);
918
+ console.warn(`[${TisRemoteUploadService.COMPONENT}] Cannot check devices - missing device IDs`, {
919
+ mobileDeviceId,
920
+ desktopDeviceId: this.deviceId
921
+ });
905
922
  return null;
906
923
  }
924
+ console.log(`[${TisRemoteUploadService.COMPONENT}] Checking devices online status...`, {
925
+ desktopDeviceId: this.deviceId,
926
+ mobileDeviceId: mobileDeviceId
927
+ });
907
928
  try {
908
929
  const response = await this.callApiWithTimeout('tis-image-mobile-uploader/check-devices-online', {
909
930
  desktopDeviceId: this.deviceId,
910
931
  mobileDeviceId: mobileDeviceId
911
932
  }, 15000);
933
+ console.log(`[${TisRemoteUploadService.COMPONENT}] Check devices response:`, response);
912
934
  // Response structure: { body: { data: { desktop: {...}, mobile: {...} } } }
913
935
  const data = response?.body?.data || response?.data || response;
914
936
  const status = {
@@ -1551,12 +1573,21 @@ class TisViewConnectionDialogComponent {
1551
1573
  return `${minutesAgo}m ago`;
1552
1574
  }
1553
1575
  }
1576
+ /**
1577
+ * Truncate device ID to show first 8 and last 8 characters
1578
+ */
1579
+ truncateDeviceId(deviceId) {
1580
+ if (!deviceId || deviceId.length <= 20) {
1581
+ return deviceId;
1582
+ }
1583
+ return `${deviceId.substring(0, 8)}...${deviceId.substring(deviceId.length - 8)}`;
1584
+ }
1554
1585
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TisViewConnectionDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: TisRemoteUploadService }], target: i0.ɵɵFactoryTarget.Component });
1555
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: TisViewConnectionDialogComponent, isStandalone: false, selector: "tis-view-connection-dialog", ngImport: i0, template: "<div class=\"dialog-container\">\n <div class=\"dialog-header\">\n <h2 mat-dialog-title>{{ data.title || 'Mobile Connection' }}</h2>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\" tabindex=\"-1\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <mat-dialog-content class=\"dialog-content\">\n @if (mobileConnection) {\n <!-- Connection Info Card -->\n <div class=\"connection-card\">\n <div class=\"connection-header\">\n <div class=\"status-indicator\" [class.online]=\"devicesStatus?.isReadyForTransfer\" [class.blinking]=\"isCheckingStatus\">\n <mat-icon>{{ devicesStatus?.isReadyForTransfer ? 'check_circle' : 'error' }}</mat-icon>\n <span class=\"status-text\">\n {{ devicesStatus?.isReadyForTransfer ? 'Connected' : 'Connection Issue' }}\n </span>\n </div>\n <button \n mat-button \n color=\"primary\" \n class=\"refresh-btn\"\n (click)=\"refreshStatus()\"\n [disabled]=\"isCheckingStatus\">\n <mat-icon [class.spinning]=\"isCheckingStatus\">refresh</mat-icon>\n <span>Refresh</span>\n </button>\n </div>\n\n <div class=\"connection-details\">\n <div class=\"detail-row\">\n <span class=\"detail-label\">Mobile Device ID:</span>\n <span class=\"detail-value\">{{ mobileConnection.mobileDeviceId }}</span>\n </div>\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected For:</span>\n <span class=\"detail-value\">{{ getConnectionDuration() }}</span>\n </div>\n @if (mobileConnection.connectedAt) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected At:</span>\n <span class=\"detail-value\">{{ mobileConnection.connectedAt | date:'short' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Devices Status Card -->\n @if (devicesStatus) {\n <div class=\"devices-status-card\">\n <h3 class=\"card-title\">Device Status</h3>\n \n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">computer</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Desktop</div>\n <div class=\"device-id\">{{ devicesStatus.desktop.deviceId }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.desktop.isOnline\">\n <mat-icon>{{ devicesStatus.desktop.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.desktop.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.desktop.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.desktop.lastPing) }}</div>\n }\n </div>\n\n <mat-divider></mat-divider>\n\n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">smartphone</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Mobile</div>\n <div class=\"device-id\">{{ devicesStatus.mobile.deviceId }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.mobile.isOnline\">\n <mat-icon>{{ devicesStatus.mobile.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.mobile.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.mobile.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.mobile.lastPing) }}</div>\n }\n </div>\n </div>\n }\n\n <!-- Warning Message -->\n @if (devicesStatus && !devicesStatus.isReadyForTransfer) {\n <div class=\"warning-message\">\n <mat-icon>warning</mat-icon>\n <span>File uploads may not work properly when devices are offline.</span>\n </div>\n }\n } @else {\n <!-- No Connection -->\n <div class=\"no-connection\">\n <mat-icon>link_off</mat-icon>\n <p>No mobile device connected</p>\n </div>\n }\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button \n mat-button \n (click)=\"close()\"\n [disabled]=\"disconnecting\">\n Close\n </button>\n @if (mobileConnection) {\n <button \n mat-raised-button \n color=\"warn\" \n (click)=\"disconnect()\"\n [disabled]=\"disconnecting\">\n <mat-icon *ngIf=\"!disconnecting\">link_off</mat-icon>\n <mat-spinner *ngIf=\"disconnecting\" diameter=\"18\"></mat-spinner>\n <span>{{ disconnecting ? 'Disconnecting...' : 'Disconnect' }}</span>\n </button>\n }\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{min-width:500px;max-width:600px}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px 0}.dialog-header h2{margin:0;font-size:20px;font-weight:500}.close-btn{margin-right:-12px}.dialog-content{padding:16px 24px!important;display:flex;flex-direction:column;gap:16px}.dialog-actions{padding:8px 16px 16px!important}.connection-card{background:#f5f5f5;border-radius:8px;padding:16px}.connection-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.status-indicator{display:flex;align-items:center;gap:8px;font-weight:500}.status-indicator mat-icon{font-size:24px;width:24px;height:24px}.status-indicator.online{color:#4caf50}.status-indicator:not(.online){color:#f44336}.status-indicator.blinking mat-icon{animation:blink 1.5s ease-in-out infinite}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.refresh-btn{min-width:auto}.refresh-btn mat-icon{margin-right:4px}.refresh-btn mat-icon.spinning{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.connection-details{display:flex;flex-direction:column;gap:8px}.detail-row{display:flex;justify-content:space-between;font-size:14px}.detail-label{color:#666;font-weight:500}.detail-value{color:#333;font-family:Courier New,monospace}.devices-status-card{border:1px solid #e0e0e0;border-radius:8px;padding:16px;background:#fff}.card-title{margin:0 0 16px;font-size:16px;font-weight:500;color:#333}.device-status-row{display:flex;flex-direction:column;gap:8px;padding:12px 0}.device-info{display:flex;align-items:center;gap:12px}.device-icon{font-size:32px;width:32px;height:32px;color:#666}.device-details{flex:1}.device-name{font-weight:500;font-size:14px;color:#333}.device-id{font-size:12px;color:#666;font-family:Courier New,monospace}.status-badge{display:flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;font-size:12px;font-weight:500;background:#ffebee;color:#c62828;align-self:flex-start}.status-badge.online{background:#e8f5e9;color:#2e7d32}.status-badge mat-icon{font-size:16px;width:16px;height:16px}.last-ping{font-size:12px;color:#999;padding-left:44px}mat-divider{margin:8px 0}.warning-message{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#fff3e0;border-left:4px solid #ff9800;border-radius:4px;font-size:14px;color:#e65100}.warning-message mat-icon{color:#ff9800}.no-connection{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;color:#999}.no-connection mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px}.no-connection p{margin:0;font-size:16px}.dialog-actions button{margin-left:8px}.dialog-actions button mat-spinner{display:inline-block;margin-right:8px}\n"], dependencies: [{ kind: "directive", type: i3$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: i7.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "pipe", type: i3$2.DatePipe, name: "date" }] });
1586
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: TisViewConnectionDialogComponent, isStandalone: false, selector: "tis-view-connection-dialog", ngImport: i0, template: "<div class=\"dialog-container\">\n <div class=\"dialog-header\">\n <h2 mat-dialog-title>{{ data.title || 'Mobile Connection' }}</h2>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\" tabindex=\"-1\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <mat-dialog-content class=\"dialog-content\">\n @if (mobileConnection) {\n <!-- Connection Info Card -->\n <div class=\"connection-card\">\n <div class=\"connection-header\">\n <div class=\"status-indicator\" [class.online]=\"devicesStatus?.isReadyForTransfer\" [class.blinking]=\"isCheckingStatus\">\n <mat-icon>{{ devicesStatus?.isReadyForTransfer ? 'check_circle' : 'error' }}</mat-icon>\n <span class=\"status-text\">\n {{ devicesStatus?.isReadyForTransfer ? 'Connected' : 'Connection Issue' }}\n </span>\n </div>\n <button \n mat-button \n color=\"primary\" \n class=\"refresh-btn\"\n (click)=\"refreshStatus()\"\n [disabled]=\"isCheckingStatus\">\n <mat-icon [class.spinning]=\"isCheckingStatus\">refresh</mat-icon>\n <span>Refresh</span>\n </button>\n </div>\n\n <div class=\"connection-details\">\n <div class=\"detail-row\">\n <span class=\"detail-label\">Mobile Device ID:</span>\n <span class=\"detail-value\">{{ truncateDeviceId(mobileConnection.mobileDeviceId) }}</span>\n </div>\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected For:</span>\n <span class=\"detail-value\">{{ getConnectionDuration() }}</span>\n </div>\n @if (mobileConnection.connectedAt) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected At:</span>\n <span class=\"detail-value\">{{ mobileConnection.connectedAt | date:'short' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Devices Status Card -->\n @if (devicesStatus) {\n <div class=\"devices-status-card\">\n <h3 class=\"card-title\">Device Status</h3>\n \n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">computer</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Desktop</div>\n <div class=\"device-id\">{{ truncateDeviceId(devicesStatus.desktop.deviceId) }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.desktop.isOnline\">\n <mat-icon>{{ devicesStatus.desktop.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.desktop.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.desktop.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.desktop.lastPing) }}</div>\n }\n </div>\n\n <mat-divider></mat-divider>\n\n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">smartphone</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Mobile</div>\n <div class=\"device-id\">{{ truncateDeviceId(devicesStatus.mobile.deviceId) }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.mobile.isOnline\">\n <mat-icon>{{ devicesStatus.mobile.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.mobile.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.mobile.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.mobile.lastPing) }}</div>\n }\n </div>\n </div>\n }\n\n <!-- Warning Message -->\n @if (devicesStatus && !devicesStatus.isReadyForTransfer) {\n <div class=\"warning-message\">\n <mat-icon>warning</mat-icon>\n <span>File uploads may not work properly when devices are offline.</span>\n </div>\n }\n } @else {\n <!-- No Connection -->\n <div class=\"no-connection\">\n <mat-icon>link_off</mat-icon>\n <p>No mobile device connected</p>\n </div>\n }\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button \n mat-button \n (click)=\"close()\"\n [disabled]=\"disconnecting\">\n Close\n </button>\n @if (mobileConnection) {\n <button \n mat-raised-button \n color=\"warn\" \n (click)=\"disconnect()\"\n [disabled]=\"disconnecting\">\n <mat-icon *ngIf=\"!disconnecting\">link_off</mat-icon>\n <mat-spinner *ngIf=\"disconnecting\" diameter=\"18\"></mat-spinner>\n <span>{{ disconnecting ? 'Disconnecting...' : 'Disconnect' }}</span>\n </button>\n }\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{min-width:500px;max-width:600px}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px 0}.dialog-header h2{margin:0;font-size:20px;font-weight:500}.close-btn{margin-right:-12px}.dialog-content{padding:16px 24px!important;display:flex;flex-direction:column;gap:16px}.dialog-actions{padding:8px 16px 16px!important}.connection-card{background:#f5f5f5;border-radius:8px;padding:16px}.connection-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.status-indicator{display:flex;align-items:center;gap:8px;font-weight:500}.status-indicator mat-icon{font-size:24px;width:24px;height:24px}.status-indicator.online{color:#4caf50}.status-indicator:not(.online){color:#f44336}.status-indicator.blinking mat-icon{animation:blink 1.5s ease-in-out infinite}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.refresh-btn{min-width:auto}.refresh-btn mat-icon{margin-right:4px}.refresh-btn mat-icon.spinning{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.connection-details{display:flex;flex-direction:column;gap:8px}.detail-row{display:flex;justify-content:space-between;font-size:14px}.detail-label{color:#666;font-weight:500}.detail-value{color:#333;font-family:Courier New,monospace}.devices-status-card{border:1px solid #e0e0e0;border-radius:8px;padding:16px;background:#fff}.card-title{margin:0 0 16px;font-size:16px;font-weight:500;color:#333}.device-status-row{display:flex;flex-direction:column;gap:8px;padding:12px 0}.device-info{display:flex;align-items:center;gap:12px}.device-icon{font-size:32px;width:32px;height:32px;color:#666}.device-details{flex:1}.device-name{font-weight:500;font-size:14px;color:#333}.device-id{font-size:12px;color:#666;font-family:Courier New,monospace}.status-badge{display:flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;font-size:12px;font-weight:500;background:#ffebee;color:#c62828;align-self:flex-start}.status-badge.online{background:#e8f5e9;color:#2e7d32}.status-badge mat-icon{font-size:16px;width:16px;height:16px}.last-ping{font-size:12px;color:#999;padding-left:44px}mat-divider{margin:8px 0}.warning-message{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#fff3e0;border-left:4px solid #ff9800;border-radius:4px;font-size:14px;color:#e65100}.warning-message mat-icon{color:#ff9800}.no-connection{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;color:#999}.no-connection mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px}.no-connection p{margin:0;font-size:16px}.dialog-actions button{margin-left:8px}.dialog-actions button mat-spinner{display:inline-block;margin-right:8px}\n"], dependencies: [{ kind: "directive", type: i3$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: i7.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "pipe", type: i3$2.DatePipe, name: "date" }] });
1556
1587
  }
1557
1588
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TisViewConnectionDialogComponent, decorators: [{
1558
1589
  type: Component,
1559
- args: [{ selector: 'tis-view-connection-dialog', standalone: false, template: "<div class=\"dialog-container\">\n <div class=\"dialog-header\">\n <h2 mat-dialog-title>{{ data.title || 'Mobile Connection' }}</h2>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\" tabindex=\"-1\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <mat-dialog-content class=\"dialog-content\">\n @if (mobileConnection) {\n <!-- Connection Info Card -->\n <div class=\"connection-card\">\n <div class=\"connection-header\">\n <div class=\"status-indicator\" [class.online]=\"devicesStatus?.isReadyForTransfer\" [class.blinking]=\"isCheckingStatus\">\n <mat-icon>{{ devicesStatus?.isReadyForTransfer ? 'check_circle' : 'error' }}</mat-icon>\n <span class=\"status-text\">\n {{ devicesStatus?.isReadyForTransfer ? 'Connected' : 'Connection Issue' }}\n </span>\n </div>\n <button \n mat-button \n color=\"primary\" \n class=\"refresh-btn\"\n (click)=\"refreshStatus()\"\n [disabled]=\"isCheckingStatus\">\n <mat-icon [class.spinning]=\"isCheckingStatus\">refresh</mat-icon>\n <span>Refresh</span>\n </button>\n </div>\n\n <div class=\"connection-details\">\n <div class=\"detail-row\">\n <span class=\"detail-label\">Mobile Device ID:</span>\n <span class=\"detail-value\">{{ mobileConnection.mobileDeviceId }}</span>\n </div>\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected For:</span>\n <span class=\"detail-value\">{{ getConnectionDuration() }}</span>\n </div>\n @if (mobileConnection.connectedAt) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected At:</span>\n <span class=\"detail-value\">{{ mobileConnection.connectedAt | date:'short' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Devices Status Card -->\n @if (devicesStatus) {\n <div class=\"devices-status-card\">\n <h3 class=\"card-title\">Device Status</h3>\n \n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">computer</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Desktop</div>\n <div class=\"device-id\">{{ devicesStatus.desktop.deviceId }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.desktop.isOnline\">\n <mat-icon>{{ devicesStatus.desktop.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.desktop.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.desktop.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.desktop.lastPing) }}</div>\n }\n </div>\n\n <mat-divider></mat-divider>\n\n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">smartphone</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Mobile</div>\n <div class=\"device-id\">{{ devicesStatus.mobile.deviceId }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.mobile.isOnline\">\n <mat-icon>{{ devicesStatus.mobile.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.mobile.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.mobile.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.mobile.lastPing) }}</div>\n }\n </div>\n </div>\n }\n\n <!-- Warning Message -->\n @if (devicesStatus && !devicesStatus.isReadyForTransfer) {\n <div class=\"warning-message\">\n <mat-icon>warning</mat-icon>\n <span>File uploads may not work properly when devices are offline.</span>\n </div>\n }\n } @else {\n <!-- No Connection -->\n <div class=\"no-connection\">\n <mat-icon>link_off</mat-icon>\n <p>No mobile device connected</p>\n </div>\n }\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button \n mat-button \n (click)=\"close()\"\n [disabled]=\"disconnecting\">\n Close\n </button>\n @if (mobileConnection) {\n <button \n mat-raised-button \n color=\"warn\" \n (click)=\"disconnect()\"\n [disabled]=\"disconnecting\">\n <mat-icon *ngIf=\"!disconnecting\">link_off</mat-icon>\n <mat-spinner *ngIf=\"disconnecting\" diameter=\"18\"></mat-spinner>\n <span>{{ disconnecting ? 'Disconnecting...' : 'Disconnect' }}</span>\n </button>\n }\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{min-width:500px;max-width:600px}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px 0}.dialog-header h2{margin:0;font-size:20px;font-weight:500}.close-btn{margin-right:-12px}.dialog-content{padding:16px 24px!important;display:flex;flex-direction:column;gap:16px}.dialog-actions{padding:8px 16px 16px!important}.connection-card{background:#f5f5f5;border-radius:8px;padding:16px}.connection-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.status-indicator{display:flex;align-items:center;gap:8px;font-weight:500}.status-indicator mat-icon{font-size:24px;width:24px;height:24px}.status-indicator.online{color:#4caf50}.status-indicator:not(.online){color:#f44336}.status-indicator.blinking mat-icon{animation:blink 1.5s ease-in-out infinite}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.refresh-btn{min-width:auto}.refresh-btn mat-icon{margin-right:4px}.refresh-btn mat-icon.spinning{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.connection-details{display:flex;flex-direction:column;gap:8px}.detail-row{display:flex;justify-content:space-between;font-size:14px}.detail-label{color:#666;font-weight:500}.detail-value{color:#333;font-family:Courier New,monospace}.devices-status-card{border:1px solid #e0e0e0;border-radius:8px;padding:16px;background:#fff}.card-title{margin:0 0 16px;font-size:16px;font-weight:500;color:#333}.device-status-row{display:flex;flex-direction:column;gap:8px;padding:12px 0}.device-info{display:flex;align-items:center;gap:12px}.device-icon{font-size:32px;width:32px;height:32px;color:#666}.device-details{flex:1}.device-name{font-weight:500;font-size:14px;color:#333}.device-id{font-size:12px;color:#666;font-family:Courier New,monospace}.status-badge{display:flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;font-size:12px;font-weight:500;background:#ffebee;color:#c62828;align-self:flex-start}.status-badge.online{background:#e8f5e9;color:#2e7d32}.status-badge mat-icon{font-size:16px;width:16px;height:16px}.last-ping{font-size:12px;color:#999;padding-left:44px}mat-divider{margin:8px 0}.warning-message{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#fff3e0;border-left:4px solid #ff9800;border-radius:4px;font-size:14px;color:#e65100}.warning-message mat-icon{color:#ff9800}.no-connection{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;color:#999}.no-connection mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px}.no-connection p{margin:0;font-size:16px}.dialog-actions button{margin-left:8px}.dialog-actions button mat-spinner{display:inline-block;margin-right:8px}\n"] }]
1590
+ args: [{ selector: 'tis-view-connection-dialog', standalone: false, template: "<div class=\"dialog-container\">\n <div class=\"dialog-header\">\n <h2 mat-dialog-title>{{ data.title || 'Mobile Connection' }}</h2>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\" tabindex=\"-1\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <mat-dialog-content class=\"dialog-content\">\n @if (mobileConnection) {\n <!-- Connection Info Card -->\n <div class=\"connection-card\">\n <div class=\"connection-header\">\n <div class=\"status-indicator\" [class.online]=\"devicesStatus?.isReadyForTransfer\" [class.blinking]=\"isCheckingStatus\">\n <mat-icon>{{ devicesStatus?.isReadyForTransfer ? 'check_circle' : 'error' }}</mat-icon>\n <span class=\"status-text\">\n {{ devicesStatus?.isReadyForTransfer ? 'Connected' : 'Connection Issue' }}\n </span>\n </div>\n <button \n mat-button \n color=\"primary\" \n class=\"refresh-btn\"\n (click)=\"refreshStatus()\"\n [disabled]=\"isCheckingStatus\">\n <mat-icon [class.spinning]=\"isCheckingStatus\">refresh</mat-icon>\n <span>Refresh</span>\n </button>\n </div>\n\n <div class=\"connection-details\">\n <div class=\"detail-row\">\n <span class=\"detail-label\">Mobile Device ID:</span>\n <span class=\"detail-value\">{{ truncateDeviceId(mobileConnection.mobileDeviceId) }}</span>\n </div>\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected For:</span>\n <span class=\"detail-value\">{{ getConnectionDuration() }}</span>\n </div>\n @if (mobileConnection.connectedAt) {\n <div class=\"detail-row\">\n <span class=\"detail-label\">Connected At:</span>\n <span class=\"detail-value\">{{ mobileConnection.connectedAt | date:'short' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Devices Status Card -->\n @if (devicesStatus) {\n <div class=\"devices-status-card\">\n <h3 class=\"card-title\">Device Status</h3>\n \n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">computer</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Desktop</div>\n <div class=\"device-id\">{{ truncateDeviceId(devicesStatus.desktop.deviceId) }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.desktop.isOnline\">\n <mat-icon>{{ devicesStatus.desktop.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.desktop.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.desktop.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.desktop.lastPing) }}</div>\n }\n </div>\n\n <mat-divider></mat-divider>\n\n <div class=\"device-status-row\">\n <div class=\"device-info\">\n <mat-icon class=\"device-icon\">smartphone</mat-icon>\n <div class=\"device-details\">\n <div class=\"device-name\">Mobile</div>\n <div class=\"device-id\">{{ truncateDeviceId(devicesStatus.mobile.deviceId) }}</div>\n </div>\n </div>\n <div class=\"status-badge\" [class.online]=\"devicesStatus.mobile.isOnline\">\n <mat-icon>{{ devicesStatus.mobile.isOnline ? 'circle' : 'cancel' }}</mat-icon>\n <span>{{ devicesStatus.mobile.isOnline ? 'Online' : 'Offline' }}</span>\n </div>\n @if (devicesStatus.mobile.lastPing) {\n <div class=\"last-ping\">Last ping: {{ getLastPing(devicesStatus.mobile.lastPing) }}</div>\n }\n </div>\n </div>\n }\n\n <!-- Warning Message -->\n @if (devicesStatus && !devicesStatus.isReadyForTransfer) {\n <div class=\"warning-message\">\n <mat-icon>warning</mat-icon>\n <span>File uploads may not work properly when devices are offline.</span>\n </div>\n }\n } @else {\n <!-- No Connection -->\n <div class=\"no-connection\">\n <mat-icon>link_off</mat-icon>\n <p>No mobile device connected</p>\n </div>\n }\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button \n mat-button \n (click)=\"close()\"\n [disabled]=\"disconnecting\">\n Close\n </button>\n @if (mobileConnection) {\n <button \n mat-raised-button \n color=\"warn\" \n (click)=\"disconnect()\"\n [disabled]=\"disconnecting\">\n <mat-icon *ngIf=\"!disconnecting\">link_off</mat-icon>\n <mat-spinner *ngIf=\"disconnecting\" diameter=\"18\"></mat-spinner>\n <span>{{ disconnecting ? 'Disconnecting...' : 'Disconnect' }}</span>\n </button>\n }\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{min-width:500px;max-width:600px}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px 0}.dialog-header h2{margin:0;font-size:20px;font-weight:500}.close-btn{margin-right:-12px}.dialog-content{padding:16px 24px!important;display:flex;flex-direction:column;gap:16px}.dialog-actions{padding:8px 16px 16px!important}.connection-card{background:#f5f5f5;border-radius:8px;padding:16px}.connection-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.status-indicator{display:flex;align-items:center;gap:8px;font-weight:500}.status-indicator mat-icon{font-size:24px;width:24px;height:24px}.status-indicator.online{color:#4caf50}.status-indicator:not(.online){color:#f44336}.status-indicator.blinking mat-icon{animation:blink 1.5s ease-in-out infinite}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.refresh-btn{min-width:auto}.refresh-btn mat-icon{margin-right:4px}.refresh-btn mat-icon.spinning{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.connection-details{display:flex;flex-direction:column;gap:8px}.detail-row{display:flex;justify-content:space-between;font-size:14px}.detail-label{color:#666;font-weight:500}.detail-value{color:#333;font-family:Courier New,monospace}.devices-status-card{border:1px solid #e0e0e0;border-radius:8px;padding:16px;background:#fff}.card-title{margin:0 0 16px;font-size:16px;font-weight:500;color:#333}.device-status-row{display:flex;flex-direction:column;gap:8px;padding:12px 0}.device-info{display:flex;align-items:center;gap:12px}.device-icon{font-size:32px;width:32px;height:32px;color:#666}.device-details{flex:1}.device-name{font-weight:500;font-size:14px;color:#333}.device-id{font-size:12px;color:#666;font-family:Courier New,monospace}.status-badge{display:flex;align-items:center;gap:6px;padding:4px 12px;border-radius:16px;font-size:12px;font-weight:500;background:#ffebee;color:#c62828;align-self:flex-start}.status-badge.online{background:#e8f5e9;color:#2e7d32}.status-badge mat-icon{font-size:16px;width:16px;height:16px}.last-ping{font-size:12px;color:#999;padding-left:44px}mat-divider{margin:8px 0}.warning-message{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#fff3e0;border-left:4px solid #ff9800;border-radius:4px;font-size:14px;color:#e65100}.warning-message mat-icon{color:#ff9800}.no-connection{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;color:#999}.no-connection mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px}.no-connection p{margin:0;font-size:16px}.dialog-actions button{margin-left:8px}.dialog-actions button mat-spinner{display:inline-block;margin-right:8px}\n"] }]
1560
1591
  }], ctorParameters: () => [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
1561
1592
  type: Inject,
1562
1593
  args: [MAT_DIALOG_DATA]