translate page agent admin guide to English
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-07-08 14:40:46 +09:00
parent 71eeac278f
commit 403d3ac0ed
4 changed files with 363 additions and 136 deletions
+30
View File
@@ -1,4 +1,5 @@
export const selectedAppStorageKey = 'studio-admin:selected-app-id';
export const selectedComponentByAppStorageKey = 'studio-admin:selected-component-by-app-id';
const legacySelectedAppStorageKey = 'studio-selected-app-id';
export function getStoredSelectedAppId() {
@@ -19,3 +20,32 @@ export function setStoredSelectedAppId(appId: string) {
if (!appId) return;
window.localStorage.setItem(selectedAppStorageKey, appId);
}
function readSelectedComponentMap(): Record<string, string> {
const raw = window.localStorage.getItem(selectedComponentByAppStorageKey);
if (!raw) return {};
try {
const parsed = JSON.parse(raw) as unknown;
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
return Object.fromEntries(
Object.entries(parsed)
.filter((entry): entry is [string, string] => typeof entry[0] === 'string' && typeof entry[1] === 'string')
);
} catch {
return {};
}
}
export function getStoredSelectedComponentId(appId: string) {
if (!appId) return '';
return readSelectedComponentMap()[appId] ?? '';
}
export function setStoredSelectedComponentId(appId: string, componentId: string) {
if (!appId || !componentId) return;
window.localStorage.setItem(selectedComponentByAppStorageKey, JSON.stringify({
...readSelectedComponentMap(),
[appId]: componentId,
}));
}
+13 -5
View File
@@ -7,6 +7,7 @@ import type { BuildJob, SourceComponent } from '../../types/application';
import { LoadingModal, useMinimumLoading } from '../operations/operation-utils';
import { AppSelector, StatusBadge, formatDate, isBuildDone, useApps } from './ApplicationControls';
import { cancelBuildJob, createBuildJob, deleteBuildJob, listBuildJobsPage, listSources } from './application-api';
import { getStoredSelectedComponentId, setStoredSelectedComponentId } from '../../lib/selected-app';
function blockPageAgentDestructiveClick(event: MouseEvent<HTMLElement>) {
if (event.nativeEvent.isTrusted) return false;
@@ -144,8 +145,11 @@ export function BuildManagementPage() {
.filter((source) => (source.imageSource ?? 'SOURCE') === 'SOURCE');
setSelectedComponentId((prev) => {
const valid = filteredSources.some((source) => source.id === prev);
const next = valid ? prev : filteredSources[0]?.id || '';
setBranch('develop');
const storedComponentId = getStoredSelectedComponentId(selectedAppId);
const storedValid = filteredSources.some((source) => source.id === storedComponentId);
const next = valid ? prev : storedValid ? storedComponentId : filteredSources[0]?.id || '';
if (next && next !== prev) setStoredSelectedComponentId(selectedAppId, next);
if (next !== prev) setBranch('develop');
return next;
});
} finally {
@@ -187,11 +191,13 @@ export function BuildManagementPage() {
useEffect(() => {
if (!componentOptions.some((source) => source.id === selectedComponentId)) {
const nextComponent = componentOptions[0];
const storedComponentId = getStoredSelectedComponentId(selectedAppId);
const nextComponent = componentOptions.find((source) => source.id === storedComponentId) ?? componentOptions[0];
setSelectedComponentId(nextComponent?.id || '');
if (nextComponent?.id) setStoredSelectedComponentId(selectedAppId, nextComponent.id);
setBranch('develop');
}
}, [componentOptions, selectedComponentId]);
}, [componentOptions, selectedAppId, selectedComponentId]);
useEffect(() => {
setPage(1);
@@ -261,7 +267,9 @@ export function BuildManagementPage() {
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
value={selectedComponent?.id ?? ''}
onChange={(event) => {
setSelectedComponentId(event.target.value);
const nextComponentId = event.target.value;
setSelectedComponentId(nextComponentId);
setStoredSelectedComponentId(selectedAppId, nextComponentId);
setBranch('develop');
}}
>
@@ -12,6 +12,7 @@ import {
listSources,
type GiteaCommit
} from './application-api';
import { getStoredSelectedComponentId, setStoredSelectedComponentId } from '../../lib/selected-app';
const giteaBaseUrl = import.meta.env.VITE_GITEA_BASE_URL ?? 'http://localhost:3000';
const giteaAppOrg = import.meta.env.VITE_GITEA_APP_ORG ?? import.meta.env.GITEA_APP_ORG ?? 'platform';
@@ -341,8 +342,15 @@ export function SourceManagementPage() {
}, []);
useEffect(() => {
setSelectedSourceId((current) => filteredSources.some((source) => source.id === current) ? current : filteredSources[0]?.id ?? '');
}, [filteredSources]);
setSelectedSourceId((current) => {
if (filteredSources.some((source) => source.id === current)) return current;
const storedSourceId = getStoredSelectedComponentId(selectedAppId);
const nextSource = filteredSources.find((source) => source.id === storedSourceId) ?? filteredSources[0];
if (nextSource?.id) setStoredSelectedComponentId(selectedAppId, nextSource.id);
return nextSource?.id ?? '';
});
}, [filteredSources, selectedAppId]);
useEffect(() => {
setCommitPage(1);
@@ -431,7 +439,11 @@ export function SourceManagementPage() {
<select
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
value={selectedSource?.id ?? ''}
onChange={(event) => setSelectedSourceId(event.target.value)}
onChange={(event) => {
const nextSourceId = event.target.value;
setSelectedSourceId(nextSourceId);
setStoredSelectedComponentId(selectedAppId, nextSourceId);
}}
disabled={filteredSources.length === 0}
>
{filteredSources.map((source) => (