This commit is contained in:
Ivan Grachyov
2025-12-26 23:36:21 +03:00
parent 0f218c1519
commit ca773a56c6
18 changed files with 315 additions and 7 deletions

Binary file not shown.

View File

@@ -13,17 +13,19 @@ declare module 'vue' {
PrimeButton: typeof import('primevue/button')['default']
PrimeButtonGroup: typeof import('primevue/buttongroup')['default']
PrimeCard: typeof import('primevue/card')['default']
PrimeDivider: typeof import('primevue/divider')['default']
PrimeFloatLabel: typeof import('primevue/floatlabel')['default']
PrimeInputText: typeof import('primevue/inputtext')['default']
PrimePassword: typeof import('primevue/password')['default']
PrimeProgressBar: typeof import('primevue/progressbar')['default']
PrimeScrollPanel: typeof import('primevue/scrollpanel')['default']
PrimeSelect: typeof import('primevue/select')['default']
PrimeSelectButton: typeof import('primevue/selectbutton')['default']
PrimeSlider: typeof import('primevue/slider')['default']
PrimeTab: typeof import('primevue/tab')['default']
PrimeTabList: typeof import('primevue/tablist')['default']
PrimeTabPanel: typeof import('primevue/tabpanel')['default']
PrimeTabPanels: typeof import('primevue/tabpanels')['default']
PrimeTabs: typeof import('primevue/tabs')['default']
PrimeTextarea: typeof import('primevue/textarea')['default']
PrimeToast: typeof import('primevue/toast')['default']
PrimeToggleSwitch: typeof import('primevue/toggleswitch')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}

View File

@@ -0,0 +1,28 @@
<template>
<div class="chat-editor">
<PrimeTextarea v-model="msg" />
<PrimeButton :disabled="!msg" @click="handleSend()">
Send
</PrimeButton>
</div>
</template>
<script lang="ts" setup>
interface Emits {
(e: 'send', msg: string): void
}
const emit = defineEmits<Emits>()
const msg = ref<string | undefined>()
function handleSend() {
emit('send', msg.value!)
msg.value = ''
}
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,27 @@
<template>
<PrimeCard>
<template #header>
<span class="font-bold">
{{ username }}
</span>
</template>
<template #content>
{{ message }}
</template>
<template #footer>
{{ createdAt }}
</template>
</PrimeCard>
</template>
<script lang="ts" setup>
interface Props {
username: string
message: string
createdAt: Date
}
defineProps<Props>()
</script>
<style lang="scss"></style>

View File

@@ -0,0 +1,33 @@
<template>
<div class="chat-tabs">
<div class="chat-tabs__messages">
<ChatMessage v-for="msg in messages" :key="msg.id" :created-at="msg.createdAt" :username="msg.username" :message="msg.message" />
</div>
<PrimeTabs :value="channels[0]">
<PrimeTabList>
<PrimeTab v-for="channel in channels" :key="channel" :value="channel">
Channel: {{ channel }}
</PrimeTab>
</PrimeTabList>
<PrimeTabPanels>
<PrimeTabPanel :value="channel">
<ChatEditor />
</PrimeTabPanel>
</PrimeTabPanels>
</PrimeTabs>
</div>
</template>
<script lang="ts" setup>
const {
channel,
messages,
channels,
} = useChat()
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,44 @@
import { createGlobalState } from '@vueuse/core'
interface ChatMessage {
id: string
username: string
message: string
}
interface ChatChannel {
id: number
name: string
}
export const useChat = createGlobalState(() => {
const messages = ref([
{
id: '1337',
username: 'Yes',
message: 'Fisting is 300 bucks',
createdAt: Date.now(),
},
])
const channel = ref<number>(0)
async function sendMsg(channelId: ChatChannel['id'], msg: ChatMessage['message']) {
console.log('Trying to send message', channelId, msg)
}
watch(channel, async (id) => {
await console.log('Yes', id)
}, {
immediate: true,
})
return {
channel,
channels,
messages,
sendMsg,
}
})

View File

@@ -3,7 +3,7 @@
<div class="flex items-center justify-center">
<PrimeCard>
<template #content>
The chat is under development.
<ChatWidget />
</template>
</PrimeCard>
</div>

View File

@@ -4,7 +4,7 @@ pub fn run() {
.plugin(tauri_plugin_global_shortcut::Builder::new().build())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_single_instance::init(|_, _, _| {}))
// .plugin(tauri_plugin_single_instance::init(|_, _, _| {}))
.setup(|app| {
if cfg!(debug_assertions) {
app.handle().plugin(

12
node_modules/.yarn-integrity generated vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"systemParams": "win32-x64-137",
"modulesFolders": [
"node_modules"
],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [],
"lockfileEntries": {},
"files": [],
"artifacts": {}
}

View File

@@ -0,0 +1,22 @@
import client from '../../prisma/client.ts'
export async function chatInit() {
const existing = client.chatChannel.findFirst({
where: {
id: 0,
},
})
if (!existing) {
await client.chatChannel.create({
create: {
id: 0,
name: 'Main channel',
},
update: null,
where: {
id: 0,
},
})
}
}

View File

@@ -0,0 +1,20 @@
/*
Warnings:
- You are about to drop the column `volumes` on the `UserPreferences` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_UserPreferences" (
"userId" TEXT NOT NULL PRIMARY KEY,
"toggleInputHotkey" TEXT DEFAULT '',
"toggleOutputHotkey" TEXT DEFAULT '',
CONSTRAINT "UserPreferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_UserPreferences" ("toggleInputHotkey", "toggleOutputHotkey", "userId") SELECT "toggleInputHotkey", "toggleOutputHotkey", "userId" FROM "UserPreferences";
DROP TABLE "UserPreferences";
ALTER TABLE "new_UserPreferences" RENAME TO "UserPreferences";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,18 @@
-- CreateTable
CREATE TABLE "ChatMessage" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"channelId" TEXT NOT NULL,
"content" TEXT NOT NULL DEFAULT '',
CONSTRAINT "ChatMessage_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "ChatMessage_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "ChatChannel" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "ChatChannel" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "ChatChannel_name_key" ON "ChatChannel"("name");

View File

@@ -0,0 +1,34 @@
/*
Warnings:
- The primary key for the `ChatChannel` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to alter the column `id` on the `ChatChannel` table. The data in that column could be lost. The data in that column will be cast from `String` to `Int`.
- You are about to alter the column `channelId` on the `ChatMessage` table. The data in that column could be lost. The data in that column will be cast from `String` to `Int`.
- Added the required column `createdAt` to the `ChatMessage` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_ChatChannel" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL
);
INSERT INTO "new_ChatChannel" ("id", "name") SELECT "id", "name" FROM "ChatChannel";
DROP TABLE "ChatChannel";
ALTER TABLE "new_ChatChannel" RENAME TO "ChatChannel";
CREATE UNIQUE INDEX "ChatChannel_name_key" ON "ChatChannel"("name");
CREATE TABLE "new_ChatMessage" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"channelId" INTEGER NOT NULL,
"content" TEXT NOT NULL DEFAULT '',
"createdAt" DATETIME NOT NULL,
CONSTRAINT "ChatMessage_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "ChatMessage_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "ChatChannel" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_ChatMessage" ("channelId", "content", "id", "userId") SELECT "channelId", "content", "id", "userId" FROM "ChatMessage";
DROP TABLE "ChatMessage";
ALTER TABLE "new_ChatMessage" RENAME TO "ChatMessage";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,17 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_ChatMessage" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"channelId" INTEGER NOT NULL,
"content" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "ChatMessage_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "ChatMessage_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "ChatChannel" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_ChatMessage" ("channelId", "content", "createdAt", "id", "userId") SELECT "channelId", "content", "createdAt", "id", "userId" FROM "ChatMessage";
DROP TABLE "ChatMessage";
ALTER TABLE "new_ChatMessage" RENAME TO "ChatMessage";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -18,6 +18,8 @@ model User {
Session Session[]
UserPreferences UserPreferences?
ChatMessage ChatMessage[]
}
model Session {
@@ -34,7 +36,26 @@ model UserPreferences {
userId String @id
toggleInputHotkey String? @default("")
toggleOutputHotkey String? @default("")
volumes Json? @default("{}")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model ChatMessage {
id String @id
userId String
channelId Int
content String
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
channel ChatChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
}
model ChatChannel {
id Int @id
name String @unique
messages ChatMessage[]
}

23
server/routes/chat.ts Normal file
View File

@@ -0,0 +1,23 @@
import type { FastifyInstance } from 'fastify'
import prisma from '../prisma/client.ts'
export default function (fastify: FastifyInstance) {
fastify.get('/chats', async (req, reply) => {
if (req.user) {
return prisma.chatChannel.findMany()
}
reply.code(401).send(false)
})
fastify.get('/chats/:id', async (req, reply) => {
if (req.user) {
console.log('Trying to fetch chat with id', req.body.id)
// return prisma.userPreferences.findFirst({ where: { userId: req.user.id } })
return true
}
reply.code(401).send(false)
})
}

View File

@@ -4,6 +4,7 @@ import FastifyAutoLoad from '@fastify/autoload'
import FastifyCookie from '@fastify/cookie'
import FastifyCors from '@fastify/cors'
import Fastify from 'fastify'
import { chatInit } from './modules/chat/index.ts'
import prisma from './prisma/client.ts'
const __filename = fileURLToPath(import.meta.url)
@@ -43,6 +44,8 @@ fastify.register(FastifyAutoLoad, {
await prisma.$connect()
fastify.log.info('Testing DB Connection. OK')
await chatInit()
}
catch (err) {
fastify.log.error(err)

4
yarn.lock Normal file
View File

@@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1