Compare commits

...

5 Commits

Author SHA1 Message Date
Jonas Plum
4e03a52b71 fix: text alignment (#1158) 2025-09-21 16:58:46 +00:00
Jonas Plum
e475b38ea4 refactor: sanitize webhook auth payload (#1157) 2025-09-21 17:26:18 +02:00
Jonas Plum
e07afd0f3a chore: remove admin interface link from dashboard cards (#1156) 2025-09-21 17:25:31 +02:00
Jonas Plum
fedda9daaf chore: add more screenshots (#1155) 2025-09-21 14:50:28 +02:00
Jonas Plum
4d844c567c fix: multiple minor fixes (#1154) 2025-09-21 12:08:28 +00:00
34 changed files with 145 additions and 72 deletions

View File

@@ -60,7 +60,7 @@ func runHook(ctx context.Context, queries *sqlc.Queries, collection, event strin
Action: event,
Collection: collection,
Record: record,
Auth: auth,
Auth: webhook.SanitizeUser(auth),
Admin: nil,
})
if err != nil {

View File

@@ -68,7 +68,7 @@ func isDemoMode(ctx context.Context, queries *sqlc.Queries) bool {
}
}
return true, nil
return len(features) > 0, nil
}); err != nil {
slog.ErrorContext(ctx, "Failed to check demo mode", "error", err)

View File

@@ -8,6 +8,7 @@ import (
"io"
"log/slog"
"net/http"
"time"
"github.com/SecurityBrewery/catalyst/app/auth/usercontext"
"github.com/SecurityBrewery/catalyst/app/database"
@@ -35,11 +36,43 @@ func BindHooks(hooks *hook.Hooks, queries *sqlc.Queries) {
}
type Payload struct {
Action string `json:"action"`
Collection string `json:"collection"`
Record any `json:"record"`
Auth *sqlc.User `json:"auth,omitempty"`
Admin *sqlc.User `json:"admin,omitempty"`
Action string `json:"action"`
Collection string `json:"collection"`
Record any `json:"record"`
Auth *AuthUser `json:"auth,omitempty"`
Admin *AuthUser `json:"admin,omitempty"`
}
type AuthUser struct {
ID string `json:"id"`
Username string `json:"username"`
Active bool `json:"active"`
Name *string `json:"name,omitempty"`
Email *string `json:"email,omitempty"`
Avatar *string `json:"avatar,omitempty"`
Lastresetsentat *time.Time `json:"lastresetsentat,omitempty"`
Lastverificationsentat *time.Time `json:"lastverificationsentat,omitempty"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
func SanitizeUser(user *sqlc.User) *AuthUser {
if user == nil {
return nil
}
return &AuthUser{
ID: user.ID,
Username: user.Username,
Active: user.Active,
Name: user.Name,
Email: user.Email,
Avatar: user.Avatar,
Lastresetsentat: user.Lastresetsentat,
Lastverificationsentat: user.Lastverificationsentat,
Created: user.Created,
Updated: user.Updated,
}
}
func event(ctx context.Context, queries *sqlc.Queries, event, collection string, record any) {
@@ -67,7 +100,7 @@ func event(ctx context.Context, queries *sqlc.Queries, event, collection string,
Action: event,
Collection: collection,
Record: record,
Auth: user,
Auth: SanitizeUser(user),
Admin: nil,
})
if err != nil {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 167 KiB

BIN
docs/screenshots/groups.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 229 KiB

BIN
docs/screenshots/types.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
docs/screenshots/users.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

View File

@@ -9,6 +9,10 @@ files=(
"ticket.png"
"tasks.png"
"reactions.png"
"settings.png"
"users.png"
"groups.png"
"types.png"
)
for file in "${files[@]}"; do

View File

@@ -49,3 +49,42 @@ test('reactions screenshot', async ({ page }) => {
await page.waitForTimeout(7000)
await page.screenshot({ path: screenshot('reactions') })
})
test('settings screenshot', async ({ page }) => {
await login(page, true)
await page.goto('settings')
await expect(page.getByRole('heading', { name: 'Settings' })).toBeVisible()
await page.getByText("Toggle Sidebar").click()
await page.waitForTimeout(7000)
await page.screenshot({ path: screenshot('settings') })
})
test('users screenshot', async ({ page }) => {
await login(page, true)
await page.goto('users')
await expect(page.getByRole('heading', { name: 'Users' })).toBeVisible()
await page.getByText("Toggle Sidebar").click()
await page.getByText("Test User").click()
await page.waitForTimeout(7000)
await page.screenshot({ path: screenshot('users') })
})
test('groups screenshot', async ({ page }) => {
await login(page, true)
await page.goto('groups')
await expect(page.getByRole('heading', { name: 'Groups' })).toBeVisible()
await page.getByText("Toggle Sidebar").click()
await page.getByText("Analyst").click()
await page.waitForTimeout(7000)
await page.screenshot({ path: screenshot('groups') })
})
test('types screenshot', async ({ page }) => {
await login(page, true)
await page.goto('types')
await expect(page.getByRole('heading', { name: 'Types' })).toBeVisible()
await page.getByText("Toggle Sidebar").click()
await page.locator('main').getByText("Incident").click()
await page.waitForTimeout(7000)
await page.screenshot({ path: screenshot('types') })
})

View File

@@ -62,7 +62,7 @@ watch(
<div v-for="(property, key) in schema?.properties" :key="key">
<FormField v-if="property.enum" :name="key" v-slot="{ componentField }" v-model="formdata[key]">
<FormItem>
<FormLabel :for="key" class="text-right">
<FormLabel :for="key" class="text-left">
{{ property.title }}
</FormLabel>
<Select :id="key" class="col-span-3" v-bind="componentField">
@@ -87,7 +87,7 @@ watch(
v-model="formdata[key]"
>
<FormItem>
<FormLabel :for="key" class="text-right">
<FormLabel :for="key" class="text-left">
{{ property.title }}
</FormLabel>
<Input :id="key" class="col-span-3" v-bind="componentField" />
@@ -120,7 +120,7 @@ watch(
v-model="formdata[key]"
>
<FormItem>
<FormLabel :for="key" class="text-right">
<FormLabel :for="key" class="text-left">
{{ property.title }}
</FormLabel>
<Input :id="key" class="col-span-3" type="number" v-bind="componentField" />

View File

@@ -133,7 +133,7 @@ const permissionItems = computed(() => config.value?.permissions || [])
<form @submit="onSubmit" class="flex w-full flex-col items-start gap-4">
<FormField name="name" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="name" class="text-right">Name</FormLabel>
<FormLabel for="name" class="text-left">Name</FormLabel>
<Input
id="name"
class="col-span-3"
@@ -152,7 +152,7 @@ const permissionItems = computed(() => config.value?.permissions || [])
>
<FormItem id="permissions" class="w-full">
<div class="space-y-0.5">
<FormLabel for="permissions" class="text-right">Permissions</FormLabel>
<FormLabel for="permissions" class="text-left">Permissions</FormLabel>
</div>
<FormControl>
<MultiSelect

View File

@@ -82,7 +82,7 @@ watch(
<form @submit="onSubmit" @change="change">
<FormField name="group" v-slot="{ componentField }">
<FormItem>
<FormLabel for="group" class="text-right"> Group</FormLabel>
<FormLabel for="group" class="text-left"> Group</FormLabel>
<Select id="group" v-bind="componentField">
<SelectTrigger>
<SelectValue placeholder="Select a group" />

View File

@@ -109,6 +109,19 @@ const initials = (user: { name?: string } | undefined) => {
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Overview</SidebarGroupLabel>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton :tooltip="'Dashboard'" as-child>
<RouterLink to="/dashboard">
<Icon name="LayoutDashboard" class="size-4" />
<span>Dashboard</span>
</RouterLink>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Tickets</SidebarGroupLabel>
<SidebarMenu>

View File

@@ -13,7 +13,7 @@ import {
<template>
<FormField name="actiondata.requirements" v-slot="{ componentField }">
<FormItem>
<FormLabel for="requirements" class="text-right">requirements.txt</FormLabel>
<FormLabel for="requirements" class="text-left">requirements.txt</FormLabel>
<FormControl>
<GrowTextarea id="requirements" class="col-span-3" v-bind="componentField" />
</FormControl>
@@ -23,7 +23,7 @@ import {
</FormField>
<FormField name="actiondata.script" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="script" class="text-right">Script</FormLabel>
<FormLabel for="script" class="text-left">Script</FormLabel>
<FormControl>
<GrowTextarea id="script" class="col-span-3" v-bind="componentField" />
</FormControl>

View File

@@ -14,7 +14,7 @@ import { Input } from '@/components/ui/input'
<template>
<FormField name="actiondata.headers" v-slot="{ value, handleChange }">
<FormItem>
<FormLabel for="headers" class="text-right">Headers</FormLabel>
<FormLabel for="headers" class="text-left">Headers</FormLabel>
<FormControl>
<GrowListTextarea
id="headers"
@@ -29,7 +29,7 @@ import { Input } from '@/components/ui/input'
</FormField>
<FormField name="actiondata.url" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="url" class="text-right">URL</FormLabel>
<FormLabel for="url" class="text-left">URL</FormLabel>
<FormControl>
<Input id="url" v-bind="componentField" placeholder="https://example.com/webhook" />
</FormControl>

View File

@@ -267,7 +267,7 @@ const curlExample = computed(() => {
<form @submit="onSubmit" class="flex w-full flex-col items-start gap-4">
<FormField name="name" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="name" class="text-right">Name</FormLabel>
<FormLabel for="name" class="text-left">Name</FormLabel>
<Input id="name" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -280,7 +280,7 @@ const curlExample = computed(() => {
<CardContent class="flex flex-col gap-4">
<FormField name="trigger" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="trigger" class="text-right">Type</FormLabel>
<FormLabel for="trigger" class="text-left">Type</FormLabel>
<FormControl>
<Select id="trigger" class="col-span-3" v-bind="componentField">
<SelectTrigger class="font-medium">
@@ -321,7 +321,7 @@ const curlExample = computed(() => {
<CardContent class="flex flex-col gap-4">
<FormField name="action" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="action" class="text-right">Type</FormLabel>
<FormLabel for="action" class="text-left">Type</FormLabel>
<FormControl>
<Select id="action" class="col-span-3" v-bind="componentField">
<SelectTrigger class="font-medium">

View File

@@ -14,7 +14,7 @@ import {
<template>
<FormField name="triggerdata.collections" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="collections" class="text-right">Collections</FormLabel>
<FormLabel for="collections" class="text-left">Collections</FormLabel>
<FormControl>
<TriggerHookFormFieldCollections id="collections" v-bind="componentField" />
</FormControl>
@@ -25,7 +25,7 @@ import {
<FormField name="triggerdata.events" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="events" class="text-right">Events</FormLabel>
<FormLabel for="events" class="text-left">Events</FormLabel>
<FormControl>
<TriggerHookFormFieldEvents id="events" v-bind="componentField" />
</FormControl>

View File

@@ -13,7 +13,7 @@ import { Input } from '@/components/ui/input'
<template>
<FormField name="triggerdata.expression" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="expression" class="text-right"> Cron Expression </FormLabel>
<FormLabel for="expression" class="text-left"> Cron Expression </FormLabel>
<FormControl>
<Input
id="expression"

View File

@@ -13,7 +13,7 @@ import { Input } from '@/components/ui/input'
<template>
<FormField name="triggerdata.token" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="token" class="text-right">Token</FormLabel>
<FormLabel for="token" class="text-left">Token</FormLabel>
<FormControl>
<Input id="token" class="col-span-3" v-bind="componentField" placeholder="Enter a token" />
</FormControl>
@@ -27,7 +27,7 @@ import { Input } from '@/components/ui/input'
<FormField name="triggerdata.path" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="path" class="text-right">Path</FormLabel>
<FormLabel for="path" class="text-left">Path</FormLabel>
<FormControl>
<Input id="path" class="col-span-3" v-bind="componentField" placeholder="Enter a path" />
</FormControl>

View File

@@ -225,7 +225,7 @@ const onSubmit = handleSubmit((vals) => {
<form @submit="onSubmit" class="flex w-full flex-col items-start gap-4">
<FormField name="meta.appName" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="meta.appName" class="text-right">App Name</FormLabel>
<FormLabel for="meta.appName" class="text-left">App Name</FormLabel>
<Input id="meta.appName" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -233,7 +233,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="meta.appUrl" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="meta.appUrl" class="text-right">App URL</FormLabel>
<FormLabel for="meta.appUrl" class="text-left">App URL</FormLabel>
<Input id="meta.appUrl" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -241,7 +241,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="meta.senderName" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="meta.senderName" class="text-right">Sender Name</FormLabel>
<FormLabel for="meta.senderName" class="text-left">Sender Name</FormLabel>
<Input id="meta.senderName" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -249,7 +249,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="meta.senderAddress" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="meta.senderAddress" class="text-right">Sender Address</FormLabel>
<FormLabel for="meta.senderAddress" class="text-left">Sender Address</FormLabel>
<Input id="meta.senderAddress" type="email" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -262,7 +262,7 @@ const onSubmit = handleSubmit((vals) => {
<CardContent class="flex flex-col gap-4">
<FormField name="maxDays" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="maxDays" class="text-right">Max Days</FormLabel>
<FormLabel for="maxDays" class="text-left">Max Days</FormLabel>
<Input id="maxDays" type="number" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -270,7 +270,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="logLevel" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="logLevel" class="text-right">Log Level</FormLabel>
<FormLabel for="logLevel" class="text-left">Log Level</FormLabel>
<FormControl>
<Select id="logLevel" class="col-span-3" v-bind="componentField">
<SelectTrigger class="font-medium">
@@ -328,7 +328,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="smtp.host" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="smtp.host" class="text-right">Host</FormLabel>
<FormLabel for="smtp.host" class="text-left">Host</FormLabel>
<Input id="smtp.host" class="col-span-3" v-bind="componentField" />
<FormMessage />
<FormDescription>SMTP server hostname (e.g., smtp.gmail.com)</FormDescription>
@@ -337,7 +337,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="smtp.port" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="smtp.port" class="text-right">Port</FormLabel>
<FormLabel for="smtp.port" class="text-left">Port</FormLabel>
<Input id="smtp.port" type="number" class="col-span-3" v-bind="componentField" />
<FormMessage />
<FormDescription>Common ports: 25, 465 (SSL), 587 (TLS)</FormDescription>
@@ -346,7 +346,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="smtp.username" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="smtp.username" class="text-right">Username</FormLabel>
<FormLabel for="smtp.username" class="text-left">Username</FormLabel>
<Input id="smtp.username" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -354,7 +354,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="smtp.password" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="smtp.password" class="text-right">Password</FormLabel>
<FormLabel for="smtp.password" class="text-left">Password</FormLabel>
<Input id="smtp.password" type="password" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -362,7 +362,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="smtp.authMethod" v-slot="{ componentField }" validate-on-input>
<FormItem>
<FormLabel for="smtp.authMethod" class="text-right"> Authentication Method </FormLabel>
<FormLabel for="smtp.authMethod" class="text-left"> Authentication Method </FormLabel>
<Select id="smtp.authMethod" class="col-span-3" v-bind="componentField">
<SelectTrigger class="font-medium">
<SelectValue placeholder="Select authentication method" />
@@ -392,7 +392,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="smtp.localName" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="smtp.localName" class="text-right">HELO domain</FormLabel>
<FormLabel for="smtp.localName" class="text-left">HELO domain</FormLabel>
<Input id="smtp.localName" class="col-span-3" v-bind="componentField" />
<FormDescription>Optional. Leave empty to use default hostname.</FormDescription>
<FormMessage />
@@ -408,7 +408,7 @@ const onSubmit = handleSubmit((vals) => {
<CardContent class="flex flex-col gap-4">
<FormField name="cron" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="cron" class="text-right">Cron Expression</FormLabel>
<FormLabel for="cron" class="text-left">Cron Expression</FormLabel>
<Input id="cron" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -416,7 +416,7 @@ const onSubmit = handleSubmit((vals) => {
<FormField name="cronMaxKeep" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="cronMaxKeep" class="text-right">Max Keep</FormLabel>
<FormLabel for="cronMaxKeep" class="text-left">Max Keep</FormLabel>
<Input id="cronMaxKeep" type="number" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>

View File

@@ -142,7 +142,7 @@ watch(
<form @submit="onSubmit">
<FormField name="name" v-slot="{ componentField }" v-model="name">
<FormItem>
<FormLabel for="name" class="text-right">Name</FormLabel>
<FormLabel for="name" class="text-left">Name</FormLabel>
<Input id="name" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -150,7 +150,7 @@ watch(
<FormField name="description" v-slot="{ componentField }" v-model="description">
<FormItem>
<FormLabel for="description" class="text-right">Description</FormLabel>
<FormLabel for="description" class="text-left">Description</FormLabel>
<Input id="description" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>

View File

@@ -86,7 +86,7 @@ const change = () => validate({ mode: 'silent' }).then((res) => (submitDisabled.
<form @submit="onSubmit" @change="change">
<FormField name="name" v-slot="{ componentField }">
<FormItem>
<FormLabel for="name" class="text-right"> Name</FormLabel>
<FormLabel for="name" class="text-left"> Name</FormLabel>
<Input id="name" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -94,7 +94,7 @@ const change = () => validate({ mode: 'silent' }).then((res) => (submitDisabled.
<FormField name="url" v-slot="{ componentField }" class="mt-2">
<FormItem>
<FormLabel for="url" class="text-right"> URL</FormLabel>
<FormLabel for="url" class="text-left"> URL</FormLabel>
<Input id="url" v-bind="componentField" />
<FormMessage />
</FormItem>

View File

@@ -138,7 +138,7 @@ const onSubmit = handleSubmit((values) => {
<form @submit="onSubmit" class="flex w-full flex-col items-start gap-4">
<FormField name="singular" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="singular" class="text-right">Singular</FormLabel>
<FormLabel for="singular" class="text-left">Singular</FormLabel>
<Input id="singular" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -146,7 +146,7 @@ const onSubmit = handleSubmit((values) => {
<FormField name="plural" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="plural" class="text-right">Plural</FormLabel>
<FormLabel for="plural" class="text-left">Plural</FormLabel>
<Input id="plural" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>

View File

@@ -6,7 +6,7 @@ export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
export const SIDEBAR_WIDTH = '16rem'
export const SIDEBAR_WIDTH_MOBILE = '18rem'
export const SIDEBAR_WIDTH_ICON = '3rem'
export const SIDEBAR_KEYBOARD_SHORTCUT = 'b'
export const SIDEBAR_KEYBOARD_SHORTCUT = '`'
export const [useSidebar, provideSidebarContext] = createContext<{
state: ComputedRef<'expanded' | 'collapsed'>

View File

@@ -153,7 +153,7 @@ const onSubmit = handleSubmit((values) => emit('submit', values))
<form @submit="onSubmit" class="flex w-full flex-col items-start gap-4">
<FormField name="name" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="name" class="text-right">Name</FormLabel>
<FormLabel for="name" class="text-left">Name</FormLabel>
<Input id="name" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -161,7 +161,7 @@ const onSubmit = handleSubmit((values) => emit('submit', values))
<FormField name="username" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="username" class="text-right">Username</FormLabel>
<FormLabel for="username" class="text-left">Username</FormLabel>
<Input id="username" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -169,7 +169,7 @@ const onSubmit = handleSubmit((values) => emit('submit', values))
<FormField name="email" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="email" class="text-right">Email</FormLabel>
<FormLabel for="email" class="text-left">Email</FormLabel>
<Input id="email" type="email" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>

View File

@@ -111,7 +111,7 @@ const onSubmit = handleSubmit((values) => emit('submit', values))
<form @submit="onSubmit" class="flex w-full flex-col items-start gap-4">
<FormField name="password" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="password" class="text-right">Password</FormLabel>
<FormLabel for="password" class="text-left">Password</FormLabel>
<Input id="password" type="password" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>
@@ -119,7 +119,7 @@ const onSubmit = handleSubmit((values) => emit('submit', values))
<FormField name="passwordConfirm" v-slot="{ componentField }" validate-on-input>
<FormItem class="w-full">
<FormLabel for="passwordConfirm" class="text-right">Confirm Password</FormLabel>
<FormLabel for="passwordConfirm" class="text-left">Confirm Password</FormLabel>
<Input id="passwordConfirm" type="password" class="col-span-3" v-bind="componentField" />
<FormMessage />
</FormItem>

View File

@@ -82,7 +82,7 @@ watch(
<form @submit="onSubmit" @change="change">
<FormField name="user" v-slot="{ componentField }">
<FormItem>
<FormLabel for="user" class="text-right"> User</FormLabel>
<FormLabel for="user" class="text-left"> User</FormLabel>
<Select id="user" v-bind="componentField">
<SelectTrigger>
<SelectValue placeholder="Select a user" />

View File

@@ -58,14 +58,6 @@ const count = (id: string) => {
Open Catalyst Handbook
<ExternalLink class="ml-2 h-4 w-4" />
</a>
<a
href="/_/"
target="_blank"
class="flex items-center rounded border p-2 text-blue-500 hover:bg-accent"
>
Open Admin Interface
<ExternalLink class="ml-2 h-4 w-4" />
</a>
</CardContent>
</Card>
<Card>
@@ -118,14 +110,6 @@ const count = (id: string) => {
Open Catalyst Handbook
<ExternalLink class="ml-2 h-4 w-4" />
</a>
<a
href="/_/"
target="_blank"
class="flex items-center rounded border p-2 text-blue-500 hover:bg-accent"
>
Open Admin Interface
<ExternalLink class="ml-2 h-4 w-4" />
</a>
</CardContent>
</Card>
<Card>

View File

@@ -86,7 +86,7 @@ watch(
<Input
v-model="mail"
type="text"
placeholder="Username"
placeholder="Email"
class="w-full"
@keydown.enter="login"
/>

View File

@@ -19,9 +19,9 @@ export const test = baseTest.extend({
export const login = async (page, admin: boolean = true) => {
await page.goto('login')
if (admin) {
await page.getByPlaceholder('Username').fill('admin@catalyst-soar.com')
await page.getByPlaceholder('Email').fill('admin@catalyst-soar.com')
} else {
await page.getByPlaceholder('Username').fill('user@catalyst-soar.com')
await page.getByPlaceholder('Email').fill('user@catalyst-soar.com')
}
await page.getByPlaceholder('Password').fill('1234567890')
await page.getByRole('button', { name: 'Login' }).click()