diff --git a/.adonisjs/server/pages.d.ts b/.adonisjs/server/pages.d.ts index 9194775..e73e235 100644 --- a/.adonisjs/server/pages.d.ts +++ b/.adonisjs/server/pages.d.ts @@ -9,7 +9,6 @@ type ExtractProps = Omit< declare module '@adonisjs/inertia/types' { export interface InertiaPages { - 'account/signup': ExtractProps<(typeof import('../../inertia/pages/account/signup.vue'))['default']> 'auth/login': ExtractProps<(typeof import('../../inertia/pages/auth/login.vue'))['default']> 'auth/signup': ExtractProps<(typeof import('../../inertia/pages/auth/signup.vue'))['default']> 'components/create': ExtractProps<(typeof import('../../inertia/pages/components/create.vue'))['default']> diff --git a/app/validators/user.ts b/app/validators/user.ts index 7225d2a..e7c28f2 100644 --- a/app/validators/user.ts +++ b/app/validators/user.ts @@ -4,7 +4,7 @@ const email = () => vine.string().email().maxLength(254) const password = () => vine.string().minLength(8).maxLength(32) export const signupValidator = vine.create({ - fullName: vine.string().nullable(), + name: vine.string().nullable(), email: email().unique({ table: 'users', column: 'email' }), password: password().confirmed({ confirmationField: 'passwordConfirmation', diff --git a/database/schema.ts b/database/schema.ts index 11a42b3..0961591 100644 --- a/database/schema.ts +++ b/database/schema.ts @@ -7,6 +7,134 @@ import { BaseModel, column } from '@adonisjs/lucid/orm' import { DateTime } from 'luxon' +export class AccessListSchema extends BaseModel { + static $columns = ['createdOn', 'id', 'isDeleted', 'meta', 'modifiedOn', 'name', 'ownerUserId', 'passAuth', 'satisfyAny'] as const + $columns = AccessListSchema.$columns + @column.dateTime() + declare createdOn: DateTime + @column({ isPrimary: true }) + declare id: number + @column() + declare isDeleted: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare name: string + @column() + declare ownerUserId: number + @column() + declare passAuth: number + @column() + declare satisfyAny: number +} + +export class AccessListAuthSchema extends BaseModel { + static $columns = ['accessListId', 'createdOn', 'id', 'meta', 'modifiedOn', 'password', 'username'] as const + $columns = AccessListAuthSchema.$columns + @column() + declare accessListId: number + @column.dateTime() + declare createdOn: DateTime + @column({ isPrimary: true }) + declare id: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column({ serializeAs: null }) + declare password: string + @column() + declare username: string +} + +export class AccessListClientSchema extends BaseModel { + static $columns = ['accessListId', 'address', 'createdOn', 'directive', 'id', 'meta', 'modifiedOn'] as const + $columns = AccessListClientSchema.$columns + @column() + declare accessListId: number + @column() + declare address: string + @column.dateTime() + declare createdOn: DateTime + @column() + declare directive: string + @column({ isPrimary: true }) + declare id: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime +} + +export class AuditLogSchema extends BaseModel { + static $columns = ['action', 'createdOn', 'id', 'meta', 'modifiedOn', 'objectId', 'objectType', 'userId'] as const + $columns = AuditLogSchema.$columns + @column() + declare action: string + @column.dateTime() + declare createdOn: DateTime + @column({ isPrimary: true }) + declare id: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare objectId: number + @column() + declare objectType: string + @column() + declare userId: number +} + +export class AuthSchema extends BaseModel { + static $columns = ['createdOn', 'id', 'isDeleted', 'meta', 'modifiedOn', 'secret', 'type', 'userId'] as const + $columns = AuthSchema.$columns + @column.dateTime() + declare createdOn: DateTime + @column({ isPrimary: true }) + declare id: number + @column() + declare isDeleted: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare secret: string + @column() + declare type: string + @column() + declare userId: number +} + +export class CertificateSchema extends BaseModel { + static $columns = ['createdOn', 'domainNames', 'expiresOn', 'id', 'isDeleted', 'meta', 'modifiedOn', 'niceName', 'ownerUserId', 'provider'] as const + $columns = CertificateSchema.$columns + @column.dateTime() + declare createdOn: DateTime + @column() + declare domainNames: any + @column.dateTime() + declare expiresOn: DateTime + @column({ isPrimary: true }) + declare id: number + @column() + declare isDeleted: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare niceName: string + @column() + declare ownerUserId: number + @column() + declare provider: string +} + export class ComponentTypeSchema extends BaseModel { static $columns = ['id', 'name', 'unique'] as const $columns = ComponentTypeSchema.$columns @@ -92,6 +220,253 @@ export class ComputerSchema extends BaseModel { declare userId: number | null } +export class DeadHostSchema extends BaseModel { + static $columns = ['advancedConfig', 'certificateId', 'createdOn', 'domainNames', 'enabled', 'hstsEnabled', 'hstsSubdomains', 'http2Support', 'id', 'isDeleted', 'meta', 'modifiedOn', 'ownerUserId', 'sslForced'] as const + $columns = DeadHostSchema.$columns + @column() + declare advancedConfig: string + @column() + declare certificateId: number + @column.dateTime() + declare createdOn: DateTime + @column() + declare domainNames: any + @column() + declare enabled: number + @column() + declare hstsEnabled: number + @column() + declare hstsSubdomains: number + @column() + declare http2Support: number + @column({ isPrimary: true }) + declare id: number + @column() + declare isDeleted: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare ownerUserId: number + @column() + declare sslForced: number +} + +export class MigrationSchema extends BaseModel { + static $columns = ['batch', 'id', 'migrationTime', 'name'] as const + $columns = MigrationSchema.$columns + @column() + declare batch: number | null + @column({ isPrimary: true }) + declare id: number + @column.dateTime() + declare migrationTime: DateTime | null + @column() + declare name: string | null +} + +export class MigrationsLockSchema extends BaseModel { + static $columns = ['index', 'isLocked'] as const + $columns = MigrationsLockSchema.$columns + @column({ isPrimary: true }) + declare index: number + @column() + declare isLocked: number | null +} + +export class ProxyHostSchema extends BaseModel { + static $columns = ['accessListId', 'advancedConfig', 'allowWebsocketUpgrade', 'blockExploits', 'cachingEnabled', 'certificateId', 'createdOn', 'domainNames', 'enabled', 'forwardHost', 'forwardPort', 'forwardScheme', 'hstsEnabled', 'hstsSubdomains', 'http2Support', 'id', 'isDeleted', 'locations', 'meta', 'modifiedOn', 'ownerUserId', 'sslForced', 'trustForwardedProto'] as const + $columns = ProxyHostSchema.$columns + @column() + declare accessListId: number + @column() + declare advancedConfig: string + @column() + declare allowWebsocketUpgrade: number + @column() + declare blockExploits: number + @column() + declare cachingEnabled: number + @column() + declare certificateId: number + @column.dateTime() + declare createdOn: DateTime + @column() + declare domainNames: any + @column() + declare enabled: number + @column() + declare forwardHost: string + @column() + declare forwardPort: number + @column() + declare forwardScheme: string + @column() + declare hstsEnabled: number + @column() + declare hstsSubdomains: number + @column() + declare http2Support: number + @column({ isPrimary: true }) + declare id: number + @column() + declare isDeleted: number + @column() + declare locations: any | null + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare ownerUserId: number + @column() + declare sslForced: number + @column() + declare trustForwardedProto: boolean +} + +export class RedirectionHostSchema extends BaseModel { + static $columns = ['advancedConfig', 'blockExploits', 'certificateId', 'createdOn', 'domainNames', 'enabled', 'forwardDomainName', 'forwardHttpCode', 'forwardScheme', 'hstsEnabled', 'hstsSubdomains', 'http2Support', 'id', 'isDeleted', 'meta', 'modifiedOn', 'ownerUserId', 'preservePath', 'sslForced'] as const + $columns = RedirectionHostSchema.$columns + @column() + declare advancedConfig: string + @column() + declare blockExploits: number + @column() + declare certificateId: number + @column.dateTime() + declare createdOn: DateTime + @column() + declare domainNames: any + @column() + declare enabled: number + @column() + declare forwardDomainName: string + @column() + declare forwardHttpCode: number + @column() + declare forwardScheme: string + @column() + declare hstsEnabled: number + @column() + declare hstsSubdomains: number + @column() + declare http2Support: number + @column({ isPrimary: true }) + declare id: number + @column() + declare isDeleted: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare ownerUserId: number + @column() + declare preservePath: number + @column() + declare sslForced: number +} + +export class SettingSchema extends BaseModel { + static $columns = ['description', 'id', 'meta', 'name', 'value'] as const + $columns = SettingSchema.$columns + @column() + declare description: string + @column({ isPrimary: true }) + declare id: string + @column() + declare meta: any + @column() + declare name: string + @column() + declare value: string +} + +export class StreamSchema extends BaseModel { + static $columns = ['certificateId', 'createdOn', 'enabled', 'forwardingHost', 'forwardingPort', 'id', 'incomingPort', 'isDeleted', 'meta', 'modifiedOn', 'ownerUserId', 'tcpForwarding', 'udpForwarding'] as const + $columns = StreamSchema.$columns + @column() + declare certificateId: number + @column.dateTime() + declare createdOn: DateTime + @column() + declare enabled: number + @column() + declare forwardingHost: string + @column() + declare forwardingPort: number + @column({ isPrimary: true }) + declare id: number + @column() + declare incomingPort: number + @column() + declare isDeleted: number + @column() + declare meta: any + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare ownerUserId: number + @column() + declare tcpForwarding: number + @column() + declare udpForwarding: number +} + +export class UserSchema extends BaseModel { + static $columns = ['avatar', 'createdOn', 'email', 'id', 'isDeleted', 'isDisabled', 'modifiedOn', 'name', 'nickname', 'roles'] as const + $columns = UserSchema.$columns + @column() + declare avatar: string + @column.dateTime() + declare createdOn: DateTime + @column() + declare email: string + @column({ isPrimary: true }) + declare id: number + @column() + declare isDeleted: number + @column() + declare isDisabled: number + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare name: string + @column() + declare nickname: string + @column() + declare roles: any +} + +export class UserPermissionSchema extends BaseModel { + static $columns = ['accessLists', 'certificates', 'createdOn', 'deadHosts', 'id', 'modifiedOn', 'proxyHosts', 'redirectionHosts', 'streams', 'userId', 'visibility'] as const + $columns = UserPermissionSchema.$columns + @column() + declare accessLists: string + @column() + declare certificates: string + @column.dateTime() + declare createdOn: DateTime + @column() + declare deadHosts: string + @column({ isPrimary: true }) + declare id: number + @column.dateTime() + declare modifiedOn: DateTime + @column() + declare proxyHosts: string + @column() + declare redirectionHosts: string + @column() + declare streams: string + @column() + declare userId: number + @column() + declare visibility: string +} + export class UserSchema extends BaseModel { static $columns = ['createdAt', 'email', 'id', 'name', 'password', 'updatedAt'] as const $columns = UserSchema.$columns diff --git a/database/seeders/component_type_seeder.ts b/database/seeders/component_type_seeder.ts new file mode 100644 index 0000000..5c16c01 --- /dev/null +++ b/database/seeders/component_type_seeder.ts @@ -0,0 +1,57 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import ComponentType from '#models/component_type' + +export default class extends BaseSeeder { + async run() { + await ComponentType.createMany([ + { + name: 'Processor', + unique: true, + }, + { + name: 'Motherboard', + unique: true, + }, + { + name: 'Graphic Card', + unique: true, + }, + { + name: 'Memory', + unique: true, + }, + { + name: 'SSD', + unique: true, + }, + { + name: 'HDD', + unique: true, + }, + { + name: 'Cooler', + unique: true, + }, + { + name: 'Power Supply', + unique: true, + }, + { + name: 'Case', + unique: true, + }, + { + name: 'Fan', + unique: false, + }, + { + name: 'WiFi-Card', + unique: true, + }, + { + name: 'Other', + unique: false, + }, + ]) + } +} diff --git a/database/seeders/computer_state_seeder.ts b/database/seeders/computer_state_seeder.ts new file mode 100644 index 0000000..da065dc --- /dev/null +++ b/database/seeders/computer_state_seeder.ts @@ -0,0 +1,18 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import ComputerState from '#models/computer_state' + +export default class extends BaseSeeder { + async run() { + await ComputerState.createMany([ + { + name: 'ON_GOING', + }, + { + name: 'FINISHED', + }, + { + name: 'SOLD', + }, + ]) + } +} diff --git a/inertia/css/app.css b/inertia/css/app.css index 3e3515d..41ca9ca 100644 --- a/inertia/css/app.css +++ b/inertia/css/app.css @@ -2,18 +2,6 @@ @tailwind components; @tailwind utilities; -:root { - --gray-1: oklch(98.5% 0 0); - --gray-2: oklch(97% 0 0); - --gray-3: oklch(92.2% 0 0); - --gray-4: oklch(87% 0 0); - --gray-6: oklch(55.6% 0 0); - --gray-7: oklch(43.9% 0 0); - --gray-8: oklch(37.1% 0 0); - --gray-10: oklch(26.9% 0 0); - --gray-12: oklch(14.5% 0 0); -} - * { box-sizing: border-box; margin: 0; @@ -23,218 +11,11 @@ html, body { height: 100%; - font-family: system-ui, sans-serif; -webkit-font-smoothing: antialiased; - background: var(--gray-2); - color: var(--gray-10); - font-size: 16px; - line-height: 1.5; } -a { - color: inherit; - text-decoration: none; -} - -[x-cloak] { - display: none; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - color: var(--gray-12); -} - -/* Header */ -header { - max-width: 1440px; - margin: auto; - padding: 0 30px; -} -header > div { - display: flex; - justify-content: space-between; - align-items: center; - height: 64px; -} -header nav { - display: flex; - align-items: center; - gap: 26px; -} -header nav a { - font-weight: 500; - color: var(--gray-8); -} -header nav a:hover, -header nav a.current { - color: var(--gray-12); -} - -/* Main */ -main { - max-width: 1440px; - margin: 0 30px; - display: flex; - flex-direction: column; - justify-content: space-between; - min-height: calc(100vh - 65px); - background: #fff; - border: 1px solid var(--gray-3); -} - -.hero { - padding: 100px 50px; - max-width: 880px; -} -.hero h1 { - margin-bottom: 15px; - font-size: 52px; - font-weight: 600; - letter-spacing: -1px; - line-height: 1.05; -} -.hero p { - font-size: 22px; - color: var(--gray-7); -} -.hero .button { - margin-top: 30px; +.material-symbols-outlined { + font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; display: inline-block; - padding: 10px 16px; -} - -.cards { - display: grid; - grid-template-columns: repeat(3, 1fr); - padding: 0 50px; - border-top: 1px solid var(--gray-3); -} -.cards a { - padding: 30px 40px; - border-right: 1px solid var(--gray-3); -} -.cards a:first-child { - border-left: 1px solid var(--gray-3); -} -.cards a:hover { - background: var(--gray-1); -} -.cards h3 { - margin-bottom: 10px; - font-size: 20px; - font-weight: 600; - letter-spacing: -0.4px; -} -.cards p { - color: var(--gray-6); -} - -/* Form */ -.form-container { - display: flex; - flex-direction: column; - justify-content: center; - max-width: 400px; - margin: auto; -} -.form-container h1 { - font-size: 32px; - letter-spacing: -0.5px; - margin-bottom: 5px; -} -.form-container p { - font-size: 18px; - margin-bottom: 48px; - color: var(--gray-6); -} -form { - display: flex; - flex-direction: column; - gap: 24px; -} -label { - margin-bottom: 4px; - display: block; - font-size: 14px; - font-weight: 500; -} -input, -textarea, -button { - width: 100%; - border-radius: 4px; - font: inherit; -} -input { - height: 40px; - border: 1px solid var(--gray-4); - padding: 0 16px; -} -input[data-invalid='true'], -textarea[data-invalid='true'] { - border-color: #fb2c36; -} -input[data-invalid='true'] + div, -textarea[data-invalid='true'] + div { - color: #fb2c36; - font-size: 14px; - font-weight: 500; - margin-top: 2px; -} - -button { - background: var(--gray-12); - color: #fff; - border: none; - padding: 10px; - font-weight: 500; -} -button:hover { - background: var(--gray-10); -} - -/* Alerts */ -.alert { - background: #fff; - position: relative; - padding: 12px 16px; - font-size: 14px; - min-width: 380px; - font-weight: 500; - border: 1px solid var(--gray-3); - border-radius: 10px; - animation: scale-up 0.2s cubic-bezier(0.39, 0.575, 0.565, 1) both; -} -.alert-destructive { - color: #fb2c36; - background: #fb2c361a; - border-color: #fb2c36; -} -.alert-success { - color: #00a63e; - background: #00a63e1a; - border-color: #00a63e; -} -.flash-container { - position: fixed; - top: 80px; - left: 0; - right: 0; - display: flex; - flex-direction: column; - align-items: center; -} - -@keyframes scale-up { - from { - transform: scale(0.7); - } - to { - transform: scale(1); - } + vertical-align: middle; } diff --git a/inertia/pages/account/signup.vue b/inertia/pages/account/signup.vue deleted file mode 100644 index a9cba73..0000000 --- a/inertia/pages/account/signup.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/inertia/pages/auth/login.vue b/inertia/pages/auth/login.vue index e544cf5..a1792fc 100644 --- a/inertia/pages/auth/login.vue +++ b/inertia/pages/auth/login.vue @@ -5,18 +5,18 @@ import EmptyLayout from '~/pages/layout/emptyLayout.vue' defineOptions({ layout: EmptyLayout }) -const props = defineProps<{ errors?: any[] | any }>() +const props = defineProps<{ errors?: Record }>() const vineErrors = computed(() => { - if (Array.isArray(props.errors)) { - return props.errors as any[] + if (props.errors && !Array.isArray(props.errors)) { + return props.errors } - return [] + return {} }) const authError = computed(() => { - if (!Array.isArray(props.errors) && props.errors) { - return props.errors as any + if (props.errors && !Array.isArray(props.errors)) { + return props.errors } return null }) @@ -27,13 +27,8 @@ const form = useForm({ }) function getErrorMessage(field: string): string | null { - const error = vineErrors.value.find((error) => error.field === field) - return error ? error.message : null + return vineErrors.value[field] || null } - -console.log(authError) -console.log(vineErrors) -console.log(props)