Skip to content

Commit 5964543

Browse files
author
Gérard Collin
committed
fix: added list details flow
1 parent 340a0bd commit 5964543

5 files changed

Lines changed: 648 additions & 3 deletions

File tree

plugins/xt-workflow/angular.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"cli": {
66
"cache": {
77
"enabled": true
8-
}
8+
},
9+
"analytics": "0b06612f-da87-425d-9f86-23d7d5349701"
910
},
1011
"projects": {
1112
"workflow": {
@@ -30,7 +31,7 @@
3031
"defaultConfiguration": "development"
3132
},
3233
"test": {
33-
"builder": "@angular-builders/jest:run",
34+
"builder": "@analogjs/vitest-angular:test",
3435
"options": {
3536
"tsConfig": "projects/workflow/tsconfig.spec.json",
3637
"polyfills": [
@@ -56,7 +57,10 @@
5657
"outputPath": "dist/workflow-plugin",
5758
"index": "projects/workflow-plugin/src/index.html",
5859
"browser": "projects/workflow-plugin/src/main.ts",
59-
"polyfills": [],
60+
"preserveSymlinks": true,
61+
"polyfills": [
62+
"es-module-shims"
63+
],
6064
"tsConfig": "projects/workflow-plugin/tsconfig.app.json",
6165
"inlineStyleLanguage": "css",
6266
"assets": [
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
:host {
2+
display: block;
3+
}
4+
5+
.list-details {
6+
display: flex;
7+
flex-direction: column;
8+
gap: 1rem;
9+
}
10+
11+
.list-details__header {
12+
display: flex;
13+
flex-direction: column;
14+
gap: 1rem;
15+
}
16+
17+
.list-details__heading {
18+
display: flex;
19+
flex-direction: column;
20+
gap: 0.25rem;
21+
}
22+
23+
.list-details__title {
24+
margin: 0;
25+
font-size: clamp(1.4rem, 2vw, 2rem);
26+
font-weight: 700;
27+
letter-spacing: -0.03em;
28+
}
29+
30+
.list-details__subtitle {
31+
margin: 0;
32+
opacity: 0.72;
33+
font-size: 0.95rem;
34+
}
35+
36+
.list-details__toolbar {
37+
border-radius: 1.25rem;
38+
padding: 0.85rem 1rem;
39+
box-shadow: 0 1px 2px rgb(0 0 0 / 0.04), 0 10px 28px rgb(0 0 0 / 0.05);
40+
}
41+
42+
.list-details__actions {
43+
display: flex;
44+
flex-wrap: wrap;
45+
gap: 0.75rem;
46+
align-items: center;
47+
}
48+
49+
.list-details__tabs {
50+
display: block;
51+
border-radius: 1.25rem;
52+
}
53+
54+
.list-details__panels {
55+
background: none;
56+
}
57+
58+
.list-details__panel {
59+
border-radius: 1.5rem;
60+
background: color-mix(in srgb, var(--p-surface-0) 92%, var(--p-primary-50) 8%);
61+
box-shadow: 0 1px 2px rgb(0 0 0 / 0.04), 0 14px 40px rgb(0 0 0 / 0.06);
62+
}
63+
64+
.list-details__form {
65+
min-width: 0;
66+
}
67+
68+
.list-details__state {
69+
min-height: 18rem;
70+
display: flex;
71+
flex-direction: column;
72+
justify-content: center;
73+
align-items: center;
74+
gap: 0.75rem;
75+
text-align: center;
76+
border-radius: 1.5rem;
77+
padding: 2rem;
78+
background: color-mix(in srgb, var(--p-surface-0) 94%, var(--p-primary-50) 6%);
79+
color: var(--p-text-color);
80+
}
81+
82+
.list-details__state i {
83+
font-size: 2rem;
84+
opacity: 0.55;
85+
}
86+
87+
.list-details__state span {
88+
font-weight: 600;
89+
}
90+
91+
.list-details__state small {
92+
opacity: 0.7;
93+
}
94+
95+
.list-details__state--empty {
96+
min-height: 16rem;
97+
}
98+
99+
.list-details--empty {
100+
padding-top: 0.5rem;
101+
}
102+
103+
:host-context(.app-dark) .list-details__panel,
104+
:host-context(.app-dark) .list-details__state {
105+
background: color-mix(in srgb, var(--p-surface-900) 94%, var(--p-primary-950) 6%);
106+
}
107+
108+
@media (max-width: 767px) {
109+
.list-details__toolbar {
110+
padding: 0.75rem 0.85rem;
111+
}
112+
113+
.list-details__actions {
114+
width: 100%;
115+
}
116+
117+
.list-details__actions > * {
118+
flex: 1 1 auto;
119+
}
120+
121+
.list-details__state {
122+
min-height: 14rem;
123+
padding: 1.5rem;
124+
}
125+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
@let entName = entityName();
2+
3+
@if (entName != null) {
4+
<section class="list-details">
5+
<header class="list-details__header">
6+
<div class="list-details__heading">
7+
<h1 class="list-details__title">{{ entName }}</h1>
8+
<p class="list-details__subtitle">
9+
Manage records, edit selected items, and keep the list in sync.
10+
</p>
11+
</div>
12+
13+
<p-toolbar class="list-details__toolbar">
14+
<ng-template #center>
15+
<div class="list-details__actions">
16+
<p-button
17+
id="btn-new"
18+
icon="pi pi-plus"
19+
label="New"
20+
severity="secondary"
21+
[loading]="newing()"
22+
(onClick)="newEntity()">
23+
</p-button>
24+
25+
<p-button
26+
id="btn-reload"
27+
icon="pi pi-refresh"
28+
label="Reload"
29+
severity="secondary"
30+
[disabled]="!canReload()"
31+
[loading]="updating()"
32+
(onClick)="reloadList()">
33+
</p-button>
34+
35+
<p-button
36+
id="btn-delete"
37+
icon="pi pi-trash"
38+
label="Delete"
39+
severity="danger"
40+
[disabled]="!selectedEntity()"
41+
[loading]="deleting()"
42+
(onClick)="deleteSelected()">
43+
</p-button>
44+
45+
<p-button
46+
id="btn-save"
47+
icon="pi pi-save"
48+
label="Save"
49+
[disabled]="!canSave()"
50+
[loading]="saving()"
51+
(onClick)="save()">
52+
</p-button>
53+
</div>
54+
</ng-template>
55+
</p-toolbar>
56+
</header>
57+
58+
<p-tabs [value]="viewMode()" class="list-details__tabs">
59+
<p-tablist>
60+
<p-tab value="list">List</p-tab>
61+
<p-tab value="edit" [disabled]="!canEdit()">Edit</p-tab>
62+
</p-tablist>
63+
64+
<p-tabpanels class="list-details__panels">
65+
<p-tabpanel value="list">
66+
@if (store?.loading()) {
67+
<div class="list-details__state">
68+
<p-progress-spinner />
69+
<span>Loading {{ entName }}…</span>
70+
</div>
71+
} @else if ((store?.entities()?.length ?? 0) === 0) {
72+
<div class="list-details__state list-details__state--empty">
73+
<i class="pi pi-inbox"></i>
74+
<span>No entity found.</span>
75+
<small>Try creating a new item with the toolbar above.</small>
76+
</div>
77+
} @else {
78+
<div class="list-details__panel">
79+
<xt-render
80+
displayMode="LIST_VIEW"
81+
[value]="store?.entities()"
82+
(models)="listModelChanged($event)" [models]="listModel"
83+
[valueType]="entityName()">
84+
</xt-render>
85+
</div>
86+
}
87+
</p-tabpanel>
88+
89+
<p-tabpanel value="edit">
90+
@if (canEdit()) {
91+
@let mainForm = editForm();
92+
<div class="list-details__panel">
93+
<div [formGroup]="mainForm" class="list-details__form">
94+
<xt-render
95+
displayMode="FULL_EDITABLE"
96+
[formGroup]="mainForm"
97+
subName="editor"
98+
[valueType]="entityName()">
99+
</xt-render>
100+
</div>
101+
</div>
102+
}
103+
</p-tabpanel>
104+
</p-tabpanels>
105+
</p-tabs>
106+
</section>
107+
} @else {
108+
<section class="list-details list-details--empty">
109+
<div class="list-details__state list-details__state--empty">
110+
<i class="pi pi-database"></i>
111+
<span>No entity to manage.</span>
112+
</div>
113+
</section>
114+
}

0 commit comments

Comments
 (0)