Delete key removes message when focused

main
Talon 2024-08-30 23:28:05 +02:00
parent ce895a6716
commit cd2f32ae02
4 changed files with 47 additions and 40 deletions

View File

@ -1,3 +1,5 @@
.env .env
backend/.env
.vscode .vscode
README.md README.md
node_modules

View File

@ -17,4 +17,5 @@ export const OLLAMA_MODEL= process.env["OLLAMA_MODEL"] || "moondream";
export const PORT = parseInt(process.env["PORT"]!) || 3000; export const PORT = parseInt(process.env["PORT"]!) || 3000;
export const USE_SSL = process.env["USE_SSL"] === "1" ? true : false; export const USE_SSL = process.env["USE_SSL"] === "1" ? true : false;
export const SSL_KEY = process.env["SSL_KEY"] || ""; export const SSL_KEY = process.env["SSL_KEY"] || "";
export const SSL_CERT = process.env["SSL_CERT"] || ""; export const SSL_CERT = process.env["SSL_CERT"] || "";
console.log(process.env);

View File

@ -1,19 +1,14 @@
# Use the official Node.js image FROM node:22-slim AS base
FROM node:18 AS base
WORKDIR /usr/src/app WORKDIR /usr/src/app
# Install dependencies into temp directories
# This will cache them and speed up future builds
FROM base AS install FROM base AS install
# Install dependencies for both backend and frontend
COPY backend/package.json backend/package-lock.json /temp/dev/backend/ COPY backend/package.json backend/package-lock.json /temp/dev/backend/
COPY frontend/package.json frontend/package-lock.json /temp/dev/frontend/ COPY frontend/package.json frontend/package-lock.json /temp/dev/frontend/
RUN cd /temp/dev/backend && npm install RUN cd /temp/dev/backend && npm install
RUN cd /temp/dev/frontend && npm install RUN cd /temp/dev/frontend && npm install
# Install with --production (exclude devDependencies)
RUN mkdir -p /temp/prod/backend /temp/prod/frontend RUN mkdir -p /temp/prod/backend /temp/prod/frontend
COPY backend/package.json backend/package-lock.json /temp/prod/backend/ COPY backend/package.json backend/package-lock.json /temp/prod/backend/
COPY frontend/package.json frontend/package-lock.json /temp/prod/frontend/ 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/backend && npm install --production
RUN cd /temp/prod/frontend && npm install --production RUN cd /temp/prod/frontend && npm install --production
# Build the frontend project
FROM install AS build-frontend FROM install AS build-frontend
WORKDIR /usr/src/app/frontend WORKDIR /usr/src/app/frontend
COPY --from=install /temp/dev/frontend/node_modules node_modules
COPY frontend/ . COPY frontend/ .
COPY --from=install /temp/dev/frontend/node_modules node_modules
RUN npm run build RUN npm run build
# Prepare for final release
FROM base AS release FROM base AS release
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY backend/ backend/
# Copy production dependencies
COPY --from=install /temp/prod/backend/node_modules backend/node_modules COPY --from=install /temp/prod/backend/node_modules backend/node_modules
COPY --from=install /temp/prod/frontend/node_modules frontend/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 COPY --from=build-frontend /usr/src/app/frontend/dist backend/public
# Set the entrypoint to run the backend server
USER node USER node
WORKDIR /usr/src/app/backend WORKDIR /usr/src/app/backend
EXPOSE 3000/tcp EXPOSE 3000/tcp

View File

@ -85,37 +85,37 @@ export class MainView extends View {
public onCreate(): void { public onCreate(): void {
this.settingsButton = new Button("Settings") this.settingsButton = new Button("Settings")
.setPosition(0, 0, 10, 10) .setPosition(0, 0, 10, 10)
.onClick(() => this.openSettingsDialog()); .onClick(() => this.openSettingsDialog());
this.channelSwitcher = new Dropdown("Channel", []) this.channelSwitcher = new Dropdown("Channel", [])
.setPosition(30, 10, 30, 10); .setPosition(30, 10, 30, 10);
this.channelInfoButton = new Button("Channel info") this.channelInfoButton = new Button("Channel info")
.setPosition(60, 10, 30, 10); .setPosition(60, 10, 30, 10);
this.searchButton = new Button("Search") this.searchButton = new Button("Search")
.setPosition(90, 10, 10, 10) .setPosition(90, 10, 10, 10)
.onClick(async () => this.openSearchDialog()); .onClick(async () => this.openSearchDialog());
this.fileInput = new FileInput("Upload file") this.fileInput = new FileInput("Upload file")
.setPosition(0, 90, 15, 10); .setPosition(0, 90, 15, 10);
this.imageInput = new Button("Image") this.imageInput = new Button("Image")
.setPosition(15, 90, 15, 10); .setPosition(15, 90, 15, 10);
this.messageInput = new MultilineInput("New message") this.messageInput = new MultilineInput("New message")
.setPosition(30, 90, 60, 10); .setPosition(30, 90, 60, 10);
this.messageInput.getElement().autofocus = true; this.messageInput.getElement().autofocus = true;
this.voiceMessageInput = new Button("Voice message") this.voiceMessageInput = new Button("Voice message")
.setPosition(70, 90, 30, 10); .setPosition(70, 90, 30, 10);
this.messageList = new List("Messages") this.messageList = new List("Messages")
.setPosition(30, 30, 60, 50); .setPosition(30, 30, 60, 50);
this.window.add(this.settingsButton) this.window.add(this.settingsButton)
.add(this.channelSwitcher) .add(this.channelSwitcher)
.add(this.channelInfoButton) .add(this.channelInfoButton)
.add(this.searchButton) .add(this.searchButton)
.add(this.messageList) .add(this.messageList)
.add(this.messageInput) .add(this.messageInput)
.add(this.fileInput) .add(this.fileInput)
.add(this.imageInput) .add(this.imageInput)
.add(this.voiceMessageInput); .add(this.voiceMessageInput);
this.channelSwitcher.getElement().addEventListener("change", (e) => this.handleChannelSwitcher(e)); this.channelSwitcher.getElement().addEventListener("change", (e) => this.handleChannelSwitcher(e));
this.voiceMessageInput.onClick(async () => this.handleVoiceMessageButton()); this.voiceMessageInput.onClick(async () => this.handleVoiceMessageButton());
@ -228,6 +228,11 @@ export class MainView extends View {
itm.onClick(() => { itm.onClick(() => {
this.openMessageDialog(message); 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; return itm;
} }
@ -563,7 +568,7 @@ export class MainView extends View {
} }
state.save(); state.save();
this.updateChannelList(); this.updateChannelList();
}); });
} }
private async handleImageButton() { private async handleImageButton() {
@ -579,7 +584,7 @@ export class MainView extends View {
this.hotkeyMap.set("v", () => this.handleVoiceMessageButton()); this.hotkeyMap.set("v", () => this.handleVoiceMessageButton());
this.hotkeyMap.set(" ", () => this.messageInput.focus()); this.hotkeyMap.set(" ", () => this.messageInput.focus());
} }
private handleHotkey(e: KeyboardEvent) { private handleHotkey(e: KeyboardEvent) {
if (e.ctrlKey && e.shiftKey) { if (e.ctrlKey && e.shiftKey) {
const action = this.hotkeyMap.get(e.key.toLowerCase()); const action = this.hotkeyMap.get(e.key.toLowerCase());
@ -593,7 +598,6 @@ export class MainView extends View {
private async openMessageDialog(message: IMessage) { private async openMessageDialog(message: IMessage) {
const d = new MessageDialog(message); const d = new MessageDialog(message);
const msg = await d.open(); const msg = await d.open();
console.log(msg);
if (!msg || msg === null) { if (!msg || msg === null) {
state.currentChannel?.removeMessage(message.id); state.currentChannel?.removeMessage(message.id);
const node = this.messageElementMap.get(message.id); const node = this.messageElementMap.get(message.id);
@ -604,4 +608,17 @@ export class MainView extends View {
state.save(); 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();
}
}
}
} }