diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 95212fb395..c2d70368d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,75 @@ # Contributing to Fluidd -Fluidd exists as an independent client of Moonraker, and by extension - Klipper. -Fluidd is built on VueJS, using TypeScript. +Fluidd is an independent web client for [Klipper](https://github.com/Klipper3d/klipper) +(via [Moonraker](https://github.com/Arksine/moonraker)), built with Vue 2.7 and TypeScript. -- Source should always pass the linting rules defined, with no warnings or type errors. -- A clean develop is preferred. This means squashing, and rebasing your feature branches prior to merge. -- PR's should off a branch other than develop or master. -- Commit messages should follow the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standard, and should have a Signed-off-by line, for example; +Contributions of all kinds are welcome — bug reports, feature requests, code, and +translations. This document covers the process and rules. For setup instructions and a +tour of the codebase, see the +[Development guide](https://docs.fluidd.xyz/development/). - ```sh - feat: My feature. +## Before you start - Some description. +- Read the [Development guide](https://docs.fluidd.xyz/development/) — it covers the + Dev Container, running Fluidd locally, and a quick architecture overview. +- After cloning, run `npm ci && npm run bootstrap` to install dependencies and set up + the Git hooks that pre-validate your commits. - Signed-off-by: Your Name +## Branching and pull requests + +- Create your work on a feature branch from `develop` — for example, + `feat/my-feature` branched from `develop`. Do not open pull requests from + `develop` or `master` directly. +- **Pull request titles must follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)**. + This is enforced by CI. +- Accepted pull requests are squashed and rebased onto `develop` when merged. + +## Commits + +- Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for every + commit message. Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, + `test`, `build`, `ci`, `chore`, `revert`, `types`, `i18n`. +- The commit subject must be **50 characters or fewer** — enforced by the + `commit-msg` Git hook. +- Every commit must include a `Signed-off-by` line. The easiest way is to commit with + `git commit -s`. Signing off acknowledges the + [Developer Certificate of Origin](./developer-certificate-of-origin) and must + contain your real name and a current email address. Example: + + ```text + feat: my feature + + Some description of what changed and why. + + Signed-off-by: Your Name ``` -- By signing off on commits, you acknowledge that you agree to the [developer certificate of origin](/developer-certificate-of-origin). -This must contain your real name and a current email address. +## Code quality + +Source must pass linting and type-checking with **zero warnings and zero type errors**. +Before pushing, run: + +```bash +npm run lint +npm run type-check +npm run test +``` + +CI runs the same checks (plus `npm run circular-check` and a production build) on +every pull request. + +## Translations + +Translations are managed via [Weblate](https://hosted.weblate.org/engage/fluidd/) — do +not edit non-English files in `src/locales/` directly. New strings should be added to +`src/locales/en.yaml`; Weblate handles the rest. See the +[Localization section](https://docs.fluidd.xyz/development/#localization) of the +Development guide for more. + +## A note on `CLAUDE.md` -After cloning the repo and running `npm install`, we recommend running `npm run bootstrap` to install a couple of git hooks that will pre-validate all new commits. +The `CLAUDE.md` file in the repository root is an exhaustive reference written for AI +coding assistants (Claude Code, Cursor, and similar tools). It documents architecture, +patterns, and gotchas in detail. Humans are welcome to read it as a deeper second +source, but the canonical onboarding doc for human contributors is the +[Development guide](https://docs.fluidd.xyz/development/). diff --git a/docs/docs/development.md b/docs/docs/development.md index ac888a9e43..d3f154c54e 100644 --- a/docs/docs/development.md +++ b/docs/docs/development.md @@ -14,6 +14,123 @@ Contributions are welcome! Please review the [CONTRIBUTING.md](https://github.com/fluidd-core/fluidd/blob/develop/CONTRIBUTING.md) file before submitting a pull request. +## Architecture overview + +This section is aimed at developers comfortable with Vue and TypeScript who want a +quick map of the codebase. For an exhaustive reference, see the `CLAUDE.md` file at +the repository root — it was written for AI coding assistants but works as a deep +second source for humans too. + +### Stack + +- **Vue 2.7** with [Vuetify 2](https://v2.vuetifyjs.com/) for UI components +- **TypeScript** throughout, with class-style components via + [`vue-property-decorator`](https://github.com/kaorun343/vue-property-decorator) +- **Vuex** for state management — namespaced modules mirror Klipper and Moonraker + domains +- **[Vite](https://vitejs.dev/) 8** as the build tool and dev server +- **[Vitest](https://vitest.dev/) 4** with `jsdom` for unit tests +- **Node.js 24** — pinned in `.node-version` (engines: `^22.12.0 || ^24`) + +### How it talks to Klipper + +Fluidd does not talk to Klipper directly. Instead, the browser keeps a single +WebSocket connection open to Moonraker, which in turn talks to Klipper: + +```text +Browser ⇄ WebSocket (JSON-RPC) ⇄ Moonraker ⇄ Klipper +``` + +All printer commands and live state updates flow through that single socket. The +client lives in `src/api/socketActions.ts` — for printer control and state, call +its methods rather than making direct HTTP requests. + +A few features still use HTTP: file upload and download (via `axios` for progress +reporting — `fetch` cannot report upload progress; see `src/mixins/files.ts`), +camera WebRTC signalling, and the initial `config.json` fetch at startup. + +### Repository layout + +```text +src/ +├── api/ WebSocket JSON-RPC client (socketActions.ts) +├── components/ +│ ├── common/ Shared dialogs and status components (auto-imported) +│ ├── layout/ App shell: AppBar, AppDrawer, etc. (auto-imported) +│ ├── ui/ Reusable widgets: AppBtn, AppDialog, etc. (auto-imported) +│ ├── settings/ Settings page components +│ └── widgets/ Feature widgets — one folder per feature +├── views/ Page components, lazy-loaded by the router +├── store/ Vuex modules — one per Klipper/Moonraker domain +├── mixins/ Shared component logic (StateMixin, FilesMixin, ...) +├── plugins/ Vue plugins (i18n, socketClient, vuetify, filters) +├── router/ Vue Router (hash mode) +├── locales/ i18n YAML files (managed via Weblate) +├── scss/ Global styles and Vuetify variable overrides +├── util/ Helper functions +├── workers/ Web Workers (G-code parser, MJPEG stream, Monaco language servers) +├── typings/ Global TypeScript declarations (Klipper, Moonraker namespaces) +└── types/ UI-specific TypeScript types +``` + +### Patterns you'll meet immediately + +**Class-style components.** Every component uses decorators — no Options API or +Composition API. Components that need printer state extend a mixin via `Mixins()`: + +```typescript +@Component({ components: { /* ... */ } }) +export default class PrinterWidget extends Mixins(StateMixin) { + @Prop({ type: String, required: true }) + readonly label!: string + + get klippyReady (): boolean { + return this.$typedGetters['printer/getKlippyReady'] + } +} +``` + +**Vuex modules** live in `src/store//` with a standard layout +(`index.ts`, `state.ts`, `getters.ts`, `mutations.ts`, `actions.ts`, `types.ts`). +Use `$typedState` and `$typedGetters` for type-safe access from components. + +**WebSocket calls** go through `SocketActions` methods. Pass a `wait` parameter +(constants in `src/globals.ts`) to drive UI loading state — for example, +`wait: Waits.onPrintPause`. + +**Auto-imported components.** Anything under `src/components/common`, `layout`, or +`ui` is registered automatically by `unplugin-vue-components` — no manual import +needed. The generated `components.d.ts` at the repo root is regenerated on every +build; do not edit it by hand. + +**Cross-component messaging.** Use the Vuex store for shared state, or the +`EventBus` (`src/eventBus.ts`) for ephemeral events such as flash messages. + +**Logging.** Use `consola`, not `console.log` (configured in `src/setupConsola.ts`). + +### Where to add things + +- **A new widget** → create a folder in `src/components/widgets//` and import + the component where it's used. +- **A new route** → add a lazy import to `src/router/index.ts` and create the page + in `src/views/.vue`. +- **New store data** → add a module under `src/store//` with the six + standard files (including the module's `index.ts`), register it in + `src/store/index.ts`, and update `src/store/types.ts` so `RootModules`, + `RootState`, and `RootGetters` pick it up. +- **A new translation key** → edit `src/locales/en.yaml`. Weblate handles the + other languages — do not edit them directly. +- **A new icon** → add an MDI mapping to the `Icons` object in `src/globals.ts`, + then use it as `{{ $globals.Icons.myIcon }}`. + +### Going deeper + +The repository's `CLAUDE.md` file is an exhaustive reference originally written +for AI coding assistants. It covers topics that are out of scope for this quick +orientation — the auth state machine and token-refresh policy, the full list of +build-toolchain gotchas, every Vuex module, and more. If you've outgrown this +overview, that's the next stop. + ## Dev Container in Visual Studio Code Fluidd includes a Dev Container configuration to easily open with Visual Studio Code @@ -82,7 +199,7 @@ npm run test Follow the instructions from [Python](https://www.python.org/) to install Python 3. -### Install dependencies +### Install Python dependencies ```bash cd .../path/to/fluidd/docs