diff --git a/.dockerignore b/.dockerignore index 8bc80fb..f7c8f97 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,5 @@ .env +backend/.env .vscode -README.md \ No newline at end of file +README.md +node_modules \ No newline at end of file diff --git a/backend/src/config.ts b/backend/src/config.ts index 2afabb0..f854ec9 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -17,4 +17,5 @@ export const OLLAMA_MODEL= process.env["OLLAMA_MODEL"] || "moondream"; export const PORT = parseInt(process.env["PORT"]!) || 3000; export const USE_SSL = process.env["USE_SSL"] === "1" ? true : false; export const SSL_KEY = process.env["SSL_KEY"] || ""; -export const SSL_CERT = process.env["SSL_CERT"] || ""; \ No newline at end of file +export const SSL_CERT = process.env["SSL_CERT"] || ""; +console.log(process.env); \ No newline at end of file diff --git a/dockerfile b/dockerfile index 5f3f412..aff7307 100644 --- a/dockerfile +++ b/dockerfile @@ -1,19 +1,14 @@ -# Use the official Node.js image -FROM node:18 AS base +FROM node:22-slim AS base WORKDIR /usr/src/app -# Install dependencies into temp directories -# This will cache them and speed up future builds FROM base AS install -# Install dependencies for both backend and frontend COPY backend/package.json backend/package-lock.json /temp/dev/backend/ COPY frontend/package.json frontend/package-lock.json /temp/dev/frontend/ RUN cd /temp/dev/backend && npm install RUN cd /temp/dev/frontend && npm install -# Install with --production (exclude devDependencies) RUN mkdir -p /temp/prod/backend /temp/prod/frontend COPY backend/package.json backend/package-lock.json /temp/prod/backend/ COPY frontend/package.json frontend/package-lock.json /temp/prod/frontend/ @@ -21,28 +16,20 @@ COPY frontend/package.json frontend/package-lock.json /temp/prod/frontend/ RUN cd /temp/prod/backend && npm install --production RUN cd /temp/prod/frontend && npm install --production -# Build the frontend project FROM install AS build-frontend WORKDIR /usr/src/app/frontend -COPY --from=install /temp/dev/frontend/node_modules node_modules COPY frontend/ . +COPY --from=install /temp/dev/frontend/node_modules node_modules RUN npm run build -# Prepare for final release FROM base AS release WORKDIR /usr/src/app - -# Copy production dependencies +COPY backend/ backend/ COPY --from=install /temp/prod/backend/node_modules backend/node_modules COPY --from=install /temp/prod/frontend/node_modules frontend/node_modules -# Copy backend source code -COPY backend/ backend/ - -# Copy the built frontend assets into the backend public directory COPY --from=build-frontend /usr/src/app/frontend/dist backend/public -# Set the entrypoint to run the backend server USER node WORKDIR /usr/src/app/backend EXPOSE 3000/tcp diff --git a/frontend/src/views/main.ts b/frontend/src/views/main.ts index ab5c716..8ff0edb 100644 --- a/frontend/src/views/main.ts +++ b/frontend/src/views/main.ts @@ -85,37 +85,37 @@ export class MainView extends View { public onCreate(): void { this.settingsButton = new Button("Settings") - .setPosition(0, 0, 10, 10) - .onClick(() => this.openSettingsDialog()); + .setPosition(0, 0, 10, 10) + .onClick(() => this.openSettingsDialog()); this.channelSwitcher = new Dropdown("Channel", []) - .setPosition(30, 10, 30, 10); + .setPosition(30, 10, 30, 10); this.channelInfoButton = new Button("Channel info") - .setPosition(60, 10, 30, 10); + .setPosition(60, 10, 30, 10); this.searchButton = new Button("Search") - .setPosition(90, 10, 10, 10) - .onClick(async () => this.openSearchDialog()); + .setPosition(90, 10, 10, 10) + .onClick(async () => this.openSearchDialog()); this.fileInput = new FileInput("Upload file") - .setPosition(0, 90, 15, 10); + .setPosition(0, 90, 15, 10); this.imageInput = new Button("Image") - .setPosition(15, 90, 15, 10); + .setPosition(15, 90, 15, 10); this.messageInput = new MultilineInput("New message") - .setPosition(30, 90, 60, 10); + .setPosition(30, 90, 60, 10); this.messageInput.getElement().autofocus = true; this.voiceMessageInput = new Button("Voice message") - .setPosition(70, 90, 30, 10); + .setPosition(70, 90, 30, 10); this.messageList = new List("Messages") - .setPosition(30, 30, 60, 50); + .setPosition(30, 30, 60, 50); this.window.add(this.settingsButton) - .add(this.channelSwitcher) - .add(this.channelInfoButton) - .add(this.searchButton) - .add(this.messageList) - .add(this.messageInput) - .add(this.fileInput) - .add(this.imageInput) - .add(this.voiceMessageInput); + .add(this.channelSwitcher) + .add(this.channelInfoButton) + .add(this.searchButton) + .add(this.messageList) + .add(this.messageInput) + .add(this.fileInput) + .add(this.imageInput) + .add(this.voiceMessageInput); this.channelSwitcher.getElement().addEventListener("change", (e) => this.handleChannelSwitcher(e)); this.voiceMessageInput.onClick(async () => this.handleVoiceMessageButton()); @@ -228,6 +228,11 @@ export class MainView extends View { itm.onClick(() => { this.openMessageDialog(message); }) + itm.onKeyDown((key: string, alt: boolean | undefined, shift: boolean | undefined, ctrl: boolean | undefined) => { + if (key === "Delete") { + this.removeMessage(message.id); + } + }); return itm; } @@ -563,7 +568,7 @@ export class MainView extends View { } state.save(); this.updateChannelList(); - }); + }); } private async handleImageButton() { @@ -579,7 +584,7 @@ export class MainView extends View { this.hotkeyMap.set("v", () => this.handleVoiceMessageButton()); this.hotkeyMap.set(" ", () => this.messageInput.focus()); } - + private handleHotkey(e: KeyboardEvent) { if (e.ctrlKey && e.shiftKey) { const action = this.hotkeyMap.get(e.key.toLowerCase()); @@ -593,7 +598,6 @@ export class MainView extends View { private async openMessageDialog(message: IMessage) { const d = new MessageDialog(message); const msg = await d.open(); - console.log(msg); if (!msg || msg === null) { state.currentChannel?.removeMessage(message.id); const node = this.messageElementMap.get(message.id); @@ -604,4 +608,17 @@ export class MainView extends View { state.save(); } } + + private async removeMessage(id: number) { + if (state.currentChannel) { + await API.deleteMessage(state.currentChannel.id.toString(), id.toString()); + state.currentChannel.removeMessage(id); + const node = this.messageElementMap.get(id); + if (node) { + this.messageList.remove(node); + this.messageElementMap.delete(id); + state.save(); + } + } + } } \ No newline at end of file