This commit is contained in:
Bastian Wagner
2026-07-20 09:01:36 +02:00
parent 8cf57d7878
commit e62673ac11
98 changed files with 17372 additions and 80 deletions

View File

@@ -14,6 +14,10 @@ import type {
NotificationStatusFilter,
PageDto,
Permission,
ProjectDto,
ProjectInvitationDto,
ProjectMemberDto,
ProjectRole,
RoleDto,
SaveItemDto,
SessionDto,
@@ -49,6 +53,104 @@ export class ApiClientService {
}>(`${this.base}/dashboard`, { withCredentials: true });
}
projects(): Observable<ProjectDto[]> {
return this.http.get<ProjectDto[]>(`${this.base}/projects`, {
withCredentials: true,
});
}
project(id: string): Observable<ProjectDto> {
return this.http.get<ProjectDto>(`${this.base}/projects/${id}`, {
withCredentials: true,
});
}
createProject(body: { name: string; description?: string }): Observable<ProjectDto> {
return this.http.post<ProjectDto>(`${this.base}/projects`, body, {
withCredentials: true,
});
}
projectMembers(projectId: string): Observable<ProjectMemberDto[]> {
return this.http.get<ProjectMemberDto[]>(`${this.base}/projects/${projectId}/members`, {
withCredentials: true,
});
}
updateProjectMember(
projectId: string,
userId: string,
role: ProjectRole,
): Observable<ProjectMemberDto> {
return this.http.patch<ProjectMemberDto>(
`${this.base}/projects/${projectId}/members/${userId}`,
{ role },
{ withCredentials: true },
);
}
removeProjectMember(projectId: string, userId: string): Observable<void> {
return this.http.delete<void>(`${this.base}/projects/${projectId}/members/${userId}`, {
withCredentials: true,
});
}
createProjectInvitation(
projectId: string,
body: { email: string; role: ProjectRole },
): Observable<ProjectInvitationDto> {
return this.http.post<ProjectInvitationDto>(
`${this.base}/projects/${projectId}/invitations`,
body,
{ withCredentials: true },
);
}
pendingProjectInvitations(): Observable<ProjectInvitationDto[]> {
return this.http.get<ProjectInvitationDto[]>(`${this.base}/invitations`, {
withCredentials: true,
});
}
acceptPendingProjectInvitation(invitationId: string): Observable<ProjectDto> {
return this.http.post<ProjectDto>(
`${this.base}/invitations/by-id/${invitationId}/accept`,
{},
{ withCredentials: true },
);
}
declinePendingProjectInvitation(invitationId: string): Observable<void> {
return this.http.post<void>(
`${this.base}/invitations/by-id/${invitationId}/decline`,
{},
{ withCredentials: true },
);
}
projectInvitation(token: string): Observable<ProjectInvitationDto> {
return this.http.get<ProjectInvitationDto>(
`${this.base}/invitations/${encodeURIComponent(token)}`,
{ withCredentials: true },
);
}
acceptProjectInvitation(token: string): Observable<ProjectDto> {
return this.http.post<ProjectDto>(
`${this.base}/invitations/${encodeURIComponent(token)}/accept`,
{},
{ withCredentials: true },
);
}
declineProjectInvitation(token: string): Observable<void> {
return this.http.post<void>(
`${this.base}/invitations/${encodeURIComponent(token)}/decline`,
{},
{ withCredentials: true },
);
}
items(
query: {
search?: string;

View File

@@ -14,7 +14,8 @@ export type Permission =
| 'sessions.manage'
| 'notifications.readOwn'
| 'notifications.updateOwn'
| 'notifications.manage';
| 'notifications.manage'
| 'projects.use';
export interface ApiErrorBody {
status: number;
@@ -35,6 +36,7 @@ export interface UserDto {
id: string;
name: string;
email: string | null;
emailVerified: boolean | null;
active: boolean;
lastLoginAt: string | null;
roles: RoleDto[];
@@ -85,6 +87,40 @@ export interface RoleDto {
users?: UserDto[];
}
export type ProjectRole = 'owner' | 'administrator' | 'editor' | 'reader';
export interface ProjectDto {
id: string;
name: string;
description: string | null;
role: ProjectRole;
createdAt: string;
updatedAt: string;
}
export interface ProjectMemberDto {
userId: string;
name: string;
email: string | null;
role: ProjectRole;
active: boolean;
joinedAt: string;
}
export interface ProjectInvitationDto {
id: string;
projectId: string | null;
projectName: string | null;
role: ProjectRole;
status: 'pending' | 'accepted' | 'declined' | 'revoked' | 'expired';
invitedEmailMasked: string;
expiresAt: string;
mailStatus: 'not_configured';
canRespond: boolean;
reason: 'email_mismatch' | 'email_unverified' | null;
invitationPath?: string;
}
export interface ItemDto {
id: string;
name: string;
@@ -124,7 +160,12 @@ export interface AuditLogDto {
requestId: string;
}
export type NotificationType = 'system' | 'item.created' | 'item.updated' | 'user.role-changed';
export type NotificationType =
| 'system'
| 'item.created'
| 'item.updated'
| 'user.role-changed'
| 'project.invitation';
export type NotificationStatusFilter = 'all' | 'read' | 'unread';