Skip to content
Draft
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
151 changes: 110 additions & 41 deletions package-lock.json

Large diffs are not rendered by default.

65 changes: 64 additions & 1 deletion src/app/app.navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,48 @@ const messageBarNavigationItem: NavigationItem = {
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.messageBar)
}

const asyncResultNavigationItem: NavigationItem = {
label: 'navigation.async_result',
icon: 'fa-solid fa-spinner',
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.asyncResult)
}

const fileDownloadNavigationItem: NavigationItem = {
label: 'navigation.file_download',
icon: 'fa-solid fa-download',
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.fileDownload)
}

const draggableDialogNavigationItem: NavigationItem = {
label: 'navigation.draggable_dialog',
icon: 'fa-solid fa-arrows-up-down-left-right',
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.draggableDialog)
}

const formsDemoNavigationItem: NavigationItem = {
label: 'navigation.forms_demo',
icon: 'fa-solid fa-pen-to-square',
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.formsDemo)
}

const routeMapNavigationItem: NavigationItem = {
label: 'navigation.route_map',
icon: 'fa-solid fa-route',
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.routeMap)
}

const signalStoreNavigationItem: NavigationItem = {
label: 'navigation.signal_store',
icon: 'fa-solid fa-database',
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.signalStore)
}

const utilsDemoNavigationItem: NavigationItem = {
label: 'navigation.utils_demo',
icon: 'fa-solid fa-wrench',
fullRouterPath: getFullRoutePath(ROUTE_MAP.components.utilsDemo)
}

const componentsNavigationItemContainer: NavigationItem = {
label: 'navigation.components',
icon: 'fa-solid fa-cubes',
Expand All @@ -46,7 +88,14 @@ const componentsNavigationItemContainer: NavigationItem = {
expandableCardNavigationItem,
tableNavigationItem,
formTableNavigationItem,
messageBarNavigationItem
messageBarNavigationItem,
asyncResultNavigationItem,
fileDownloadNavigationItem,
draggableDialogNavigationItem,
formsDemoNavigationItem,
routeMapNavigationItem,
signalStoreNavigationItem,
utilsDemoNavigationItem
]
}

Expand All @@ -62,6 +111,18 @@ const globalErrorHandlerNavigationItem: NavigationItem = {
fullRouterPath: getFullRoutePath(ROUTE_MAP.globalErrorHandler)
}

const subscriptionHandlingNavigationItem: NavigationItem = {
label: 'navigation.subscription_handling',
icon: 'fa-solid fa-link-slash',
fullRouterPath: getFullRoutePath(ROUTE_MAP.subscriptionHandling)
}

const localStorageNavigationItem: NavigationItem = {
label: 'navigation.local_storage',
icon: 'fa-solid fa-hard-drive',
fullRouterPath: getFullRoutePath(ROUTE_MAP.localStorage)
}

const peoplewareWebsiteNavigationItem: NavigationItem = {
label: 'navigation.peopleware_website',
icon: 'fa-solid fa-earth-europe',
Expand All @@ -74,6 +135,8 @@ export const getNavigationItems = () => {
dashboardNavigationItem,
componentsNavigationItemContainer,
inMemoryLoggingNavigationItem,
subscriptionHandlingNavigationItem,
localStorageNavigationItem,
globalErrorHandlerNavigationItem,
peoplewareWebsiteNavigationItem
]
Expand Down
25 changes: 23 additions & 2 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ export const ROUTE_MAP = {
expandableCard: defineRoute('expandable-card'),
table: defineRoute('table'),
formTable: defineRoute('form-table'),
messageBar: defineRoute('message-bar')
messageBar: defineRoute('message-bar'),
asyncResult: defineRoute('async-result'),
fileDownload: defineRoute('file-download'),
draggableDialog: defineRoute('draggable-dialog'),
formsDemo: defineRoute('forms'),
routeMap: defineRoute('route-map'),
signalStore: defineRoute('signal-store'),
utilsDemo: defineRoute('utils')
}),
dashboardItem: defineRoute('dashboard-item'),
globalErrorHandler: defineRoute('global-error-handler'),
inMemoryLogging: defineRoute('in-memory-logging')
inMemoryLogging: defineRoute('in-memory-logging'),
subscriptionHandling: defineRoute('subscription-handling'),
localStorage: defineRoute('local-storage')
}

export const routes: Routes = [
Expand All @@ -43,5 +52,17 @@ export const routes: Routes = [
path: getRouteSegment(ROUTE_MAP.globalErrorHandler),
component: GlobalErrorHandlerComponent,
title: 'navigation.global_error_handler'
},
{
path: getRouteSegment(ROUTE_MAP.subscriptionHandling),
loadComponent: () =>
import('./subscription-handling-demo/subscription-handling-demo.component').then((m) => m.SubscriptionHandlingDemoComponent),
title: 'navigation.subscription_handling'
},
{
path: getRouteSegment(ROUTE_MAP.localStorage),
loadComponent: () =>
import('./local-storage-demo/local-storage-demo.component').then((m) => m.LocalStorageDemoComponent),
title: 'navigation.local_storage'
}
]
33 changes: 33 additions & 0 deletions src/app/async-result-demo/async-result-demo.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div class="flex-column gap-16">
<p>Use the buttons below to switch between AsyncResult states. Demonstrates createSuccessAsyncResult, createFailedAsyncResult, executeAsyncOperation, and isAsyncResult.</p>
<div class="flex-row gap-8 flex-wrap">
<button mat-flat-button (click)="setInitial()">Initial</button>
<button mat-flat-button (click)="setSuccess()">Success</button>
<button mat-flat-button (click)="setEmpty()">Empty</button>
<button mat-flat-button (click)="setFailed()">Failed</button>
<button mat-flat-button (click)="simulateLoad()" [disabled]="isLoading$ | async">Simulate load</button>
<button mat-flat-button (click)="checkIsAsyncResult()">Check isAsyncResult</button>
</div>
@if (isAsyncResultGuardResult(); as msg) {
@if (msg) {
<p><strong>isAsyncResult guard:</strong> {{ msg }}</p>
}
}
<ppw-async-result [asyncResult]="asyncResult()" [pending]="isLoading$ | async">
<ng-template ppwAsyncResultInitial>
<p>Click a button above or "Simulate load" to see content.</p>
</ng-template>
<ng-template ppwAsyncResultSuccess [contextTyper]="asyncResult" let-data>
@if (data.entity; as items) {
<ul>
@for (item of items; track item.id) {
<li>{{ item.name }}</li>
}
</ul>
}
</ng-template>
<ng-template ppwAsyncResultEmpty>
<p>No items.</p>
</ng-template>
</ppw-async-result>
</div>
3 changes: 3 additions & 0 deletions src/app/async-result-demo/async-result-demo.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
83 changes: 83 additions & 0 deletions src/app/async-result-demo/async-result-demo.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { AsyncPipe } from '@angular/common'
import { ChangeDetectionStrategy, Component, signal } from '@angular/core'
import { MatButtonModule } from '@angular/material/button'
import { AsyncResultModule, createFailedAsyncResult, createSuccessAsyncResult, AsyncResult, isAsyncResult } from '@ppwcode/ng-async'
import { BehaviorSubject } from 'rxjs'
import { delay, map, of } from 'rxjs'
import { executeAsyncOperation } from '@ppwcode/ng-async'

interface DemoItem {
id: number
name: string
}

@Component({
selector: 'ppw-async-result-demo',
standalone: true,
imports: [AsyncResultModule, MatButtonModule, AsyncPipe],
templateUrl: './async-result-demo.component.html',
styleUrl: './async-result-demo.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AsyncResultDemoComponent {
readonly asyncResult = signal<AsyncResult<DemoItem[] | null, null> | null>(null)
readonly isAsyncResultGuardResult = signal<string>('')

readonly isLoading$ = new BehaviorSubject<boolean>(false)

setInitial(): void {
this.asyncResult.set({
status: 'initial',
entity: null,
filters: null
})
this.isLoading$.next(false)
}

setSuccess(): void {
this.asyncResult.set(
createSuccessAsyncResult<DemoItem[], null>([
{ id: 1, name: 'Alpha' },
{ id: 2, name: 'Beta' }
])
)
this.isLoading$.next(false)
}

setEmpty(): void {
this.asyncResult.set(createSuccessAsyncResult<DemoItem[] | null>(null))
this.isLoading$.next(false)
}

setFailed(): void {
this.asyncResult.set(
createFailedAsyncResult(new Error('Something went wrong'), [], null)
)
this.isLoading$.next(false)
}

async simulateLoad(): Promise<void> {
const result$ = of(
createSuccessAsyncResult<DemoItem[], null>([{ id: 1, name: 'Loaded' }])
).pipe(
delay(1500),
map((r) => r)
)
await executeAsyncOperation(
result$,
{
success: (r) => this.asyncResult.set(r),
error: (r) => this.asyncResult.set(r)
},
this.isLoading$,
true,
false
)
}

checkIsAsyncResult(): void {
const current = this.asyncResult()
const result = isAsyncResult(current) ? `Yes, status: ${current.status}` : 'No'
this.isAsyncResultGuardResult.set(result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MatProgressSpinner } from '@angular/material/progress-spinner'
import { Router } from '@angular/router'
import { DashboardItem, DashboardItemAction, DashboardItemsTableComponent } from '@ppwcode/ng-common-components'
import { getFullRoutePath } from '@ppwcode/ng-router'
import type { RouteMapRoute } from '@ppwcode/ng-router'
import { ROUTE_MAP } from '../app.routes'

@Component({
Expand All @@ -23,7 +24,16 @@ export default class ComponentsDashboardDemoComponent {
this.#getConfirmationDemoItem(),
this.#getExpandableCardDemoItem(),
this.#getTableDemoItem(),
this.#getMessageBarDemoItem()
this.#getMessageBarDemoItem(),
this.#getAsyncResultDemoItem(),
this.#getFileDownloadDemoItem(),
this.#getDraggableDialogDemoItem(),
this.#getFormsDemoItem(),
this.#getRouteMapDemoItem(),
this.#getSignalStoreDemoItem(),
this.#getUtilsDemoItem(),
this.#getSubscriptionHandlingDemoItem(),
this.#getLocalStorageDemoItem()
])

#getConfirmationDemoItem(): DashboardItem {
Expand Down Expand Up @@ -109,4 +119,59 @@ export default class ComponentsDashboardDemoComponent {
#openMessageBarDemo(): void {
this.#router.navigateByUrl(getFullRoutePath(ROUTE_MAP.components.messageBar))
}

#getAsyncResultDemoItem(): DashboardItem {
return this.#item('navigation.async_result', 'dashboard.async-result-description', 'fa-solid fa-spinner', ROUTE_MAP.components.asyncResult)
}

#getFileDownloadDemoItem(): DashboardItem {
return this.#item('navigation.file_download', 'dashboard.file-download-description', 'fa-solid fa-download', ROUTE_MAP.components.fileDownload)
}

#getDraggableDialogDemoItem(): DashboardItem {
return this.#item('navigation.draggable_dialog', 'dashboard.draggable-dialog-description', 'fa-solid fa-arrows-up-down-left-right', ROUTE_MAP.components.draggableDialog)
}

#getFormsDemoItem(): DashboardItem {
return this.#item('navigation.forms_demo', 'dashboard.forms-demo-description', 'fa-solid fa-pen-to-square', ROUTE_MAP.components.formsDemo)
}

#getRouteMapDemoItem(): DashboardItem {
return this.#item('navigation.route_map', 'dashboard.route-map-description', 'fa-solid fa-route', ROUTE_MAP.components.routeMap)
}

#getSignalStoreDemoItem(): DashboardItem {
return this.#item('navigation.signal_store', 'dashboard.signal-store-description', 'fa-solid fa-database', ROUTE_MAP.components.signalStore)
}

#getUtilsDemoItem(): DashboardItem {
return this.#item('navigation.utils_demo', 'dashboard.utils-demo-description', 'fa-solid fa-wrench', ROUTE_MAP.components.utilsDemo)
}

#getSubscriptionHandlingDemoItem(): DashboardItem {
return this.#item('navigation.subscription_handling', 'dashboard.subscription-handling-description', 'fa-solid fa-link-slash', ROUTE_MAP.subscriptionHandling)
}

#getLocalStorageDemoItem(): DashboardItem {
return this.#item('navigation.local_storage', 'dashboard.local-storage-description', 'fa-solid fa-hard-drive', ROUTE_MAP.localStorage)
}

#item(
titleKey: string,
descriptionKey: string,
iconClass: string,
route: RouteMapRoute
): DashboardItem {
const openAction: DashboardItemAction = {
labelKey: 'button.open',
clickFn: () => this.#router.navigateByUrl(getFullRoutePath(route))
}
return {
iconClass,
titleKey,
descriptionKey,
actions: [openAction],
defaultAction: openAction
}
}
}
36 changes: 36 additions & 0 deletions src/app/components.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,41 @@ export const componentsRoutes: Routes = [
path: getRouteSegment(ROUTE_MAP.components.messageBar),
component: MessageBarComponent,
title: 'navigation.message_bar'
},
{
path: getRouteSegment(ROUTE_MAP.components.asyncResult),
loadComponent: () => import('./async-result-demo/async-result-demo.component').then((m) => m.AsyncResultDemoComponent),
title: 'navigation.async_result'
},
{
path: getRouteSegment(ROUTE_MAP.components.fileDownload),
loadComponent: () => import('./file-download-demo/file-download-demo.component').then((m) => m.FileDownloadDemoComponent),
title: 'navigation.file_download'
},
{
path: getRouteSegment(ROUTE_MAP.components.draggableDialog),
loadComponent: () =>
import('./draggable-dialog-demo/draggable-dialog-demo.component').then((m) => m.DraggableDialogDemoComponent),
title: 'navigation.draggable_dialog'
},
{
path: getRouteSegment(ROUTE_MAP.components.formsDemo),
loadComponent: () => import('./forms-demo/forms-demo.component').then((m) => m.FormsDemoComponent),
title: 'navigation.forms_demo'
},
{
path: getRouteSegment(ROUTE_MAP.components.routeMap),
loadComponent: () => import('./route-map-demo/route-map-demo.component').then((m) => m.RouteMapDemoComponent),
title: 'navigation.route_map'
},
{
path: getRouteSegment(ROUTE_MAP.components.signalStore),
loadComponent: () => import('./signal-store-demo/signal-store-demo.component').then((m) => m.SignalStoreDemoComponent),
title: 'navigation.signal_store'
},
{
path: getRouteSegment(ROUTE_MAP.components.utilsDemo),
loadComponent: () => import('./utils-demo/utils-demo.component').then((m) => m.UtilsDemoComponent),
title: 'navigation.utils_demo'
}
]
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<p class="sdk-overview">
This demo showcases the ppwcode Angular SDK: ng-async, ng-common, ng-common-components, ng-dialogs, ng-forms, ng-router, ng-state-management, ng-utils, ng-wireframe, and ng-unit-testing. Use the sidebar or the cards below to open each demo.
</p>
<ppw-dashboard-items-table
[dashboardItems]="dashboardItems()"
(executeAction)="$event ? $event.clickFn() : undefined"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.sdk-overview {
margin-bottom: 16px;
}

ppw-dashboard-items-table {
--ppw-dashboard-items-table-width: 1920px;
}
Expand Down
Loading
Loading