Files
sencho/frontend
Anso 07a2e8f0e3 feat(stack-logs): WebSocket reconnect with backoff and gap sentinel (#1197)
The structured log viewer opened its WebSocket once and never tried to
recover. When the remote node dropped the tunnel mid-tail or the central
restarted, log output went silent with no indicator. The 10k row buffer
kept prior content on screen, so the silence looked like the stack had
just stopped producing logs.

Adds exponential-backoff reconnect (1s, 2s, 4s, 8s, 16s, cap 30s) with
a "reconnecting..." banner replacing the green "following" pip while
the socket is down. Backoff resets to the first delay after every
successful re-open.

docker logs -f has no resumable offset, so on successful reconnect the
viewer drops a synthetic warning sentinel into the row stream:

  --- reconnected; older lines may be missing ---

The sentinel renders at 70% opacity to distinguish it from container
output. Operators see at a glance that there was a gap.

The closedByCleanup flag prevents the reconnect loop from racing the
effect cleanup path: when the component unmounts or stackName changes,
the flag is set BEFORE ws.close() so the onclose handler short-circuits
instead of scheduling another reconnect.

Resolves M-1 from the stack-management audit.
2026-05-24 15:39:48 -04:00
..

React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.

Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...

      // Remove tseslint.configs.recommended and replace with this
      tseslint.configs.recommendedTypeChecked,
      // Alternatively, use this for stricter rules
      tseslint.configs.strictTypeChecked,
      // Optionally, add this for stylistic rules
      tseslint.configs.stylisticTypeChecked,

      // Other configs...
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])

You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:

// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...
      // Enable lint rules for React
      reactX.configs['recommended-typescript'],
      // Enable lint rules for React DOM
      reactDom.configs.recommended,
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])