mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-01 10:18:37 +00:00
refactor: move project star state from localStorage to backend
This commit is contained in:
78
server/modules/projects/services/project-star.service.ts
Normal file
78
server/modules/projects/services/project-star.service.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { projectsDb } from '@/modules/database/index.js';
|
||||
import { AppError } from '@/shared/utils.js';
|
||||
|
||||
type ToggleProjectStarResult = {
|
||||
isStarred: boolean;
|
||||
};
|
||||
|
||||
type ApplyLegacyStarredProjectIdsResult = {
|
||||
updated: number;
|
||||
};
|
||||
|
||||
function normalizeProjectId(projectId: string): string {
|
||||
return projectId.trim();
|
||||
}
|
||||
|
||||
function uniqueProjectIds(projectIds: string[]): string[] {
|
||||
const uniqueIds = new Set<string>();
|
||||
for (const projectId of projectIds) {
|
||||
const normalizedProjectId = normalizeProjectId(projectId);
|
||||
if (!normalizedProjectId) {
|
||||
continue;
|
||||
}
|
||||
uniqueIds.add(normalizedProjectId);
|
||||
}
|
||||
return [...uniqueIds];
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies legacy `localStorage` stars keyed by DB `projectId` onto `projects.isStarred`.
|
||||
*
|
||||
* The operation is idempotent: already-starred projects are ignored, unknown ids are skipped.
|
||||
*/
|
||||
export function applyLegacyStarredProjectIds(projectIds: string[]): ApplyLegacyStarredProjectIdsResult {
|
||||
const normalizedProjectIds = uniqueProjectIds(projectIds);
|
||||
let updated = 0;
|
||||
|
||||
for (const projectId of normalizedProjectIds) {
|
||||
const project = projectsDb.getProjectById(projectId);
|
||||
if (!project) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Boolean(project.isStarred)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
projectsDb.updateProjectIsStarredById(projectId, true);
|
||||
updated += 1;
|
||||
}
|
||||
|
||||
return { updated };
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips `projects.isStarred` for one project and returns the new state.
|
||||
*/
|
||||
export function toggleProjectStar(projectId: string): ToggleProjectStarResult {
|
||||
const normalizedProjectId = normalizeProjectId(projectId);
|
||||
if (!normalizedProjectId) {
|
||||
throw new AppError('projectId is required', {
|
||||
code: 'PROJECT_ID_REQUIRED',
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const project = projectsDb.getProjectById(normalizedProjectId);
|
||||
if (!project) {
|
||||
throw new AppError('Project not found', {
|
||||
code: 'PROJECT_NOT_FOUND',
|
||||
statusCode: 404,
|
||||
});
|
||||
}
|
||||
|
||||
const nextStarredState = !Boolean(project.isStarred);
|
||||
projectsDb.updateProjectIsStarredById(normalizedProjectId, nextStarredState);
|
||||
|
||||
return { isStarred: nextStarredState };
|
||||
}
|
||||
@@ -21,6 +21,7 @@ export type ProjectListItem = {
|
||||
path: string;
|
||||
displayName: string;
|
||||
fullPath: string;
|
||||
isStarred: boolean;
|
||||
sessions: SessionSummary[];
|
||||
cursorSessions: SessionSummary[];
|
||||
codexSessions: SessionSummary[];
|
||||
@@ -201,6 +202,7 @@ export async function getProjectsWithSessions(): Promise<ProjectListItem[]> {
|
||||
project_id: string;
|
||||
project_path: string;
|
||||
custom_project_name?: string | null;
|
||||
isStarred?: number;
|
||||
}>;
|
||||
const totalProjects = projectRows.length;
|
||||
const projects: ProjectListItem[] = [];
|
||||
@@ -233,6 +235,7 @@ export async function getProjectsWithSessions(): Promise<ProjectListItem[]> {
|
||||
path: projectPath,
|
||||
displayName,
|
||||
fullPath: projectPath,
|
||||
isStarred: Boolean(row.isStarred),
|
||||
sessions: claudeSessions,
|
||||
cursorSessions: sessionsByProvider.cursor,
|
||||
codexSessions: sessionsByProvider.codex,
|
||||
|
||||
Reference in New Issue
Block a user