Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .github/workflows/desktop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Build Desktop App

on:
pull_request:
branches: [main, dev]
paths:
- 'desktop/**'
- '.github/workflows/desktop.yml'
push:
branches: [dev]
paths:
- 'desktop/**'
- '.github/workflows/desktop.yml'
workflow_dispatch:
release:
types: [published]

permissions:
contents: write

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- platform: ubuntu-22.04
target: x86_64-unknown-linux-gnu
- platform: macos-latest
target: aarch64-apple-darwin
- platform: macos-latest
target: x86_64-apple-darwin
- platform: windows-latest
target: x86_64-pc-windows-msvc

runs-on: ${{ matrix.platform }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: desktop/src-tauri -> target

- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
libssl-dev

- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2"

- name: Build desktop app
working-directory: desktop
run: cargo tauri build --target ${{ matrix.target }}

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: quack-desktop-${{ matrix.target }}
path: |
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.deb
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.AppImage
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.dmg
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.msi
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.exe

- name: Upload to GitHub Release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v2
with:
files: |
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.deb
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.AppImage
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.dmg
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.msi
desktop/src-tauri/target/${{ matrix.target }}/release/bundle/**/*.exe
11 changes: 10 additions & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ on:
push:
tags:
- v*
workflow_call:
inputs:
version:
required: true
type: string
workflow_dispatch:

permissions:
contents: write
Expand Down Expand Up @@ -73,6 +79,9 @@ jobs:
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=ref,event=tag
type=raw,value=${{ inputs.version }},enable=${{ inputs.version != '' }}

- name: Build and push Docker image
id: push
Expand All @@ -85,7 +94,7 @@ jobs:
push: true
platforms: linux/amd64,linux/arm64
build-args: |
APP_VERSION=${{ github.ref_name }}
APP_VERSION=${{ inputs.version || github.ref_name }}
cache-from: type=gha
cache-to: type=gha,mode=max

Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.version.outputs.result }}

steps:
- name: Extract version from labels
Expand Down Expand Up @@ -47,3 +49,10 @@ jobs:
});

core.info(`Created release ${version}`);

docker:
needs: release
uses: ./.github/workflows/docker.yml
with:
version: ${{ needs.release.outputs.version }}
secrets: inherit
23 changes: 18 additions & 5 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,13 @@ Create standard story template with:
## 2. Code Cleanup

### 2.1 Type Safety (HIGH PRIORITY)
- [ ] Fix pre-existing TypeScript errors (17 errors in base)
- [ ] Remove `any` types - 20 instances in app/src
- [ ] Fix `style: any` unused prop in `ActionButton.tsx:10`
- [ ] Add proper typing to API module (`deno/api/mod.ts` - `payload: any`, `document: any`)
- [ ] Fix pre-existing TypeScript errors (16 errors in base)
- [x] Remove `any` types from backend core (serializers, bus, command/query, repos, HTTP/CLI) — PR #272
- [x] Remove `any` types from storage, encryption, config, migrate, tools modules — PR #273
- [x] Remove `any` types from API module (`deno/api/`) — PR #274
- [x] Remove `any` types from frontend — client, plugins, utils, models, components — PR #275
- [x] Remove `any` types from test files (chat.ts helper, 14 test files, users.ts) — PR #276
- [x] Fix `style: any` prop in `ActionButton.tsx` — typed as `string` (PR #275)
- [ ] Remove `@ts-ignore` comments in `deno/api/files.ts` (5+ instances)
- [ ] Standardize Props interface naming

Expand Down Expand Up @@ -288,7 +291,7 @@ Create standard story template with:
## Notes

- Created: 2026-02-06
- Last updated: 2026-02-08
- Last updated: 2026-02-09
- Progress:
- ✅ **Section 1: Storybook Cleanup - COMPLETE**
- PR #249: Config fixes
Expand All @@ -299,6 +302,16 @@ Create standard story template with:
- PR #254: Message story image fix
- 🔄 **Section 2: Code Cleanup - IN PROGRESS**
- PR #255: Dependency updates (npm packages, @std alignment, ESLint React version)
<<<<<<< HEAD
- PRs #272-276: Remove `any` types across codebase (~120 instances)
=======
- PR #272: Remove `any` types from backend core
- PR #273: Remove `any` types from storage, encryption, config, migrate, tools
<<<<<<< HEAD
- PR #274: Remove `any` types from API module
=======
>>>>>>> origin/dev
>>>>>>> origin/dev
- 🔄 **Section 3: Architecture Refactoring - IN PROGRESS**
- ✅ 3.7 Documentation: ARCHITECTURE.md, CONVENTIONS.md, 14 ADRs, CLAUDE.md
- PR #256: Architecture docs
Expand Down
4 changes: 2 additions & 2 deletions app/src/js/components/contexts/tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type TooltipContextType = {
content: React.ReactNode,
parent: React.ReactNode | HTMLElement,
) => void;
hide: (p: any) => void;
hide: (p: React.ReactNode | HTMLElement) => void;
};

export const TooltipContext = createContext<TooltipContextType | undefined>(
Expand Down Expand Up @@ -67,7 +67,7 @@ export const TooltipProvider = ({ children }: TooltipContextProps) => {
[setContent, setPos, setParent],
);

const hide = useCallback((p: any) => {
const hide = useCallback((p: React.ReactNode | HTMLElement) => {
if (parent === p) {
setParent(null);
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/js/components/molecules/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { observer } from "mobx-react-lite";
type ActionButtonProps = {
children: React.ReactNode;
action: string;
style: any;
payload: any;
style?: string;
payload?: Record<string, unknown>;
};

export const ActionButton = observer(
Expand Down
2 changes: 1 addition & 1 deletion app/src/js/components/molecules/NavChannels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const NavChannels = observer(({ icon }: NavChannelsProps) => {
className={{ active: id === c.id }}
key={c.id}
icon={icon ?? "hash"}
badge={badges.getForChannel(c.id as any)}
badge={badges.getForChannel(String(c.id))}
onClick={() => {
if (isMobile()) {
hideSidebar();
Expand Down
10 changes: 5 additions & 5 deletions app/src/js/components/molecules/NavUsers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export const NavUserButton = ({
const NavUserContainer = observer(
({ user, badges }: { user: User; badges: ReadReceiptsModel }) => {
const app = useApp();
const channel = app.channels.getDirect(user.id as any);
const channel = app.channels.getDirect(String(user.id));
let navigate = (_path: string) => {};
try {
navigate = useNavigate();
Expand All @@ -128,11 +128,11 @@ const NavUserContainer = observer(
return (
<NavUserButton
size={30}
user={user as any}
user={user as unknown as NavUserButtonProps["user"]}
className={{ active: id === channel?.id }}
badge={badges.getForChannel(channel?.id as any)}
badge={badges.getForChannel(channel?.id ? String(channel.id) : "")}
onClick={async () => {
const channel = await client.api.putDirectChannel(user.id as any);
const channel = await client.api.putDirectChannel(String(user.id));
if (isMobile()) {
hideSidebar();
}
Expand All @@ -152,7 +152,7 @@ export const NavUsers = observer(() => {
<SectionHeader title="users" />
{users && users.map((user) => (
<NavUserContainer
key={user.id as any}
key={String(user.id)}
user={user}
badges={app.readReceipts}
/>
Expand Down
2 changes: 1 addition & 1 deletion app/src/js/components/molecules/UserMention.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const UserMentionBase = observer(({ user }: UserMentionBaseProps) => {
data-id={user.id}
href="#"
>
<span className="name">@{user?.name || (user.id as any)}</span>
<span className="name">@{user?.name || String(user.id)}</span>
</StyledLink>
);
});
Expand Down
2 changes: 1 addition & 1 deletion app/src/js/components/organisms/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export const SearchResults = observer(
<div key="bottom" id="scroll-stop" />
<MessageList
renderer={BaseRenderer}
model={threadModelWrapper as any}
model={threadModelWrapper as unknown as import("../../core/models/thread").ThreadModel}
onMessageClicked={(msg: MessageModel) => {
gotoMessage(msg);
}}
Expand Down
2 changes: 1 addition & 1 deletion app/src/js/components/pages/ErrorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const Container = styled.div`

type ErrorPageProps = {
title?: string;
debug?: any;
debug?: Record<string, unknown>;
buttons?: ("retry" | "back" | "home")[];
description?: string | string[];
};
Expand Down
5 changes: 3 additions & 2 deletions app/src/js/components/pages/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ export const Register = () => {
console.log(err);
setMsg(err.message);
} else {
if ((err as any)?.errorCode === "USER_ALREADY_EXISTS") {
setMsg((err as any).message);
const errObj = err as { errorCode?: string; message?: string };
if (errObj.errorCode === "USER_ALREADY_EXISTS") {
setMsg(errObj.message ?? "User already exists");
} else {
console.log(err);
setMsg("Unknown error");
Expand Down
4 changes: 3 additions & 1 deletion app/src/js/core/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class Client {
return this.api.req(...args);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
on(name: string, cb: (e: any) => void) {
this.api.on(name, (ev: Event) => {
if (ev instanceof CustomEvent) {
Expand All @@ -32,6 +33,7 @@ export class Client {
return this;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
on2(name: string, cb: (e: any) => void) {
const handler = (ev: Event) => {
if (ev instanceof CustomEvent) {
Expand All @@ -45,7 +47,7 @@ export class Client {
return () => this.api.off(name, handler);
}

emit(type: string, data: any) {
emit(type: string, data: unknown) {
return this.api.emit(new CustomEvent(type, { detail: data }));
}
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/js/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { AppModel } from "./models/app.ts";
import { client } from "./client.ts";
import { stopTauriNotifications } from "./notifications.ts";
export * from "./client.ts";

export const app = new AppModel();
client.on2("auth:logout", async () => {
await stopTauriNotifications();
await app.dispose();
window.location.reload();
});
4 changes: 2 additions & 2 deletions app/src/js/core/models/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class FileModel {
async dispose() {
this.id = undefined;
this.clientId = "";
this.stream = null as any;
this.stream = null as unknown as ReadableStream;
this.status = "pending";
this.fileSize = 0;
this.fileName = "";
Expand Down Expand Up @@ -144,7 +144,7 @@ export class FilesModel {
local.patch({ status: "error", progress: 0, error: "unknown error" });
}
});
toJSON(): any {
toJSON(): Array<{ id?: string; clientId: string; fileName: string; fileSize: number; contentType: string }> {
return this.list.map((f) => ({
id: f.id,
clientId: f.clientId,
Expand Down
1 change: 1 addition & 0 deletions app/src/js/core/models/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export class InputModel {
}

send = flow(function* (this: InputModel, html: HTMLElement) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const payload: any = fromDom(html);
html.innerHTML = "";
payload.attachments = this.files.toJSON();
Expand Down
2 changes: 1 addition & 1 deletion app/src/js/core/models/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class MessageModel implements ViewMessage {
favicons: string[];
charset: string;
}[];
parsingErrors?: any[];
parsingErrors?: Array<{ message: string; nodeAttributes?: Record<string, string | null>; nodeName?: string }>;
attachments?: Array<{
id: string;
fileName: string;
Expand Down
Loading