feat: Add slashcommand api
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
/>
|
||||
<span class="text-sm">Process RAM</span>
|
||||
</div>
|
||||
<span class="font-mono text-sm text-foreground">{{ ramLabel() ?? '—' }}</span>
|
||||
<span class="font-mono text-sm text-foreground">{{ ramLabel() ?? '-' }}</span>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-muted-foreground">Live total working set from Electron app metrics. Updates every 2 seconds.</p>
|
||||
</section>
|
||||
|
||||
@@ -14,11 +14,104 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@if (!isElectron) {
|
||||
<section class="rounded-lg border border-border bg-secondary/30 p-5">
|
||||
<p class="text-sm text-muted-foreground">Automatic updates are only available in the packaged Electron desktop app.</p>
|
||||
@if (isCapacitor) {
|
||||
<section class="rounded-lg border border-border bg-card/60 p-5">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<h4 class="text-base font-semibold text-foreground">Mobile app updates</h4>
|
||||
<p class="mt-1 text-sm text-muted-foreground">
|
||||
Check the Play Store or App Store for newer native builds. Android can install in-app updates when Google Play allows it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<span class="inline-flex items-center rounded-full border border-primary/30 bg-primary/10 px-3 py-1 text-xs font-medium text-primary">
|
||||
{{ mobileStatusLabel() }}
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
} @else {
|
||||
|
||||
@if (!mobileState().isSupported) {
|
||||
<section class="rounded-lg border border-border bg-secondary/30 p-5">
|
||||
<p class="text-sm text-muted-foreground">Store updates are only available in the packaged Android or iOS app.</p>
|
||||
</section>
|
||||
} @else {
|
||||
<section class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Installed</p>
|
||||
<p class="mt-2 text-lg font-semibold text-foreground">{{ mobileState().currentVersion }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Store version</p>
|
||||
<p class="mt-2 text-lg font-semibold text-foreground">{{ mobileState().availableVersion || 'Unknown' }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Last checked</p>
|
||||
<p class="mt-2 text-sm font-medium text-foreground">
|
||||
{{ mobileState().lastCheckedAt ? (mobileState().lastCheckedAt | date: 'medium') : 'Not checked yet' }}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-4 rounded-lg border border-border bg-card/60 p-5">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-sm font-medium text-foreground">Status</p>
|
||||
<p class="mt-1 text-sm text-muted-foreground">
|
||||
{{ mobileState().statusMessage || 'Waiting for the first store update check.' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button
|
||||
type="button"
|
||||
(click)="refreshMobileReleaseInfo()"
|
||||
class="inline-flex items-center rounded-lg border border-border bg-secondary px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-secondary/80"
|
||||
>
|
||||
Check for updates
|
||||
</button>
|
||||
|
||||
@if (mobileState().status === 'update-available') {
|
||||
<button
|
||||
type="button"
|
||||
(click)="openMobileAppStore()"
|
||||
class="inline-flex items-center rounded-lg border border-border bg-secondary px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-secondary/80"
|
||||
>
|
||||
Open app store
|
||||
</button>
|
||||
|
||||
@if (mobileState().immediateUpdateAllowed || mobileState().flexibleUpdateAllowed) {
|
||||
<button
|
||||
type="button"
|
||||
(click)="installMobileUpdateNow()"
|
||||
class="inline-flex items-center rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
|
||||
>
|
||||
Install update
|
||||
</button>
|
||||
}
|
||||
|
||||
@if (mobileState().flexibleUpdateAllowed && mobileState().status === 'downloading') {
|
||||
<button
|
||||
type="button"
|
||||
(click)="completeMobileFlexibleUpdate()"
|
||||
class="inline-flex items-center rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
|
||||
>
|
||||
Restart to finish update
|
||||
</button>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
@if (!isElectron && !isCapacitor) {
|
||||
<section class="rounded-lg border border-border bg-secondary/30 p-5">
|
||||
<p class="text-sm text-muted-foreground">Automatic updates are only available in the packaged Electron desktop app or native mobile app.</p>
|
||||
</section>
|
||||
}
|
||||
|
||||
@if (isElectron) {
|
||||
<section class="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
<div class="rounded-lg border border-border bg-secondary/20 p-4">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">Installed</p>
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DesktopAppUpdateService } from '../../../../core/services/desktop-app-update.service';
|
||||
import { MobileAppUpdateService, getMobileUpdateStatusLabel } from '../../../../infrastructure/mobile';
|
||||
|
||||
type AutoUpdateMode = 'auto' | 'off' | 'version';
|
||||
type DesktopUpdateStatus =
|
||||
@@ -29,9 +30,15 @@ type DesktopUpdateStatus =
|
||||
templateUrl: './updates-settings.component.html'
|
||||
})
|
||||
export class UpdatesSettingsComponent {
|
||||
readonly updates = inject(DesktopAppUpdateService);
|
||||
readonly isElectron = this.updates.isElectron;
|
||||
readonly state = this.updates.state;
|
||||
readonly desktopUpdates = inject(DesktopAppUpdateService);
|
||||
readonly mobileUpdates = inject(MobileAppUpdateService);
|
||||
readonly isElectron = this.desktopUpdates.isElectron;
|
||||
readonly isCapacitor = this.mobileUpdates.isCapacitor;
|
||||
readonly state = this.desktopUpdates.state;
|
||||
readonly mobileState = this.mobileUpdates.state;
|
||||
readonly mobileStatusLabel = computed(() =>
|
||||
getMobileUpdateStatusLabel(this.mobileState().status)
|
||||
);
|
||||
readonly hasPendingManifestUrlChanges = signal(false);
|
||||
readonly manifestUrlsText = signal('');
|
||||
readonly statusLabel = computed(() => this.getStatusLabel(this.state().status));
|
||||
@@ -60,18 +67,18 @@ export class UpdatesSettingsComponent {
|
||||
? this.state().preferredVersion ?? this.state().availableVersions[0] ?? null
|
||||
: this.state().preferredVersion;
|
||||
|
||||
await this.updates.saveUpdatePreferences(mode, preferredVersion);
|
||||
await this.desktopUpdates.saveUpdatePreferences(mode, preferredVersion);
|
||||
}
|
||||
|
||||
async onVersionChange(event: Event): Promise<void> {
|
||||
const select = event.target as HTMLSelectElement;
|
||||
|
||||
await this.updates.saveUpdatePreferences('version', select.value || null);
|
||||
await this.desktopUpdates.saveUpdatePreferences('version', select.value || null);
|
||||
}
|
||||
|
||||
async refreshReleaseInfo(): Promise<void> {
|
||||
await this.updates.refreshServerContext();
|
||||
await this.updates.checkForUpdates();
|
||||
await this.desktopUpdates.refreshServerContext();
|
||||
await this.desktopUpdates.checkForUpdates();
|
||||
}
|
||||
|
||||
onManifestUrlsInput(event: Event): void {
|
||||
@@ -82,7 +89,7 @@ export class UpdatesSettingsComponent {
|
||||
}
|
||||
|
||||
async saveManifestUrls(): Promise<void> {
|
||||
await this.updates.saveManifestUrls(
|
||||
await this.desktopUpdates.saveManifestUrls(
|
||||
this.parseManifestUrls(this.manifestUrlsText())
|
||||
);
|
||||
|
||||
@@ -90,12 +97,37 @@ export class UpdatesSettingsComponent {
|
||||
}
|
||||
|
||||
async useConnectedServerDefaults(): Promise<void> {
|
||||
await this.updates.saveManifestUrls([]);
|
||||
await this.desktopUpdates.saveManifestUrls([]);
|
||||
this.hasPendingManifestUrlChanges.set(false);
|
||||
}
|
||||
|
||||
async restartNow(): Promise<void> {
|
||||
await this.updates.restartToApplyUpdate();
|
||||
await this.desktopUpdates.restartToApplyUpdate();
|
||||
}
|
||||
|
||||
async refreshMobileReleaseInfo(): Promise<void> {
|
||||
await this.mobileUpdates.checkForUpdates();
|
||||
}
|
||||
|
||||
async openMobileAppStore(): Promise<void> {
|
||||
await this.mobileUpdates.openAppStore();
|
||||
}
|
||||
|
||||
async installMobileUpdateNow(): Promise<void> {
|
||||
const mobileState = this.mobileState();
|
||||
|
||||
if (mobileState.immediateUpdateAllowed) {
|
||||
await this.mobileUpdates.performImmediateUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mobileState.flexibleUpdateAllowed) {
|
||||
await this.mobileUpdates.startFlexibleUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
async completeMobileFlexibleUpdate(): Promise<void> {
|
||||
await this.mobileUpdates.completeFlexibleUpdate();
|
||||
}
|
||||
|
||||
private parseManifestUrls(rawValue: string): string[] {
|
||||
|
||||
Reference in New Issue
Block a user