Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DcWorkflow } from '../definition/dc-workflow';
import { Component, computed, effect, inject, input } from '@angular/core';
import { Component, computed, effect, inject, input, linkedSignal, signal } from '@angular/core';
import { DcWorkflowModel, DcWorkflowSortOption } from '../models/dc-workflow-model';
import { XtCompositeComponent, XtResolverService } from 'xt-components';
import { XtCompositeComponent, XtMessageHandler, XtResolverService } from 'xt-components';
import {
XtSignalStore,
XtSortBy,
Expand All @@ -10,6 +10,7 @@ import {
XtStoreManagerService
} from 'xt-store';
import { ManagedData } from 'xt-type';
import { FormGroup } from '@angular/forms';

/**
* A workflow base class based on the xt-store signalStore
Expand All @@ -28,9 +29,37 @@ export class AbstractDcWorkflow<T extends ManagedData=ManagedData> extends XtCom

protected readonly resolver = inject (XtResolverService);
protected readonly storeMgr = inject(XtStoreManagerService);
protected readonly errorHandler = inject(XtMessageHandler);


/**
* The store that manages the access to the data
* @protected
*/
protected store : XtSignalStore<T> | null | undefined = undefined;

/**
* True whenever the store is updating something
*/
updating = signal (false);

/**
* A shortcut to the entityname being managed
*/
entityName = linkedSignal( () => {
return this.config().entity;
});

/**
* A simple signal telling when a new store is being used. For example, when the entity handled has changed
* @protected
*/
protected storeChanged=signal<boolean>(false);

/**
* Triggered when the workflow config has been updated. Do we need another store, or just reconfigure the sort / filtering ?
* @protected
*/
protected configUpdated = effect( async ()=> {
const config = this.config();
const curStore = this.store;
Expand Down Expand Up @@ -68,6 +97,7 @@ export class AbstractDcWorkflow<T extends ManagedData=ManagedData> extends XtCom
* @protected
*/
protected displayableElements = computed(() => {
const enforceStoreChange = this.storeChanged(); // Recalculate in case the store has changed
const config = this.config();
const entities = this.safeFindStore().entities();
const selectConfig = config.display;
Expand All @@ -87,7 +117,37 @@ export class AbstractDcWorkflow<T extends ManagedData=ManagedData> extends XtCom
return true;
});
});
/**

/**
* Safely loads the data from the store.
*/
protected fetchFromStore () {
//console.debug("ListDetails fetchFromStore");
const entityName = this.entityName();
if (entityName!=null) {
try {
this.updating.set(true);
// If the entity is different, then we must change the whole store
if (this.store?.entityName()!=entityName) {
this.store = this.safeFindStore();
this.storeChanged.update((oldVal)=> !oldVal); // Force update whenever the store changed
}
// console.debug("Store set to "+this.store.entityName());
this.store.fetchEntities().catch((error) => {
this.errorHandler.errorOccurred(error, "Error loading entities "+entityName);
}).finally(() => {
this.updating.set(false);
// console.debug("Store fetched values ",this.store?.entities());
});//.then(() => {console.debug('Yes')}).finally(() => {console.debug('Finish')});
} catch (error) {
this.updating.set(false);
}
} else {
this.store = null;
}
}

/**
* Returns the element that should be selected given the config and the store content
* @protected
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { XtTypeInfo } from 'xt-type';
import { XtOutputType } from '../xt-component';
import { XtActionHandler } from '../action/xt-action-handler';
import { XtWorkflow } from '../workflow/xt-workflow';

/** Information about a registered component plugin */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { beforeEach, describe, expect, it } from 'vitest';
import { xtPluginRegistry } from '../../globals';
import { XtActionHandler, XtActionResult } from '../action/xt-action-handler';
import { XtContext } from '../xt-context';
import { IStoreProvider } from '../store/store-support';

describe('XtPluginRegistry', () => {

Expand Down
51 changes: 50 additions & 1 deletion plugins/xt-default/projects/default-plugin/src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,64 @@ import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { providePrimeNG } from 'primeng/config';
import { definePreset } from '@primeuix/themes';
import Aura from '@primeuix/themes/aura';

const AppPreset = definePreset(Aura, {
semantic: {
colorScheme: {
light: {
surface: {
0: '#ffffff',
50: '#f8f8fc',
100: '#efeff8',
200: '#dedff0',
300: '#c4c7df',
400: '#9aa0bf',
500: '#747b9a',
600: '#5a607a',
700: '#42475b',
800: '#2a2f3c',
900: '#171a22',
950: '#0b0d12'
},
content: {
background: '{surface.50}'
}
},
dark: {
surface: {
950: '#101118',
900: '#171923',
800: '#222737',
700: '#333a52',
600: '#48506c',
500: '#66708c',
400: '#97a0b8',
300: '#c4cadb',
200: '#e2e6f0',
100: '#f3f5fa',
50: '#fafbfe',
0: '#ffffff'
},
content: {
background: '{surface.950}'
}
}
}
}
});

export const appConfig: ApplicationConfig = {
providers: [provideZonelessChangeDetection(),
provideBrowserGlobalErrorListeners(),
provideAnimationsAsync(),
providePrimeNG({
theme: {
preset: Aura
preset: AppPreset,
options: {
darkModeSelector: '.app-dark'
}
}
}),
provideRouter(routes)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.list_view_container {
padding: 4rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@
<div class="m-3" id="TypeSelector">
<p-autocomplete [suggestions]="listOfObjects()" [ngModel]="selectedObject()" (onSelect)="objectSwitch($event)" [dropdown]="true"></p-autocomplete>
</div>
<label class="text-xl m-3" for="ComponentSelector">Select the component to use</label>
<div class="m-3" id="ComponentSelector">
<p-autocomplete [suggestions]="componentOptions()" [ngModel]="selectedComponent()" (onSelect)="componentSwitch($event)" [dropdown]="true"></p-autocomplete>
</div>
</p-panel>
<p-panel header="List View Mode">
<xt-render id="listView" [componentType]="objectComponentType()" displayMode="LIST_VIEW" (outputs)="componentOutputChange($event)" [valueType]="valueType()" [value]="value()" ></xt-render>
<span class="m-3 mt-6">Selected element is {{selectedValue() | json}}</span>
</p-panel>
<div class="list_view_container">
<span class="text-2xl">List View</span>
<xt-render id="listView" [componentType]="objectComponentType()" displayMode="LIST_VIEW" [models]="{valueSelected: selectedModel}" [valueType]="valueType()" [value]="value()" ></xt-render>
<span class="m-3 mt-6">Selected element is {{selectedModel() | json}}</span>
</div>
</div>

Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, model, signal } from '@angular/core';
import { AutoComplete, AutoCompleteSelectEvent } from 'primeng/autocomplete';
import { JsonPipe } from '@angular/common';
import { XtComponentOutput, XtRenderComponent } from 'xt-components';
import { XtRenderComponent } from 'xt-components';
import { FormsModule } from '@angular/forms';
import { Panel } from 'primeng/panel';
import { DefaultObjectSetComponent } from '../../../../default/src/lib/object-set/default-object-set.component';
import { CarouselObjectSetComponent } from '../../../../default/src/lib/object-set/carousel-object-set.component';
import { AppComponent } from '../app.component';

@Component({
Expand All @@ -21,7 +22,13 @@ import { AppComponent } from '../app.component';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestObjectSetComponent {
selectedObject= signal<string>('simple');
selectedObject = signal<string>('simple');

selectedComponent = signal<string>('Default');

componentOptions() {
return ['Default', 'Carousel'];
}

value = signal<any>(this.loadObject('simple') );

Expand All @@ -34,6 +41,10 @@ export class TestObjectSetComponent {
this.value.set(this.loadObject ($event.value));
}

componentSwitch($event: AutoCompleteSelectEvent) {
this.selectedComponent.set($event.value);
}

loadObject (objName:string) :any {
if (objName=='long') {
const ret = [];
Expand Down Expand Up @@ -119,21 +130,13 @@ export class TestObjectSetComponent {
}[objName];
}

objectComponentType() {
return DefaultObjectSetComponent;
}

selectedValue = signal<any>(null);
objectComponentType = computed(() =>
this.selectedComponent() === 'Carousel' ? CarouselObjectSetComponent : DefaultObjectSetComponent
);

componentOutputChange (newOutput:XtComponentOutput|null) {
if (newOutput?.valueSelected!=null) {
newOutput.valueSelected.subscribe ((value) => {
this.selectedValue.set(value);
})
}
}
selectedModel = model<any>(null);

valueType= computed(() => {
valueType = computed(() => {
const displayedType=this.selectedObject();
return displayedType=='references'?'bookType':undefined;
});
Expand Down
6 changes: 6 additions & 0 deletions plugins/xt-default/projects/default-plugin/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,11 @@ import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';

const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
document.documentElement.classList.toggle('app-dark', prefersDark.matches);
prefersDark.addEventListener('change', (e) => {
document.documentElement.classList.toggle('app-dark', e.matches);
});

bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
:host {
display: block;
margin: 0 auto;
max-width: 100vw;

}

:host ::ng-deep .p-carousel-viewport {
max-height: 30vh;
padding: 1.5rem 0.5rem;
}

.carousel-object-set__panel {
cursor: pointer;
border: 2px solid transparent;
border-radius: 0.75rem;
padding: 1rem;
min-width: 0;
transition:
transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
border-color 0.2s ease,
box-shadow 0.2s ease;
background: var(--p-content-background);
}

.carousel-object-set__panel:hover {
border-color: var(--p-primary-200);
}

.carousel-object-set__panel--selected {
border-color: var(--p-primary-400);
box-shadow: 0 0 0 1px var(--p-primary-400), 0 2px 8px rgba(0, 0, 0, 0.08);
}

.carousel-object-set__panel--selected-scale {
transform: scale(1.12);
}

@media (max-width: 600px) {
:host ::ng-deep .p-carousel-viewport {
max-height: 65vh;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<p-carousel #carouselRef [value]="valueSet()" [numVisible]="numVisible()" [numScroll]="1" [orientation]="carouselOrientation()" contentClass="carousel-object-set" (onPage)="onCarouselPage($event)">
<ng-template #item let-elt let-i="rowIndex">
@let isSelected = selectedElement() === elt;
@let isHorizontal = carouselOrientation() === 'horizontal';
<div class="carousel-object-set__panel"
[class.carousel-object-set__panel--selected]="isSelected"
[class.carousel-object-set__panel--selected-scale]="isSelected && isHorizontal"
(click)="selectionChange(elt)">
<xt-render displayMode="FULL_VIEW" [value]="elt" [valueType]="valueType()">
</xt-render>
</div>
</ng-template>
</p-carousel>
Loading