FlowFuse / FlowFuse/flowfuse

Typescript: Phase 5 — Composables + Utils

Open
#7,218 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
400
Forks
89
Avg merge
1d 21h
Merged PRs (30d)
146

Description

### Composables + Utils

> `frontend/src/composables/` (15 to convert, 1 already `.ts`) + `frontend/src/utils/` (16 to convert, 1 already `.ts`) — mostly pure functions, plus a handful of stateful `use*()` composables. See `frontend/src/utils/instanceVersion.ts` for the established pattern (interface alongside the function, `Maybe` from `@/types/common/types`).

**Per file:**
- [ ] Rename `.js` → `.ts`
- [ ] Drop `.js` extensions from imports of converted siblings (`'../api/devices.js'` → `'../api/devices'`)
- [ ] Annotate parameters and return types on every export
- [ ] For `use*()` composables, type internal `ref()`s the same way as in stores: `ref(null)` for nullable / complex state
- [ ] LLM-assisted: feed file + relevant types, review output
- [ ] Rename `.spec.js` → `.spec.ts` alongside each converted source file (Vitest is already TS-native)

**Per phase**:

- [ ] Enable `strict: true` per-directory as each Phase 3 directory is fully converted

#### Composable example

```ts
import { ref, type Ref } from 'vue'
import type { Device } from '@/types'

export function useDeviceHelper () {
const device = ref(null)
// ...
return { device }
}
```

#### Utils — gotchas

- **`roles.js` is CommonJS** (`module.exports = { Roles, RoleNames, TeamRoles }`). Convert to ES exports and lock the literals with `as const` so consumers get the narrow values, not `number`. Place in `@/types` re-exports per the Phase 2 plan.
- **Default export with multiple positional args** (`paginateUrl`): keep the signature; just type the params (`url: string, cursor?: string | null, limit?: number, query?: string, extraParams?: Record`).
- **Word lists** (`name-generator/adjectives.js`, `nouns.js`): export `as const` so the `index.ts` consumer gets a string-literal union, not `string[]`.
- **Stateful mutators** (`DeviceStateMutator`, `InstanceStateMutator`): these classes touch the same `Device` / `Instance` shapes as the API layer — use the same domain types. If a mutator adds derived fields, prefer the same view-model intersection pattern the API modules use.
- **Schema-audit reminder:** `snapshot.js` works with the inline narrow snapshot user shape — **do not** import `UserSummary` for it (PR2 leak risk).

#### Composables — `frontend/src/composables/`

| # | File | Notes |
|---|---|---|
| 1 | `DateHelpers.js` | Pure |
| 2 | `DeviceHelper.js` | Touches `Device` / `DeviceSummary` |
| 3 | `Download.js` | |
| 4 | `Hubspot.js` | |
| 5 | `InstanceStates.js` | |
| 6 | `NavigationHelper.js` | |
| 7 | `Permissions.js` | Touches `Team \| TeamSummary` union |
| 8 | `ResizingHelper.js` | |
| 9 | `StreamingListHelper.js` | |
| 10 | `TeamProperties.js` | Touches `Team \| TeamSummary` union |
| 11 | `TimerHelper.js` | |
| 12 | `Ux.js` | |
| 13 | `strings/Markdown.js` | Pure |
| 14 | `strings/String.js` | Pure |
| 15 | `strings/StreamingWords.js` | Pure |
| — | ~~`services/MqttExpertTopicHelper.ts`~~ | Already converted |

#### Utils — `frontend/src/utils/`

| # | File | Notes |
|---|---|---|
| 1 | `DeviceStateMutator.js` | Touches `Device` shape |
| 2 | `InstanceStateMutator.js` | Touches `Instance` / `Project` shape |
| 3 | `daysSince.js` | Pure |
| 4 | `elapsedTime.js` | Pure |
| 5 | `ensureAdmin.js` | Route guard |
| 6 | `ensurePermission.js` | Route guard |
| 7 | `eventHandling.js` | |
| 8 | `name-generator/index.js` | Pure |
| 9 | `name-generator/adjectives.js` | Word list — `as const` candidate |
| 10 | `name-generator/nouns.js` | Word list — `as const` candidate |
| 11 | `paginateUrl.js` | Pure |
| 12 | `pipelineValidation.js` | Touches `Pipeline` / `PipelineStage` |
| 13 | `roles.js` | Enum — hand-written `as const` in `@/types` |
| 14 | `slugify.js` | Pure |
| 15 | `snapshot.js` | Inline narrow snapshot user shape — don't reuse `UserSummary` |
| 16 | `timers.js` | |
| — | ~~`instanceVersion.ts`~~ | Already converted |

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.