diff --git a/.gitignore b/.gitignore index 0237449..db73275 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist/ *.log .DS_Store backend/prisma/*.db +frontend/dist diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts index 40c9f65..a06eb72 100644 --- a/backend/src/auth/auth.controller.ts +++ b/backend/src/auth/auth.controller.ts @@ -1,7 +1,8 @@ -import { Controller, Post, Get, Put, Body, Request, UseGuards } from '@nestjs/common'; +import { Controller, Post, Get, Put, Body, Request, UseGuards, InternalServerErrorException } from '@nestjs/common'; import { AuthService } from './auth.service'; import { JwtAuthGuard } from './jwt-auth.guard'; import { LoginDto } from './dto/login.dto'; +import { UpdateProfileDto } from './dto/update-profile.dto'; @Controller('auth') export class AuthController { @@ -20,8 +21,14 @@ export class AuthController { @UseGuards(JwtAuthGuard) @Put('profile') - updateProfile(@Request() req: any, @Body() body: { email?: string; displayName?: string; currentPassword?: string; newPassword?: string }) { - return this.auth.updateProfile(req.user.sub, body); + async updateProfile(@Request() req: any, @Body() dto: UpdateProfileDto) { + try { + return await this.auth.updateProfile(req.user.sub, dto); + } catch (e: any) { + console.error('Profile update error:', e); + if (e.status) throw e; + throw new InternalServerErrorException(e.message || 'Profile update failed'); + } } @UseGuards(JwtAuthGuard) diff --git a/backend/src/auth/dto/update-profile.dto.ts b/backend/src/auth/dto/update-profile.dto.ts new file mode 100644 index 0000000..11f1931 --- /dev/null +++ b/backend/src/auth/dto/update-profile.dto.ts @@ -0,0 +1,20 @@ +import { IsEmail, IsString, IsOptional, MinLength } from 'class-validator'; + +export class UpdateProfileDto { + @IsOptional() + @IsEmail() + email?: string; + + @IsOptional() + @IsString() + displayName?: string; + + @IsOptional() + @IsString() + currentPassword?: string; + + @IsOptional() + @IsString() + @MinLength(6) + newPassword?: string; +} diff --git a/frontend/components/connections/GroupEditDialog.vue b/frontend/components/connections/GroupEditDialog.vue index 116585a..22eb218 100644 --- a/frontend/components/connections/GroupEditDialog.vue +++ b/frontend/components/connections/GroupEditDialog.vue @@ -69,42 +69,40 @@ async function save() { diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index 3b8a719..6a9a910 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -87,6 +87,28 @@ function dismissSavePrompt() { pendingQuickConnect.value = null } +// Inline modal state (bypasses component issues) +const inlineHost = ref({ name: '', hostname: '', port: 22, protocol: 'ssh' as 'ssh' | 'rdp' }) + +async function createGroupInline() { + const nameEl = document.getElementById('grp-name') as HTMLInputElement + if (!nameEl?.value) return + await connections.createGroup({ name: nameEl.value }) + showGroupDialog.value = false +} + +async function createHostInline() { + if (!inlineHost.value.name || !inlineHost.value.hostname) return + await connections.createHost({ + name: inlineHost.value.name, + hostname: inlineHost.value.hostname, + port: inlineHost.value.port, + protocol: inlineHost.value.protocol, + }) + showHostDialog.value = false + inlineHost.value = { name: '', hostname: '', port: 22, protocol: 'ssh' } +} + // Client-side search filtering const filteredHosts = computed(() => { if (!searchQuery.value.trim()) return connections.hosts @@ -192,8 +214,53 @@ const recentHosts = computed(() => { - - - + +
+
+
+

{{ showGroupDialog ? 'New Group' : 'New Host' }}

+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+