diff --git a/apps/showcase/db/contacts.json b/apps/showcase/db/contacts.json new file mode 100644 index 0000000000..0e3755dbd3 --- /dev/null +++ b/apps/showcase/db/contacts.json @@ -0,0 +1,109 @@ +{ + "contacts": [ + { + "id": "1", + "firstName": "Winnie", + "lastName": "The Pooh" + }, + { + "id": "2", + "firstName": "Christopher", + "lastName": "Robin" + }, + { + "id": "3", + "firstName": "Eyeore", + "lastName": "The Donkey" + }, + { + "id": "5", + "firstName": "Scrooge", + "lastName": "McDuck" + }, + { + "id": "6", + "firstName": "Tinker", + "lastName": "Bell" + }, + { + "id": "7", + "firstName": "Peter", + "lastName": "Pan" + }, + { + "id": "8", + "firstName": "Capitan", + "lastName": "Hook" + }, + { + "id": "9", + "firstName": "Snow", + "lastName": "White" + }, + { + "id": "10", + "firstName": "Prince", + "lastName": "Charming" + }, + { + "id": "11", + "firstName": "Fairy", + "lastName": "Godmother" + }, + { + "id": "12", + "firstName": "Simba", + "lastName": "The Lion" + }, + { + "id": "13", + "firstName": "Mufasa", + "lastName": "The Lion King" + }, + { + "id": "14", + "firstName": "Mike", + "lastName": "Wazowski" + }, + { + "id": "15", + "firstName": "James", + "lastName": "P. Sullivan" + }, + { + "id": "16", + "firstName": "Randall", + "lastName": "Boggs" + }, + { + "id": "17", + "firstName": "Buzz", + "lastName": "Lightyear" + }, + { + "id": "18", + "firstName": "Launchpad", + "lastName": "McQuack" + }, + { + "id": "19", + "firstName": "Minnie", + "lastName": "Mouse" + }, + { + "id": "20", + "firstName": "Mickey", + "lastName": "Mouse" + }, + { + "id": "21", + "firstName": "Donald", + "lastName": "Duck" + }, + { + "id": "22", + "firstName": "Daisy", + "lastName": "Duck" + } + ] +} diff --git a/apps/showcase/package.json b/apps/showcase/package.json index ff9a029dcc..25702acc9f 100644 --- a/apps/showcase/package.json +++ b/apps/showcase/package.json @@ -9,6 +9,7 @@ "nx": "nx", "start": "ng run showcase:run", "build": "yarn run generate:translations && ng build", + "db": "json-server --watch db/contacts.json", "watch": "ng compile --watch --configuration development", "test": "ng test", "start:no-translation": "ng serve", @@ -61,6 +62,8 @@ "@o3r/styling": "workspace:^", "@o3r/testing": "workspace:^", "@popperjs/core": "^2.11.5", + "@tanstack/angular-query-devtools-experimental": "^5.28.8", + "@tanstack/angular-query-experimental": "^5.28.8", "ag-grid-angular": "~31.1.0", "ag-grid-community": "~31.1.0", "bootstrap": "5.3.3", @@ -112,6 +115,7 @@ "jest-environment-jsdom": "~29.7.0", "jest-junit": "~16.0.0", "jest-preset-angular": "~14.0.3", + "json-server": "^1.0.0-alpha.23", "jsonc-eslint-parser": "~2.4.0", "lighthouse": "9.6.8", "playwright-lighthouse": "2.2.2", diff --git a/apps/showcase/project.json b/apps/showcase/project.json index 9f80c0b61a..12be176789 100644 --- a/apps/showcase/project.json +++ b/apps/showcase/project.json @@ -135,8 +135,18 @@ "^build" ] }, + "serve-db": { + "executor": "nx:run-commands", + "options": { + "commands": ["yarn db", "yarn ng serve showcase"], + "parallel": true + } + }, "serve-app": { "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "proxyConfig": "./proxy.config.js" + }, "configurations": { "production": { "buildTarget": "showcase:compile:production" diff --git a/apps/showcase/src/app/app-routing.module.ts b/apps/showcase/src/app/app-routing.module.ts index 5fe834d86b..9e4b6c12eb 100644 --- a/apps/showcase/src/app/app-routing.module.ts +++ b/apps/showcase/src/app/app-routing.module.ts @@ -13,6 +13,7 @@ const appRoutes: Routes = [ {path: 'run-app-locally', loadComponent: () => import('./run-app-locally/index').then((m) => m.RunAppLocallyComponent), title: 'Otter Showcase - Run App Locally'}, {path: 'sdk', loadComponent: () => import('./sdk/index').then((m) => m.SdkComponent), title: 'Otter Showcase - SDK'}, {path: 'placeholder', loadComponent: () => import('./placeholder/index').then((m) => m.PlaceholderComponent), title: 'Otter Showcase - Placeholder'}, + {path: 'tanstack', loadComponent: () => import('./tanstack/index').then((m) => m.TanstackComponent)}, {path: '**', redirectTo: '/home', pathMatch: 'full'} ]; diff --git a/apps/showcase/src/app/app.component.ts b/apps/showcase/src/app/app.component.ts index 6fbb700323..dbf383d408 100644 --- a/apps/showcase/src/app/app.component.ts +++ b/apps/showcase/src/app/app.component.ts @@ -39,6 +39,12 @@ export class AppComponent implements OnDestroy { links: [ { url: '/sdk', label: 'Generator' } ] + }, + { + label: 'Server side storage', + links: [ + { url: '/tanstack', label: 'Tanstack' } + ] } ]; diff --git a/apps/showcase/src/app/app.module.ts b/apps/showcase/src/app/app.module.ts index 280744f223..018cea64d0 100644 --- a/apps/showcase/src/app/app.module.ts +++ b/apps/showcase/src/app/app.module.ts @@ -33,6 +33,13 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +// Tanstack +import { + provideAngularQuery, + QueryClient +} from '@tanstack/angular-query-experimental'; +import { HttpClientModule } from '@angular/common/http'; + const runtimeChecks: Partial = { strictActionImmutability: false, strictActionSerializability: false, @@ -87,6 +94,7 @@ export function registerCustomComponents(): Map { ], imports: [ BrowserModule, + HttpClientModule, BrowserAnimationsModule.withConfig({disableAnimations: prefersReducedMotion()}), EffectsModule.forRoot([]), StoreModule.forRoot({}, { runtimeChecks }), @@ -133,7 +141,8 @@ export function registerCustomComponents(): Map { {provide: OTTER_RULES_ENGINE_DEVTOOLS_OPTIONS, useValue: {isActivatedOnBootstrap: true}}, {provide: OTTER_COMPONENTS_DEVTOOLS_OPTIONS, useValue: {isActivatedOnBootstrap: true}}, {provide: OTTER_APPLICATION_DEVTOOLS_OPTIONS, useValue: {isActivatedOnBootstrap: true}}, - {provide: OTTER_STYLING_DEVTOOLS_OPTIONS, useValue: {isActivatedOnBootstrap: true}} + {provide: OTTER_STYLING_DEVTOOLS_OPTIONS, useValue: {isActivatedOnBootstrap: true}}, + provideAngularQuery(new QueryClient()) ], bootstrap: [AppComponent] }) diff --git a/apps/showcase/src/app/tanstack/README.md b/apps/showcase/src/app/tanstack/README.md new file mode 100644 index 0000000000..107ede2c1e --- /dev/null +++ b/apps/showcase/src/app/tanstack/README.md @@ -0,0 +1,3 @@ +# Tanstack usage + +the Tanstack query page diff --git a/apps/showcase/src/app/tanstack/index.ts b/apps/showcase/src/app/tanstack/index.ts new file mode 100644 index 0000000000..9376d9218e --- /dev/null +++ b/apps/showcase/src/app/tanstack/index.ts @@ -0,0 +1 @@ +export * from './tanstack.component'; diff --git a/apps/showcase/src/app/tanstack/tanstack.component.ts b/apps/showcase/src/app/tanstack/tanstack.component.ts new file mode 100644 index 0000000000..5ae31fe412 --- /dev/null +++ b/apps/showcase/src/app/tanstack/tanstack.component.ts @@ -0,0 +1,40 @@ +import { AsyncPipe } from '@angular/common'; +import { AfterViewInit, ChangeDetectionStrategy, Component, QueryList, ViewChildren, ViewEncapsulation } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { O3rComponent } from '@o3r/core'; +import { + CopyTextPresComponent, + IN_PAGE_NAV_PRES_DIRECTIVES, + InPageNavLink, + InPageNavLinkDirective, + InPageNavPresService, + TanstackPresComponent +} from '../../components'; + +@O3rComponent({ componentType: 'Page' }) +@Component({ + selector: 'o3r-tanstack', + standalone: true, + imports: [ + CopyTextPresComponent, + RouterLink, + TanstackPresComponent, + IN_PAGE_NAV_PRES_DIRECTIVES, + AsyncPipe + ], + templateUrl: './tanstack.template.html', + styleUrls: ['./tanstack.style.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TanstackComponent implements AfterViewInit { + @ViewChildren(InPageNavLinkDirective) + private readonly inPageNavLinkDirectives!: QueryList; + public links$ = this.inPageNavPresService.links$; + + constructor(private readonly inPageNavPresService: InPageNavPresService) {} + + public ngAfterViewInit() { + this.inPageNavPresService.initialize(this.inPageNavLinkDirectives); + } +} diff --git a/apps/showcase/src/app/tanstack/tanstack.spec.ts b/apps/showcase/src/app/tanstack/tanstack.spec.ts new file mode 100644 index 0000000000..4b6f325e56 --- /dev/null +++ b/apps/showcase/src/app/tanstack/tanstack.spec.ts @@ -0,0 +1,35 @@ +import { PetApi } from '@ama-sdk/showcase-sdk'; +import { PetApiFixture } from '@ama-sdk/showcase-sdk/fixtures'; +import { AsyncPipe } from '@angular/common'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterModule } from '@angular/router'; + +import { TanstackComponent } from './tanstack.component'; +import '@angular/localize/init'; + +describe('TanstackComponent', () => { + let component: TanstackComponent; + let fixture: ComponentFixture; + const petApiFixture = new PetApiFixture(); + petApiFixture.findPetsByStatus = petApiFixture.findPetsByStatus.mockResolvedValue([]); + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + TanstackComponent, + RouterModule.forRoot([]), + AsyncPipe + ], + providers: [ + {provide: PetApi, useValue: petApiFixture} + ] + }); + fixture = TestBed.createComponent(TanstackComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/showcase/src/app/tanstack/tanstack.style.scss b/apps/showcase/src/app/tanstack/tanstack.style.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/showcase/src/app/tanstack/tanstack.template.html b/apps/showcase/src/app/tanstack/tanstack.template.html new file mode 100644 index 0000000000..e8c4ea18f4 --- /dev/null +++ b/apps/showcase/src/app/tanstack/tanstack.template.html @@ -0,0 +1,46 @@ +

SDK Generator

+
+
+ + +
+
+

Description

+
+

This module provide generators to create an SDK that can be used to simplify the communication with an API.

+

It also generates the Typescript classes matching the models of the API.

+
+ +

Example

+
+

+ Let's try to use the API https://petstore3.swagger.io +
+ Fortunately, this API provides the specification as Yaml file + that we can use to generate an SDK. +
+ Here, you can check the generated SDK +

+ +

+ Do not hesitate to run the application locally, if not installed yet, follow the instructions. +

+ Source code +
+ +

How to use

+
+ +
+ +

References

+ +
+
diff --git a/apps/showcase/src/components/showcase/index.ts b/apps/showcase/src/components/showcase/index.ts index e0afc6c4c1..d9c64742fa 100644 --- a/apps/showcase/src/components/showcase/index.ts +++ b/apps/showcase/src/components/showcase/index.ts @@ -6,3 +6,4 @@ export * from './localization/index'; export * from './placeholder/index'; export * from './rules-engine/index'; export * from './sdk/index'; +export * from './tanstack/index'; diff --git a/apps/showcase/src/components/showcase/tanstack/README.md b/apps/showcase/src/components/showcase/tanstack/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/showcase/src/components/showcase/tanstack/backend.service.ts b/apps/showcase/src/components/showcase/tanstack/backend.service.ts new file mode 100644 index 0000000000..369025fc26 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/backend.service.ts @@ -0,0 +1,57 @@ +import { inject, Injectable, signal} from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Contact, type ContactWithoutId } from './contact'; +import { URL } from './config'; +import { lastValueFrom, tap } from 'rxjs'; +import { Store } from '@ngrx/store'; +import { selectAllContact, selectContactStorePendingStatus } from './store/contact/contact.selectors'; +import { setContactEntitiesFromApi } from './store/contact/contact.actions'; + +interface ContactResponse { + data: Contact[]; + next: number | undefined; + prev: number | undefined; +} + + +@Injectable({ + providedIn: 'root' +}) +export class BackEndService { + /// Tanstack query usage + private readonly http = inject(HttpClient); + public currentId = signal('1'); + public filter = signal(''); + public currentStart = signal(0); + public currentLimit = signal(5); + public currentPage = signal(1); + + // store solution + public readonly store = inject(Store); + + public allContact = this.store.select(selectAllContact); + + public isPending = this.store.select(selectContactStorePendingStatus); + + public isFailing = this.store.select(selectContactStorePendingStatus); + + constructor() { + // store solution + this.store.dispatch(setContactEntitiesFromApi({call: lastValueFrom(this.http.get(`${URL}?q=`))})); + } + + public saveFn(contact: ContactWithoutId) { + if (contact.id) { + return this.http.put(`${URL}/${contact.id}`, contact); + } + return this.http.post(`${URL}`, contact); + } + + public removeFn(id: string) { + return this.http.delete(`${URL}/${id}`); + } + + public getInfiniteContacts(pageParam: number) { + return this.http.get(`${URL}?_page=${pageParam.toString()}&_per_page=${this.currentLimit().toString()}`).pipe(tap(() => this.currentPage.set(pageParam))); + } +} diff --git a/apps/showcase/src/components/showcase/tanstack/config.ts b/apps/showcase/src/components/showcase/tanstack/config.ts new file mode 100644 index 0000000000..b96310ad40 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/config.ts @@ -0,0 +1 @@ +export const URL = 'http://localhost:4200/contacts'; diff --git a/apps/showcase/src/components/showcase/tanstack/contact.service.ts b/apps/showcase/src/components/showcase/tanstack/contact.service.ts new file mode 100644 index 0000000000..92ea25b3f4 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/contact.service.ts @@ -0,0 +1,58 @@ +// import { inject, Injectable, OnDestroy } from '@angular/core'; +// import { BackEndService } from './backend.service'; +// import { BehaviorSubject, Subject, Subscription } from 'rxjs'; +// import { map, shareReplay, switchMap } from 'rxjs/operators'; +// import { filterSuccess } from '@ngneat/query'; + +// @Injectable({ +// providedIn: 'root' +// }) +// export class ContactService implements OnDestroy { +// // private state +// private _subscription = new Subscription(); +// private _filter$ = new BehaviorSubject(''); +// private backend = inject(BackEndService); +// private _contactId$ = new Subject(); + +// // public readable API +// filter$ = this._filter$.asObservable(); +// contactId$ = this._contactId$.asObservable(); +// filteredContacts$ = this._filter$.pipe( +// switchMap((filter) => { +// return this.backend.getContacts$(filter).result$.pipe( +// filterSuccess(), +// map((project) => project.data) +// ); +// }) +// ); +// contactsCount$ = this.filteredContacts$.pipe(map((data) => data.length)); +// saveMutation = this.backend.createMutationSaveContact(); +// saveMutationResult$ = this.saveMutation.result$.pipe(shareReplay(1)); +// removeMutation = this.backend.createMutationRemoveContact(); +// removeMutationResult$ = this.removeMutation.result$.pipe(shareReplay(1)); + +// getContact$(id: string) { +// return this.backend.getContact$(id); +// } + +// getFilter$Value() { +// return this._filter$.value; +// } + +// // public writable API +// // remove(id: string) { +// // // TODO We can display an error if it fail ? +// // this.removeMutation.mutate(id); +// // } +// // save(contact: Contact) { +// // this.saveMutation.mutate(contact); +// // } + +// filter(text: string) { +// this._filter$.next(text); +// } + +// ngOnDestroy(): void { +// this._subscription.unsubscribe(); +// } +// } diff --git a/apps/showcase/src/components/showcase/tanstack/contact.ts b/apps/showcase/src/components/showcase/tanstack/contact.ts new file mode 100644 index 0000000000..3de56e804a --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/contact.ts @@ -0,0 +1,13 @@ +export interface Contact { + id: string; + firstName: string; + lastName: string; +} + +export interface ContactWithoutId { + id?: string; + firstName: string; + lastName: string; +} + + diff --git a/apps/showcase/src/components/showcase/tanstack/index.ts b/apps/showcase/src/components/showcase/tanstack/index.ts new file mode 100644 index 0000000000..4003638bf8 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/index.ts @@ -0,0 +1 @@ +export * from './tanstack-pres.component'; diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.actions.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.actions.ts new file mode 100644 index 0000000000..3ec18aa36c --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.actions.ts @@ -0,0 +1,78 @@ +import { + asyncProps, + AsyncRequest, + FailAsyncStoreItemEntitiesActionPayload, + FromApiActionPayload, + SetActionPayload, + SetAsyncStoreItemEntitiesActionPayload, + UpdateActionPayload, + UpdateAsyncStoreItemEntitiesActionPayloadWithId +} from '@o3r/core'; + +import {createAction, props} from '@ngrx/store'; +// import {ContactModel} from './contact.state'; +import {ContactStateDetails} from './contact.state'; +import type { Contact } from '../../contact'; + +/** StateDetailsActions */ +const ACTION_SET = '[Contact] set'; +const ACTION_UPDATE = '[Contact] update'; +const ACTION_RESET = '[Contact] reset'; +const ACTION_CANCEL_REQUEST = '[Contact] cancel request'; + +/** Entity Actions */ +const ACTION_CLEAR_ENTITIES = '[Contact] clear entities'; +const ACTION_UPDATE_ENTITIES = '[Contact] update entities'; +const ACTION_UPSERT_ENTITIES = '[Contact] upsert entities'; +const ACTION_SET_ENTITIES = '[Contact] set entities'; +const ACTION_FAIL_ENTITIES = '[Contact] fail entities'; + +/** Async Actions */ +const ACTION_SET_ENTITIES_FROM_API = '[Contact] set entities from api'; +const ACTION_UPDATE_ENTITIES_FROM_API = '[Contact] update entities from api'; +const ACTION_UPSERT_ENTITIES_FROM_API = '[Contact] upsert entities from api'; + +/** Action to clear the StateDetails of the store and replace it */ +export const setContact = createAction(ACTION_SET, props>()); + +/** Action to change a part or the whole object in the store. */ +export const updateContact = createAction(ACTION_UPDATE, props>()); + +/** Action to reset the whole state, by returning it to initial state. */ +export const resetContact = createAction(ACTION_RESET); + +/** Action to cancel a Request ID registered in the store. Can happen from effect based on a switchMap for instance */ +export const cancelContactRequest = createAction(ACTION_CANCEL_REQUEST, props()); + +/** Action to clear all contact and fill the store with the payload */ +export const setContactEntities = createAction(ACTION_SET_ENTITIES, props>()); + +/** Action to update contact with known IDs, ignore the new ones */ +export const updateContactEntities = createAction(ACTION_UPDATE_ENTITIES, props>()); + +/** Action to update contact with known IDs, insert the new ones */ +export const upsertContactEntities = createAction(ACTION_UPSERT_ENTITIES, props>()); + +/** Action to empty the list of entities, keeping the global state */ +export const clearContactEntities = createAction(ACTION_CLEAR_ENTITIES); + +/** Action to update failureStatus for every ContactModel */ +export const failContactEntities = createAction(ACTION_FAIL_ENTITIES, props>()); + +/** + * Action to put the global status of the store in a pending state. Call SET action with the list of ContactModels received, when this action resolves. + * If the call fails, dispatch FAIL_ENTITIES action + */ +export const setContactEntitiesFromApi = createAction(ACTION_SET_ENTITIES_FROM_API, asyncProps>()); + +/** + * Action to change isPending status of elements to be updated with a request. Call UPDATE action with the list of ContactModels received, when this action resolves. + * If the call fails, dispatch FAIL_ENTITIES action + */ +export const updateContactEntitiesFromApi = createAction(ACTION_UPDATE_ENTITIES_FROM_API, asyncProps & { ids: string[] }>()); + +/** + * Action to put global status of the store in a pending state. Call UPSERT action with the list of ContactModels received, when this action resolves. + * If the call fails, dispatch FAIL_ENTITIES action + */ +export const upsertContactEntitiesFromApi = createAction(ACTION_UPSERT_ENTITIES_FROM_API, asyncProps>()); diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.effect.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.effect.ts new file mode 100644 index 0000000000..2ac0dbdc41 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.effect.ts @@ -0,0 +1,66 @@ +import {Injectable} from '@angular/core'; +import {Actions, createEffect, ofType} from '@ngrx/effects'; +import {from, of} from 'rxjs'; +import {catchError, map, mergeMap} from 'rxjs/operators'; +import {fromApiEffectSwitchMap} from '@o3r/core'; +import { + cancelContactRequest, + failContactEntities, + setContactEntities, setContactEntitiesFromApi, + updateContactEntities, updateContactEntitiesFromApi, + upsertContactEntities, upsertContactEntitiesFromApi +} from './contact.actions'; + +/** + * Service to handle async Contact actions + */ +@Injectable() +export class ContactEffect { + + /** + * Set the entities with the reply content, dispatch failContactEntities if it catches a failure + */ + public setEntitiesFromApi$ = createEffect(() => + this.actions$.pipe( + ofType(setContactEntitiesFromApi), + fromApiEffectSwitchMap( + (reply, action) => setContactEntities({entities: reply, requestId: action.requestId}), + (error, action) => of(failContactEntities({error, requestId: action.requestId})), + cancelContactRequest + ) + ) + ); + + /** + * Update the entities with the reply content, dispatch failContactEntities if it catches a failure + */ + public updateEntitiesFromApi$ = createEffect(() => + this.actions$.pipe( + ofType(updateContactEntitiesFromApi), + mergeMap((payload) => + from(payload.call).pipe( + map((reply) => updateContactEntities({entities: reply, requestId: payload.requestId})), + catchError((err) => of(failContactEntities({ids: payload.ids, error: err, requestId: payload.requestId}))) + ) + ) + ) + ); + + /** + * Upsert the entities with the reply content, dispatch failContactEntities if it catches a failure + */ + public upsertEntitiesFromApi$ = createEffect(() => + this.actions$.pipe( + ofType(upsertContactEntitiesFromApi), + mergeMap((payload) => + from(payload.call).pipe( + map((reply) => upsertContactEntities({entities: reply, requestId: payload.requestId})), + catchError((err) => of(failContactEntities({error: err, requestId: payload.requestId}))) + ) + ) + ) + ); + + constructor(protected actions$: Actions) { + } +} diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.module.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.module.ts new file mode 100644 index 0000000000..9803fa8011 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.module.ts @@ -0,0 +1,34 @@ +import { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core'; +import { Action, ActionReducer, StoreModule } from '@ngrx/store'; + +import { EffectsModule } from '@ngrx/effects'; +import { ContactEffect } from './contact.effect'; +import { contactReducer } from './contact.reducer'; +import { CONTACT_STORE_NAME, ContactState } from './contact.state'; + +/** Token of the Contact reducer */ +export const CONTACT_REDUCER_TOKEN = new InjectionToken>('Feature Contact Reducer'); + +/** Provide default reducer for Contact store */ +export function getDefaultContactReducer() { + return contactReducer; +} + +@NgModule({ + imports: [ + StoreModule.forFeature(CONTACT_STORE_NAME, CONTACT_REDUCER_TOKEN), EffectsModule.forFeature([ContactEffect]) + ], + providers: [ + { provide: CONTACT_REDUCER_TOKEN, useFactory: getDefaultContactReducer } + ] +}) +export class ContactStoreModule { + public static forRoot(reducerFactory: () => ActionReducer): ModuleWithProviders { + return { + ngModule: ContactStoreModule, + providers: [ + { provide: CONTACT_REDUCER_TOKEN, useFactory: reducerFactory } + ] + }; + } +} diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.reducer.spec.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.reducer.spec.ts new file mode 100644 index 0000000000..3fd2d24d18 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.reducer.spec.ts @@ -0,0 +1,121 @@ +import * as actions from './contact.actions'; +import {contactInitialState, contactReducer} from './contact.reducer'; +import {ContactState} from './contact.state'; + +describe('Contact Store reducer', () => { + + let entitiesState: ContactState; + const firstContact: any = {id: 'contact1', genericItems: []}; + const secondContact: any = {id: 'contact2', genericItems: []}; + const contactReply: any = [firstContact]; + + it('should have the correct initial state', () => { + expect(contactInitialState.ids.length).toBe(0); + }); + + + it('should by default return the initial state', () => { + const state = contactReducer(contactInitialState, {type: 'fake'} as any); + expect(state).toEqual(contactInitialState); + }); + + describe('Actions on state details', () => { + beforeEach(() => { + entitiesState = contactReducer(contactInitialState, actions.setContactEntities({entities: [firstContact, secondContact]})); + }); + + it('SET action should clear current state details and return a state with the new one', () => { + const firstState = contactReducer(entitiesState, actions.setContact({stateDetails: {requestIds: []}})); + const secondState = contactReducer(firstState, actions.setContact({stateDetails: {requestIds: [], isPending: false}})); + expect(secondState.isPending).toEqual(false); + }); + + it('UPDATE should update the state details without modifying entities', () => { + const firstState = contactReducer(entitiesState, actions.setContact({stateDetails: {requestIds: []}})); + const secondState = contactReducer(firstState, actions.updateContact({stateDetails: {isPending: false}})); + expect(secondState.isPending).toEqual(false); + }); + + it('RESET action should return initial state', () => { + const state = contactReducer(entitiesState, actions.resetContact()); + expect(state).toEqual(contactInitialState); + }); + + it('FAIL action should update the isPending to false and the isFailure to true', () => { + const state = contactReducer({...contactInitialState, isPending: true}, actions.failContactEntities({})); + expect(state.ids.length).toBe(0); + expect(state.isPending).toBe(false); + expect(state.isFailure).toBe(true); + }); + }); + + describe('Entity actions', () => { + it('SET_ENTITIES action should clear current entities and set new ones', () => { + const firstState = contactReducer(contactInitialState, actions.setContactEntities({entities: [firstContact]})); + const secondState = contactReducer(firstState, actions.setContactEntities({entities: [secondContact]})); + expect(secondState.ids.length).toEqual(1); + expect((secondState.ids as string[]).find((id) => (id === firstContact.id))).toBeUndefined(); + expect((secondState.ids as string[]).find((id) => (id === secondContact.id))).toBeDefined(); + }); + + it('UPDATE_ENTITTIES action should only update existing entities', () => { + const firstContactUpdated = {...firstContact, genericField: 'genericId'}; + const firstState = contactReducer(contactInitialState, actions.setContactEntities({entities: [firstContact]})); + const secondState = contactReducer(firstState, + actions.updateContactEntities({entities: [firstContactUpdated, secondContact]})); + expect(secondState.ids.length).toEqual(1); + expect((secondState.ids as string[]).find((id) => (id === firstContact.id))).toBeDefined(); + expect((secondState.ids as string[]).find((id) => (id === secondContact.id))).toBeUndefined(); + }); + + it('UPSERT_ENTITIES action should update existing entities and add the new ones', () => { + const firstContactUpdated = {...firstContact, genericField: 'genericId'}; + const firstState = contactReducer(contactInitialState, actions.setContactEntities({entities: [firstContact]})); + const secondState = contactReducer(firstState, + actions.upsertContactEntities({entities: [firstContactUpdated, secondContact]})); + expect(secondState.ids.length).toEqual(2); + expect((secondState.ids as string[]).find((id) => (id === firstContact.id))).toBeDefined(); + expect((secondState.ids as string[]).find((id) => (id === secondContact.id))).toBeDefined(); + }); + + it('CLEAR_ENTITIES action should clear only the entities', () => { + const firstState = contactReducer(contactInitialState, actions.setContactEntities({entities: [firstContact, secondContact]})); + const secondState = contactReducer(firstState, actions.setContact({stateDetails: {requestIds: [], isPending: false}})); + const thirdState = contactReducer(secondState, actions.clearContactEntities()); + expect(thirdState.ids.length).toEqual(0); + }); + + it('FAIL_ENTITIES action should update the isPending to false and the isFailure to true', () => { + const state = contactReducer({...contactInitialState, isPending: true}, actions.failContactEntities({})); + expect(state.ids.length).toBe(0); + expect(state.isPending).toBe(false); + expect(state.isFailure).toBe(true); + }); + + it('FAIL_ENTITIES action should update the global isPending to false in case there are some newIds in the payload', () => { + const firstState = contactReducer(contactInitialState, actions.setContactEntities({entities: [firstContact]})); + const secondState = contactReducer({...firstState, isPending : true}, + actions.failContactEntities({error: 'dummy error', ids: [secondContact.id]})); + expect(secondState.isPending).toBe(false); + expect(secondState.isFailure).toBe(true); + }); + }); + + describe('API call actions', () => { + it('SET_ENTITIES_FROM_API action should clear current entities and set new ones', () => { + const firstState = contactReducer(contactInitialState, actions.setContactEntitiesFromApi({call: Promise.resolve(contactReply), requestId: 'test'})); + expect(firstState.isPending).toEqual(true); + }); + it('UPDATE_ENTITIES_FROM_API action should clear current entities and set new ones', () => { + const firstState = contactReducer(contactInitialState, actions.setContactEntities({entities: [firstContact]})); + const secondState = contactReducer(firstState, + actions.updateContactEntitiesFromApi({call: Promise.resolve(contactReply), ids: [firstContact.id], requestId: 'test'})); + expect(secondState.isPending).toBeFalsy(); + expect(secondState.entities[firstContact.id]!.isPending).toEqual(true); + }); + it('UPSERT_ENTITIES_FROM_API action should clear current entities and set new ones', () => { + const firstState = contactReducer(contactInitialState, actions.upsertContactEntitiesFromApi({call: Promise.resolve(contactReply), requestId: 'test'})); + expect(firstState.isPending).toEqual(true); + }); + }); +}); diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.reducer.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.reducer.ts new file mode 100644 index 0000000000..e2929141f0 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.reducer.ts @@ -0,0 +1,69 @@ +import {ActionCreator, createReducer, on, ReducerTypes} from '@ngrx/store'; +import {createEntityAdapter} from '@ngrx/entity'; +import {asyncStoreItemAdapter, createEntityAsyncRequestAdapter} from '@o3r/core'; +import * as actions from './contact.actions'; +import {ContactModel, ContactState, ContactStateDetails} from './contact.state'; + +/** + * Contact Store adapter + */ +export const contactAdapter = createEntityAsyncRequestAdapter(createEntityAdapter({ + selectId: (model) => model.id +})); + +/** + * Contact Store initial value + */ +export const contactInitialState: ContactState = contactAdapter.getInitialState({ + requestIds: [] +}); + +/** + * List of basic actions for Contact Store + */ +export const contactReducerFeatures: ReducerTypes[] = [ + on(actions.resetContact, () => contactInitialState), + + on(actions.setContact, (state, payload) => ({ids: state.ids, entities: state.entities, ...payload.stateDetails})), + + on(actions.cancelContactRequest, (state, action) => asyncStoreItemAdapter.resolveRequest(state, action.requestId)), + + on(actions.updateContact, (state, payload) => ({...state, ...payload.stateDetails})), + + on(actions.setContactEntities, (state, payload) => + contactAdapter.addMany( + payload.entities.map((entity) => asyncStoreItemAdapter.initialize(entity)), + contactAdapter.removeAll(asyncStoreItemAdapter.resolveRequest(state, payload.requestId))) + ), + + on(actions.updateContactEntities, (state, payload) => + contactAdapter.resolveRequestMany(state, payload.entities, payload.requestId) + ), + + on(actions.upsertContactEntities, (state, payload) => + contactAdapter.upsertMany( + payload.entities.map((entity) => asyncStoreItemAdapter.initialize(entity)), + asyncStoreItemAdapter.resolveRequest(state, payload.requestId) + ) + ), + + on(actions.clearContactEntities, (state) => contactAdapter.removeAll(state)), + + on(actions.failContactEntities, (state, payload) => + contactAdapter.failRequestMany(state, payload && payload.ids, payload.requestId) + ), + + on(actions.setContactEntitiesFromApi, actions.upsertContactEntitiesFromApi, (state, payload) => + asyncStoreItemAdapter.addRequest(state, payload.requestId)), + + on(actions.updateContactEntitiesFromApi, (state, payload) => + contactAdapter.addRequestMany(state, payload.ids, payload.requestId)) +]; + +/** + * Contact Store reducer + */ +export const contactReducer = createReducer( + contactInitialState, + ...contactReducerFeatures +); diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.selectors.spec.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.selectors.spec.ts new file mode 100644 index 0000000000..86638597d6 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.selectors.spec.ts @@ -0,0 +1,10 @@ +import {contactInitialState} from './contact.reducer'; +import * as selectors from './contact.selectors'; + +describe('Contact Selectors tests', () => { + it('should provide the pending status of the store', () => { + expect(selectors.selectContactStorePendingStatus.projector(contactInitialState)).toBeFalsy(); + expect(selectors.selectContactStorePendingStatus.projector({...contactInitialState, isPending: false})).toBe(false); + expect(selectors.selectContactStorePendingStatus.projector({...contactInitialState, isPending: true})).toBe(true); + }); +}); diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.selectors.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.selectors.ts new file mode 100644 index 0000000000..d7b1e0e797 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.selectors.ts @@ -0,0 +1,26 @@ +import {createFeatureSelector, createSelector} from '@ngrx/store'; +import {contactAdapter} from './contact.reducer'; +import {CONTACT_STORE_NAME, ContactState} from './contact.state'; + +const {selectIds, selectEntities, selectAll, selectTotal} = contactAdapter.getSelectors(); + +/** Select Contact State */ +export const selectContactState = createFeatureSelector(CONTACT_STORE_NAME); + +/** Select the array of Contact ids */ +export const selectContactIds = createSelector(selectContactState, selectIds); + +/** Select the array of Contact */ +export const selectAllContact = createSelector(selectContactState, selectAll); + +/** Select the dictionary of Contact entities */ +export const selectContactEntities = createSelector(selectContactState, selectEntities); + +/** Select the total Contact count */ +export const selectContactTotal = createSelector(selectContactState, selectTotal); + +/** Select the store pending status */ +export const selectContactStorePendingStatus = createSelector(selectContactState, (state) => state.isPending || false); + +export const selectContactStoreFailureStatus = createSelector(selectContactState, (state) => state.isFailure || false); + diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.state.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.state.ts new file mode 100644 index 0000000000..864bef04dc --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.state.ts @@ -0,0 +1,31 @@ +import {EntityState} from '@ngrx/entity'; +import {AsyncStoreItem} from '@o3r/core'; +import type { Contact } from '../../contact'; + +/** + * Contact model + */ +export interface ContactModel extends AsyncStoreItem, Contact {} + +/** + * Contact state details + */ +export interface ContactStateDetails extends AsyncStoreItem {} + +/** + * Contact store state + */ +export interface ContactState extends EntityState, ContactStateDetails {} + +/** + * Name of the Contact Store + */ +export const CONTACT_STORE_NAME = 'contact'; + +/** + * Contact Store Interface + */ +export interface ContactStore { + /** Contact state */ + [CONTACT_STORE_NAME]: ContactState; +} diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/contact.sync.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.sync.ts new file mode 100644 index 0000000000..2b84ee327b --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/contact.sync.ts @@ -0,0 +1,25 @@ +import { ContactModel } from './contact.state'; + + +import {asyncEntitySerializer, Serializer} from '@o3r/core'; +import {contactAdapter, contactInitialState} from './contact.reducer'; +import {ContactState} from './contact.state'; + +export const contactStorageSerializer = asyncEntitySerializer; + +export const contactStorageDeserializer = (rawObject: any) => { + if (!rawObject || !rawObject.ids) { + return contactInitialState; + } + const storeObject = contactAdapter.getInitialState(rawObject); + for (const id of rawObject.ids) { + storeObject.entities[id] = rawObject.entities[id] as ContactModel; + + } + return storeObject; +}; + +export const contactStorageSync: Serializer = { + serialize: contactStorageSerializer, + deserialize: contactStorageDeserializer +}; diff --git a/apps/showcase/src/components/showcase/tanstack/store/contact/index.ts b/apps/showcase/src/components/showcase/tanstack/store/contact/index.ts new file mode 100644 index 0000000000..643678cb1a --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/contact/index.ts @@ -0,0 +1,7 @@ +export * from './contact.actions'; +export * from './contact.effect'; +export * from './contact.module'; +export * from './contact.reducer'; +export * from './contact.selectors'; +export * from './contact.state'; +export * from './contact.sync'; diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/index.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/index.ts new file mode 100644 index 0000000000..a5bba65a5c --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/index.ts @@ -0,0 +1,7 @@ +export * from './petstore.actions'; +export * from './petstore.effect'; +export * from './petstore.module'; +export * from './petstore.reducer'; +export * from './petstore.selectors'; +export * from './petstore.state'; +export * from './petstore.sync'; diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.actions.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.actions.ts new file mode 100644 index 0000000000..1bb5930dfb --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.actions.ts @@ -0,0 +1,84 @@ +import { + asyncProps, + AsyncRequest, + FailAsyncStoreItemEntitiesActionPayload, + FromApiActionPayload, + SetActionPayload, + SetAsyncStoreItemEntitiesActionPayload, + UpdateActionPayload, + UpdateAsyncStoreItemEntitiesActionPayloadWithId +} from '@o3r/core'; +import {Pet} from '@ama-sdk/showcase-sdk'; +import {createAction, props} from '@ngrx/store'; +import {PetstoreStateDetails} from './petstore.state'; + +/** StateDetailsActions */ +const ACTION_SET = '[Petstore] set'; +const ACTION_UPDATE = '[Petstore] update'; +const ACTION_RESET = '[Petstore] reset'; +const ACTION_CANCEL_REQUEST = '[Petstore] cancel request'; + +/** Entity Actions */ +const ACTION_CLEAR_ENTITIES = '[Petstore] clear entities'; +const ACTION_UPDATE_ENTITIES = '[Petstore] update entities'; +const ACTION_UPSERT_ENTITIES = '[Petstore] upsert entities'; +const ACTION_SET_ENTITIES = '[Petstore] set entities'; +const ACTION_FAIL_ENTITIES = '[Petstore] fail entities'; + +/** Async Actions */ +const ACTION_SET_ENTITIES_FROM_API = '[Petstore] set entities from api'; +const ACTION_UPDATE_ENTITIES_FROM_API = '[Petstore] update entities from api'; +const ACTION_UPSERT_ENTITIES_FROM_API = '[Petstore] upsert entities from api'; +const ACTION_CREATE_ENTITIES_FROM_API = '[Petstore] create entity'; + + +/** Action to clear the StateDetails of the store and replace it */ +export const setPetstore = createAction(ACTION_SET, props>()); + +/** Action to change a part or the whole object in the store. */ +export const updatePetstore = createAction(ACTION_UPDATE, props>()); + +/** Action to reset the whole state, by returning it to initial state. */ +export const resetPetstore = createAction(ACTION_RESET); + +/** Action to cancel a Request ID registered in the store. Can happen from effect based on a switchMap for instance */ +export const cancelPetstoreRequest = createAction(ACTION_CANCEL_REQUEST, props()); + +/** Action to clear all petstore and fill the store with the payload */ +export const setPetstoreEntities = createAction(ACTION_SET_ENTITIES, props>()); + +/** Action to update petstore with known IDs, ignore the new ones */ +export const updatePetstoreEntities = createAction(ACTION_UPDATE_ENTITIES, props>()); + +/** Action to update petstore with known IDs, insert the new ones */ +export const upsertPetstoreEntities = createAction(ACTION_UPSERT_ENTITIES, props>()); + +/** Action to empty the list of entities, keeping the global state */ +export const clearPetstoreEntities = createAction(ACTION_CLEAR_ENTITIES); + +/** Action to update failureStatus for every Pet */ +export const failPetstoreEntities = createAction(ACTION_FAIL_ENTITIES, props>()); + +/** + * Action to put the global status of the store in a pending state. Call SET action with the list of Pets received, when this action resolves. + * If the call fails, dispatch FAIL_ENTITIES action + */ +export const setPetstoreEntitiesFromApi = createAction(ACTION_SET_ENTITIES_FROM_API, asyncProps>()); + +/** + * Action to change isPending status of elements to be updated with a request. Call UPDATE action with the list of Pets received, when this action resolves. + * If the call fails, dispatch FAIL_ENTITIES action + */ +export const updatePetstoreEntitiesFromApi = createAction(ACTION_UPDATE_ENTITIES_FROM_API, asyncProps & { ids: string[] }>()); + +/** + * Action to put global status of the store in a pending state. Call UPSERT action with the list of Pets received, when this action resolves. + * If the call fails, dispatch FAIL_ENTITIES action + */ +export const upsertPetstoreEntitiesFromApi = createAction(ACTION_UPSERT_ENTITIES_FROM_API, asyncProps>()); + +/** + * Action to put the global status of the store in a pending state. Call SET action with the list of Pets received, when this action resolves. + * If the call fails, dispatch FAIL_ENTITIES action + */ +export const setPetstoreEntityFromApi = createAction(ACTION_CREATE_ENTITIES_FROM_API, asyncProps>()); diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.effect.spec.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.effect.spec.ts new file mode 100644 index 0000000000..484ec8a5f8 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.effect.spec.ts @@ -0,0 +1,41 @@ +import { getTestBed, TestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { Store } from '@ngrx/store'; +import { ReplaySubject, Subject, Subscription } from 'rxjs'; +import { PetstoreEffect } from './petstore.effect'; + +describe('Petstore Effects', () => { + beforeAll(() => getTestBed().platform || TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false } + })); + + let effect: PetstoreEffect; + let actions: Subject; + const subscriptions: Subscription[] = []; + + const storeValue = new Subject(); + const mockStore = { + pipe: jasmine.createSpy('select').and.returnValue(storeValue), + dispatch: jasmine.createSpy('dispatch') + }; + + afterEach(() => subscriptions.forEach((subscription) => subscription.unsubscribe())); + + beforeEach(async () => { + actions = new ReplaySubject(1); + await TestBed.configureTestingModule({ + providers: [ + provideMockActions(() => actions), + PetstoreEffect, + {provide: Store, useValue: mockStore} + ] + }).compileComponents(); + + effect = TestBed.inject(PetstoreEffect); + }); + + it('Check if effect is correctly injected', () => { + expect(effect).toBeDefined(); + }); +}); diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.effect.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.effect.ts new file mode 100644 index 0000000000..22b52446cc --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.effect.ts @@ -0,0 +1,82 @@ +import {Injectable} from '@angular/core'; +import {Actions, createEffect, ofType} from '@ngrx/effects'; +import {from, of} from 'rxjs'; +import {catchError, map, mergeMap} from 'rxjs/operators'; +import {fromApiEffectSwitchMap} from '@o3r/core'; +import { + cancelPetstoreRequest, + failPetstoreEntities, + setPetstoreEntities, setPetstoreEntitiesFromApi, + setPetstoreEntityFromApi, + updatePetstoreEntities, updatePetstoreEntitiesFromApi, + upsertPetstoreEntities, upsertPetstoreEntitiesFromApi +} from './petstore.actions'; + +/** + * Service to handle async Petstore actions + */ +@Injectable() +export class PetstoreEffect { + + /** + * Set the entities with the reply content, dispatch failPetstoreEntities if it catches a failure + */ + public setEntitiesFromApi$ = createEffect(() => + this.actions$.pipe( + ofType(setPetstoreEntitiesFromApi), + fromApiEffectSwitchMap( + (reply, action) => setPetstoreEntities({entities: reply, requestId: action.requestId}), + (error, action) => of(failPetstoreEntities({error, requestId: action.requestId})), + cancelPetstoreRequest + ) + ) + ); + + /** + * Update the entities with the reply content, dispatch failPetstoreEntities if it catches a failure + */ + public updateEntitiesFromApi$ = createEffect(() => + this.actions$.pipe( + ofType(updatePetstoreEntitiesFromApi), + mergeMap((payload) => + from(payload.call).pipe( + map((reply) => updatePetstoreEntities({entities: reply, requestId: payload.requestId})), + catchError((err) => of(failPetstoreEntities({ids: payload.ids, error: err, requestId: payload.requestId}))) + ) + ) + ) + ); + + /** + * Update the entities with the reply content, dispatch failPetstoreEntities if it catches a failure + */ + public updateEntityFromApi$ = createEffect(() => + this.actions$.pipe( + ofType(setPetstoreEntityFromApi), + mergeMap((payload) => + from(payload.call).pipe( + map((reply) => upsertPetstoreEntities({entities: [reply], requestId: payload.requestId})), + catchError((err) => of(failPetstoreEntities({error: err, requestId: payload.requestId}))) + ) + ) + ) + ); + + /** + * Upsert the entities with the reply content, dispatch failPetstoreEntities if it catches a failure + */ + public upsertEntitiesFromApi$ = createEffect(() => + this.actions$.pipe( + ofType(upsertPetstoreEntitiesFromApi), + mergeMap((payload) => + from(payload.call).pipe( + map((reply) => upsertPetstoreEntities({entities: reply, requestId: payload.requestId})), + catchError((err) => of(failPetstoreEntities({error: err, requestId: payload.requestId}))) + ) + ) + ) + ); + + constructor(protected actions$: Actions) { + } +} diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.module.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.module.ts new file mode 100644 index 0000000000..ee0962fffe --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.module.ts @@ -0,0 +1,34 @@ +import { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core'; +import { Action, ActionReducer, StoreModule } from '@ngrx/store'; + +import { EffectsModule } from '@ngrx/effects'; +import { PetstoreEffect } from './petstore.effect'; +import { petstoreReducer } from './petstore.reducer'; +import { PETSTORE_STORE_NAME, PetstoreState } from './petstore.state'; + +/** Token of the Petstore reducer */ +export const PETSTORE_REDUCER_TOKEN = new InjectionToken>('Feature Petstore Reducer'); + +/** Provide default reducer for Petstore store */ +export function getDefaultPetstoreReducer() { + return petstoreReducer; +} + +@NgModule({ + imports: [ + StoreModule.forFeature(PETSTORE_STORE_NAME, PETSTORE_REDUCER_TOKEN), EffectsModule.forFeature([PetstoreEffect]) + ], + providers: [ + { provide: PETSTORE_REDUCER_TOKEN, useFactory: getDefaultPetstoreReducer } + ] +}) +export class PetstoreStoreModule { + public static forRoot(reducerFactory: () => ActionReducer): ModuleWithProviders { + return { + ngModule: PetstoreStoreModule, + providers: [ + { provide: PETSTORE_REDUCER_TOKEN, useFactory: reducerFactory } + ] + }; + } +} diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.reducer.spec.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.reducer.spec.ts new file mode 100644 index 0000000000..fc556b6839 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.reducer.spec.ts @@ -0,0 +1,121 @@ +import * as actions from './petstore.actions'; +import {petstoreInitialState, petstoreReducer} from './petstore.reducer'; +import {PetstoreState} from './petstore.state'; + +describe('Petstore Store reducer', () => { + + let entitiesState: PetstoreState; + const firstPetstore: any = {id: 'petstore1', genericItems: []}; + const secondPetstore: any = {id: 'petstore2', genericItems: []}; + const petstoreReply: any = [firstPetstore]; + + it('should have the correct initial state', () => { + expect(petstoreInitialState.ids.length).toBe(0); + }); + + + it('should by default return the initial state', () => { + const state = petstoreReducer(petstoreInitialState, {type: 'fake'} as any); + expect(state).toEqual(petstoreInitialState); + }); + + describe('Actions on state details', () => { + beforeEach(() => { + entitiesState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntities({entities: [firstPetstore, secondPetstore]})); + }); + + it('SET action should clear current state details and return a state with the new one', () => { + const firstState = petstoreReducer(entitiesState, actions.setPetstore({stateDetails: {requestIds: []}})); + const secondState = petstoreReducer(firstState, actions.setPetstore({stateDetails: {requestIds: [], isPending: false}})); + expect(secondState.isPending).toEqual(false); + }); + + it('UPDATE should update the state details without modifying entities', () => { + const firstState = petstoreReducer(entitiesState, actions.setPetstore({stateDetails: {requestIds: []}})); + const secondState = petstoreReducer(firstState, actions.updatePetstore({stateDetails: {isPending: false}})); + expect(secondState.isPending).toEqual(false); + }); + + it('RESET action should return initial state', () => { + const state = petstoreReducer(entitiesState, actions.resetPetstore()); + expect(state).toEqual(petstoreInitialState); + }); + + it('FAIL action should update the isPending to false and the isFailure to true', () => { + const state = petstoreReducer({...petstoreInitialState, isPending: true}, actions.failPetstoreEntities({})); + expect(state.ids.length).toBe(0); + expect(state.isPending).toBe(false); + expect(state.isFailure).toBe(true); + }); + }); + + describe('Entity actions', () => { + it('SET_ENTITIES action should clear current entities and set new ones', () => { + const firstState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntities({entities: [firstPetstore]})); + const secondState = petstoreReducer(firstState, actions.setPetstoreEntities({entities: [secondPetstore]})); + expect(secondState.ids.length).toEqual(1); + expect((secondState.ids as string[]).find((id) => (id === firstPetstore.id))).toBeUndefined(); + expect((secondState.ids as string[]).find((id) => (id === secondPetstore.id))).toBeDefined(); + }); + + it('UPDATE_ENTITTIES action should only update existing entities', () => { + const firstPetstoreUpdated = {...firstPetstore, genericField: 'genericId'}; + const firstState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntities({entities: [firstPetstore]})); + const secondState = petstoreReducer(firstState, + actions.updatePetstoreEntities({entities: [firstPetstoreUpdated, secondPetstore]})); + expect(secondState.ids.length).toEqual(1); + expect((secondState.ids as string[]).find((id) => (id === firstPetstore.id))).toBeDefined(); + expect((secondState.ids as string[]).find((id) => (id === secondPetstore.id))).toBeUndefined(); + }); + + it('UPSERT_ENTITIES action should update existing entities and add the new ones', () => { + const firstPetstoreUpdated = {...firstPetstore, genericField: 'genericId'}; + const firstState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntities({entities: [firstPetstore]})); + const secondState = petstoreReducer(firstState, + actions.upsertPetstoreEntities({entities: [firstPetstoreUpdated, secondPetstore]})); + expect(secondState.ids.length).toEqual(2); + expect((secondState.ids as string[]).find((id) => (id === firstPetstore.id))).toBeDefined(); + expect((secondState.ids as string[]).find((id) => (id === secondPetstore.id))).toBeDefined(); + }); + + it('CLEAR_ENTITIES action should clear only the entities', () => { + const firstState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntities({entities: [firstPetstore, secondPetstore]})); + const secondState = petstoreReducer(firstState, actions.setPetstore({stateDetails: {requestIds: [], isPending: false}})); + const thirdState = petstoreReducer(secondState, actions.clearPetstoreEntities()); + expect(thirdState.ids.length).toEqual(0); + }); + + it('FAIL_ENTITIES action should update the isPending to false and the isFailure to true', () => { + const state = petstoreReducer({...petstoreInitialState, isPending: true}, actions.failPetstoreEntities({})); + expect(state.ids.length).toBe(0); + expect(state.isPending).toBe(false); + expect(state.isFailure).toBe(true); + }); + + it('FAIL_ENTITIES action should update the global isPending to false in case there are some newIds in the payload', () => { + const firstState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntities({entities: [firstPetstore]})); + const secondState = petstoreReducer({...firstState, isPending : true}, + actions.failPetstoreEntities({error: 'dummy error', ids: [secondPetstore.id]})); + expect(secondState.isPending).toBe(false); + expect(secondState.isFailure).toBe(true); + }); + }); + + describe('API call actions', () => { + it('SET_ENTITIES_FROM_API action should clear current entities and set new ones', () => { + const firstState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntitiesFromApi({call: Promise.resolve(petstoreReply), requestId: 'test'})); + expect(firstState.isPending).toEqual(true); + }); + it('UPDATE_ENTITIES_FROM_API action should clear current entities and set new ones', () => { + const firstState = petstoreReducer(petstoreInitialState, actions.setPetstoreEntities({entities: [firstPetstore]})); + const secondState = petstoreReducer(firstState, + actions.updatePetstoreEntitiesFromApi({call: Promise.resolve(petstoreReply), ids: [firstPetstore.id], requestId: 'test'})); + expect(secondState.isPending).toBeFalsy(); + expect(secondState.entities[firstPetstore.id]!.isPending).toEqual(true); + }); + it('UPSERT_ENTITIES_FROM_API action should clear current entities and set new ones', () => { + const firstState = petstoreReducer(petstoreInitialState, actions.upsertPetstoreEntitiesFromApi({call: Promise.resolve(petstoreReply), requestId: 'test'})); + expect(firstState.isPending).toEqual(true); + }); + }); +}); diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.reducer.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.reducer.ts new file mode 100644 index 0000000000..452820f16a --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.reducer.ts @@ -0,0 +1,70 @@ +import {ActionCreator, createReducer, on, ReducerTypes} from '@ngrx/store'; +import {createEntityAdapter} from '@ngrx/entity'; +import {asyncStoreItemAdapter, createEntityAsyncRequestAdapter} from '@o3r/core'; +import * as actions from './petstore.actions'; +import {PetModel, PetstoreState, PetstoreStateDetails} from './petstore.state'; + +/** + * Petstore Store adapter + */ +export const petstoreAdapter = createEntityAsyncRequestAdapter(createEntityAdapter({ + selectId: (model) => model.id +})); + +/** + * Petstore Store initial value + */ +export const petstoreInitialState: PetstoreState = petstoreAdapter.getInitialState({ + requestIds: [] +}); + +/** + * List of basic actions for Petstore Store + */ +export const petstoreReducerFeatures: ReducerTypes[] = [ + on(actions.resetPetstore, () => petstoreInitialState), + + on(actions.setPetstore, (state, payload) => ({ids: state.ids, entities: state.entities, ...payload.stateDetails})), + + on(actions.cancelPetstoreRequest, (state, action) => asyncStoreItemAdapter.resolveRequest(state, action.requestId)), + + on(actions.updatePetstore, (state, payload) => ({...state, ...payload.stateDetails})), + + on(actions.setPetstoreEntities, (state, payload) => + petstoreAdapter.addMany( + payload.entities.map((entity) => asyncStoreItemAdapter.initialize(entity)), + petstoreAdapter.removeAll(asyncStoreItemAdapter.resolveRequest(state, payload.requestId))) + ), + + on(actions.updatePetstoreEntities, (state, payload) => + petstoreAdapter.resolveRequestMany(state, payload.entities, payload.requestId) + ), + + on(actions.upsertPetstoreEntities, (state, payload) => + petstoreAdapter.upsertMany( + payload.entities.map((entity) => asyncStoreItemAdapter.initialize(entity)), + asyncStoreItemAdapter.resolveRequest(state, payload.requestId) + ) + ), + + on(actions.clearPetstoreEntities, (state) => petstoreAdapter.removeAll(state)), + + on(actions.failPetstoreEntities, (state, payload) => + petstoreAdapter.failRequestMany(state, payload && payload.ids, payload.requestId) + ), + + on(actions.setPetstoreEntitiesFromApi, actions.upsertPetstoreEntitiesFromApi, actions.setPetstoreEntityFromApi, (state, payload) => + asyncStoreItemAdapter.addRequest(state, payload.requestId)), + + + on(actions.updatePetstoreEntitiesFromApi, (state, payload) => + petstoreAdapter.addRequestMany(state, payload.ids, payload.requestId)) +]; + +/** + * Petstore Store reducer + */ +export const petstoreReducer = createReducer( + petstoreInitialState, + ...petstoreReducerFeatures +); diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.selectors.spec.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.selectors.spec.ts new file mode 100644 index 0000000000..944b8b7bd3 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.selectors.spec.ts @@ -0,0 +1,10 @@ +import {petstoreInitialState} from './petstore.reducer'; +import * as selectors from './petstore.selectors'; + +describe('Petstore Selectors tests', () => { + it('should provide the pending status of the store', () => { + expect(selectors.selectPetstoreStorePendingStatus.projector(petstoreInitialState)).toBeFalsy(); + expect(selectors.selectPetstoreStorePendingStatus.projector({...petstoreInitialState, isPending: false})).toBe(false); + expect(selectors.selectPetstoreStorePendingStatus.projector({...petstoreInitialState, isPending: true})).toBe(true); + }); +}); diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.selectors.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.selectors.ts new file mode 100644 index 0000000000..590f3b5827 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.selectors.ts @@ -0,0 +1,26 @@ +import {createFeatureSelector, createSelector} from '@ngrx/store'; +import {petstoreAdapter} from './petstore.reducer'; +import {PETSTORE_STORE_NAME, PetstoreState} from './petstore.state'; + +const {selectIds, selectEntities, selectAll, selectTotal} = petstoreAdapter.getSelectors(); + +/** Select Petstore State */ +export const selectPetstoreState = createFeatureSelector(PETSTORE_STORE_NAME); + +/** Select the array of Petstore ids */ +export const selectPetstoreIds = createSelector(selectPetstoreState, selectIds); + +/** Select the array of Petstore */ +export const selectAllPetstore = createSelector(selectPetstoreState, selectAll); + +/** Select the dictionary of Petstore entities */ +export const selectPetstoreEntities = createSelector(selectPetstoreState, selectEntities); + +/** Select the total Petstore count */ +export const selectPetstoreTotal = createSelector(selectPetstoreState, selectTotal); + +/** Select the store pending status */ +export const selectPetstoreStorePendingStatus = createSelector(selectPetstoreState, (state) => state.isPending || false); + +/** Select the store pending status */ +export const selectPetstoreStoreFailingStatus = createSelector(selectPetstoreState, (state) => state.isFailure || false); diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.state.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.state.ts new file mode 100644 index 0000000000..ea8f3276bd --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.state.ts @@ -0,0 +1,33 @@ +import {Pet} from '@ama-sdk/showcase-sdk'; +import {EntityState} from '@ngrx/entity'; +import {AsyncStoreItem} from '@o3r/core'; + +/** + * Pet model + */ +export interface PetModel extends AsyncStoreItem, Pet { + +} + +/** + * Petstore state details + */ +export interface PetstoreStateDetails extends AsyncStoreItem {} + +/** + * Petstore store state + */ +export interface PetstoreState extends EntityState, PetstoreStateDetails {} + +/** + * Name of the Petstore Store + */ +export const PETSTORE_STORE_NAME = 'petstore'; + +/** + * Petstore Store Interface + */ +export interface PetstoreStore { + /** Petstore state */ + [PETSTORE_STORE_NAME]: PetstoreState; +} diff --git a/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.sync.ts b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.sync.ts new file mode 100644 index 0000000000..f4d68a9b14 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/store/petstore/petstore.sync.ts @@ -0,0 +1,23 @@ +import { revivePet } from '@ama-sdk/showcase-sdk'; + +import {asyncEntitySerializer, Serializer} from '@o3r/core'; +import {petstoreAdapter, petstoreInitialState} from './petstore.reducer'; +import {PetstoreState} from './petstore.state'; + +export const petstoreStorageSerializer = asyncEntitySerializer; + +export const petstoreStorageDeserializer = (rawObject: any) => { + if (!rawObject || !rawObject.ids) { + return petstoreInitialState; + } + const storeObject = petstoreAdapter.getInitialState(rawObject); + for (const id of rawObject.ids) { + storeObject.entities[id] = revivePet(rawObject.entities[id]); + } + return storeObject; +}; + +export const petstoreStorageSync: Serializer = { + serialize: petstoreStorageSerializer, + deserialize: petstoreStorageDeserializer +}; diff --git a/apps/showcase/src/components/showcase/tanstack/tanstack-pres.component.ts b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.component.ts new file mode 100644 index 0000000000..1266b5a6d9 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.component.ts @@ -0,0 +1,37 @@ +import { ChangeDetectionStrategy, Component, inject, ViewEncapsulation } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { NgbHighlight, NgbPagination, NgbPaginationPages } from '@ng-bootstrap/ng-bootstrap'; +import { O3rComponent } from '@o3r/core'; +import { OtterPickerPresComponent } from '../../utilities'; +import { TanstackService } from './tanstack.service'; +import { AngularQueryDevtools } from '@tanstack/angular-query-devtools-experimental'; +import { AsyncPipe, JsonPipe } from '@angular/common'; +import { PetstoreStoreModule } from './store/petstore/index'; +import { ContactStoreModule } from './store/contact/index'; + + +@O3rComponent({ componentType: 'Component' }) +@Component({ + selector: 'o3r-tanstack-pres', + standalone: true, + imports: [ + NgbHighlight, + FormsModule, + NgbPagination, + OtterPickerPresComponent, + NgbPaginationPages, + AngularQueryDevtools, + JsonPipe, + AsyncPipe, + PetstoreStoreModule, + ContactStoreModule + ], + providers: [TanstackService], + templateUrl: './tanstack-pres.template.html', + styleUrls: ['./tanstack-pres.style.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TanstackPresComponent { + public service = inject(TanstackService); +} diff --git a/apps/showcase/src/components/showcase/tanstack/tanstack-pres.spec.ts b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.spec.ts new file mode 100644 index 0000000000..db7cc1e1c0 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.spec.ts @@ -0,0 +1,29 @@ +import { PetApi } from '@ama-sdk/showcase-sdk'; +import { PetApiFixture } from '@ama-sdk/showcase-sdk/fixtures'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TanstackPresComponent } from './tanstack-pres.component'; +import '@angular/localize/init'; + +describe('SdkPresComponent', () => { + let component: TanstackPresComponent; + let fixture: ComponentFixture; + const petApiFixture = new PetApiFixture(); + petApiFixture.findPetsByStatus = petApiFixture.findPetsByStatus.mockResolvedValue([]); + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TanstackPresComponent], + providers: [ + {provide: PetApi, useValue: petApiFixture} + ] + }); + fixture = TestBed.createComponent(TanstackPresComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/showcase/src/components/showcase/tanstack/tanstack-pres.style.scss b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.style.scss new file mode 100644 index 0000000000..d90338c857 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.style.scss @@ -0,0 +1,18 @@ +o3r-sdk-pres { + .table-container { + min-height: 41rem; + } + + .table-column-photo, .table-column-actions { + width: 2em; + } + + .scroll-container { + width: 100%; + overflow-x: auto; + } + + td, th { + vertical-align: middle; + } +} diff --git a/apps/showcase/src/components/showcase/tanstack/tanstack-pres.template.html b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.template.html new file mode 100644 index 0000000000..9f984f0e12 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/tanstack-pres.template.html @@ -0,0 +1,179 @@ +
+
+ isloading here: + {{ service.isLoading | async}} + was it here? + isFailing here: + {{ service.isFailing | async}} + was it here? +
+
+ +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+ + @if (service.isLoading | async) { +
+ Loading... +
+ } + @if (service.isFailing | async) { +
+ Reload + +
+ } +
+ Reload + +
+
+
+
+
+ + + + + + + + + + + @for (pet of service.displayedPets(); track pet.id) { + + + + + + + } + +
IconNameTagsActions
+ @if (pet.photoUrls?.[0]; as icon) { + {{icon}} + } + + + + +
+
+
+
+ + + @if (pages.length > 0) { +
  • +
    + + + of {{pages.length}} +
    +
  • + } +
    +
    + + +
    +
    +
    +
    + + + +All Pets: +{{service.pets() | json}} +All Contacts: +{{service.backend.allContact | async | json}} + + diff --git a/apps/showcase/src/components/showcase/tanstack/tanstack.service.ts b/apps/showcase/src/components/showcase/tanstack/tanstack.service.ts new file mode 100644 index 0000000000..451a2eac67 --- /dev/null +++ b/apps/showcase/src/components/showcase/tanstack/tanstack.service.ts @@ -0,0 +1,166 @@ +import { computed, inject, Injectable, type OnInit, signal } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { DfMedia } from '@design-factory/design-factory'; +import { PetApi} from '@ama-sdk/showcase-sdk'; +import type { Pet, Tag } from '@ama-sdk/showcase-sdk'; +import { Store } from '@ngrx/store'; + +const FILTER_PAG_REGEX = /[^0-9]/g; + +import { BackEndService } from './backend.service'; +import { setPetstoreEntitiesFromApi/* , setPetstoreEntityFromApi*/, upsertPetstoreEntitiesFromApi } from './store/petstore/petstore.actions'; +import { selectAllPetstore, selectPetstoreStoreFailingStatus, selectPetstoreStorePendingStatus } from './store/petstore/petstore.selectors'; + +@Injectable() +export class TanstackService implements OnInit { + private readonly petStoreApi = inject(PetApi); + private readonly mediaService = inject(DfMedia); + public readonly backend = inject(BackEndService); + public readonly store = inject(Store); + + /** + * Name input used to create new pets + */ + public petName = signal(''); + + /** + * File input used to create new pets + */ + public petImage = signal(''); + + /** + * Search term used to filter the list of pets + */ + public searchTerm = signal(''); + + /** + * Number of items to display on a table page + */ + public pageSize = signal(10); + + /** + * Currently opened page on the table + */ + public currentPage = signal(1); + + public isLoading = this.store.select(selectPetstoreStorePendingStatus); + + public isFailing = this.store.select(selectPetstoreStoreFailingStatus); + + public pets = signal([]); + + /** + * List of pets filtered according to search term + */ + public filteredPets = computed(() => { + let pets = this.pets(); + if (this.searchTerm()) { + const matchString = new RegExp(this.searchTerm().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'), 'i'); + const matchTag = (tag: Tag) => tag.name && matchString.test(tag.name); + pets = pets.filter((pet: Pet) => + (pet.id && matchString.test(String(pet.id))) || + matchString.test(pet.name) || + (pet.category?.name && matchString.test(pet.category.name)) || + (pet.tags && pet.tags.some(matchTag))); + } + return pets; + }); + + /** + * Total amount of pet in the filtered list + */ + public totalPetsAmount = computed(() => this.filteredPets().length); + + /** + * List of pets displayed in the currently selected table page + */ + public displayedPets = computed(() => + this.filteredPets().slice((this.currentPage() - 1) * this.pageSize(), (this.currentPage()) * this.pageSize()) + ); + + /** + * True if screen size is 'xs' or 'sm' + */ + public isSmallScreen = toSignal(this.mediaService.getObservable(['xs', 'sm'])); + + /** Base URL where the images can be fetched */ + public baseUrl = location.href.split('/#', 1)[0]; + + constructor() { + this.store.select(selectAllPetstore).subscribe((pets) => this.pets.set(pets)); + } + + + private getNextId() { + return this.pets().reduce((maxId: number, pet: Pet) => pet.id && pet.id < Number.MAX_SAFE_INTEGER ? Math.max(maxId, pet.id) : maxId, 0) + 1; + } + + // eslint-disable-next-line @angular-eslint/contextual-lifecycle, @typescript-eslint/explicit-member-accessibility + async ngOnInit(): Promise { + await this.reload(); + } + + // How to abort the queries ? + public loadPets = async (/* abortSignal: AbortSignal*/) => { + const call = this.petStoreApi.findPetsByStatus({status: 'available'}/* , {signal: abortSignal}*/).then((pets: Pet[]) => + pets.filter((p: Pet) => p.category?.name === 'otter').sort((a: Pet, b: Pet) => a.id && b.id && a.id - b.id || 0)); + this.store.dispatch(setPetstoreEntitiesFromApi({call})); + try { + await call; + } catch (e) { + // eslint-disable-next-line no-console + console.log('error', e); + } + }; + + /** + * Trigger a full reload of the list of pets by calling the API + */ + public async reload() { + await this.loadPets(); + } + + + /** + * Call the API to create a new pet + */ + public create() { + const pet: Pet = { + id: this.getNextId(), + name: this.petName(), + category: {name: 'otter'}, + tags: [{name: 'otter'}], + status: 'available', + photoUrls: this.petName() ? [this.petImage()] : [] + }; + // eslint-disable-next-line @typescript-eslint/naming-convention + // this.store.dispatch(setPetstoreEntityFromApi({call: this.petStoreApi.addPet({Pet: pet})})); + + // eslint-disable-next-line @typescript-eslint/naming-convention + this.store.dispatch(upsertPetstoreEntitiesFromApi({call: this.petStoreApi.addPet({Pet: pet}).then(p => new Array(p))})); + } + + // TODO + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async delete(petToDelete: Pet) { + if (petToDelete.id) { + const call = this.petStoreApi.deletePet({petId: petToDelete.id}); + // this.store.dispatch() // here we need to create a new action to delete the elements + // an optimistic update would be to remove the element directly in the store + try { + await call; + } catch (error) { + // process with the error of deleting + } + await this.reload(); // because one element has been deleted + } + } + + public getTags(pet: Pet) { + return pet.tags?.map((tag: Tag) => tag.name).join(','); + } + + public formatPaginationInput(input: HTMLInputElement) { + input.value = input.value.replace(FILTER_PAG_REGEX, ''); + } +} diff --git a/apps/showcase/src/style/dark-theme/dark-theme.scss b/apps/showcase/src/style/dark-theme/dark-theme.scss index c26ebe206a..c3773cf080 100644 --- a/apps/showcase/src/style/dark-theme/dark-theme.scss +++ b/apps/showcase/src/style/dark-theme/dark-theme.scss @@ -1,4 +1,3 @@ -@import "highlight.js/styles/a11y-dark.css"; :root { /* --- BEGIN THEME Auto-generated --- */ @@ -97,15 +96,4 @@ .card { --bs-card-color: #ffffff; } .card { --bs-card-bg: #000000; } /* --- END THEME Auto-generated --- */ - - .nav.nav-pills .nav-link { - --bs-scrollspy-color: #ffffff; - --bs-nav-pills-link-active-bg: transparent; - } - .input-group-text { - background-color: var(--bs-tertiary-bg); - } - .form-select { - --bs-form-select-bg-img: url("data:image/svg+xml;charset=utf8,%3Csvg version='1.1' viewBox='0 0 1792 1792' style='fill%3a%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m1408 704q0 26-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45t19-45 45-19h896q26 0 45 19t19 45z'/%3E%3C/svg%3E"); - } -} +} \ No newline at end of file diff --git a/package.json b/package.json index bbf73c94c5..7457abff77 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "build:tools": "yarn nx run-many --target=build --projects=eslint-plugin,workspace --parallel $(yarn get:cpus-number)", "build:lint": "yarn nx run-many --target=build --projects=eslint-plugin --parallel $(yarn get:cpus-number)", "build:swagger-gen": "yarn nx run-many --target=build-swagger --parallel $(yarn get:cpus-number)", + "db": "json-server --watch apps/showcase/db/contacts.json", "prepare:publish": "yarn prepare-publish \"$(yarn workspaces:list)\" --append dist", "publish": "yarn run prepare:publish && yarn nx run-many --target=publish --parallel $(yarn get:cpus-number) --nx-bail", "publish:extensions": "yarn nx run-many --target=publish-extension --parallel $(yarn get:cpus-number)", @@ -133,6 +134,8 @@ "dependencies": { "@angular/core": "~17.3.0", "@angular/platform-browser": "~17.3.0", + "@tanstack/angular-query-devtools-experimental": "^5.28.8", + "@tanstack/angular-query-experimental": "^5.28.8", "pixelmatch": "^5.2.1", "pngjs": "^7.0.0", "rxjs": "^7.8.1", diff --git a/packages/@ama-sdk/showcase-sdk/.openapi-generator-ignore b/packages/@ama-sdk/showcase-sdk/.openapi-generator-ignore index 42c7f7fa35..5c384f64ae 100644 --- a/packages/@ama-sdk/showcase-sdk/.openapi-generator-ignore +++ b/packages/@ama-sdk/showcase-sdk/.openapi-generator-ignore @@ -1 +1,2 @@ # Indicate the index.ts file you have override to redirect to custom interface definition +src/models/base/pet/index.ts diff --git a/packages/@ama-sdk/showcase-sdk/openapitools.json b/packages/@ama-sdk/showcase-sdk/openapitools.json index 8a49a5ed20..d5f6f6ed1b 100644 --- a/packages/@ama-sdk/showcase-sdk/openapitools.json +++ b/packages/@ama-sdk/showcase-sdk/openapitools.json @@ -10,7 +10,7 @@ "output": ".", "inputSpec": "./swagger-spec.yaml", "globalProperty": { - "stringifyDate": true + "allowModelExtension": true } } } diff --git a/packages/@ama-sdk/showcase-sdk/src/api/pet/pet-api.ts b/packages/@ama-sdk/showcase-sdk/src/api/pet/pet-api.ts index b993a4618a..99dbe8d689 100644 --- a/packages/@ama-sdk/showcase-sdk/src/api/pet/pet-api.ts +++ b/packages/@ama-sdk/showcase-sdk/src/api/pet/pet-api.ts @@ -1,5 +1,7 @@ import { ApiResponse } from '../../models/base/api-response/index'; +import { reviveApiResponse } from '../../models/base/api-response/api-response.reviver'; import { Pet } from '../../models/base/pet/index'; +import { revivePet } from '../../models/base/pet/pet.reviver'; import { Api, ApiClient, ApiTypes, computePiiParameterTokens, isJsonMimeType, RequestBody, RequestMetadata } from '@ama-sdk/core'; export type FindPetsByStatusStatusEnum = 'available' | 'pending' | 'sold'; @@ -134,7 +136,7 @@ export class PetApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, undefined, 'addPet'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, { 200: revivePet } , 'addPet'); return ret; } @@ -160,7 +162,7 @@ export class PetApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, undefined, 'deletePet'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, { 200: undefined } , 'deletePet'); return ret; } @@ -186,7 +188,7 @@ export class PetApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, undefined, 'findPetsByStatus'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, { 200: revivePet } , 'findPetsByStatus'); return ret; } @@ -211,7 +213,7 @@ export class PetApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, undefined, 'findPetsByTags'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, { 200: revivePet } , 'findPetsByTags'); return ret; } @@ -236,7 +238,7 @@ export class PetApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, undefined, 'getPetById'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, { 200: revivePet } , 'getPetById'); return ret; } @@ -266,7 +268,7 @@ export class PetApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'PUT', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, undefined, 'updatePet'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, { 200: revivePet } , 'updatePet'); return ret; } @@ -321,7 +323,7 @@ export class PetApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, undefined, 'uploadFile'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, PetApi.apiName, { 200: reviveApiResponse } , 'uploadFile'); return ret; } diff --git a/packages/@ama-sdk/showcase-sdk/src/api/store/store-api.ts b/packages/@ama-sdk/showcase-sdk/src/api/store/store-api.ts index 3ca562dcf7..9e9af19b42 100644 --- a/packages/@ama-sdk/showcase-sdk/src/api/store/store-api.ts +++ b/packages/@ama-sdk/showcase-sdk/src/api/store/store-api.ts @@ -1,4 +1,5 @@ import { Order } from '../../models/base/order/index'; +import { reviveOrder } from '../../models/base/order/order.reviver'; import { Api, ApiClient, ApiTypes, computePiiParameterTokens, isJsonMimeType, RequestBody, RequestMetadata } from '@ama-sdk/core'; export interface DeleteOrderRequestData { @@ -104,7 +105,7 @@ export class StoreApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall<{ [key: string]: number }>(url, options, ApiTypes.DEFAULT, StoreApi.apiName, undefined, 'getInventory'); + const ret = this.client.processCall<{ [key: string]: number }>(url, options, ApiTypes.DEFAULT, StoreApi.apiName, { 200: undefined } , 'getInventory'); return ret; } @@ -129,7 +130,7 @@ export class StoreApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, StoreApi.apiName, undefined, 'getOrderById'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, StoreApi.apiName, { 200: reviveOrder } , 'getOrderById'); return ret; } @@ -159,7 +160,7 @@ export class StoreApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, StoreApi.apiName, undefined, 'placeOrder'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, StoreApi.apiName, { 200: reviveOrder } , 'placeOrder'); return ret; } diff --git a/packages/@ama-sdk/showcase-sdk/src/api/user/user-api.ts b/packages/@ama-sdk/showcase-sdk/src/api/user/user-api.ts index d206d447d1..a2b4f9583c 100644 --- a/packages/@ama-sdk/showcase-sdk/src/api/user/user-api.ts +++ b/packages/@ama-sdk/showcase-sdk/src/api/user/user-api.ts @@ -1,4 +1,5 @@ import { User } from '../../models/base/user/index'; +import { reviveUser } from '../../models/base/user/user.reviver'; import { Api, ApiClient, ApiTypes, computePiiParameterTokens, isJsonMimeType, RequestBody, RequestMetadata } from '@ama-sdk/core'; export interface CreateUserRequestData { @@ -145,7 +146,7 @@ export class UserApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, UserApi.apiName, undefined, 'createUsersWithListInput'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, UserApi.apiName, { 200: reviveUser } , 'createUsersWithListInput'); return ret; } @@ -195,7 +196,7 @@ export class UserApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, UserApi.apiName, undefined, 'getUserByName'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, UserApi.apiName, { 200: reviveUser } , 'getUserByName'); return ret; } @@ -220,7 +221,7 @@ export class UserApi implements Api { const options = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined, tokenizedOptions, metadata); const url = this.client.prepareUrl(options.basePath, options.queryParams); - const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, UserApi.apiName, undefined, 'loginUser'); + const ret = this.client.processCall(url, options, ApiTypes.DEFAULT, UserApi.apiName, { 200: undefined } , 'loginUser'); return ret; } diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/address/address.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/address/address.reviver.ts new file mode 100644 index 0000000000..a2dd7acbc1 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/address/address.reviver.ts @@ -0,0 +1,20 @@ +/** + * Reviver: Address + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { Address } from './address'; +import { ReviverOptions } from '@ama-sdk/core'; + +export function reviveAddress(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function reviveAddress(data: Address, dictionaries?: any, options?: ReviverOptions): Address ; +export function reviveAddress(data: any, dictionaries?: any, options?: ReviverOptions): Address | undefined; +export function reviveAddress(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function reviveAddress(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function reviveAddress(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/address/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/address/index.ts index 648c78ec30..5da3a61600 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/address/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/address/index.ts @@ -1,2 +1,2 @@ export type { Address } from './address'; - +export { reviveAddress } from './address.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/api-response/api-response.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/api-response/api-response.reviver.ts new file mode 100644 index 0000000000..a39c4febb9 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/api-response/api-response.reviver.ts @@ -0,0 +1,20 @@ +/** + * Reviver: ApiResponse + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { ApiResponse } from './api-response'; +import { ReviverOptions } from '@ama-sdk/core'; + +export function reviveApiResponse(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function reviveApiResponse(data: ApiResponse, dictionaries?: any, options?: ReviverOptions): ApiResponse ; +export function reviveApiResponse(data: any, dictionaries?: any, options?: ReviverOptions): ApiResponse | undefined; +export function reviveApiResponse(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function reviveApiResponse(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function reviveApiResponse(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/api-response/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/api-response/index.ts index 078fd29d41..4a57e250d4 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/api-response/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/api-response/index.ts @@ -1,2 +1,2 @@ export type { ApiResponse } from './api-response'; - +export { reviveApiResponse } from './api-response.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/category/category.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/category/category.reviver.ts new file mode 100644 index 0000000000..d912095f1c --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/category/category.reviver.ts @@ -0,0 +1,20 @@ +/** + * Reviver: Category + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { Category } from './category'; +import { ReviverOptions } from '@ama-sdk/core'; + +export function reviveCategory(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function reviveCategory(data: Category, dictionaries?: any, options?: ReviverOptions): Category ; +export function reviveCategory(data: any, dictionaries?: any, options?: ReviverOptions): Category | undefined; +export function reviveCategory(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function reviveCategory(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function reviveCategory(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/category/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/category/index.ts index baa54142c2..13f75fdda8 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/category/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/category/index.ts @@ -1,2 +1,2 @@ export type { Category } from './category'; - +export { reviveCategory } from './category.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/customer/customer.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/customer/customer.reviver.ts new file mode 100644 index 0000000000..49f2926dd2 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/customer/customer.reviver.ts @@ -0,0 +1,23 @@ +/** + * Reviver: Customer + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { Customer } from './customer'; +import { Address } from '../address'; +import { reviveAddress } from '../address'; +import { reviveArray, ReviverOptions } from '@ama-sdk/core'; + +export function reviveCustomer(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function reviveCustomer(data: Customer, dictionaries?: any, options?: ReviverOptions): Customer ; +export function reviveCustomer(data: any, dictionaries?: any, options?: ReviverOptions): Customer | undefined; +export function reviveCustomer(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function reviveCustomer(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function reviveCustomer(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + data.address = reviveArray
    (data.address, dictionaries, reviveAddress) as Address[]; + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/customer/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/customer/index.ts index d4ecd6b9a6..72cb947b16 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/customer/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/customer/index.ts @@ -1,2 +1,2 @@ export type { Customer } from './customer'; - +export { reviveCustomer } from './customer.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/order/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/order/index.ts index f32354cae9..ce53850d5a 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/order/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/order/index.ts @@ -1,2 +1,2 @@ export type { Order } from './order'; - +export { reviveOrder } from './order.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/order/order.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/order/order.reviver.ts new file mode 100644 index 0000000000..2ab63e4486 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/order/order.reviver.ts @@ -0,0 +1,21 @@ +/** + * Reviver: Order + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { Order } from './order'; +import { ReviverOptions, utils } from '@ama-sdk/core'; + +export function reviveOrder(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function reviveOrder(data: Order, dictionaries?: any, options?: ReviverOptions): Order ; +export function reviveOrder(data: any, dictionaries?: any, options?: ReviverOptions): Order | undefined; +export function reviveOrder(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function reviveOrder(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function reviveOrder(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + data.shipDate = data.shipDate ? new utils.DateTime(data.shipDate) : undefined; + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/order/order.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/order/order.ts index 7ec3d10877..c851b95a51 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/order/order.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/order/order.ts @@ -5,13 +5,15 @@ * */ +import {utils} from '@ama-sdk/core'; export interface Order { id?: number; petId?: number; quantity?: number; - shipDate?: string; + /** @see utils.DateTime */ + shipDate?: utils.DateTime; /** Order Status */ status?: StatusEnum; complete?: boolean; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/pet/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/pet/index.ts index e6f3c15c8c..a717992d1b 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/pet/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/pet/index.ts @@ -1,2 +1,5 @@ -export type { Pet } from './pet'; +export { Pet } from '../../core/pet/pet'; +export { revivePet } from '../../core/pet/pet.reviver'; +export {Pet as BasePet} from './pet'; +export {revivePet as baseRevivePet} from './pet.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/pet/pet.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/pet/pet.reviver.ts new file mode 100644 index 0000000000..b8f1abf509 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/pet/pet.reviver.ts @@ -0,0 +1,25 @@ +/** + * Reviver: Pet + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { Pet } from './pet'; +import { reviveCategory } from '../category'; +import { Tag } from '../tag'; +import { reviveTag } from '../tag'; +import { reviveArray, ReviverOptions } from '@ama-sdk/core'; + +export function revivePet(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function revivePet(data: Pet, dictionaries?: any, options?: ReviverOptions): Pet ; +export function revivePet(data: any, dictionaries?: any, options?: ReviverOptions): Pet | undefined; +export function revivePet(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function revivePet(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function revivePet(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + data.category = reviveCategory(data.category, dictionaries); + data.tags = reviveArray(data.tags, dictionaries, reviveTag) as Tag[]; + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/revivers.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/revivers.ts new file mode 100644 index 0000000000..ca24e812d4 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/revivers.ts @@ -0,0 +1,8 @@ +export { reviveAddress } from './address'; +export { reviveApiResponse } from './api-response'; +export { reviveCategory } from './category'; +export { reviveCustomer } from './customer'; +export { reviveOrder } from './order'; +export { revivePet } from './pet'; +export { reviveTag } from './tag'; +export { reviveUser } from './user'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/tag/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/tag/index.ts index b509d56d4a..f88c4c17d5 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/tag/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/tag/index.ts @@ -1,2 +1,2 @@ export type { Tag } from './tag'; - +export { reviveTag } from './tag.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/tag/tag.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/tag/tag.reviver.ts new file mode 100644 index 0000000000..aee84cdd7e --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/tag/tag.reviver.ts @@ -0,0 +1,20 @@ +/** + * Reviver: Tag + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { Tag } from './tag'; +import { ReviverOptions } from '@ama-sdk/core'; + +export function reviveTag(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function reviveTag(data: Tag, dictionaries?: any, options?: ReviverOptions): Tag ; +export function reviveTag(data: any, dictionaries?: any, options?: ReviverOptions): Tag | undefined; +export function reviveTag(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function reviveTag(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function reviveTag(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/user/index.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/user/index.ts index bccad11167..1412b16d3c 100644 --- a/packages/@ama-sdk/showcase-sdk/src/models/base/user/index.ts +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/user/index.ts @@ -1,2 +1,2 @@ export type { User } from './user'; - +export { reviveUser } from './user.reviver'; diff --git a/packages/@ama-sdk/showcase-sdk/src/models/base/user/user.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/base/user/user.reviver.ts new file mode 100644 index 0000000000..cc60eb18e3 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/base/user/user.reviver.ts @@ -0,0 +1,20 @@ +/** + * Reviver: User + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { User } from './user'; +import { ReviverOptions } from '@ama-sdk/core'; + +export function reviveUser(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function reviveUser(data: User, dictionaries?: any, options?: ReviverOptions): User ; +export function reviveUser(data: any, dictionaries?: any, options?: ReviverOptions): User | undefined; +export function reviveUser(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function reviveUser(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** + * + */ +export function reviveUser(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/core/pet/pet.reviver.ts b/packages/@ama-sdk/showcase-sdk/src/models/core/pet/pet.reviver.ts new file mode 100644 index 0000000000..dcbeeddeb0 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/core/pet/pet.reviver.ts @@ -0,0 +1,24 @@ +/** + * Reviver: Pet + * + * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. + */ +import { Pet } from './pet'; +import { baseRevivePet } from '../../base'; +import type { ReviverOptions } from '@ama-sdk/core'; + +/** */ +export function revivePet(data: undefined, dictionaries?: any, options?: ReviverOptions): undefined; +export function revivePet(data: Pet, dictionaries?: any, options?: ReviverOptions): Pet ; +export function revivePet(data: any, dictionaries?: any, options?: ReviverOptions): Pet | undefined; +export function revivePet(data: T, dictionaries?: any, options?: ReviverOptions): T ; +export function revivePet(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined; +/** */ +export function revivePet(data: any, dictionaries?: any, options?: ReviverOptions): T | undefined { + if (!data) { return ; } + data = { + ...baseRevivePet(data, dictionaries), + id: data.id || Date.now() + }; + return data as T; +} diff --git a/packages/@ama-sdk/showcase-sdk/src/models/core/pet/pet.ts b/packages/@ama-sdk/showcase-sdk/src/models/core/pet/pet.ts new file mode 100644 index 0000000000..1d9daf2e23 --- /dev/null +++ b/packages/@ama-sdk/showcase-sdk/src/models/core/pet/pet.ts @@ -0,0 +1,7 @@ +import {BasePet} from '../../base/pet'; + +export interface Pet extends BasePet{ + id: number; +} + + diff --git a/proxy.config.js b/proxy.config.js new file mode 100644 index 0000000000..4f1ac60c8f --- /dev/null +++ b/proxy.config.js @@ -0,0 +1,12 @@ +// Used to redirect the different call using angular to specific URLs +// This serve kind of the role of a nginx or apache in PROD +// Called after the kassette proxy in browser +const PROXY_CONFIG = [ + { + context: ['/contacts'], + target: 'http://localhost:3000', + secure: false + } +]; + +module.exports = PROXY_CONFIG; diff --git a/yarn.lock b/yarn.lock index 009617ced9..4528910a4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -625,24 +625,24 @@ __metadata: languageName: node linkType: hard -"@angular-devkit/architect@npm:0.1703.5, @angular-devkit/architect@npm:~0.1703.0": - version: 0.1703.5 - resolution: "@angular-devkit/architect@npm:0.1703.5" +"@angular-devkit/architect@npm:0.1703.2, @angular-devkit/architect@npm:~0.1703.0": + version: 0.1703.2 + resolution: "@angular-devkit/architect@npm:0.1703.2" dependencies: - "@angular-devkit/core": "npm:17.3.5" + "@angular-devkit/core": "npm:17.3.2" rxjs: "npm:7.8.1" - checksum: 10/99eea109d720e6dcef5486cdc42de57c4e2bf64d9c924a4fe4ce0bb6cf3f0e029bf2f7e57312f8ef0e439e2a74641d976bf61cef304f3b4a930decb27752a8f3 + checksum: 10/094e8f0b3563dff55d98941e1dfbb7dee820e2cab3eeb0791669fac374de24bec0ba0c838beeb982e21e1dae13ea192699ebbe154fb1567c56e0d6c4a205cd82 languageName: node linkType: hard "@angular-devkit/build-angular@npm:~17.3.0": - version: 17.3.5 - resolution: "@angular-devkit/build-angular@npm:17.3.5" + version: 17.3.2 + resolution: "@angular-devkit/build-angular@npm:17.3.2" dependencies: "@ampproject/remapping": "npm:2.3.0" - "@angular-devkit/architect": "npm:0.1703.5" - "@angular-devkit/build-webpack": "npm:0.1703.5" - "@angular-devkit/core": "npm:17.3.5" + "@angular-devkit/architect": "npm:0.1703.2" + "@angular-devkit/build-webpack": "npm:0.1703.2" + "@angular-devkit/core": "npm:17.3.2" "@babel/core": "npm:7.24.0" "@babel/generator": "npm:7.23.6" "@babel/helper-annotate-as-pure": "npm:7.22.5" @@ -653,7 +653,7 @@ __metadata: "@babel/preset-env": "npm:7.24.0" "@babel/runtime": "npm:7.24.0" "@discoveryjs/json-ext": "npm:0.5.7" - "@ngtools/webpack": "npm:17.3.5" + "@ngtools/webpack": "npm:17.3.2" "@vitejs/plugin-basic-ssl": "npm:1.1.0" ansi-colors: "npm:4.1.3" autoprefixer: "npm:10.4.18" @@ -743,20 +743,20 @@ __metadata: optional: true tailwindcss: optional: true - checksum: 10/c5bb027c5363208d1a1558eda29a84753ee32c4114e77f07833a32e04934f70379a635170b84c2dc3f8a9100f88b8c73c28fbc42c08133f45287978bf82724b0 + checksum: 10/5d1ff7ff5fd0e648e5cf9f5a468b3d52845a397d7c3fa559a57cf4e3528a1562c2a97f32d3ab34164690730a4c8f5c18c70cfc71cf2eac3ac364e71dc17b8e97 languageName: node linkType: hard -"@angular-devkit/build-webpack@npm:0.1703.5": - version: 0.1703.5 - resolution: "@angular-devkit/build-webpack@npm:0.1703.5" +"@angular-devkit/build-webpack@npm:0.1703.2": + version: 0.1703.2 + resolution: "@angular-devkit/build-webpack@npm:0.1703.2" dependencies: - "@angular-devkit/architect": "npm:0.1703.5" + "@angular-devkit/architect": "npm:0.1703.2" rxjs: "npm:7.8.1" peerDependencies: webpack: ^5.30.0 webpack-dev-server: ^4.0.0 - checksum: 10/7244d13afe1f1598ae02c74daad62390a9d7ce670d701191cbff527be7c34707d47e9a867215e962b6bc783d0b124fcea0a91847c7d50fca7f00fa53d38d8324 + checksum: 10/97a4ea0dd4f14ed40da25391d21994e9574258060bbfa91f1235cce6e735f8a8fcb46723be03c323bcb89341cf99cf5074157eff3104437221084709b714b5a6 languageName: node linkType: hard @@ -778,9 +778,9 @@ __metadata: languageName: node linkType: hard -"@angular-devkit/core@npm:17.3.5, @angular-devkit/core@npm:~17.3.0": - version: 17.3.5 - resolution: "@angular-devkit/core@npm:17.3.5" +"@angular-devkit/core@npm:17.3.2, @angular-devkit/core@npm:~17.3.0": + version: 17.3.2 + resolution: "@angular-devkit/core@npm:17.3.2" dependencies: ajv: "npm:8.12.0" ajv-formats: "npm:2.1.1" @@ -793,23 +793,23 @@ __metadata: peerDependenciesMeta: chokidar: optional: true - checksum: 10/3d97e5cabaa2e1748bdf6813fed1701284ad8f28281947c883ca56cba19e19d76ac51e6ffafaade3f115093bf53c695735ef186e4e7c9af48f69da0dca61f22f + checksum: 10/0362e94df2993c790542b7b00c50034f1a4f80e78c5b845d5f1423d578c1b984b966ae6317f9c0b7c99166ef8362fd7b0be837b9af0f6feb19ff1127cbab4675 languageName: node linkType: hard "@angular-devkit/schematics-cli@npm:~17.3.0": - version: 17.3.5 - resolution: "@angular-devkit/schematics-cli@npm:17.3.5" + version: 17.3.2 + resolution: "@angular-devkit/schematics-cli@npm:17.3.2" dependencies: - "@angular-devkit/core": "npm:17.3.5" - "@angular-devkit/schematics": "npm:17.3.5" + "@angular-devkit/core": "npm:17.3.2" + "@angular-devkit/schematics": "npm:17.3.2" ansi-colors: "npm:4.1.3" inquirer: "npm:9.2.15" symbol-observable: "npm:4.0.0" yargs-parser: "npm:21.1.1" bin: schematics: bin/schematics.js - checksum: 10/77cc4fef041e6f0ac789b299c4ac7ee4711630c74fda535804c5d36e04be63d90a3a821c1d4f571578f60c6063a78f97aacd284a167f395caf59d7c2315522eb + checksum: 10/72569da333396e71cc83ddf9bca0b22da1abfaef94a38fd18fc25c3e231b1cccae67d87c8d9ba8b454d192fd9e7f62cf880554a048a0ca07a1de1362f568762b languageName: node linkType: hard @@ -826,16 +826,16 @@ __metadata: languageName: node linkType: hard -"@angular-devkit/schematics@npm:17.3.5, @angular-devkit/schematics@npm:~17.3.0": - version: 17.3.5 - resolution: "@angular-devkit/schematics@npm:17.3.5" +"@angular-devkit/schematics@npm:17.3.2, @angular-devkit/schematics@npm:~17.3.0": + version: 17.3.2 + resolution: "@angular-devkit/schematics@npm:17.3.2" dependencies: - "@angular-devkit/core": "npm:17.3.5" + "@angular-devkit/core": "npm:17.3.2" jsonc-parser: "npm:3.2.1" magic-string: "npm:0.30.8" ora: "npm:5.4.1" rxjs: "npm:7.8.1" - checksum: 10/1663bbc0a617f8d1b1fd292b4f7a2c61c4d1c013b786f9404cfe65da66b8026ab0f396b54ff9dbab062f3dcf1e283a65d24f9cc2612ebf6af2581bc7032ebb07 + checksum: 10/48c3828e545cb58a40ac0e8857b28e2744d27eb3496b6e4f27f1a04b2db56d99afc607af24aadf7d8c3d72e65824a074bcbb654f6bacfac5dd899f5c186d9ccf languageName: node linkType: hard @@ -944,13 +944,13 @@ __metadata: linkType: hard "@angular/cli@npm:~17.3.0": - version: 17.3.5 - resolution: "@angular/cli@npm:17.3.5" + version: 17.3.2 + resolution: "@angular/cli@npm:17.3.2" dependencies: - "@angular-devkit/architect": "npm:0.1703.5" - "@angular-devkit/core": "npm:17.3.5" - "@angular-devkit/schematics": "npm:17.3.5" - "@schematics/angular": "npm:17.3.5" + "@angular-devkit/architect": "npm:0.1703.2" + "@angular-devkit/core": "npm:17.3.2" + "@angular-devkit/schematics": "npm:17.3.2" + "@schematics/angular": "npm:17.3.2" "@yarnpkg/lockfile": "npm:1.1.0" ansi-colors: "npm:4.1.3" ini: "npm:4.1.2" @@ -967,7 +967,7 @@ __metadata: yargs: "npm:17.7.2" bin: ng: bin/ng.js - checksum: 10/40c6e4853de3095f4b5deeebdd03061a2ee38dc1653d805c0d5f03f4544c2ef7d4800146cfff1c80d11a110de573a13f6bb1c9d1116ddf07189d721a9f9a71e7 + checksum: 10/2acdd273250228c71f896ae0608497e8d4600b7360a9a15ae8bac8969adea745bf007e3526289a4a53d80c6bbc6690102043a9f9b5925b2874e0180dd3173d2d languageName: node linkType: hard @@ -4224,7 +4224,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": version: 4.10.0 resolution: "@eslint-community/regexpp@npm:4.10.0" checksum: 10/8c36169c815fc5d726078e8c71a5b592957ee60d08c6470f9ce0187c8046af1a00afbda0a065cc40ff18d5d83f82aed9793c6818f7304a74a7488dc9f3ecbd42 @@ -5840,14 +5840,14 @@ __metadata: languageName: node linkType: hard -"@ngtools/webpack@npm:17.3.5": - version: 17.3.5 - resolution: "@ngtools/webpack@npm:17.3.5" +"@ngtools/webpack@npm:17.3.2": + version: 17.3.2 + resolution: "@ngtools/webpack@npm:17.3.2" peerDependencies: "@angular/compiler-cli": ^17.0.0 typescript: ">=5.2 <5.5" webpack: ^5.54.0 - checksum: 10/66e2d938f8dbfb1213d0631a8ab7c27606714f52a8404313c40df18bf575ebbf58fae2e92dd7ba88f34592126e8832bce27b05f65caa83e908e361d05c2f3d92 + checksum: 10/862d115606d3ddfa2d05e5be537701f6b9ce82ab5048b92dedd78a5fab554937c4bc9848ce0fefe00a7697d998a1b527b0ee353753104ec80d185793f9969fc9 languageName: node linkType: hard @@ -5990,88 +5990,88 @@ __metadata: languageName: node linkType: hard -"@nrwl/angular@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/angular@npm:18.3.3" +"@nrwl/angular@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/angular@npm:18.3.4" dependencies: - "@nx/angular": "npm:18.3.3" + "@nx/angular": "npm:18.3.4" tslib: "npm:^2.3.0" - checksum: 10/185c25aa9ce84b1489ea9df0c9fc6a159928cf2c8ca3608653c5b5217c12a20fba88b1ccd06ccde14887d7cf1aaea7dd451f25fff87d4d527913ff4df982899d + checksum: 10/c492f3b804c745353754055918984e42994cd7e50528fb297b220d2bc7ee21f7707547fd9d0d23b4ee832d17d69980d7529785c2ee2e63b150862d78f0fe1ff3 languageName: node linkType: hard -"@nrwl/devkit@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/devkit@npm:18.3.3" +"@nrwl/devkit@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/devkit@npm:18.3.4" dependencies: - "@nx/devkit": "npm:18.3.3" - checksum: 10/bcf3e919e61fff8ecd95896ffa40e122963a3881ccc1cb804812868ad5841ce426b95ad065c1a34ed1c8a208b84fbe7a4c5f3dac62b1a5ba1e850adfb3ea33da + "@nx/devkit": "npm:18.3.4" + checksum: 10/8741f48cc93cb81f3964a1220f1382d7441e87a200f3aa58e4e1af4d5b54c32da435e021cd503e62d1d36fdc08fe03ee042882e1aa0abc4af08cf3e35d5c090d languageName: node linkType: hard -"@nrwl/eslint-plugin-nx@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/eslint-plugin-nx@npm:18.3.3" +"@nrwl/eslint-plugin-nx@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/eslint-plugin-nx@npm:18.3.4" dependencies: - "@nx/eslint-plugin": "npm:18.3.3" - checksum: 10/ae62112618d3b599f79c5303faf609f74b6aee012be81e521fb5ec1b7f5f72192a19e52440f7148805e22133e1e979f997ef7479631cda4794d4c46fcbe6b0fb + "@nx/eslint-plugin": "npm:18.3.4" + checksum: 10/d66e89aabf077efd6ce83380c6adb20b774e28d299ac39a0f94c8a7ff9eaae47124e6b77388ec015b8ae1c7ffedc039a79fa223c8f006859c2b8662a20e80022 languageName: node linkType: hard -"@nrwl/jest@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/jest@npm:18.3.3" +"@nrwl/jest@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/jest@npm:18.3.4" dependencies: - "@nx/jest": "npm:18.3.3" - checksum: 10/eb94bf94f20ef76bde199edc945cb35f6bfb56c9e738643835488d4361771c3159a044f4e77e5f76551e9d7b3f2c4bda9edc7b7501912ba9be247d9b11e15e82 + "@nx/jest": "npm:18.3.4" + checksum: 10/481c2d57ccfe1f33e3304473f0221ca04da7b48b4ab5941e2748fe7083ed1e30d4c448b40042c8a77e37c435e29241a62bcd70edd61d4262dd10001ce7053946 languageName: node linkType: hard -"@nrwl/js@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/js@npm:18.3.3" +"@nrwl/js@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/js@npm:18.3.4" dependencies: - "@nx/js": "npm:18.3.3" - checksum: 10/a7d66ff70a53e52992651569252bab2c3f9005860968cd49b618ee05811de995892101bd22523446cca0f10492e112c907be0f8e14dc4ef9385a4332deb5c5b4 + "@nx/js": "npm:18.3.4" + checksum: 10/9b478c3b4cb52c6b0b4a027ab960d6c9ac4b8c2274c977363183f7e38d7f3e4405151a6b141135bfa626f04df35592e974757d6a1b7675933552ea8132e8ef81 languageName: node linkType: hard -"@nrwl/tao@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/tao@npm:18.3.3" +"@nrwl/tao@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/tao@npm:18.3.4" dependencies: - nx: "npm:18.3.3" + nx: "npm:18.3.4" tslib: "npm:^2.3.0" bin: tao: index.js - checksum: 10/c68bce02e9315497756fbc234c1773aa1188ea2a30289938d694cbcf4286cb98dd49a0f3e3e3c97cf22209cad3a6f47ebd53830f71e926c32af4029bc5430523 + checksum: 10/4aae6ddf4835244f91d2d7df0fc95b1f2b84aa8b6ec9af197e8f2b4e42fa402d4be467e9e584dbeebc490928ba2e0968da4cbb9cf233271b9752098e4626921a languageName: node linkType: hard -"@nrwl/web@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/web@npm:18.3.3" +"@nrwl/web@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/web@npm:18.3.4" dependencies: - "@nx/web": "npm:18.3.3" - checksum: 10/852683091751be3b1106319c24864895caa19651aa5e19d40f8d3cb68f33de67bb6f7a1c8e9862b4c2ea4159d0ea9ead72dff55c5652573acca6b834168317c2 + "@nx/web": "npm:18.3.4" + checksum: 10/323acd32513da18f1a6f89c7f879495be0ecff62bbd09091a8f1dcf54a7bc393a2a10c21b9c02cc3dceb04500858f27e2e5dad8e3315e9f2d7833e6b02ed081c languageName: node linkType: hard -"@nrwl/webpack@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/webpack@npm:18.3.3" +"@nrwl/webpack@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/webpack@npm:18.3.4" dependencies: - "@nx/webpack": "npm:18.3.3" - checksum: 10/02d0263f06403c5618e2bdee710b0fb89797154606cdccdd90a4d85dd1d823b2dbead72e247682a966743383319acedd3cb87cccdcb093f5892257034255f36a + "@nx/webpack": "npm:18.3.4" + checksum: 10/feaed2848a23587d7da3cfcbe0f8c39dfb9354f455ab07e528f437c0c03383f7985974376acffe5b004a1c54bfe8f6e95de39a4c4b190ba9a9b4062c6ff1d603 languageName: node linkType: hard -"@nrwl/workspace@npm:18.3.3": - version: 18.3.3 - resolution: "@nrwl/workspace@npm:18.3.3" +"@nrwl/workspace@npm:18.3.4": + version: 18.3.4 + resolution: "@nrwl/workspace@npm:18.3.4" dependencies: - "@nx/workspace": "npm:18.3.3" - checksum: 10/1ebea4d1e02db2b15461fe2c964d3d1de45c79c358584b1ab3dc7d6d814382296ac0761cd529f7ac577cb6559944acacc2463bb49f6cff31883f5e5e30d7a9bd + "@nx/workspace": "npm:18.3.4" + checksum: 10/8d23521887e05afeb9a4364f8123237391c666aa9b915e337be9d01567a943e5a5bb15c8a219bb2964469f8269a337d51e82aa4b7ac946a6dd0a2d23aed9fb6a languageName: node linkType: hard @@ -6088,17 +6088,17 @@ __metadata: languageName: node linkType: hard -"@nx/angular@npm:18.3.3, @nx/angular@npm:~18.3.0": - version: 18.3.3 - resolution: "@nx/angular@npm:18.3.3" +"@nx/angular@npm:18.3.4, @nx/angular@npm:~18.3.0": + version: 18.3.4 + resolution: "@nx/angular@npm:18.3.4" dependencies: - "@nrwl/angular": "npm:18.3.3" - "@nx/devkit": "npm:18.3.3" - "@nx/eslint": "npm:18.3.3" - "@nx/js": "npm:18.3.3" - "@nx/web": "npm:18.3.3" - "@nx/webpack": "npm:18.3.3" - "@nx/workspace": "npm:18.3.3" + "@nrwl/angular": "npm:18.3.4" + "@nx/devkit": "npm:18.3.4" + "@nx/eslint": "npm:18.3.4" + "@nx/js": "npm:18.3.4" + "@nx/web": "npm:18.3.4" + "@nx/webpack": "npm:18.3.4" + "@nx/workspace": "npm:18.3.4" "@phenomnomnominal/tsquery": "npm:~5.0.1" "@typescript-eslint/type-utils": "npm:^7.3.0" chalk: "npm:^4.1.0" @@ -6121,15 +6121,15 @@ __metadata: peerDependenciesMeta: esbuild: optional: true - checksum: 10/d9f75d06e0c30fe84dce5bef677e4d4cdf50ba3ecb29a9b760a3eb43da076a207f4034c995726679f62b83e78b398c7d627ed194fa9da032a227bcfa8eddb213 + checksum: 10/4e2ef335e7811ed8358bb5b9c0bd360c6eaadf8c948262cf1d890d6f00aa1baa56347a7bf1d886856b4e08c3f17bb682c912d4e626943d4dce353cf364a148e7 languageName: node linkType: hard -"@nx/devkit@npm:18.3.3, @nx/devkit@npm:^17.2.8 || ^18.0.0": - version: 18.3.3 - resolution: "@nx/devkit@npm:18.3.3" +"@nx/devkit@npm:18.3.4, @nx/devkit@npm:^17.2.8 || ^18.0.0": + version: 18.3.4 + resolution: "@nx/devkit@npm:18.3.4" dependencies: - "@nrwl/devkit": "npm:18.3.3" + "@nrwl/devkit": "npm:18.3.4" ejs: "npm:^3.1.7" enquirer: "npm:~2.3.6" ignore: "npm:^5.0.4" @@ -6139,17 +6139,17 @@ __metadata: yargs-parser: "npm:21.1.1" peerDependencies: nx: ">= 16 <= 19" - checksum: 10/c9b67bb09394e2e1432f18d3c04ff589e5fa7aee05040037688abdccc3893edba851bc826852f3cb98e1cffcf345fb72037c9f5a723510b08afe269142b4dac3 + checksum: 10/a547004c1e5d934db8a0a27653bba9ca781e86c1590a9839a6e9befb41f9a5957fb3f3479216698d873008b9be681e415e15e795314a9406c909ed9c0c7021ab languageName: node linkType: hard -"@nx/eslint-plugin@npm:18.3.3, @nx/eslint-plugin@npm:~18.3.0": - version: 18.3.3 - resolution: "@nx/eslint-plugin@npm:18.3.3" +"@nx/eslint-plugin@npm:18.3.4, @nx/eslint-plugin@npm:~18.3.0": + version: 18.3.4 + resolution: "@nx/eslint-plugin@npm:18.3.4" dependencies: - "@nrwl/eslint-plugin-nx": "npm:18.3.3" - "@nx/devkit": "npm:18.3.3" - "@nx/js": "npm:18.3.3" + "@nrwl/eslint-plugin-nx": "npm:18.3.4" + "@nx/devkit": "npm:18.3.4" + "@nx/js": "npm:18.3.4" "@typescript-eslint/type-utils": "npm:^7.3.0" "@typescript-eslint/utils": "npm:^7.3.0" chalk: "npm:^4.1.0" @@ -6163,17 +6163,17 @@ __metadata: peerDependenciesMeta: eslint-config-prettier: optional: true - checksum: 10/c089543ec7d628e0e95674ff30453ff90e4ee0eaa5666a23792a94758f4c7f47022952057c1f71d37885689536d4cdbe9935e5660b06daa5e9e96bfb2f2ffbb0 + checksum: 10/2faf222944b66ce54e180c067cee095165c9e6904b1c5176b6058f4a01aaae3b3378bccd7d23471c9b8f9309aac29d1542688c2f118eb89ff07833d1b2234d9c languageName: node linkType: hard -"@nx/eslint@npm:18.3.3, @nx/eslint@npm:~18.3.0": - version: 18.3.3 - resolution: "@nx/eslint@npm:18.3.3" +"@nx/eslint@npm:18.3.4, @nx/eslint@npm:~18.3.0": + version: 18.3.4 + resolution: "@nx/eslint@npm:18.3.4" dependencies: - "@nx/devkit": "npm:18.3.3" - "@nx/js": "npm:18.3.3" - "@nx/linter": "npm:18.3.3" + "@nx/devkit": "npm:18.3.4" + "@nx/js": "npm:18.3.4" + "@nx/linter": "npm:18.3.4" eslint: "npm:^8.0.0" tslib: "npm:^2.3.0" typescript: "npm:~5.4.2" @@ -6182,19 +6182,19 @@ __metadata: peerDependenciesMeta: js-yaml: optional: true - checksum: 10/2aac8bacf686abdab65a9e673b3a14d789343845e6338eeca0a3095aaa71ed8a294565ab0be5ffac3ed575f3ea82c58661bb14089ab3a862bc9378b648ba4d75 + checksum: 10/9b3c2247ce3db67742728c015e44b5b472c2a54047ac8a0180a6f5fe9b5c57f06a133dae24bd39644d2b9d063877e62ecc135eb5ff0c80e214e7f4df6f6d3d98 languageName: node linkType: hard -"@nx/jest@npm:18.3.3, @nx/jest@npm:~18.3.0": - version: 18.3.3 - resolution: "@nx/jest@npm:18.3.3" +"@nx/jest@npm:18.3.4, @nx/jest@npm:~18.3.0": + version: 18.3.4 + resolution: "@nx/jest@npm:18.3.4" dependencies: "@jest/reporters": "npm:^29.4.1" "@jest/test-result": "npm:^29.4.1" - "@nrwl/jest": "npm:18.3.3" - "@nx/devkit": "npm:18.3.3" - "@nx/js": "npm:18.3.3" + "@nrwl/jest": "npm:18.3.4" + "@nx/devkit": "npm:18.3.4" + "@nx/js": "npm:18.3.4" "@phenomnomnominal/tsquery": "npm:~5.0.1" chalk: "npm:^4.1.0" identity-obj-proxy: "npm:3.0.0" @@ -6205,13 +6205,13 @@ __metadata: resolve.exports: "npm:1.1.0" tslib: "npm:^2.3.0" yargs-parser: "npm:21.1.1" - checksum: 10/98380f85bb3409580249bb47c7d15d1009abf6405d704fa5bed291e73875c3b02fc13245d0844cf988fdd02801a789d2ece1321df3eb47ef53f1e7634c569a93 + checksum: 10/4afe7c1cfbf12cf13245d1da154f3f10b78830e56a73c9c4994ac466c72d6b4914a25e6449280e777e891e7e48d616354f0359e7d35b0fd5fe62a630b66277c1 languageName: node linkType: hard -"@nx/js@npm:18.3.3, @nx/js@npm:~18.3.0": - version: 18.3.3 - resolution: "@nx/js@npm:18.3.3" +"@nx/js@npm:18.3.4, @nx/js@npm:~18.3.0": + version: 18.3.4 + resolution: "@nx/js@npm:18.3.4" dependencies: "@babel/core": "npm:^7.23.2" "@babel/plugin-proposal-decorators": "npm:^7.22.7" @@ -6220,9 +6220,9 @@ __metadata: "@babel/preset-env": "npm:^7.23.2" "@babel/preset-typescript": "npm:^7.22.5" "@babel/runtime": "npm:^7.22.6" - "@nrwl/js": "npm:18.3.3" - "@nx/devkit": "npm:18.3.3" - "@nx/workspace": "npm:18.3.3" + "@nrwl/js": "npm:18.3.4" + "@nx/devkit": "npm:18.3.4" + "@nx/workspace": "npm:18.3.4" "@phenomnomnominal/tsquery": "npm:~5.0.1" babel-plugin-const-enum: "npm:^1.0.1" babel-plugin-macros: "npm:^2.8.0" @@ -6248,112 +6248,112 @@ __metadata: peerDependenciesMeta: verdaccio: optional: true - checksum: 10/8472f62ec9b19ecdca7b7a10996ff894469306e34698979c90d8ad91ebb595e7ef21e06b653cba08a42e0f0251e928c3ab884d8227ba74f3f4d4df4457916b53 + checksum: 10/b4f20dc21096f0f3c6865d246abc59b648dd710dfd3d8be19fdf14e61d34d609dbd3daa7dff5d7077595a39102428c7f4b66d1f1a9a7e50edf22b6372a1d78f2 languageName: node linkType: hard -"@nx/linter@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/linter@npm:18.3.3" +"@nx/linter@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/linter@npm:18.3.4" dependencies: - "@nx/eslint": "npm:18.3.3" - checksum: 10/1180fbcff36bacfe7bfbac3a6f8458c67ba5e8252673d7f8b07141920c6e46408c3358fbf753591782220fbab54c7df0b82a168117af551e54f5cc85130a43af + "@nx/eslint": "npm:18.3.4" + checksum: 10/12e8cda6eb315e3e55ef52c0b42fbd7c0cd654c8a17c212aa7e14bd9e630560579437c85fca0f71b948dbaecb6f563178c00b79156d428682d3b665221861d9c languageName: node linkType: hard -"@nx/nx-darwin-arm64@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-darwin-arm64@npm:18.3.3" +"@nx/nx-darwin-arm64@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-darwin-arm64@npm:18.3.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@nx/nx-darwin-x64@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-darwin-x64@npm:18.3.3" +"@nx/nx-darwin-x64@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-darwin-x64@npm:18.3.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@nx/nx-freebsd-x64@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-freebsd-x64@npm:18.3.3" +"@nx/nx-freebsd-x64@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-freebsd-x64@npm:18.3.4" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@nx/nx-linux-arm-gnueabihf@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-linux-arm-gnueabihf@npm:18.3.3" +"@nx/nx-linux-arm-gnueabihf@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-linux-arm-gnueabihf@npm:18.3.4" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@nx/nx-linux-arm64-gnu@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-linux-arm64-gnu@npm:18.3.3" +"@nx/nx-linux-arm64-gnu@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-linux-arm64-gnu@npm:18.3.4" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@nx/nx-linux-arm64-musl@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-linux-arm64-musl@npm:18.3.3" +"@nx/nx-linux-arm64-musl@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-linux-arm64-musl@npm:18.3.4" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@nx/nx-linux-x64-gnu@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-linux-x64-gnu@npm:18.3.3" +"@nx/nx-linux-x64-gnu@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-linux-x64-gnu@npm:18.3.4" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@nx/nx-linux-x64-musl@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-linux-x64-musl@npm:18.3.3" +"@nx/nx-linux-x64-musl@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-linux-x64-musl@npm:18.3.4" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@nx/nx-win32-arm64-msvc@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-win32-arm64-msvc@npm:18.3.3" +"@nx/nx-win32-arm64-msvc@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-win32-arm64-msvc@npm:18.3.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@nx/nx-win32-x64-msvc@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/nx-win32-x64-msvc@npm:18.3.3" +"@nx/nx-win32-x64-msvc@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/nx-win32-x64-msvc@npm:18.3.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@nx/web@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/web@npm:18.3.3" +"@nx/web@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/web@npm:18.3.4" dependencies: - "@nrwl/web": "npm:18.3.3" - "@nx/devkit": "npm:18.3.3" - "@nx/js": "npm:18.3.3" + "@nrwl/web": "npm:18.3.4" + "@nx/devkit": "npm:18.3.4" + "@nx/js": "npm:18.3.4" chalk: "npm:^4.1.0" detect-port: "npm:^1.5.1" http-server: "npm:^14.1.0" tslib: "npm:^2.3.0" - checksum: 10/9e64e7b11e72e980f4cb97d2c3d0807bca3cc1cb0b0db19e4df8e987391f55d34bf8e5e629eab5b50e572b87d666bee175ffcd1820ab7543977f3c833e54dd52 + checksum: 10/6718aa91d2ca031ec56c4579038f839e6c4f6f73823f9a0706fd68a6f2fe39e584133503f91c2afade5e90dbb12c756c6e6bfdafb703f7e71f231141b1b3a5f6 languageName: node linkType: hard -"@nx/webpack@npm:18.3.3": - version: 18.3.3 - resolution: "@nx/webpack@npm:18.3.3" +"@nx/webpack@npm:18.3.4": + version: 18.3.4 + resolution: "@nx/webpack@npm:18.3.4" dependencies: "@babel/core": "npm:^7.23.2" - "@nrwl/webpack": "npm:18.3.3" - "@nx/devkit": "npm:18.3.3" - "@nx/js": "npm:18.3.3" + "@nrwl/webpack": "npm:18.3.4" + "@nx/devkit": "npm:18.3.4" + "@nx/js": "npm:18.3.4" ajv: "npm:^8.12.0" autoprefixer: "npm:^10.4.9" babel-loader: "npm:^9.1.2" @@ -6387,22 +6387,22 @@ __metadata: webpack-dev-server: "npm:^4.9.3" webpack-node-externals: "npm:^3.0.0" webpack-subresource-integrity: "npm:^5.1.0" - checksum: 10/4642e49d1523b46f48c297263253aba214e44013913e07901f325e58bf977371ea4bca97f9a922209bc8d1467f3cafa174b0611f52347919aade08e85fd06603 + checksum: 10/bf6b9b9804cda9525249170d126aad7a8017b6a0b0b0c90870d252057a891f9a6f4d25996efeb5217f843cadee14983311a496ad9279743200dd47621f9cb521 languageName: node linkType: hard -"@nx/workspace@npm:18.3.3, @nx/workspace@npm:~18.3.0": - version: 18.3.3 - resolution: "@nx/workspace@npm:18.3.3" +"@nx/workspace@npm:18.3.4, @nx/workspace@npm:~18.3.0": + version: 18.3.4 + resolution: "@nx/workspace@npm:18.3.4" dependencies: - "@nrwl/workspace": "npm:18.3.3" - "@nx/devkit": "npm:18.3.3" + "@nrwl/workspace": "npm:18.3.4" + "@nx/devkit": "npm:18.3.4" chalk: "npm:^4.1.0" enquirer: "npm:~2.3.6" - nx: "npm:18.3.3" + nx: "npm:18.3.4" tslib: "npm:^2.3.0" yargs-parser: "npm:21.1.1" - checksum: 10/3279c381988b3821543aee75a49985a97df8e01334c2a25c711edff6c173fa76e540d300f4029621d69ec8cef21154b3fc659beeea4b39d858c4f26d29c5405f + checksum: 10/fd171376db1aba7febf5d9bd48ad2bb10dece14efbe892a62cd7bc68eab52c0a213b299ed1f4191c79434a51ddbece3c8f3d9de00e1833c6c135c7210e8b48b9 languageName: node linkType: hard @@ -7967,6 +7967,8 @@ __metadata: "@stylistic/eslint-plugin-ts": "npm:^1.5.4" "@swc-node/register": "npm:^1.6.7" "@swc/core": "npm:^1.3.85" + "@tanstack/angular-query-devtools-experimental": "npm:^5.28.8" + "@tanstack/angular-query-experimental": "npm:^5.28.8" "@types/estree": "npm:^1.0.5" "@types/jest": "npm:~29.5.2" "@types/node": "npm:^20.0.0" @@ -8726,6 +8728,8 @@ __metadata: "@popperjs/core": "npm:^2.11.5" "@schematics/angular": "npm:~17.3.0" "@stylistic/eslint-plugin-ts": "npm:^1.5.4" + "@tanstack/angular-query-devtools-experimental": "npm:^5.28.8" + "@tanstack/angular-query-experimental": "npm:^5.28.8" "@types/bootstrap": "npm:^5.2.10" "@types/jest": "npm:~29.5.2" "@types/node": "npm:^20.0.0" @@ -8749,6 +8753,7 @@ __metadata: jest-environment-jsdom: "npm:~29.7.0" jest-junit: "npm:~16.0.0" jest-preset-angular: "npm:~14.0.3" + json-server: "npm:^1.0.0-alpha.23" jsonc-eslint-parser: "npm:~2.4.0" lighthouse: "npm:9.6.8" ngx-highlightjs: "npm:^10.0.0" @@ -9806,6 +9811,13 @@ __metadata: languageName: node linkType: hard +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.25 + resolution: "@polka/url@npm:1.0.0-next.25" + checksum: 10/4ab1d7a37163139c0e7bfc9d1e3f6a2a0db91a78b9f0a21f571d6aec2cdaeaacced744d47886c117aa7579aa5694b303fe3e0bd1922bb9cb3ce6bf7c2dc09801 + languageName: node + linkType: hard + "@popperjs/core@npm:^2.11.5, @popperjs/core@npm:^2.9.2": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" @@ -10590,14 +10602,14 @@ __metadata: languageName: node linkType: hard -"@schematics/angular@npm:17.3.5, @schematics/angular@npm:~17.3.0": - version: 17.3.5 - resolution: "@schematics/angular@npm:17.3.5" +"@schematics/angular@npm:17.3.2, @schematics/angular@npm:~17.3.0": + version: 17.3.2 + resolution: "@schematics/angular@npm:17.3.2" dependencies: - "@angular-devkit/core": "npm:17.3.5" - "@angular-devkit/schematics": "npm:17.3.5" + "@angular-devkit/core": "npm:17.3.2" + "@angular-devkit/schematics": "npm:17.3.2" jsonc-parser: "npm:3.2.1" - checksum: 10/9ae3ceda28a9e32f53fe6f7d30503e2e15185a10f1b0cd17d6c9cd76574c9963d02cf0b0162941ff1fb029f67b1dada12bfb295d555602b79653e15ea3cf88d7 + checksum: 10/fddc9f109649d40c428ab54833419943b0229c3202a87907f354447d19eb44e068262c9b1f59161b566ca26f42b957bc0359a9ecb52775956bbb4aacac515001 languageName: node linkType: hard @@ -11396,90 +11408,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-darwin-arm64@npm:1.4.16" +"@swc/core-darwin-arm64@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-darwin-arm64@npm:1.4.11" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-darwin-x64@npm:1.4.16" +"@swc/core-darwin-x64@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-darwin-x64@npm:1.4.11" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.4.16" +"@swc/core-linux-arm-gnueabihf@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.4.11" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-linux-arm64-gnu@npm:1.4.16" +"@swc/core-linux-arm64-gnu@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-linux-arm64-gnu@npm:1.4.11" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-linux-arm64-musl@npm:1.4.16" +"@swc/core-linux-arm64-musl@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-linux-arm64-musl@npm:1.4.11" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-linux-x64-gnu@npm:1.4.16" +"@swc/core-linux-x64-gnu@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-linux-x64-gnu@npm:1.4.11" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-linux-x64-musl@npm:1.4.16" +"@swc/core-linux-x64-musl@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-linux-x64-musl@npm:1.4.11" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-win32-arm64-msvc@npm:1.4.16" +"@swc/core-win32-arm64-msvc@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-win32-arm64-msvc@npm:1.4.11" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-win32-ia32-msvc@npm:1.4.16" +"@swc/core-win32-ia32-msvc@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-win32-ia32-msvc@npm:1.4.11" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.4.16": - version: 1.4.16 - resolution: "@swc/core-win32-x64-msvc@npm:1.4.16" +"@swc/core-win32-x64-msvc@npm:1.4.11": + version: 1.4.11 + resolution: "@swc/core-win32-x64-msvc@npm:1.4.11" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.82, @swc/core@npm:^1.3.85": - version: 1.4.16 - resolution: "@swc/core@npm:1.4.16" - dependencies: - "@swc/core-darwin-arm64": "npm:1.4.16" - "@swc/core-darwin-x64": "npm:1.4.16" - "@swc/core-linux-arm-gnueabihf": "npm:1.4.16" - "@swc/core-linux-arm64-gnu": "npm:1.4.16" - "@swc/core-linux-arm64-musl": "npm:1.4.16" - "@swc/core-linux-x64-gnu": "npm:1.4.16" - "@swc/core-linux-x64-musl": "npm:1.4.16" - "@swc/core-win32-arm64-msvc": "npm:1.4.16" - "@swc/core-win32-ia32-msvc": "npm:1.4.16" - "@swc/core-win32-x64-msvc": "npm:1.4.16" + version: 1.4.11 + resolution: "@swc/core@npm:1.4.11" + dependencies: + "@swc/core-darwin-arm64": "npm:1.4.11" + "@swc/core-darwin-x64": "npm:1.4.11" + "@swc/core-linux-arm-gnueabihf": "npm:1.4.11" + "@swc/core-linux-arm64-gnu": "npm:1.4.11" + "@swc/core-linux-arm64-musl": "npm:1.4.11" + "@swc/core-linux-x64-gnu": "npm:1.4.11" + "@swc/core-linux-x64-musl": "npm:1.4.11" + "@swc/core-win32-arm64-msvc": "npm:1.4.11" + "@swc/core-win32-ia32-msvc": "npm:1.4.11" + "@swc/core-win32-x64-msvc": "npm:1.4.11" "@swc/counter": "npm:^0.1.2" "@swc/types": "npm:^0.1.5" peerDependencies: @@ -11508,7 +11520,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10/c68c8776511b11f411ea961679a0860cb6f31b90af78b972e0a3443e065e2bdf3a49529660c3a73a0cc20b3d6a0d93b116cd2f48d1c8fd12d3856166fdbfb20b + checksum: 10/c2b6ccfd00b126b4d7a5d571c9acf81e926f25bba051d2cd618065720c3c27d16c141c698df8dc1676eb44f4f5af6cc293b3c1bc9eb0749897ea5b1826c340ea languageName: node linkType: hard @@ -11546,6 +11558,47 @@ __metadata: languageName: node linkType: hard +"@tanstack/angular-query-devtools-experimental@npm:^5.28.8": + version: 5.28.8 + resolution: "@tanstack/angular-query-devtools-experimental@npm:5.28.8" + dependencies: + "@tanstack/query-devtools": "npm:5.28.6" + tslib: "npm:^2.6.2" + peerDependencies: + "@angular/common": ">=16.0.0" + "@angular/core": ">=16.0.0" + "@tanstack/angular-query-experimental": ^5.28.8 + checksum: 10/42eed1bf9043f96a6831e755194b95f24e555479fa244c10f658bdf8093cac583b8ddd3123c783f789eb448bd2236b334c0d22262078f767719386f46542b6b0 + languageName: node + linkType: hard + +"@tanstack/angular-query-experimental@npm:^5.28.8": + version: 5.28.8 + resolution: "@tanstack/angular-query-experimental@npm:5.28.8" + dependencies: + "@tanstack/query-core": "npm:5.28.8" + tslib: "npm:^2.6.2" + peerDependencies: + "@angular/common": ">=16.0.0" + "@angular/core": ">=16.0.0" + checksum: 10/63651184c7a6d6eb6c9a494157a5301574fc3c0344c15b8d1342b38beee2d5e85eaa737f53fda495b762274548990a3828ca037c48525b205cd9c993a81cfa83 + languageName: node + linkType: hard + +"@tanstack/query-core@npm:5.28.8": + version: 5.28.8 + resolution: "@tanstack/query-core@npm:5.28.8" + checksum: 10/aeda2a4b88e3ae44d139ef9d99e09eb5bb78e39abb66cd32a21ca79e654379665ffa0c9ddd2560aeac9cbf287d648bc0ee16a4b2f45bd051d7a070d8f48912fd + languageName: node + linkType: hard + +"@tanstack/query-devtools@npm:5.28.6": + version: 5.28.6 + resolution: "@tanstack/query-devtools@npm:5.28.6" + checksum: 10/7a62925752e02f136fa7163e43395086585e06261095f3dd9faca71b3304e44a18e986420b69eb24a41c91b1a73e1c31ab8303ed30e8872feed7c6c0c2bb0d1a + languageName: node + linkType: hard + "@thednp/event-listener@npm:^2.0.4": version: 2.0.4 resolution: "@thednp/event-listener@npm:2.0.4" @@ -11560,6 +11613,170 @@ __metadata: languageName: node linkType: hard +"@tinyhttp/accepts@npm:2.2.1": + version: 2.2.1 + resolution: "@tinyhttp/accepts@npm:2.2.1" + dependencies: + mime: "npm:4.0.1" + negotiator: "npm:^0.6.3" + checksum: 10/f7202b93f7cda8f92736b6549e631237a321ef1a963a978bc015c7c73c413979088979ef318f01170ac2c07e7811783dcf9721ad9806224c0cfb3b691c41c99d + languageName: node + linkType: hard + +"@tinyhttp/app@npm:^2.2.3": + version: 2.2.3 + resolution: "@tinyhttp/app@npm:2.2.3" + dependencies: + "@tinyhttp/cookie": "npm:2.1.0" + "@tinyhttp/proxy-addr": "npm:2.1.3" + "@tinyhttp/req": "npm:2.2.2" + "@tinyhttp/res": "npm:2.2.2" + "@tinyhttp/router": "npm:2.2.2" + header-range-parser: "npm:1.1.3" + regexparam: "npm:^2.0.1" + checksum: 10/9c22dd885cb6545c4e18c0e983e5922ddba856a45aac91c7a3b7b4f9ac8cc2daef551d1db7b93b7d26d8f88b577e3b4f53ec573ec33566f1efc26b83669cddd6 + languageName: node + linkType: hard + +"@tinyhttp/content-disposition@npm:2.2.0": + version: 2.2.0 + resolution: "@tinyhttp/content-disposition@npm:2.2.0" + checksum: 10/a77fe93f985bb484c9fac2ef67c57139cdd9b1ecd61ee3350e79b84fb8929a64ef1bb016c871942534564c68c06785a22d8e354d3c5843d287e70397f4dc71a8 + languageName: node + linkType: hard + +"@tinyhttp/content-type@npm:^0.1.4": + version: 0.1.4 + resolution: "@tinyhttp/content-type@npm:0.1.4" + checksum: 10/1ce23ba34f5e30c03f87ffc0309697c9a4de67314ed6f5e183be1b0c2f5990ce0f8f06ca2d3624ad642d84ad56db0fa944760757960eca77b546947668d8258c + languageName: node + linkType: hard + +"@tinyhttp/cookie-signature@npm:2.1.0": + version: 2.1.0 + resolution: "@tinyhttp/cookie-signature@npm:2.1.0" + checksum: 10/c6f8cb03ffcbf26366267a5797cb642589390f14a2d9a86000220109ec8d74bbb6687693c670a3386ac4ac57de79444990151eee0d6b71fd945022480ddd0629 + languageName: node + linkType: hard + +"@tinyhttp/cookie@npm:2.1.0": + version: 2.1.0 + resolution: "@tinyhttp/cookie@npm:2.1.0" + checksum: 10/651df2197e333fe0199287ef0c9c658fc702bdf617ab16fb9d4553b0787207035715c7f3fc92902cac9cca8696fc8e86eb7a907e259f6140d3fff6a9f5265d15 + languageName: node + linkType: hard + +"@tinyhttp/cors@npm:^2.0.0": + version: 2.0.0 + resolution: "@tinyhttp/cors@npm:2.0.0" + dependencies: + es-vary: "npm:^0.1.1" + checksum: 10/5091928da3af7659f6078ec6498a21d0174421a15fc414cabe6672f347a4283e8747545fec09f668deff68fa55c99dcc81090b6a4cae773df6621a679f18723a + languageName: node + linkType: hard + +"@tinyhttp/encode-url@npm:2.1.1": + version: 2.1.1 + resolution: "@tinyhttp/encode-url@npm:2.1.1" + checksum: 10/fe0f10b774afa526c8390949f6ece7d06644e3a34cdcd7ab594569ee2dea28f28514ec802e86e0736bd240fa9406a88f2d5455990e1c9ddb2257e791b92b2c3e + languageName: node + linkType: hard + +"@tinyhttp/etag@npm:2.1.1": + version: 2.1.1 + resolution: "@tinyhttp/etag@npm:2.1.1" + checksum: 10/fb02e274d1ca5a4e4c550f3f6eeb7200b00a42b58856240b1ec8f3f358cd45500f8659f45be18de10f10de6a9ef722871fe46afec7f539fd04770dd7ca91208b + languageName: node + linkType: hard + +"@tinyhttp/forwarded@npm:2.1.2": + version: 2.1.2 + resolution: "@tinyhttp/forwarded@npm:2.1.2" + checksum: 10/e60cd17f5e082ab7178ef0e4cf1d76557eab6d4c3b15897e23a5bacc173c37da2641d87be6fda36ca7f77dbffefd2f64df080c71637db2b041c6340390942fc5 + languageName: node + linkType: hard + +"@tinyhttp/proxy-addr@npm:2.1.3": + version: 2.1.3 + resolution: "@tinyhttp/proxy-addr@npm:2.1.3" + dependencies: + "@tinyhttp/forwarded": "npm:2.1.2" + ipaddr.js: "npm:^2.1.0" + checksum: 10/3f5bc6d334b1717d5a6f908c89db9ba6113fd7f1b673ef0025aa2f695e8736d8c11788618d09e29b17d13957cf2ce35e4b86198543357d7539b49f9123f48c09 + languageName: node + linkType: hard + +"@tinyhttp/req@npm:2.2.2": + version: 2.2.2 + resolution: "@tinyhttp/req@npm:2.2.2" + dependencies: + "@tinyhttp/accepts": "npm:2.2.1" + "@tinyhttp/type-is": "npm:2.2.2" + "@tinyhttp/url": "npm:2.1.1" + header-range-parser: "npm:^1.1.3" + checksum: 10/d7d0dfa400978c788a904523d136b09bee2e1a73e87eae76bf8ee4068255d4a0ab04f5d525eb77ae65d7cf186fc3bdfde3e2b474f87fc69c00480ee73d2394ff + languageName: node + linkType: hard + +"@tinyhttp/res@npm:2.2.2": + version: 2.2.2 + resolution: "@tinyhttp/res@npm:2.2.2" + dependencies: + "@tinyhttp/content-disposition": "npm:2.2.0" + "@tinyhttp/cookie": "npm:2.1.0" + "@tinyhttp/cookie-signature": "npm:2.1.0" + "@tinyhttp/encode-url": "npm:2.1.1" + "@tinyhttp/req": "npm:2.2.2" + "@tinyhttp/send": "npm:2.2.1" + "@tinyhttp/vary": "npm:^0.1.3" + es-escape-html: "npm:^0.1.1" + mime: "npm:4.0.1" + checksum: 10/cddccec7819dca01388166672ed376b35dc483054acd28cd3d564790e7c2f7db60747933ef67b4cdd6c3399c4a10998517dd827547ac7002de7ded73e814ee13 + languageName: node + linkType: hard + +"@tinyhttp/router@npm:2.2.2": + version: 2.2.2 + resolution: "@tinyhttp/router@npm:2.2.2" + checksum: 10/8d48e82c2eeece7f04e4b0bb9ed82e96d3485eb8b1ce17d6ebd8f975e3b070fcd17a17d204938d567a805d8ff34dd9055893db26da7d051353f47dfd68795e6c + languageName: node + linkType: hard + +"@tinyhttp/send@npm:2.2.1": + version: 2.2.1 + resolution: "@tinyhttp/send@npm:2.2.1" + dependencies: + "@tinyhttp/content-type": "npm:^0.1.4" + "@tinyhttp/etag": "npm:2.1.1" + mime: "npm:4.0.1" + checksum: 10/e08d4a9e25469bb306ed767c74f2a72f948409719de374d53680d79f4b7dd55a5e03a64abf887ada45fc271b8648737f027a3d03ab484cd895188ba77b4152c7 + languageName: node + linkType: hard + +"@tinyhttp/type-is@npm:2.2.2": + version: 2.2.2 + resolution: "@tinyhttp/type-is@npm:2.2.2" + dependencies: + "@tinyhttp/content-type": "npm:^0.1.4" + mime: "npm:4.0.1" + checksum: 10/d652798e73154064186302e0a9d08ba1af343b37ef65ecdedade10c29ee8046a763f7da7946785409745bfb72a64ec159991a94d99420245fa4c72fe38711ed5 + languageName: node + linkType: hard + +"@tinyhttp/url@npm:2.1.1": + version: 2.1.1 + resolution: "@tinyhttp/url@npm:2.1.1" + checksum: 10/7663cbd035a0a141f58406fb553d13cb44301e8c7a152a65e432025d978a9f1eeb1bdce0b97366c15850f9617aff29b01bf40713b555a9b6875435b205a22921 + languageName: node + linkType: hard + +"@tinyhttp/vary@npm:^0.1.3": + version: 0.1.3 + resolution: "@tinyhttp/vary@npm:0.1.3" + checksum: 10/ef4887d171ff8730fe7a5a0816bb73cb5b738786363e99960ddb4dbb66c81a03d630816e0ab535d0f25b554354baf1115033991174ab9a2fbe28b5be280f248c + languageName: node + linkType: hard + "@tokenizer/token@npm:^0.3.0": version: 0.3.0 resolution: "@tokenizer/token@npm:0.3.0" @@ -11594,9 +11811,9 @@ __metadata: linkType: hard "@tsconfig/node10@npm:^1.0.7": - version: 1.0.11 - resolution: "@tsconfig/node10@npm:1.0.11" - checksum: 10/51fe47d55fe1b80ec35e6e5ed30a13665fd3a531945350aa74a14a1e82875fb60b350c2f2a5e72a64831b1b6bc02acb6760c30b3738b54954ec2dea82db7a267 + version: 1.0.10 + resolution: "@tsconfig/node10@npm:1.0.10" + checksum: 10/1204c05940c3669e897c1bcdf20668acc7fdbbeb41b4e8a3eb83ec486d6a442ba0f5d3b8122c93cb813fa498a232946ecb09e5a59a02828db3f1c27529563046 languageName: node linkType: hard @@ -12245,12 +12462,12 @@ __metadata: linkType: hard "@types/react@npm:^18.0.0": - version: 18.2.79 - resolution: "@types/react@npm:18.2.79" + version: 18.2.71 + resolution: "@types/react@npm:18.2.71" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10/2ef833e7d0a5c226beddbbe090811582371f6ae5e2f092a3d9f47cc6087c8bce0b96ee33e351de6d1d470f0a0ec5892d971933f841ef31538c1821681fc6569e + checksum: 10/b9473a30b541de7ddd603fef65240c09459c04ede28959f9499d779c3dfb6bcb8fd969b377e097eb5b6bc3182ff094548bff47a2c8b8f57a7b601de22a225eb6 languageName: node linkType: hard @@ -12485,14 +12702,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^7.2.0": - version: 7.7.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.7.0" - dependencies: - "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.7.0" - "@typescript-eslint/type-utils": "npm:7.7.0" - "@typescript-eslint/utils": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" + version: 7.4.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.4.0" + dependencies: + "@eslint-community/regexpp": "npm:^4.5.1" + "@typescript-eslint/scope-manager": "npm:7.4.0" + "@typescript-eslint/type-utils": "npm:7.4.0" + "@typescript-eslint/utils": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" @@ -12505,25 +12722,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/9e6b6fbb9920581813c01daaa2f89419c3476e42823755c0627f4491640cfaffaebeb0592231ed4f318eefadfcdd4560b77b2903d66ab4e0c8df746a7037a603 + checksum: 10/9bd8852c7e4e9608c3fded94f7c60506cc7d2b6d8a8c1cad6d48969a7363751b20282874e55ccdf180635cf204cb10b3e1e5c3d1cff34d4fcd07762be3fc138e languageName: node linkType: hard "@typescript-eslint/parser@npm:^7.2.0": - version: 7.7.0 - resolution: "@typescript-eslint/parser@npm:7.7.0" + version: 7.4.0 + resolution: "@typescript-eslint/parser@npm:7.4.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.7.0" - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/typescript-estree": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" + "@typescript-eslint/scope-manager": "npm:7.4.0" + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/typescript-estree": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/9f8c53ca29af09cd366e37420410319c8f69e9f4a676513ecd91f5e6d822b9935b6a8ad7ec931d604fc4a0ecd93d51063d0c93227f78f2380196c8a7fa6970d1 + checksum: 10/142a9e1187d305ed43b4fef659c36fa4e28359467198c986f0955c70b4067c9799f4c85d9881fbf099c55dfb265e30666e28b3ef290520e242b45ca7cb8e4ca9 languageName: node linkType: hard @@ -12557,13 +12774,23 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/scope-manager@npm:7.7.0" +"@typescript-eslint/scope-manager@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/scope-manager@npm:7.4.0" + dependencies: + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" + checksum: 10/8cf9292444f9731017a707cac34bef5ae0eb33b5cd42ed07fcd046e981d97889d9201d48e02f470f2315123f53771435e10b1dc81642af28a11df5352a8e8be2 + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/scope-manager@npm:7.7.1" dependencies: - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" - checksum: 10/c8890aaf99b57543774e50549c5b178c13695b21a6b30c65292268137fe5e6856cc0e050c118b47b5835dd8a48c96e042fc75891a7f6093a0b94b6b3b251afd9 + "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/visitor-keys": "npm:7.7.1" + checksum: 10/7823cd15e7205d2c0d9e69432717c385b2ecd7559d5edba79113c2e97c6c5e8ca3dae9343a734bc740be97e096bfcb9dfb81a3da697f9fbf5600a56a42cf70e9 languageName: node linkType: hard @@ -12584,12 +12811,29 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.7.0, @typescript-eslint/type-utils@npm:^7.3.0": - version: 7.7.0 - resolution: "@typescript-eslint/type-utils@npm:7.7.0" +"@typescript-eslint/type-utils@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/type-utils@npm:7.4.0" + dependencies: + "@typescript-eslint/typescript-estree": "npm:7.4.0" + "@typescript-eslint/utils": "npm:7.4.0" + debug: "npm:^4.3.4" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + eslint: ^8.56.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/a8bd0929d8237679b2b8a7817f070a4b9658ee976882fba8ff37e4a70dd33f87793e1b157771104111fe8054eaa8ad437a010b6aa465072fbdb932647125db2d + languageName: node + linkType: hard + +"@typescript-eslint/type-utils@npm:^7.3.0": + version: 7.7.1 + resolution: "@typescript-eslint/type-utils@npm:7.7.1" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.7.0" - "@typescript-eslint/utils": "npm:7.7.0" + "@typescript-eslint/typescript-estree": "npm:7.7.1" + "@typescript-eslint/utils": "npm:7.7.1" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -12597,7 +12841,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/a3f5358b4b7046458ea573607f3d6ea7f48e16524390b24c9360bdf8b03cc89fc6eb5da31b3e541e7f1e5f6958194ecaad5b644ca9b0d90c9a7b182f345451aa + checksum: 10/c64dfd3e535741270012d289d1327e487df877adfa8a9920b1f8d6616f3b7159ef8ee1d6b62e866b6a5c64d675c5008e87f4ea20b5fc032e95f197a749d38ae6 languageName: node linkType: hard @@ -12622,10 +12866,17 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.7.0, @typescript-eslint/types@npm:^7.2.0": - version: 7.7.0 - resolution: "@typescript-eslint/types@npm:7.7.0" - checksum: 10/d54ff9eeea168188fcbf1c8efe42892d1646ead801ea0a0f1312c80cfb74ee5dd61a145bc982919fb396683fb4578f98f7ad90e5d466d7aa1ca593e4338e1a2e +"@typescript-eslint/types@npm:7.4.0, @typescript-eslint/types@npm:^7.2.0": + version: 7.4.0 + resolution: "@typescript-eslint/types@npm:7.4.0" + checksum: 10/2782c5bf65cd3dfa9cd32bc3023676bbca22144987c3f6c6b67fd96c73d4a60b85a57458c49fd11b9971ac6531824bb3ae0664491e7a6de25d80c523c9be92b7 + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/types@npm:7.7.1" + checksum: 10/a1ecbaf3b8a5243394d421644f2b3eb164feea645e36dd07f1afb5008598201f19c7988141fc162c647f380dda7cf571017c0eabbbc4c5432b0143383853e134 languageName: node linkType: hard @@ -12685,12 +12936,31 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.7.0" +"@typescript-eslint/typescript-estree@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.4.0" dependencies: - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" + debug: "npm:^4.3.4" + globby: "npm:^11.1.0" + is-glob: "npm:^4.0.3" + minimatch: "npm:9.0.3" + semver: "npm:^7.5.4" + ts-api-utils: "npm:^1.0.1" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/162ec9d7582f45588342e1be36fdb60e41f50bbdfbc3035c91b517ff5d45244f776921c88d88e543e1c7d0f1e6ada5474a8316b78f1b0e6d2233b101bc45b166 + languageName: node + linkType: hard + +"@typescript-eslint/typescript-estree@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/typescript-estree@npm:7.7.1" + dependencies: + "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/visitor-keys": "npm:7.7.1" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -12700,7 +12970,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/40af26b3edb07af439f99728aa149bbc8668dae4a700a128abaf98d7f9bc0d5d31f8027aa1d13d6a55b22c20738d7cab84a3046a56417a2551de58671b39dbdf + checksum: 10/df5fe6c573b15e8058b88d1535eeca11115118adc54225f511d2762d74e2d453205ba27e63f6666cb5f3dc73d639208a183fb05db1f75063b115d52b1fae3e20 languageName: node linkType: hard @@ -12721,20 +12991,37 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.7.0, @typescript-eslint/utils@npm:^7.3.0, @typescript-eslint/utils@npm:~7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/utils@npm:7.7.0" +"@typescript-eslint/utils@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/utils@npm:7.4.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@types/json-schema": "npm:^7.0.12" + "@types/semver": "npm:^7.5.0" + "@typescript-eslint/scope-manager": "npm:7.4.0" + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/typescript-estree": "npm:7.4.0" + semver: "npm:^7.5.4" + peerDependencies: + eslint: ^8.56.0 + checksum: 10/ffed27e770c486cd000ff892d9049b0afe8b9d6318452a5355b78a37436cbb414bceacae413a2ac813f3e584684825d5e0baa2e6376b7ad6013a108ac91bc19d + languageName: node + linkType: hard + +"@typescript-eslint/utils@npm:7.7.1, @typescript-eslint/utils@npm:^7.3.0, @typescript-eslint/utils@npm:~7.7.0": + version: 7.7.1 + resolution: "@typescript-eslint/utils@npm:7.7.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.15" "@types/semver": "npm:^7.5.8" - "@typescript-eslint/scope-manager": "npm:7.7.0" - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/typescript-estree": "npm:7.7.0" + "@typescript-eslint/scope-manager": "npm:7.7.1" + "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/typescript-estree": "npm:7.7.1" semver: "npm:^7.6.0" peerDependencies: eslint: ^8.56.0 - checksum: 10/4223233ee022460a74f389302b50779537dfbb3bd414486dca356d2628a08d5b2c4c6002bae3bdffad92b368569024faf25faee9be739340d9459c23549a866f + checksum: 10/5a352c3a849300b5d676bf5f451418a2fb0cd3ab515f3733521ad03cf047849c52c76f6e5d2406e08f6d0dbad3a4708b490f909c91a1a9e3d73060a750b3bca2 languageName: node linkType: hard @@ -12803,13 +13090,23 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.7.0" +"@typescript-eslint/visitor-keys@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.4.0" + dependencies: + "@typescript-eslint/types": "npm:7.4.0" + eslint-visitor-keys: "npm:^3.4.1" + checksum: 10/70dc99f2ad116c6e2d9e55af249e4453e06bba2ceea515adef2d2e86e97e557865bb1b1d467667462443eb0d624baba36f7442fd1082f3874339bbc381c26e93 + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/visitor-keys@npm:7.7.1" dependencies: - "@typescript-eslint/types": "npm:7.7.0" + "@typescript-eslint/types": "npm:7.7.1" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10/9f03591ab60b0b164f6bb222b5d5ae75f73fbe7f264be9318f770be9dc5dff8138d34701928940ffc18924058ae80754a738a1e623912a297d57a8a59cdfb41d + checksum: 10/dcc5748b10bb1b169516b33e87b6d86b562e25725a95e5ac515cb197589d9667aaa7cfffa93234095a73c80addb6dd88e2a9ab01d2be0c274254b5be1ca4057a languageName: node linkType: hard @@ -14778,9 +15075,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001587, caniuse-lite@npm:^1.0.30001591, caniuse-lite@npm:^1.0.30001599": - version: 1.0.30001612 - resolution: "caniuse-lite@npm:1.0.30001612" - checksum: 10/8fb95102aade9147694541a9e576ec16d8d455f37e1456f497403af45f1ddd24465a62057d619d57c052e9634e090e5115e383ab066f8f9f9b87d14f738f81df + version: 1.0.30001600 + resolution: "caniuse-lite@npm:1.0.30001600" + checksum: 10/4c52f83ed71bc5f6e443bd17923460f1c77915adc2c2aa79ddaedceccc690b5917054b0c41b79e9138cbbd9abcdc0db9e224e79e3e734e581dfec06505f3a2b4 languageName: node linkType: hard @@ -17102,6 +17399,15 @@ __metadata: languageName: node linkType: hard +"dot-prop@npm:^8.0.2": + version: 8.0.2 + resolution: "dot-prop@npm:8.0.2" + dependencies: + type-fest: "npm:^3.8.0" + checksum: 10/b321e43393c6efba35875c493ebfc6115d8a56c251431e88f055b82224e104c8a6eeb567877339715fb81cdbb67009bfa9cffb57cc423a560756874989dabb45 + languageName: node + linkType: hard + "dot@npm:^2.0.0-beta.1": version: 2.0.0-beta.1 resolution: "dot@npm:2.0.0-beta.1" @@ -17226,9 +17532,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.668": - version: 1.4.745 - resolution: "electron-to-chromium@npm:1.4.745" - checksum: 10/790c04406e09529845f77f1dd946156ca0ff129a5fb713a0b798ba19952b8109ec8e9b3894160267357a03a3df8bd10c1bfece9bf4143a89acfbc6f202ce7f48 + version: 1.4.717 + resolution: "electron-to-chromium@npm:1.4.717" + checksum: 10/ec5df5f0731cd4b7e42d93ab9d17ac5c53bc6c6a0cd298af090c96717652cc8962a72094fd602aff3245eb839712ed7a2587f4e0d90a6bf7834f105a06fefa85 languageName: node linkType: hard @@ -17469,6 +17775,13 @@ __metadata: languageName: node linkType: hard +"es-escape-html@npm:^0.1.1": + version: 0.1.1 + resolution: "es-escape-html@npm:0.1.1" + checksum: 10/26f5174516e40cb7856cb7d60fba202084c4cebc0910970b66aa2453325af2bc0bcb8b4f95bc909fba7feb37ebde4a3fbd204e4d59cacd9fdd64a2ffd6d2da30 + languageName: node + linkType: hard + "es-module-lexer@npm:^1.2.1, es-module-lexer@npm:^1.4.1": version: 1.5.0 resolution: "es-module-lexer@npm:1.5.0" @@ -17507,6 +17820,13 @@ __metadata: languageName: node linkType: hard +"es-vary@npm:^0.1.1": + version: 0.1.2 + resolution: "es-vary@npm:0.1.2" + checksum: 10/57135ad6f21c651d6f8e549e54878d44dd5d1bfb7be94edea7a51839c1a3cd59484d5b86e027e069c447c2bb322b83f6230ef74cd510e708ca2fc3dc12023eba + languageName: node + linkType: hard + "es6-promise@npm:^4.0.3": version: 4.2.8 resolution: "es6-promise@npm:4.2.8" @@ -18402,6 +18722,13 @@ __metadata: languageName: node linkType: hard +"eta@npm:^3.2.0": + version: 3.4.0 + resolution: "eta@npm:3.4.0" + checksum: 10/68040fb608086ce9148a3b2bb6f1b21ed9ed3cbede6690eba953cfb3bf40fca3f9690fa4b984a7446190878a6250bbe29de62ca8253ab2007753f53fc6491cb5 + languageName: node + linkType: hard + "etag@npm:~1.8.1": version: 1.8.1 resolution: "etag@npm:1.8.1" @@ -20053,6 +20380,13 @@ __metadata: languageName: node linkType: hard +"header-range-parser@npm:1.1.3, header-range-parser@npm:^1.1.3": + version: 1.1.3 + resolution: "header-range-parser@npm:1.1.3" + checksum: 10/e8e4cc11dda4b101e270ad0b8c30a94d5cdf11ca96846136b05c3b18357780d682b8cf0956031729f573df9731fbf46a935234e9b2ce33f472748a5a447cfac5 + languageName: node + linkType: hard + "highlight.js@npm:^11.8.0": version: 11.9.0 resolution: "highlight.js@npm:11.9.0" @@ -20576,6 +20910,13 @@ __metadata: languageName: node linkType: hard +"inflection@npm:^3.0.0": + version: 3.0.0 + resolution: "inflection@npm:3.0.0" + checksum: 10/e8aae6abb872a8aa19184a1b84470fff7120806329c78011befcf50bce04a7b0d65012ac373f2cc5caeaaf241874c7ae20a26038ff7dbe0cdae0b863f25b5e02 + languageName: node + linkType: hard + "inflight@npm:^1.0.4": version: 1.0.6 resolution: "inflight@npm:1.0.6" @@ -20765,10 +21106,10 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:^2.0.1": - version: 2.2.0 - resolution: "ipaddr.js@npm:2.2.0" - checksum: 10/9e1cdd9110b3bca5d910ab70d7fb1933e9c485d9b92cb14ef39f30c412ba3fe02a553921bf696efc7149cc653453c48ccf173adb996ec27d925f1f340f872986 +"ipaddr.js@npm:^2.0.1, ipaddr.js@npm:^2.1.0": + version: 2.1.0 + resolution: "ipaddr.js@npm:2.1.0" + checksum: 10/42c16d95cf451399707c2c46e605b88db1ea2b1477b25774b5a7ee96852b0bb1efdc01adbff01fedbe702ff246e1aca5c5e915a6f5a1f1485233a5f7c2eb73c2 languageName: node linkType: hard @@ -22194,6 +22535,28 @@ __metadata: languageName: node linkType: hard +"json-server@npm:^1.0.0-alpha.23": + version: 1.0.0-alpha.23 + resolution: "json-server@npm:1.0.0-alpha.23" + dependencies: + "@tinyhttp/app": "npm:^2.2.3" + "@tinyhttp/cors": "npm:^2.0.0" + chalk: "npm:^5.3.0" + chokidar: "npm:^3.5.3" + dot-prop: "npm:^8.0.2" + eta: "npm:^3.2.0" + inflection: "npm:^3.0.0" + json5: "npm:^2.2.3" + lowdb: "npm:^7.0.1" + milliparsec: "npm:^2.3.0" + sirv: "npm:^2.0.4" + sort-on: "npm:^6.0.0" + bin: + json-server: lib/bin.js + checksum: 10/75e24171046f4ef68728615922b3f376a7b555e22d1c2cef13f7fecc2030e469ba05e253058a2142750e59e27a0dc63b4519033b651a110025f9984635d2559c + languageName: node + linkType: hard + "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" @@ -23103,6 +23466,15 @@ __metadata: languageName: node linkType: hard +"lowdb@npm:^7.0.1": + version: 7.0.1 + resolution: "lowdb@npm:7.0.1" + dependencies: + steno: "npm:^4.0.2" + checksum: 10/089cb878515b3b4634980c77b1697991571832a440f0fbc8cabe410ff9bb22b377387fc6cf6ebd9a6430707a835ebd69561f89d30aae7def43c93410b6f82b58 + languageName: node + linkType: hard + "lower-case@npm:^2.0.2": version: 2.0.2 resolution: "lower-case@npm:2.0.2" @@ -23499,6 +23871,13 @@ __metadata: languageName: node linkType: hard +"milliparsec@npm:^2.3.0": + version: 2.3.0 + resolution: "milliparsec@npm:2.3.0" + checksum: 10/fa7df167714f39cf9c6e6479d4c83904a6f897a2e7f2a9114efbb63ca1c07bfce825c5c0e58c2aa19ca11b72c728e86a13e92bbd081123b87c756ead191f1a0e + languageName: node + linkType: hard + "mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2, mime-db@npm:^1.28.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -23524,6 +23903,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:4.0.1": + version: 4.0.1 + resolution: "mime@npm:4.0.1" + bin: + mime: bin/cli.js + checksum: 10/4598030457488c240a4ba30561a619cfb627f96271ecced5d715eb5c44d33105e3f28d28fe46d72eeadb78d7de5aeb1f8e62d448c14b0e518a7ace76d2af5f2d + languageName: node + linkType: hard + "mime@npm:^2.0.3": version: 2.6.0 resolution: "mime@npm:2.6.0" @@ -23842,7 +24230,7 @@ __metadata: languageName: node linkType: hard -"mrmime@npm:2.0.0": +"mrmime@npm:2.0.0, mrmime@npm:^2.0.0": version: 2.0.0 resolution: "mrmime@npm:2.0.0" checksum: 10/8d95f714ea200c6cf3e3777cbc6168be04b05ac510090a9b41eef5ec081efeb1d1de3e535ffb9c9689fffcc42f59864fd52a500e84a677274f070adeea615c45 @@ -24467,21 +24855,21 @@ __metadata: languageName: node linkType: hard -"nx@npm:18.3.3, nx@npm:^17.2.8 || ^18.0.0, nx@npm:~18.3.0": - version: 18.3.3 - resolution: "nx@npm:18.3.3" +"nx@npm:18.3.4, nx@npm:^17.2.8 || ^18.0.0, nx@npm:~18.3.0": + version: 18.3.4 + resolution: "nx@npm:18.3.4" dependencies: - "@nrwl/tao": "npm:18.3.3" - "@nx/nx-darwin-arm64": "npm:18.3.3" - "@nx/nx-darwin-x64": "npm:18.3.3" - "@nx/nx-freebsd-x64": "npm:18.3.3" - "@nx/nx-linux-arm-gnueabihf": "npm:18.3.3" - "@nx/nx-linux-arm64-gnu": "npm:18.3.3" - "@nx/nx-linux-arm64-musl": "npm:18.3.3" - "@nx/nx-linux-x64-gnu": "npm:18.3.3" - "@nx/nx-linux-x64-musl": "npm:18.3.3" - "@nx/nx-win32-arm64-msvc": "npm:18.3.3" - "@nx/nx-win32-x64-msvc": "npm:18.3.3" + "@nrwl/tao": "npm:18.3.4" + "@nx/nx-darwin-arm64": "npm:18.3.4" + "@nx/nx-darwin-x64": "npm:18.3.4" + "@nx/nx-freebsd-x64": "npm:18.3.4" + "@nx/nx-linux-arm-gnueabihf": "npm:18.3.4" + "@nx/nx-linux-arm64-gnu": "npm:18.3.4" + "@nx/nx-linux-arm64-musl": "npm:18.3.4" + "@nx/nx-linux-x64-gnu": "npm:18.3.4" + "@nx/nx-linux-x64-musl": "npm:18.3.4" + "@nx/nx-win32-arm64-msvc": "npm:18.3.4" + "@nx/nx-win32-x64-msvc": "npm:18.3.4" "@yarnpkg/lockfile": "npm:^1.1.0" "@yarnpkg/parsers": "npm:3.0.0-rc.46" "@zkochan/js-yaml": "npm:0.0.6" @@ -24547,7 +24935,7 @@ __metadata: bin: nx: bin/nx.js nx-cloud: bin/nx-cloud.js - checksum: 10/8dd21404db1cc4b0fda34d7b2fe2074b3e748cefae2930211bdc19b7b3e67d413e8c675d6ba5b5549cd151b726dcbca662b5c0546f69459ac9c864023e02c195 + checksum: 10/7f1255c04ad4a558f3eed0d134742742d5571cf25628cb7acb178f70b3c5561bdfd6f5dee634625df6dba93edc02900a2eb139439eaa262c59f05985b11d6dd0 languageName: node linkType: hard @@ -27097,6 +27485,13 @@ __metadata: languageName: node linkType: hard +"regexparam@npm:^2.0.1": + version: 2.0.2 + resolution: "regexparam@npm:2.0.2" + checksum: 10/e7d6ae57a528a291392fa8c56705aa42f9f20107811930e82153b73836a3793b6ca0cc9016f0cc5abb7b85f6edccba3735701fb336d50e3e322025fbfc87899b + languageName: node + linkType: hard + "regexpu-core@npm:^5.3.1": version: 5.3.2 resolution: "regexpu-core@npm:5.3.2" @@ -28102,6 +28497,17 @@ __metadata: languageName: node linkType: hard +"sirv@npm:^2.0.4": + version: 2.0.4 + resolution: "sirv@npm:2.0.4" + dependencies: + "@polka/url": "npm:^1.0.0-next.24" + mrmime: "npm:^2.0.0" + totalist: "npm:^3.0.0" + checksum: 10/24f42cf06895017e589c9d16fc3f1c6c07fe8b0dbafce8a8b46322cfba67b7f2498610183954cb0e9d089c8cb60002a7ee7e8bca6a91a0d7042bfbc3473c95c3 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -28247,6 +28653,15 @@ __metadata: languageName: node linkType: hard +"sort-on@npm:^6.0.0": + version: 6.0.0 + resolution: "sort-on@npm:6.0.0" + dependencies: + dot-prop: "npm:^8.0.2" + checksum: 10/4734aac689fae97cc03bf34a37ad7f6bd21fba24df7cadbbd76273c37f26f7944b4322b4baec1ab5d8d8f4aa033b50c08971b2fba6051cf4646dc68b286da4e1 + languageName: node + linkType: hard + "source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.0": version: 1.2.0 resolution: "source-map-js@npm:1.2.0" @@ -28588,6 +29003,13 @@ __metadata: languageName: node linkType: hard +"steno@npm:^4.0.2": + version: 4.0.2 + resolution: "steno@npm:4.0.2" + checksum: 10/cb8beb6b6da410f6a307261da813e57569ff3c85b11695437259f49f081fc6b0eeb26c059f0ec661c4098a09f361057fe834b04d3f94ece885e96a9e0eeba697 + languageName: node + linkType: hard + "stoppable@npm:^1.1.0": version: 1.1.0 resolution: "stoppable@npm:1.1.0" @@ -28929,8 +29351,8 @@ __metadata: linkType: hard "stylelint@npm:^16.0.2": - version: 16.3.1 - resolution: "stylelint@npm:16.3.1" + version: 16.3.0 + resolution: "stylelint@npm:16.3.0" dependencies: "@csstools/css-parser-algorithms": "npm:^2.6.1" "@csstools/css-tokenizer": "npm:^2.2.4" @@ -28973,7 +29395,7 @@ __metadata: write-file-atomic: "npm:^5.0.1" bin: stylelint: bin/stylelint.mjs - checksum: 10/2dbc040512a7a97d4565de7af3289e7ecdf2a56d9174c253ad18c6aef55cd221731240e89c9b8c52bb9894205fe3929e06a6d8c8269e130e8947952210db4e68 + checksum: 10/6d765ae2d7c13e9aed39e3b830e039ca4f3ac580abfdbde5dfa25b7659ecf4c4cb046010011319de18024c7d2081d9355125c6bfb7f763b255773005feca6444 languageName: node linkType: hard @@ -29505,6 +29927,13 @@ __metadata: languageName: node linkType: hard +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 10/5132d562cf88ff93fd710770a92f31dbe67cc19b5c6ccae2efc0da327f0954d211bbfd9456389655d726c624f284b4a23112f56d1da931ca7cfabbe1f45e778a + languageName: node + linkType: hard + "tough-cookie@npm:^2.3.3, tough-cookie@npm:~2.5.0": version: 2.5.0 resolution: "tough-cookie@npm:2.5.0" @@ -29931,10 +30360,17 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^3.8.0": + version: 3.13.1 + resolution: "type-fest@npm:3.13.1" + checksum: 10/9a8a2359ada34c9b3affcaf3a8f73ee14c52779e89950db337ce66fb74c3399776c697c99f2532e9b16e10e61cfdba3b1c19daffb93b338b742f0acd0117ce12 + languageName: node + linkType: hard + "type-fest@npm:^4.10.2": - version: 4.15.0 - resolution: "type-fest@npm:4.15.0" - checksum: 10/8f897551877daa0df7bb17a21b6acd8a21ac5a0bdb14dbfd353b16013fed99f23c6d9c12a2c7685c8dededb4739ec8bfb120a914330f8b11a478a89758a11acc + version: 4.14.0 + resolution: "type-fest@npm:4.14.0" + checksum: 10/fcf3b62fed194a3fc3d22bf287af3b1e1e93d4b5cb9723c093b694998d1588f27cc78dc4942ff4d319bb94ec60cb4afe5d1cd3d50ef144e47e327acbc34a5234 languageName: node linkType: hard @@ -30805,7 +31241,7 @@ __metadata: languageName: node linkType: hard -"webpack-dev-middleware@npm:6.1.2": +"webpack-dev-middleware@npm:6.1.2, webpack-dev-middleware@npm:^6.1.1": version: 6.1.2 resolution: "webpack-dev-middleware@npm:6.1.2" dependencies: @@ -30838,24 +31274,6 @@ __metadata: languageName: node linkType: hard -"webpack-dev-middleware@npm:^6.1.1": - version: 6.1.3 - resolution: "webpack-dev-middleware@npm:6.1.3" - dependencies: - colorette: "npm:^2.0.10" - memfs: "npm:^3.4.12" - mime-types: "npm:^2.1.31" - range-parser: "npm:^1.2.1" - schema-utils: "npm:^4.0.0" - peerDependencies: - webpack: ^5.0.0 - peerDependenciesMeta: - webpack: - optional: true - checksum: 10/ee699430c33c4dfa2a016becc85e32a9b04aa0b6edbce0bb173c4dfd29c80c77d192d14fd2f2ec500dbdede4e0f1c5557993aa20a04a44190750a1e8e13f6d67 - languageName: node - linkType: hard - "webpack-dev-server@npm:4.15.1": version: 4.15.1 resolution: "webpack-dev-server@npm:4.15.1"