diff --git a/.cursor/agents/reviewer-tests.md b/.cursor/agents/reviewer-tests.md index c464399..6faa49f 100644 --- a/.cursor/agents/reviewer-tests.md +++ b/.cursor/agents/reviewer-tests.md @@ -7,11 +7,11 @@ You are a unit test and coverage reviewer for code reviews. ## When Invoked -**IMPORTANT:** Run `yarn test:unit` exactly ONCE. Do NOT re-run the command for any reason (verification, double-checking, etc.). Base your entire report on the single execution. +**IMPORTANT:** Run `yarn test` exactly ONCE. Do NOT re-run the command for any reason (verification, double-checking, etc.). Base your entire report on the single execution. ### Step 1: Run Unit Tests -1. Run `yarn test:unit` once to execute all unit tests +1. Run `yarn test` once to execute all unit tests 2. Analyze the exit code and output from that single run 3. If any tests fail, report them as **Critical Issues** diff --git a/.cursor/rules/CODE_STYLE.mdc b/.cursor/rules/CODE_STYLE.mdc index 13b1502..ee78674 100644 --- a/.cursor/rules/CODE_STYLE.mdc +++ b/.cursor/rules/CODE_STYLE.mdc @@ -661,8 +661,8 @@ const count = 0 **Tools:** -- Prettier: `yarn prettier` +- Prettier: `yarn format` - ESLint: `yarn lint` - Type Check: `yarn build` -- Unit Tests: `yarn test:unit` +- Unit Tests: `yarn test` - E2E Tests: `yarn test:e2e` diff --git a/.cursor/rules/TESTING_GUIDELINES.mdc b/.cursor/rules/TESTING_GUIDELINES.mdc index 18cdf72..6a85313 100644 --- a/.cursor/rules/TESTING_GUIDELINES.mdc +++ b/.cursor/rules/TESTING_GUIDELINES.mdc @@ -18,7 +18,7 @@ The project uses Vitest for unit testing with workspace-based configuration: ```typescript // vitest.config.mts -import { defineConfig } from 'vitest/config'; +import { defineConfig } from 'vitest/config' export default defineConfig({ test: { @@ -48,7 +48,7 @@ export default defineConfig({ }, ], }, -}); +}) ``` ### Playwright for E2E Tests @@ -57,8 +57,8 @@ E2E tests use Playwright with the service auto-started: ```typescript // playwright.config.ts -import type { PlaywrightTestConfig } from '@playwright/test'; -import { devices } from '@playwright/test'; +import type { PlaywrightTestConfig } from '@playwright/test' +import { devices } from '@playwright/test' const config: PlaywrightTestConfig = { testDir: 'e2e', @@ -76,7 +76,7 @@ const config: PlaywrightTestConfig = { { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, ], -}; +} ``` ## Unit Testing with Vitest @@ -98,22 +98,22 @@ service/src/ Use `describe`, `it`, and `expect` from Vitest: ```typescript -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' describe('MyService', () => { describe('methodName', () => { it('should do something when condition', () => { // Arrange - const input = 'test'; - + const input = 'test' + // Act - const result = myFunction(input); - + const result = myFunction(input) + // Assert - expect(result).toBe('expected'); - }); - }); -}); + expect(result).toBe('expected') + }) + }) +}) ``` ### Testing Services @@ -121,27 +121,27 @@ describe('MyService', () => { Test service methods with mocked dependencies: ```typescript -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { Injector } from '@furystack/inject'; +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { Injector } from '@furystack/inject' describe('SessionService', () => { - let injector: Injector; - let sessionService: SessionService; - + let injector: Injector + let sessionService: SessionService + beforeEach(() => { - injector = new Injector(); + injector = new Injector() // Set up mocks const mockApiClient = { call: vi.fn(), - }; - injector.setExplicitInstance(BoilerplateApiClient, mockApiClient); - sessionService = injector.getInstance(SessionService); - }); - + } + injector.setExplicitInstance(BoilerplateApiClient, mockApiClient) + sessionService = injector.getInstance(SessionService) + }) + it('should initialize with unauthenticated state', async () => { - expect(sessionService.state.getValue()).toBe('initializing'); - }); -}); + expect(sessionService.state.getValue()).toBe('initializing') + }) +}) ``` ### Mocking with Vitest @@ -149,24 +149,24 @@ describe('SessionService', () => { Use `vi.fn()` for function mocks and `vi.spyOn()` for spying: ```typescript -import { vi } from 'vitest'; +import { vi } from 'vitest' // Mock a function -const mockFn = vi.fn().mockReturnValue('mocked'); +const mockFn = vi.fn().mockReturnValue('mocked') // Mock with implementation -const mockFn = vi.fn().mockImplementation((arg) => `result: ${arg}`); +const mockFn = vi.fn().mockImplementation((arg) => `result: ${arg}`) // Mock async function -const mockAsync = vi.fn().mockResolvedValue({ data: 'test' }); +const mockAsync = vi.fn().mockResolvedValue({ data: 'test' }) // Spy on method -const spy = vi.spyOn(service, 'method'); +const spy = vi.spyOn(service, 'method') // Verify calls -expect(mockFn).toHaveBeenCalled(); -expect(mockFn).toHaveBeenCalledWith('arg'); -expect(mockFn).toHaveBeenCalledTimes(2); +expect(mockFn).toHaveBeenCalled() +expect(mockFn).toHaveBeenCalledWith('arg') +expect(mockFn).toHaveBeenCalledTimes(2) ``` ### Testing Observable Values @@ -174,21 +174,21 @@ expect(mockFn).toHaveBeenCalledTimes(2); Test ObservableValue subscriptions: ```typescript -import { ObservableValue } from '@furystack/utils'; +import { ObservableValue } from '@furystack/utils' describe('ObservableValue', () => { it('should notify subscribers on value change', () => { - const observable = new ObservableValue('initial'); - const values: string[] = []; - - const subscription = observable.subscribe((value) => values.push(value)); - observable.setValue('updated'); - - expect(values).toEqual(['initial', 'updated']); - - subscription.dispose(); - }); -}); + const observable = new ObservableValue('initial') + const values: string[] = [] + + const subscription = observable.subscribe((value) => values.push(value)) + observable.setValue('updated') + + expect(values).toEqual(['initial', 'updated']) + + subscription.dispose() + }) +}) ``` ## E2E Testing with Playwright @@ -209,26 +209,26 @@ e2e/ Use Playwright's test API: ```typescript -import { expect, test } from '@playwright/test'; +import { expect, test } from '@playwright/test' test.describe('Feature Name', () => { test('should do something', async ({ page }) => { // Navigate - await page.goto('/'); - + await page.goto('/') + // Find elements - const element = page.locator('selector'); - + const element = page.locator('selector') + // Assert visibility - await expect(element).toBeVisible(); - + await expect(element).toBeVisible() + // Interact - await element.click(); - + await element.click() + // Assert result - await expect(page.locator('.result')).toHaveText('Expected'); - }); -}); + await expect(page.locator('.result')).toHaveText('Expected') + }) +}) ``` ### Locating Shades Components @@ -238,21 +238,21 @@ Use shadow DOM component names as selectors: ```typescript test('should interact with Shades components', async ({ page }) => { // Locate by shadow DOM name - const loginForm = page.locator('shade-login form'); - await expect(loginForm).toBeVisible(); - + const loginForm = page.locator('shade-login form') + await expect(loginForm).toBeVisible() + // Locate inputs within components - const usernameInput = loginForm.locator('input[name="userName"]'); - const passwordInput = loginForm.locator('input[name="password"]'); - + const usernameInput = loginForm.locator('input[name="userName"]') + const passwordInput = loginForm.locator('input[name="password"]') + // Fill inputs - await usernameInput.type('testuser'); - await passwordInput.type('password'); - + await usernameInput.type('testuser') + await passwordInput.type('password') + // Click buttons - const submitButton = page.locator('button', { hasText: 'Login' }); - await submitButton.click(); -}); + const submitButton = page.locator('button', { hasText: 'Login' }) + await submitButton.click() +}) ``` ### Authentication Flow Test @@ -260,36 +260,36 @@ test('should interact with Shades components', async ({ page }) => { Example of testing login/logout: ```typescript -import { expect, test } from '@playwright/test'; +import { expect, test } from '@playwright/test' test.describe('Authentication', () => { test('Login and logout roundtrip', async ({ page }) => { - await page.goto('/'); - + await page.goto('/') + // Wait for login form - const loginForm = page.locator('shade-login form'); - await expect(loginForm).toBeVisible(); - + const loginForm = page.locator('shade-login form') + await expect(loginForm).toBeVisible() + // Fill credentials - await loginForm.locator('input[name="userName"]').type('testuser'); - await loginForm.locator('input[name="password"]').type('password'); - + await loginForm.locator('input[name="userName"]').type('testuser') + await loginForm.locator('input[name="password"]').type('password') + // Submit - await page.locator('button', { hasText: 'Login' }).click(); - + await page.locator('button', { hasText: 'Login' }).click() + // Verify logged in state - const welcomeTitle = page.locator('hello-world div h2'); - await expect(welcomeTitle).toBeVisible(); - await expect(welcomeTitle).toHaveText('Hello, testuser !'); - + const welcomeTitle = page.locator('hello-world div h2') + await expect(welcomeTitle).toBeVisible() + await expect(welcomeTitle).toHaveText('Hello, testuser !') + // Logout - const logoutButton = page.locator('shade-app-bar button >> text="Log Out"'); - await logoutButton.click(); - + const logoutButton = page.locator('shade-app-bar button >> text="Log Out"') + await logoutButton.click() + // Verify logged out - await expect(page.locator('shade-login form')).toBeVisible(); - }); -}); + await expect(page.locator('shade-login form')).toBeVisible() + }) +}) ``` ### Waiting for Elements @@ -298,14 +298,14 @@ Use Playwright's auto-waiting or explicit waits: ```typescript // Auto-wait (recommended) -await expect(element).toBeVisible(); +await expect(element).toBeVisible() // Explicit wait -await page.waitForSelector('selector'); -await page.waitForLoadState('networkidle'); +await page.waitForSelector('selector') +await page.waitForLoadState('networkidle') // Wait for response -await page.waitForResponse('**/api/endpoint'); +await page.waitForResponse('**/api/endpoint') ``` ## Running Tests @@ -314,16 +314,16 @@ await page.waitForResponse('**/api/endpoint'); ```bash # Run all unit tests -yarn test:unit +yarn test # Run with coverage -yarn test:unit --coverage +yarn test --coverage # Run specific workspace -yarn test:unit --project=Service +yarn test --project=Service # Watch mode -yarn test:unit --watch +yarn test --watch ``` ### E2E Tests @@ -391,7 +391,7 @@ coverage: { **Commands:** -- Unit tests: `yarn test:unit` +- Unit tests: `yarn test` - E2E tests: `yarn test:e2e` -- Coverage: `yarn test:unit --coverage` +- Coverage: `yarn test --coverage` - Debug E2E: `yarn playwright test --debug` diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 3af41e2..ba1a3da 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -29,7 +29,7 @@ jobs: - name: Recreate JSON Schemas run: yarn create-schemas && yarn build # an incremental rebuild is necessary to use the updated schema - name: Test - run: yarn test:unit + run: yarn test - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/publish-to-dockerhub.yml b/.github/workflows/publish-to-dockerhub.yml index ecfcf82..e0bb281 100644 --- a/.github/workflows/publish-to-dockerhub.yml +++ b/.github/workflows/publish-to-dockerhub.yml @@ -43,7 +43,7 @@ jobs: run: yarn lint - name: Test - run: yarn test:unit + run: yarn test - name: Apply release changes run: yarn applyReleaseChanges diff --git a/.yarn/changelogs/common.d3ee42b5.md b/.yarn/changelogs/common.d3ee42b5.md new file mode 100644 index 0000000..e1476f7 --- /dev/null +++ b/.yarn/changelogs/common.d3ee42b5.md @@ -0,0 +1,7 @@ + +# common + +## ⬆️ Dependencies + +- Updated `@furystack/rest` from ^8.0.32 to ^8.0.34 +- Updated `@types/node` from ^25.0.10 to ^25.1.0 diff --git a/.yarn/changelogs/frontend.d3ee42b5.md b/.yarn/changelogs/frontend.d3ee42b5.md new file mode 100644 index 0000000..b918c81 --- /dev/null +++ b/.yarn/changelogs/frontend.d3ee42b5.md @@ -0,0 +1,27 @@ + +# frontend + +## ♻️ Refactoring + +### Migrated from inline styles to CSS property with theme variables + +Replaced inline styles with the `css` component property and migrated from `ThemeProviderService` injection to `cssVariableTheme` for theming. This approach leverages CSS variables for better performance and consistency. + +**Affected components:** +- `header.tsx` - Link styling with hover and focus states +- `layout.tsx` - Root layout container styles +- `hello-world.tsx` - Page content structure and typography +- `init.tsx` - Loading state layout +- `login.tsx` - Form styling with error and helper text states +- `offline.tsx` - Link styling with accessibility-friendly focus states + +## ⬆️ Dependencies + +- Updated `@furystack/core` from ^15.0.32 to ^15.0.34 +- Updated `@furystack/inject` from ^12.0.26 to ^12.0.28 +- Updated `@furystack/logging` from ^8.0.26 to ^8.0.28 +- Updated `@furystack/rest-client-fetch` from ^8.0.32 to ^8.0.34 +- Updated `@furystack/shades` from ^11.0.33 to ^11.1.0 +- Updated `@furystack/shades-common-components` from ^10.0.33 to ^11.0.0 (major version bump with `cssVariableTheme` support) +- Updated `@furystack/utils` from ^8.1.8 to ^8.1.9 +- Updated `@types/node` from ^25.0.10 to ^25.1.0 diff --git a/.yarn/changelogs/furystack-boilerplate-app.d3ee42b5.md b/.yarn/changelogs/furystack-boilerplate-app.d3ee42b5.md new file mode 100644 index 0000000..01b9b97 --- /dev/null +++ b/.yarn/changelogs/furystack-boilerplate-app.d3ee42b5.md @@ -0,0 +1,19 @@ + +# furystack-boilerplate-app + +## 👷 CI + +### Updated release workflow to use develop branch + +Changed the Docker Hub publish workflow to use `develop` as the release branch instead of `master`. Releases are now triggered from `develop` and merged to `master` after successful deployment. + +- Renamed `test:unit` npm script to `test` for consistency with the FuryStack monorepo conventions + +## ⬆️ Dependencies + +- Updated `@furystack/yarn-plugin-changelog` from ^1.0.1 to ^1.0.2 +- Updated `@playwright/test` from ^1.58.0 to ^1.58.1 +- Updated `@types/node` from ^25.0.10 to ^25.1.0 +- Updated `eslint-plugin-jsdoc` from ^62.4.0 to ^62.5.0 +- Updated `eslint-plugin-playwright` from ^2.5.0 to ^2.5.1 +- Updated `typescript-eslint` from ^8.53.1 to ^8.54.0 diff --git a/.yarn/changelogs/service.d3ee42b5.md b/.yarn/changelogs/service.d3ee42b5.md new file mode 100644 index 0000000..14289d6 --- /dev/null +++ b/.yarn/changelogs/service.d3ee42b5.md @@ -0,0 +1,13 @@ + +# service + +## ⬆️ Dependencies + +- Updated `@furystack/core` from ^15.0.32 to ^15.0.34 +- Updated `@furystack/filesystem-store` from ^7.0.32 to ^7.0.34 +- Updated `@furystack/inject` from ^12.0.26 to ^12.0.28 +- Updated `@furystack/logging` from ^8.0.26 to ^8.0.28 +- Updated `@furystack/repository` from ^10.0.32 to ^10.0.34 +- Updated `@furystack/rest-service` from ^10.1.3 to ^11.0.2 (major version bump) +- Updated `@furystack/security` from ^6.0.32 to ^6.0.34 +- Updated `@types/node` from ^25.0.10 to ^25.1.0 diff --git a/.yarn/versions/d3ee42b5.yml b/.yarn/versions/d3ee42b5.yml new file mode 100644 index 0000000..6e6773b --- /dev/null +++ b/.yarn/versions/d3ee42b5.yml @@ -0,0 +1,5 @@ +releases: + common: patch + frontend: patch + furystack-boilerplate-app: patch + service: patch diff --git a/README.md b/README.md index 68490d1..f6c62a4 100644 --- a/README.md +++ b/README.md @@ -10,5 +10,5 @@ Boilerplate app with common type api definitions, a furystack-based backend serv # Testing -- You can execute the example Vitest tests with `yarn test:unit` +- You can execute the example Vitest tests with `yarn test` - You can execute E2E tests with `yarn test:e2e` diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7b899c0..a65ebfb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -31,7 +31,7 @@ steps: - script: yarn lint displayName: 'Yarn Lint' - - script: yarn test:unit + - script: yarn test displayName: 'Unit tests' - script: yarn playwright install --with-deps diff --git a/common/package.json b/common/package.json index 7210287..287f605 100644 --- a/common/package.json +++ b/common/package.json @@ -25,11 +25,11 @@ "create-schemas": "node ./dist/bin/create-schemas.js" }, "devDependencies": { - "@types/node": "^25.0.10", + "@types/node": "^25.1.0", "ts-json-schema-generator": "^2.4.0", "vitest": "^4.0.18" }, "dependencies": { - "@furystack/rest": "^8.0.32" + "@furystack/rest": "^8.0.34" } } diff --git a/frontend/package.json b/frontend/package.json index 318724b..a7679ab 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,14 +17,14 @@ "vitest": "^4.0.18" }, "dependencies": { - "@furystack/core": "^15.0.32", - "@furystack/inject": "^12.0.26", - "@furystack/logging": "^8.0.26", - "@furystack/rest-client-fetch": "^8.0.32", - "@furystack/shades": "^11.0.33", - "@furystack/shades-common-components": "^10.0.33", - "@furystack/utils": "^8.1.8", - "@types/node": "^25.0.10", + "@furystack/core": "^15.0.34", + "@furystack/inject": "^12.0.28", + "@furystack/logging": "^8.0.28", + "@furystack/rest-client-fetch": "^8.0.34", + "@furystack/shades": "^11.1.0", + "@furystack/shades-common-components": "^11.0.0", + "@furystack/utils": "^8.1.9", + "@types/node": "^25.1.0", "common": "workspace:^" } } diff --git a/frontend/src/components/header.tsx b/frontend/src/components/header.tsx index 6b95cc4..4df43a8 100644 --- a/frontend/src/components/header.tsx +++ b/frontend/src/components/header.tsx @@ -5,30 +5,40 @@ import { SessionService } from '../services/session.js' import { GithubLogo } from './github-logo/index.js' import { ThemeSwitch } from './theme-switch/index.js' -export interface HeaderProps { +export type HeaderProps = { title: string links: Array<{ name: string; url: string }> } -const urlStyle: Partial = { - color: '#aaa', - textDecoration: 'none', -} - export const Header = Shade({ shadowDomName: 'shade-app-header', + css: { + '& a[is="route-link"]': { + color: '#aaa', + textDecoration: 'none', + cursor: 'pointer', + transition: 'color 0.2s ease', + }, + '& a[is="route-link"]:hover': { + color: '#fff', + }, + '& a[is="route-link"]:focus': { + outline: '2px solid #aaa', + outlineOffset: '2px', + }, + }, render: ({ props, injector, useObservable }) => { const [sessionState] = useObservable('sessionState', injector.getInstance(SessionService).state) return ( -

- +

+ {props.title}

{props.links.map((link) => ( - + {link.name || ''} ))} diff --git a/frontend/src/components/layout.tsx b/frontend/src/components/layout.tsx index bd5fce1..5df929a 100644 --- a/frontend/src/components/layout.tsx +++ b/frontend/src/components/layout.tsx @@ -1,29 +1,27 @@ import { createComponent, Shade } from '@furystack/shades' -import { ThemeProviderService } from '@furystack/shades-common-components' +import { cssVariableTheme } from '@furystack/shades-common-components' import { Body } from './body.js' import { Header } from './header.js' export const Layout = Shade({ shadowDomName: 'shade-app-layout', - render: ({ injector }) => { + css: { + position: 'fixed', + top: '0', + left: '0', + width: '100%', + height: '100%', + display: 'flex', + flexDirection: 'column', + lineHeight: '1.6', + overflow: 'hidden', + padding: '0', + margin: '0', + backgroundColor: cssVariableTheme.background.default, + }, + render: () => { return ( -
+
diff --git a/frontend/src/pages/hello-world.tsx b/frontend/src/pages/hello-world.tsx index 48211cd..88ff5a9 100644 --- a/frontend/src/pages/hello-world.tsx +++ b/frontend/src/pages/hello-world.tsx @@ -1,88 +1,88 @@ import { Shade, createComponent } from '@furystack/shades' -import { ThemeProviderService } from '@furystack/shades-common-components' +import { cssVariableTheme } from '@furystack/shades-common-components' import { SessionService } from '../services/session.js' export const HelloWorld = Shade({ shadowDomName: 'hello-world', + css: { + overflow: 'auto', + paddingTop: '64px', + '& .content': { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + color: cssVariableTheme.text.secondary, + }, + '& .content-body': { + margin: '2em', + }, + }, render: ({ useObservable, injector }) => { const [currentUser] = useObservable('userName', injector.getInstance(SessionService).currentUser) - const { theme } = injector.getInstance(ThemeProviderService) return ( -
-
-

Hello, {currentUser?.username || 'unknown'} !

+
+

Hello, {currentUser?.username || 'unknown'} !

-
-

Egyesült Államok

-

- A nagy múltú szórakoztató- és divatmagazin, a Cosmopolitan egyik 1967-es száma lelkes hangvételű, bíztató - cikket közölt arról, milyen nagy jövő vár a nőkre a programozás területén. A cikk további érdekessége, - hogy benne épp Grace Hoppert – a számítástechnika területén lenyűgöző újdonságokat megalkotó programozónőt - – idézik, aki szerint: „Programozni olyan, mint megtervezni egy vacsorát […] előre kell tervezni és - időzíteni, így minden készen lesz, amikor szükség van rá. -

-

- Bár ennek a kijelentésnek feltételezhetően az a célja, hogy a programozói pályára bátorítsa a nőket, - valószínűleg nem segít abban, hogy kevésbé sztereotipikusan, komplex és értékes feladatként tekintsenek a - programozásra. -

-

- Nehéz pontos statisztikát találnunk arról, mennyi női és férfi programozó volt az egyes évtizedekben, - hiszen az, hogy hányan végeztek számítástechnikai szakokon, még nem mutatja meg, mennyien dolgoztak utána - a területen. Fordítva is igaz ez, nem feltétlenül az egyetemi képzésekről kikerülők végezték mindig a - programozói feladatokat, ahogy napjainkban sem. -

-

- Az 1980-as évek első felében az Egyesült Államokban az informatikai diplomával rendelkezők 37%-a volt nő, - összességében a munkavállalók között pedig még többségben voltak ezen a területen. Ezután következett a - fordulópont, a nők részvétele a számítástechnikai felsőoktatásban és a munkaerőpiacon a következő - évtizedekben drasztikusan csökkent. A 2010-es években a hallgatók kb. 20%-a volt nő, és az IT szektor - munkavállalóira is hasonló arány jellemző. -

-

Európa

-

- Az európai munkaerőpiac helyzetéről, foglalkoztatottsági arányokról, a különböző területeken dolgozók - számának változásáról az Eurostat készít részletes felmérést. Alapos kutatásaik eredményei számos - érdekességgel szolgálnak, nem csak a nemek arányára vonatkozóan. -

-

- Az Eurostat vizsgálata nem kifejezetten a programozói szakmára irányul, hanem a programozást magába - foglaló területet, az infokommunikációt (IKT, angol rövidítése ICT) veszik górcső alá. Európában az IKT - területen egyértelműen a férfiak dominálnak, a munkavállalók 83,5%-át teszik ki. -

-

- Bár a nők száma nőtt a területen (1.071.500-ról 1.231.700-ra), arányuk mégis csökkent az elmúlt 10 évben, - hiszen maga a terület olyan dinamikusan növekszik, hogy az arányok megváltoztatásához ez a - létszámgyarapodás nem elég. 2008-ban az IKT területen dolgozók 22%-a volt nő, 2018-ra ez az arány 16,5%-ra - csökkent az EU-ban. -

-

- A 2008-as adatok még több országban kiegyenlítettebb viszonyokat mutatnak a maiaknál. Lehetséges, hogy a - szovjet éra utóhatását tükrözik ezek a számok, például Bulgáriában, Észtországban, Litvániában, - Magyarországon és Romániában is kiegyenlítettebb volt a nemek aránya (65% férfi, 35% nő). A volt szovjet - hatalmi blokk országaiban jellemző volt, hogy a hagyományos nemi szerepektől eltérő munkakörökben is - képviseltetik magukat a nők (gondolhatunk a traktorista lányok toborzására például). Ebben a - blogbejegyzésben a szerző arról ír, hogy amikor az édesanyja tanult programozni, (az 1970-es években, a - Szovjetunióban) az osztály 100%-ban nőkből állt, illetve, hogy a programozás nem maszkulin munkának - számított. A BBC oldalán található cikkben szintén olvashatunk arról, hogyan vonták be a gazdasági - prioritásnak számító technológiai fejlődésbe a nőket is és hogyan tették számukra is egyformán elérhetővé - a képzést mérnöki, programozói, matematikai területen. -

-

- Mára ezekben az országokban is az európai átlaghoz közelebbi arányok jellemzők. A női IKT szakemberek - aránya 2019-ben Bulgáriában a legmagasabb (28%) és Magyarországon a legalacsonyabb (10,6%) az Európai - Unióban. -

-
+
+

Egyesült Államok

+

+ A nagy múltú szórakoztató- és divatmagazin, a Cosmopolitan egyik 1967-es száma lelkes hangvételű, bíztató + cikket közölt arról, milyen nagy jövő vár a nőkre a programozás területén. A cikk további érdekessége, hogy + benne épp Grace Hoppert – a számítástechnika területén lenyűgöző újdonságokat megalkotó programozónőt – + idézik, aki szerint: „Programozni olyan, mint megtervezni egy vacsorát […] előre kell tervezni és időzíteni, + így minden készen lesz, amikor szükség van rá. +

+

+ Bár ennek a kijelentésnek feltételezhetően az a célja, hogy a programozói pályára bátorítsa a nőket, + valószínűleg nem segít abban, hogy kevésbé sztereotipikusan, komplex és értékes feladatként tekintsenek a + programozásra. +

+

+ Nehéz pontos statisztikát találnunk arról, mennyi női és férfi programozó volt az egyes évtizedekben, hiszen + az, hogy hányan végeztek számítástechnikai szakokon, még nem mutatja meg, mennyien dolgoztak utána a + területen. Fordítva is igaz ez, nem feltétlenül az egyetemi képzésekről kikerülők végezték mindig a + programozói feladatokat, ahogy napjainkban sem. +

+

+ Az 1980-as évek első felében az Egyesült Államokban az informatikai diplomával rendelkezők 37%-a volt nő, + összességében a munkavállalók között pedig még többségben voltak ezen a területen. Ezután következett a + fordulópont, a nők részvétele a számítástechnikai felsőoktatásban és a munkaerőpiacon a következő + évtizedekben drasztikusan csökkent. A 2010-es években a hallgatók kb. 20%-a volt nő, és az IT szektor + munkavállalóira is hasonló arány jellemző. +

+

Európa

+

+ Az európai munkaerőpiac helyzetéről, foglalkoztatottsági arányokról, a különböző területeken dolgozók + számának változásáról az Eurostat készít részletes felmérést. Alapos kutatásaik eredményei számos + érdekességgel szolgálnak, nem csak a nemek arányára vonatkozóan. +

+

+ Az Eurostat vizsgálata nem kifejezetten a programozói szakmára irányul, hanem a programozást magába foglaló + területet, az infokommunikációt (IKT, angol rövidítése ICT) veszik górcső alá. Európában az IKT területen + egyértelműen a férfiak dominálnak, a munkavállalók 83,5%-át teszik ki. +

+

+ Bár a nők száma nőtt a területen (1.071.500-ról 1.231.700-ra), arányuk mégis csökkent az elmúlt 10 évben, + hiszen maga a terület olyan dinamikusan növekszik, hogy az arányok megváltoztatásához ez a létszámgyarapodás + nem elég. 2008-ban az IKT területen dolgozók 22%-a volt nő, 2018-ra ez az arány 16,5%-ra csökkent az EU-ban. +

+

+ A 2008-as adatok még több országban kiegyenlítettebb viszonyokat mutatnak a maiaknál. Lehetséges, hogy a + szovjet éra utóhatását tükrözik ezek a számok, például Bulgáriában, Észtországban, Litvániában, + Magyarországon és Romániában is kiegyenlítettebb volt a nemek aránya (65% férfi, 35% nő). A volt szovjet + hatalmi blokk országaiban jellemző volt, hogy a hagyományos nemi szerepektől eltérő munkakörökben is + képviseltetik magukat a nők (gondolhatunk a traktorista lányok toborzására például). Ebben a + blogbejegyzésben a szerző arról ír, hogy amikor az édesanyja tanult programozni, (az 1970-es években, a + Szovjetunióban) az osztály 100%-ban nőkből állt, illetve, hogy a programozás nem maszkulin munkának + számított. A BBC oldalán található cikkben szintén olvashatunk arról, hogyan vonták be a gazdasági + prioritásnak számító technológiai fejlődésbe a nőket is és hogyan tették számukra is egyformán elérhetővé a + képzést mérnöki, programozói, matematikai területen. +

+

+ Mára ezekben az országokban is az európai átlaghoz közelebbi arányok jellemzők. A női IKT szakemberek aránya + 2019-ben Bulgáriában a legmagasabb (28%) és Magyarországon a legalacsonyabb (10,6%) az Európai Unióban. +

) diff --git a/frontend/src/pages/init.tsx b/frontend/src/pages/init.tsx index 80f91a9..2ac39e8 100644 --- a/frontend/src/pages/init.tsx +++ b/frontend/src/pages/init.tsx @@ -3,32 +3,27 @@ import { Loader } from '@furystack/shades-common-components' export const Init = Shade({ shadowDomName: 'shade-init', + css: { + display: 'flex', + height: '100%', + alignItems: 'center', + justifyContent: 'center', + '& .initLoader': { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + }, + }, render: () => ( -
-
+ - -

Initializing app...

-
+ /> +

Initializing app...

), }) diff --git a/frontend/src/pages/login.tsx b/frontend/src/pages/login.tsx index 59b2825..adbd8da 100644 --- a/frontend/src/pages/login.tsx +++ b/frontend/src/pages/login.tsx @@ -1,72 +1,75 @@ import { Shade, createComponent } from '@furystack/shades' -import { Button, Form, Input, Paper } from '@furystack/shades-common-components' +import { Button, cssVariableTheme, Form, Input, Paper } from '@furystack/shades-common-components' import { SessionService } from '../services/session.js' type LoginPayload = { userName: string; password: string } export const Login = Shade({ shadowDomName: 'shade-login', + css: { + display: 'flex', + flexDirection: 'column', + height: '100%', + alignItems: 'center', + justifyContent: 'center', + padding: '0 100px', + paddingTop: '100px', + '& .form-actions': { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + flexDirection: 'row', + padding: '1em 0', + }, + '& .error-message': { + color: cssVariableTheme.palette.error.main, + fontSize: '12px', + }, + '& .helper-text': { + fontSize: '10px', + }, + }, render: ({ injector, useObservable }) => { const sessionService = injector.getInstance(SessionService) const [isOperationInProgress] = useObservable('isOperationInProgress', sessionService.isOperationInProgress) const [error] = useObservable('loginError', sessionService.loginError) return ( -
- - - className="login-form" - validate={(data): data is LoginPayload => { - return (data as LoginPayload).userName?.length > 0 && (data as LoginPayload).password?.length > 0 - }} - onSubmit={({ userName, password }) => { - void sessionService.login(userName, password) - }} - > -

Login

- "The user's login name"} - type="text" - /> - 'The password for the user'} - type="password" - /> -
- {error ?
{error}
:
} - -
-

You can login with the default 'testuser' / 'password' credentials

- - -
+ + + className="login-form" + validate={(data): data is LoginPayload => { + return (data as LoginPayload).userName?.length > 0 && (data as LoginPayload).password?.length > 0 + }} + onSubmit={({ userName, password }) => { + void sessionService.login(userName, password) + }} + > +

Login

+ "The user's login name"} + type="text" + /> + 'The password for the user'} + type="password" + /> +
+ {error ?
{error}
:
} + +
+

You can login with the default 'testuser' / 'password' credentials

+ + ) }, }) diff --git a/frontend/src/pages/offline.tsx b/frontend/src/pages/offline.tsx index ecf3490..bfc9f0d 100644 --- a/frontend/src/pages/offline.tsx +++ b/frontend/src/pages/offline.tsx @@ -1,8 +1,24 @@ import { Shade, createComponent } from '@furystack/shades' +import { cssVariableTheme } from '@furystack/shades-common-components' import { environmentOptions } from '../environment-options.js' export const Offline = Shade({ shadowDomName: 'shade-offline', + css: { + '& a': { + color: cssVariableTheme.palette.primary.main, + textDecoration: 'none', + transition: 'color 0.2s ease', + }, + '& a:hover': { + color: cssVariableTheme.palette.primary.light, + textDecoration: 'underline', + }, + '& a:focus': { + outline: `2px solid ${cssVariableTheme.palette.primary.main}`, + outlineOffset: '2px', + }, + }, render: () => { return (
=4.8.4 <6.0.0" - checksum: 10c0/d24e41d0117ef841cc05e4c52d33277de2e57981fa38412f93034082a3467f804201c180f1baca9f967388c7e5965ffcc61e445cf726a0064b8ed71a84f59aa2 + checksum: 10c0/e533c8285880b883e02a833f378597c2776e6b0c20a5935440e2a02c1c42f40069a8badcf6d581bb4ec35a6856a806c4b66674c1c15c33cd64cc6b9c0cdd1dad languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/parser@npm:8.53.1" +"@typescript-eslint/parser@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/parser@npm:8.54.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.53.1" - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" - "@typescript-eslint/visitor-keys": "npm:8.53.1" + "@typescript-eslint/scope-manager": "npm:8.54.0" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/typescript-estree": "npm:8.54.0" + "@typescript-eslint/visitor-keys": "npm:8.54.0" debug: "npm:^4.4.3" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/fb7602dc3ea45b838f4da2d0173161b222442ed2007487dfce57d6ce24ff16606ec99de9eb6ac114a815e11a47248303d941dca1a7bf13f70350372cee509886 + checksum: 10c0/60a1cfe94bc23086f03701640f4d83d7e37b8f4d729011e0f029e5accf2b3d099c50938c0a798a399e86046279432ff663f33102ba4338c4c82f7acead2bcbac languageName: node linkType: hard -"@typescript-eslint/project-service@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/project-service@npm:8.53.1" +"@typescript-eslint/project-service@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/project-service@npm:8.54.0" dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.53.1" - "@typescript-eslint/types": "npm:^8.53.1" + "@typescript-eslint/tsconfig-utils": "npm:^8.54.0" + "@typescript-eslint/types": "npm:^8.54.0" debug: "npm:^4.4.3" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/eecc7ad86b45c6969a05e984e645a4ece2a1cc27d825af046efb6ed369cab32062c17f33a1154ab6dcab349099885db7b39945f1b318753395630f3dfa1e5895 + checksum: 10c0/3392ae259199021a80616a44d9484d1c363f61bc5c631dff2d08c6a906c98716a20caa7b832b8970120a1eb1eb2de3ee890cd527d6edb04f532f4e48a690a792 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/scope-manager@npm:8.53.1" +"@typescript-eslint/scope-manager@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/scope-manager@npm:8.54.0" dependencies: - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/visitor-keys": "npm:8.53.1" - checksum: 10c0/d971eb115f2a2c4c25c79df9eee68b93354b32d7cc1174c167241cd2ebbc77858fe7a032c7ecdbacef936b56e8317b56037d21461cb83b4789f7e764e9faa455 + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/visitor-keys": "npm:8.54.0" + checksum: 10c0/794740a5c0c1afc38d71e6bc59cc62870286e40d99f15e9760e76fb3d4197e961ee151c286c428535c404f5137721242a14da21350b749d0feb1f589f167814f languageName: node linkType: hard -"@typescript-eslint/tsconfig-utils@npm:8.53.1, @typescript-eslint/tsconfig-utils@npm:^8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.53.1" +"@typescript-eslint/tsconfig-utils@npm:8.54.0, @typescript-eslint/tsconfig-utils@npm:^8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.54.0" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/e2bfa91f9306dbfa82bdcb64bfcf634fee6313b03e93b35b0010907983c9ffc73c732264deff870896dea18f34b872d39d90d32f7631fd4618e4a6866ffff578 + checksum: 10c0/e8598b0f051650c085d749002138d12249a3efd03e7de02e9e7913939dddd649d159b91f29ca3d28f5ee798b3f528a7195688e23c5e0b315d534e7af20a0c99a languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/type-utils@npm:8.53.1" +"@typescript-eslint/type-utils@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/type-utils@npm:8.54.0" dependencies: - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" - "@typescript-eslint/utils": "npm:8.53.1" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/typescript-estree": "npm:8.54.0" + "@typescript-eslint/utils": "npm:8.54.0" debug: "npm:^4.4.3" ts-api-utils: "npm:^2.4.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/d97ac3bf901eeeb1ad01a423409db654f849d49f8ce7a2b0d482e093d5c8c9cab9ed810554d130a1eaf4921ddb2d98dbe9a8d22bfd08fd6c8ab004fb640a3fbe + checksum: 10c0/ad807800d8b2662f823505249a84a6f5b1246b192a7ff08c49f298e220e4d9bb3d76f1f0852510421e030161604a4b939bff87f11b9074f118a3bd1d26139c6f + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:8.54.0, @typescript-eslint/types@npm:^8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/types@npm:8.54.0" + checksum: 10c0/2219594fe5e8931ff91fd1b7a2606d33cd4f093d43f9ca71bcaa37f106ef79ad51f830dea51392f7e3d8bca77f7077ef98733f87bc008fad2f0bbd9ea5fb8a40 languageName: node linkType: hard -"@typescript-eslint/types@npm:8.53.1, @typescript-eslint/types@npm:^8.53.1": +"@typescript-eslint/types@npm:^8.53.1": version: 8.53.1 resolution: "@typescript-eslint/types@npm:8.53.1" checksum: 10c0/fa49f5f60de6851de45a9aff0a3ba3c4d00a0991100414e8af1a5d6f32764a48b6b7c0f65748a651f0da0e57df0745cdb8f11c590fa0fb22dd0e54e4c6b5c878 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.53.1" +"@typescript-eslint/typescript-estree@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.54.0" dependencies: - "@typescript-eslint/project-service": "npm:8.53.1" - "@typescript-eslint/tsconfig-utils": "npm:8.53.1" - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/visitor-keys": "npm:8.53.1" + "@typescript-eslint/project-service": "npm:8.54.0" + "@typescript-eslint/tsconfig-utils": "npm:8.54.0" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/visitor-keys": "npm:8.54.0" debug: "npm:^4.4.3" minimatch: "npm:^9.0.5" semver: "npm:^7.7.3" @@ -1559,32 +1557,32 @@ __metadata: ts-api-utils: "npm:^2.4.0" peerDependencies: typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/e1b48990ba90f0ee5c9630fe91e2d5123c55348e374e586de6cf25e6e03e6e8274bf15317794d171a2e82d9dc663c229807e603ecc661dbe70d61bd23d0c37c4 + checksum: 10c0/1a1a7c0a318e71f3547ab5573198d36165ea152c50447ef92e6326303f9a5c397606201ba80c7b86a725dcdd2913e924be94466a0c33b1b0c3ee852059e646b6 languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/utils@npm:8.53.1" +"@typescript-eslint/utils@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/utils@npm:8.54.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.9.1" - "@typescript-eslint/scope-manager": "npm:8.53.1" - "@typescript-eslint/types": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" + "@typescript-eslint/scope-manager": "npm:8.54.0" + "@typescript-eslint/types": "npm:8.54.0" + "@typescript-eslint/typescript-estree": "npm:8.54.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/9a2a11c00b97eb9a053782e303cc384649807779e9adeb0b645bc198c83f54431f7ca56d4b38411dcf7ed06a2c2d9aa129874c20c037de2393a4cd0fa3b93c25 + checksum: 10c0/949a97dca8024d39666e04ecdf2d4e12722f5064c387901e72bdcc7adafb96cf650a070dc79f9dd46fa1aae6ac2b5eac5ae3fe5a6979385208c28809a1bd143f languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.53.1": - version: 8.53.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.53.1" +"@typescript-eslint/visitor-keys@npm:8.54.0": + version: 8.54.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.54.0" dependencies: - "@typescript-eslint/types": "npm:8.53.1" + "@typescript-eslint/types": "npm:8.54.0" eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/73a21d34052bcb0b46ed738f8fddb76ae8f56a0c27932616b49022cf8603c3e36bb6ab30acd709f9bc05c673708180527b4c4aaffcb858acfc66d8fb39cc6c29 + checksum: 10c0/f83a9aa92f7f4d1fdb12cbca28c6f5704c36371264606b456388b2c869fc61e73c86d3736556e1bb6e253f3a607128b5b1bf6c68395800ca06f18705576faadd languageName: node linkType: hard @@ -2924,13 +2922,6 @@ __metadata: languageName: node linkType: hard -"comment-parser@npm:1.4.4": - version: 1.4.4 - resolution: "comment-parser@npm:1.4.4" - checksum: 10c0/85eaa6b8cd05206b6dcde9c779879ab5d36b7640ec5ed9f0709f1529a2d84638603860ea0a78df3fab9443db8c31f6f881e37d2264edadb653ebd9736a5f9ad8 - languageName: node - linkType: hard - "comment-parser@npm:1.4.5": version: 1.4.5 resolution: "comment-parser@npm:1.4.5" @@ -2942,8 +2933,8 @@ __metadata: version: 0.0.0-use.local resolution: "common@workspace:common" dependencies: - "@furystack/rest": "npm:^8.0.32" - "@types/node": "npm:^25.0.10" + "@furystack/rest": "npm:^8.0.34" + "@types/node": "npm:^25.1.0" ts-json-schema-generator: "npm:^2.4.0" vitest: "npm:^4.0.18" languageName: unknown @@ -3493,11 +3484,11 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsdoc@npm:^62.4.0": - version: 62.4.0 - resolution: "eslint-plugin-jsdoc@npm:62.4.0" +"eslint-plugin-jsdoc@npm:^62.5.0": + version: 62.5.0 + resolution: "eslint-plugin-jsdoc@npm:62.5.0" dependencies: - "@es-joy/jsdoccomment": "npm:~0.82.0" + "@es-joy/jsdoccomment": "npm:~0.83.0" "@es-joy/resolve.exports": "npm:1.2.0" are-docs-informative: "npm:^0.0.2" comment-parser: "npm:1.4.5" @@ -3513,18 +3504,18 @@ __metadata: to-valid-identifier: "npm:^1.0.0" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/c7552785b20f6c52d9aaa90625a6ead67a9f3b70f0766cc8a64aee67d619e977ba8581e3fb7a1381d5ebee601854813d73b8b8f5c9d05e2133dc1592caba4292 + checksum: 10c0/840e62319bcd1cd24bbf25a709239881dc9a064c548a34e6933261429ff182b720898b45760c0e8e645b00e9597c73a68c7d89d2c7a714b72ac80714907f968d languageName: node linkType: hard -"eslint-plugin-playwright@npm:^2.5.0": - version: 2.5.0 - resolution: "eslint-plugin-playwright@npm:2.5.0" +"eslint-plugin-playwright@npm:^2.5.1": + version: 2.5.1 + resolution: "eslint-plugin-playwright@npm:2.5.1" dependencies: globals: "npm:^16.4.0" peerDependencies: eslint: ">=8.40.0" - checksum: 10c0/89cf12779a9341f35c3c6992233485ea26f97ae82bfedd2e9c664375d237e724c6188d24f4473ca5de3d97e06a11022119b7c39b35bcf6b10d9acce77b38c215 + checksum: 10c0/b8b752f8692b20b062f218be344c25ad366192b15e4b5c764e25b67a1fa6cfaffb67456aadd6fce5bc8ac7b0922a4413b76be35c7121a3c76e2fc09d09071f53 languageName: node linkType: hard @@ -3860,14 +3851,14 @@ __metadata: resolution: "frontend@workspace:frontend" dependencies: "@codecov/vite-plugin": "npm:^1.9.1" - "@furystack/core": "npm:^15.0.32" - "@furystack/inject": "npm:^12.0.26" - "@furystack/logging": "npm:^8.0.26" - "@furystack/rest-client-fetch": "npm:^8.0.32" - "@furystack/shades": "npm:^11.0.33" - "@furystack/shades-common-components": "npm:^10.0.33" - "@furystack/utils": "npm:^8.1.8" - "@types/node": "npm:^25.0.10" + "@furystack/core": "npm:^15.0.34" + "@furystack/inject": "npm:^12.0.28" + "@furystack/logging": "npm:^8.0.28" + "@furystack/rest-client-fetch": "npm:^8.0.34" + "@furystack/shades": "npm:^11.1.0" + "@furystack/shades-common-components": "npm:^11.0.0" + "@furystack/utils": "npm:^8.1.9" + "@types/node": "npm:^25.1.0" common: "workspace:^" typescript: "npm:^5.9.3" vite: "npm:^7.3.1" @@ -3971,22 +3962,22 @@ __metadata: resolution: "furystack-boilerplate-app@workspace:." dependencies: "@eslint/js": "npm:^9.39.2" - "@furystack/yarn-plugin-changelog": "npm:^1.0.1" - "@playwright/test": "npm:^1.58.0" - "@types/node": "npm:^25.0.10" + "@furystack/yarn-plugin-changelog": "npm:^1.0.2" + "@playwright/test": "npm:^1.58.1" + "@types/node": "npm:^25.1.0" "@vitest/coverage-v8": "npm:^4.0.18" eslint: "npm:^9.39.2" eslint-config-prettier: "npm:^10.1.8" eslint-plugin-import: "npm:2.32.0" - eslint-plugin-jsdoc: "npm:^62.4.0" - eslint-plugin-playwright: "npm:^2.5.0" + eslint-plugin-jsdoc: "npm:^62.5.0" + eslint-plugin-playwright: "npm:^2.5.1" eslint-plugin-prettier: "npm:^5.5.5" husky: "npm:^9.1.7" lint-staged: "npm:^16.2.7" prettier: "npm:^3.8.1" rimraf: "npm:^6.1.2" typescript: "npm:^5.9.3" - typescript-eslint: "npm:^8.53.1" + typescript-eslint: "npm:^8.54.0" vite: "npm:^7.3.1" vitest: "npm:^4.0.18" languageName: unknown @@ -5710,27 +5701,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.58.0": - version: 1.58.0 - resolution: "playwright-core@npm:1.58.0" +"playwright-core@npm:1.58.1": + version: 1.58.1 + resolution: "playwright-core@npm:1.58.1" bin: playwright-core: cli.js - checksum: 10c0/72f59ffed79357f3042ba8ebced54d63a1bdb01e4422e1d3238415ac1ee25254d4a1809f77c562045fc25805e71ad3de8e8ac0e3521e48b9c6f108cd5419ec48 + checksum: 10c0/2c12755579148cbd13811cc1a01e9693432f0e4595c76ebb02d2e1b4ee7286719c6769fdb26cda61f218bc49b7ddd4de5d856abbd034acde4ff3dbeee93e4773 languageName: node linkType: hard -"playwright@npm:1.58.0": - version: 1.58.0 - resolution: "playwright@npm:1.58.0" +"playwright@npm:1.58.1": + version: 1.58.1 + resolution: "playwright@npm:1.58.1" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.58.0" + playwright-core: "npm:1.58.1" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10c0/f0565966a485f0bf0748897c19aa403f97c4c83bb936b7dfc6b2f1c056d4befb24810f451e4b8cb760db3733bfef1cf7f00b369664637e48befd6fe9e42f541a + checksum: 10c0/29cb2b34ad80f9dc1b27d26d8cf56e0964d7787e0beb18b25fd9d087a09ce56a359779104d2a1717d08789c2f2713928ef59140b2905e6ef00b2cb6df58bb107 languageName: node linkType: hard @@ -6242,14 +6233,14 @@ __metadata: version: 0.0.0-use.local resolution: "service@workspace:service" dependencies: - "@furystack/core": "npm:^15.0.32" - "@furystack/filesystem-store": "npm:^7.0.32" - "@furystack/inject": "npm:^12.0.26" - "@furystack/logging": "npm:^8.0.26" - "@furystack/repository": "npm:^10.0.32" - "@furystack/rest-service": "npm:^10.1.3" - "@furystack/security": "npm:^6.0.32" - "@types/node": "npm:^25.0.10" + "@furystack/core": "npm:^15.0.34" + "@furystack/filesystem-store": "npm:^7.0.34" + "@furystack/inject": "npm:^12.0.28" + "@furystack/logging": "npm:^8.0.28" + "@furystack/repository": "npm:^10.0.34" + "@furystack/rest-service": "npm:^11.0.2" + "@furystack/security": "npm:^6.0.34" + "@types/node": "npm:^25.1.0" common: "workspace:^" typescript: "npm:^5.9.3" vitest: "npm:^4.0.18" @@ -6982,18 +6973,18 @@ __metadata: languageName: node linkType: hard -"typescript-eslint@npm:^8.53.1": - version: 8.53.1 - resolution: "typescript-eslint@npm:8.53.1" +"typescript-eslint@npm:^8.54.0": + version: 8.54.0 + resolution: "typescript-eslint@npm:8.54.0" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.53.1" - "@typescript-eslint/parser": "npm:8.53.1" - "@typescript-eslint/typescript-estree": "npm:8.53.1" - "@typescript-eslint/utils": "npm:8.53.1" + "@typescript-eslint/eslint-plugin": "npm:8.54.0" + "@typescript-eslint/parser": "npm:8.54.0" + "@typescript-eslint/typescript-estree": "npm:8.54.0" + "@typescript-eslint/utils": "npm:8.54.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/520d68df8e1e1bba99c2713029b63837b101370c460bf5e75b8065fb0a6bc1ac9c6eb967432dbc220464479fe981630a6b2eddf31cfb378441ee8b8a43c0eb5a + checksum: 10c0/0ba92aa22c0aa10c88b0f4732950ed64245947f1c4ac17328dff94b43eaeddd3068595788725781fba07a87cc964304a075b3e37f9a86312173498fcc6ab4338 languageName: node linkType: hard