feat: implement account settings and API tokens management

- Added SettingsComponent for user profile management, including display name and password change functionality.
- Introduced TokensComponent for managing API tokens, including creation and revocation.
- Created LayoutComponent for consistent application layout with navigation and user information.
- Established main application structure in index.html and main.ts.
- Integrated Tailwind CSS for styling and responsive design.
- Configured TypeScript settings for strict type checking and module resolution.
This commit is contained in:
2025-11-27 22:15:38 +00:00
parent a6c6ea1393
commit ab88ac896f
71 changed files with 9446 additions and 0 deletions

100
ts/models/team.ts Normal file
View File

@@ -0,0 +1,100 @@
/**
* Team model for Stack.Gallery Registry
*/
import * as plugins from '../plugins.ts';
import type { ITeam } from '../interfaces/auth.interfaces.ts';
import { getDb } from './db.ts';
@plugins.smartdata.Collection(() => getDb())
export class Team extends plugins.smartdata.SmartDataDbDoc<Team, Team> implements ITeam {
@plugins.smartdata.unI()
public id: string = '';
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public organizationId: string = '';
@plugins.smartdata.svDb()
@plugins.smartdata.searchable()
public name: string = '';
@plugins.smartdata.svDb()
public description?: string;
@plugins.smartdata.svDb()
public isDefaultTeam: boolean = false;
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public createdAt: Date = new Date();
@plugins.smartdata.svDb()
public updatedAt: Date = new Date();
/**
* Create a new team
*/
public static async createTeam(data: {
organizationId: string;
name: string;
description?: string;
isDefaultTeam?: boolean;
}): Promise<Team> {
// Validate name
const nameRegex = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
if (!nameRegex.test(data.name.toLowerCase())) {
throw new Error('Team name must be lowercase alphanumeric with optional hyphens');
}
// Check for duplicate name in org
const existing = await Team.getInstance({
organizationId: data.organizationId,
name: data.name.toLowerCase(),
});
if (existing) {
throw new Error('Team with this name already exists in the organization');
}
const team = new Team();
team.id = await Team.getNewId();
team.organizationId = data.organizationId;
team.name = data.name.toLowerCase();
team.description = data.description;
team.isDefaultTeam = data.isDefaultTeam || false;
team.createdAt = new Date();
team.updatedAt = new Date();
await team.save();
return team;
}
/**
* Find team by name in organization
*/
public static async findByName(organizationId: string, name: string): Promise<Team | null> {
return await Team.getInstance({
organizationId,
name: name.toLowerCase(),
});
}
/**
* Get all teams in an organization
*/
public static async getOrgTeams(organizationId: string): Promise<Team[]> {
return await Team.getInstances({
organizationId,
});
}
/**
* Lifecycle hook
*/
public async beforeSave(): Promise<void> {
this.updatedAt = new Date();
if (!this.id) {
this.id = await Team.getNewId();
}
}
}