@weaver-apps/service-desk 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"weaver-apps-service-desk.mjs","names":[],"sources":["../../../../libs/service-desk/src/lib/gateway/service-desk-gateway.ts","../../../../libs/service-desk/src/lib/plugin/service-desk-host.ts","../../../../libs/service-desk/src/lib/plugin/service-desk-paths.ts","../../../../libs/service-desk/src/lib/views/desk-list-page.ts","../../../../libs/service-desk/src/lib/views/desk-list-page.html","../../../../libs/service-desk/src/lib/views/active-locale.ts","../../../../libs/service-desk/src/lib/api/models/serviceRequestOrigin.ts","../../../../libs/service-desk/src/lib/api/models/serviceRequestPriority.ts","../../../../libs/service-desk/src/lib/api/models/serviceRequestStatus.ts","../../../../libs/service-desk/src/lib/api/models/serviceRequestType.ts","../../../../libs/service-desk/src/lib/views/vocabulary.ts","../../../../libs/service-desk/src/lib/views/request-dialog.ts","../../../../libs/service-desk/src/lib/views/request-dialog.html","../../../../libs/service-desk/src/lib/views/request-table.ts","../../../../libs/service-desk/src/lib/views/request-table.html","../../../../libs/service-desk/src/lib/views/desk-page.ts","../../../../libs/service-desk/src/lib/views/desk-page.html","../../../../libs/service-desk/src/lib/plugin/service-desk-icons.ts","../../../../libs/service-desk/src/lib/plugin/service-desk.plugin.ts","../../../../libs/service-desk/src/lib/api/endpoints.ts","../../../../libs/service-desk/src/lib/gateway/http-service-desk-gateway.ts"],"sourcesContent":["import { InjectionToken, Provider } from '@angular/core';\nimport type {\n DeskResponse,\n NewServiceRequest,\n ServiceDeskRequestsListParams,\n ServiceRequestChanges,\n ServiceRequestPage,\n ServiceRequestResponse,\n ServiceRequestStatus,\n} from '../api/models';\n\nexport type ServiceRequestOutcome =\n | { readonly kind: 'saved'; readonly request: ServiceRequestResponse }\n | { readonly kind: 'closed' }\n | { readonly kind: 'changed' }\n | { readonly kind: 'invalid' }\n | { readonly kind: 'missing' };\n\nexport type ServiceRequestListing = ServiceDeskRequestsListParams;\n\nexport interface ServiceDeskGateway {\n desks(): Promise<readonly DeskResponse[]>;\n desk(deskId: string): Promise<DeskResponse | null>;\n saveDesk(deskId: string, name: string): Promise<DeskResponse>;\n requests(deskId: string, listing: ServiceRequestListing, signal?: AbortSignal): Promise<ServiceRequestPage>;\n raise(deskId: string, request: NewServiceRequest): Promise<ServiceRequestOutcome>;\n edit(deskId: string, requestId: string, changes: ServiceRequestChanges): Promise<ServiceRequestOutcome>;\n setStatus(deskId: string, requestId: string, status: ServiceRequestStatus): Promise<ServiceRequestOutcome>;\n complete(deskId: string, requestId: string): Promise<ServiceRequestOutcome>;\n cancel(deskId: string, requestId: string, reason: string | null): Promise<ServiceRequestOutcome>;\n remove(deskId: string, requestId: string): Promise<void>;\n}\n\nexport class ServiceDeskGatewayError extends Error {\n constructor(readonly status: number) {\n super(`The service desk answered ${status}.`);\n }\n}\n\nexport const SERVICE_DESK_GATEWAY = new InjectionToken<ServiceDeskGateway>('weaver-apps.service-desk.gateway');\n\nexport function provideServiceDeskGateway(gateway: ServiceDeskGateway): Provider {\n return { provide: SERVICE_DESK_GATEWAY, useValue: gateway };\n}\n","import type { PluginContext } from '@loomweaver/plugin-sdk';\n\ntype HostContext = Pick<PluginContext, 'ui' | 'navigateContent'>;\n\nclass ServiceDeskHost {\n private ctx?: HostContext;\n\n bind(ctx: HostContext): void {\n this.ctx = ctx;\n }\n\n unbind(): void {\n this.ctx = undefined;\n }\n\n get ui(): HostContext['ui'] {\n if (!this.ctx) {\n throw new Error('The service-desk plugin is not active.');\n }\n return this.ctx.ui;\n }\n\n navigate(path: string): void {\n this.ctx?.navigateContent(path);\n }\n}\n\nexport const serviceDeskHost = new ServiceDeskHost();\n","export const deskListPath = 'service-desk';\n\nexport function deskPath(deskId: string): string {\n return `${deskListPath}/${deskId}`;\n}\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, inject, resource } from '@angular/core';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport { SERVICE_DESK_GATEWAY } from '../gateway/service-desk-gateway';\nimport { serviceDeskHost } from '../plugin/service-desk-host';\nimport { deskPath } from '../plugin/service-desk-paths';\n\n@Component({\n selector: 'wa-desk-list-page',\n imports: [TranslocoPipe],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './desk-list-page.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DeskListPage {\n private readonly gateway = inject(SERVICE_DESK_GATEWAY);\n\n protected readonly desks = resource({ loader: () => this.gateway.desks() });\n\n protected open(deskId: string): void {\n serviceDeskHost.navigate(deskPath(deskId));\n }\n\n protected async create(): Promise<void> {\n const name = await serviceDeskHost.ui.prompt({\n title: 'service-desk.desks.create',\n message: 'service-desk.desks.createMessage',\n confirmLabel: 'service-desk.desks.createConfirm',\n });\n if (!name?.trim()) {\n return;\n }\n try {\n const desk = await this.gateway.saveDesk(crypto.randomUUID(), name.trim());\n this.open(desk.id);\n } catch {\n serviceDeskHost.ui.toast({ message: 'service-desk.errors.create', kind: 'error' });\n }\n }\n}\n","<div class=\"flex h-full flex-col gap-4 overflow-auto p-6\">\n <div class=\"flex items-center justify-between gap-4\">\n <h2 class=\"text-lg font-semibold text-content\">{{ 'service-desk.desks.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'service-desk.desks.create' | transloco }}</button>\n </div>\n @if (desks.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'service-desk.errors.load' | transloco }}</p>\n } @else if (desks.hasValue()) {\n <ul role=\"list\" class=\"divide-y divide-border rounded-xl border border-border bg-surface\">\n @for (desk of desks.value(); track desk.id) {\n <li>\n <button type=\"button\" class=\"flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-content hover:bg-surface-overlay\" (click)=\"open(desk.id)\">\n <lw-icon name=\"serviceDesk\" size=\"1.25rem\"></lw-icon>\n <span>{{ desk.name }}</span>\n </button>\n </li>\n } @empty {\n <li class=\"px-4 py-8 text-center text-sm text-content-faint\">{{ 'service-desk.desks.empty' | transloco }}</li>\n }\n </ul>\n }\n</div>\n","import { inject, Signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { TranslocoService } from '@jsverse/transloco';\n\nexport function activeLocale(): Signal<string> {\n const transloco = inject(TranslocoService);\n return toSignal(transloco.langChanges$, { initialValue: transloco.getActiveLang() });\n}\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\n\n/**\n * How a service request came about.\n */\nexport type ServiceRequestOrigin = typeof ServiceRequestOrigin[keyof typeof ServiceRequestOrigin];\n\n\nexport const ServiceRequestOrigin = {\n manual: 'manual',\n voiceChat: 'voiceChat',\n textChat: 'textChat',\n widget: 'widget',\n email: 'email',\n phone: 'phone',\n} as const;\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\n\n/**\n * How urgent a service request is.\n */\nexport type ServiceRequestPriority = typeof ServiceRequestPriority[keyof typeof ServiceRequestPriority];\n\n\nexport const ServiceRequestPriority = {\n low: 'low',\n normal: 'normal',\n high: 'high',\n urgent: 'urgent',\n} as const;\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\n\n/**\n * Where a service request stands.\n */\nexport type ServiceRequestStatus = typeof ServiceRequestStatus[keyof typeof ServiceRequestStatus];\n\n\nexport const ServiceRequestStatus = {\n open: 'open',\n inProgress: 'inProgress',\n completed: 'completed',\n cancelled: 'cancelled',\n} as const;\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\n\n/**\n * What kind of matter a service request is.\n */\nexport type ServiceRequestType = typeof ServiceRequestType[keyof typeof ServiceRequestType];\n\n\nexport const ServiceRequestType = {\n inquiry: 'inquiry',\n task: 'task',\n callbackRequest: 'callbackRequest',\n conversationSummary: 'conversationSummary',\n complaint: 'complaint',\n quote: 'quote',\n} as const;\n","import {\n ServiceRequestOrigin,\n ServiceRequestPriority,\n ServiceRequestStatus,\n ServiceRequestType,\n} from '../api/models';\n\nexport const requestTypes: readonly ServiceRequestType[] = Object.values(ServiceRequestType);\nexport const requestPriorities: readonly ServiceRequestPriority[] = Object.values(ServiceRequestPriority);\nexport const requestOrigins: readonly ServiceRequestOrigin[] = Object.values(ServiceRequestOrigin);\nexport const settableStatuses: readonly ServiceRequestStatus[] = [ServiceRequestStatus.open, ServiceRequestStatus.inProgress];\n\nexport const statusFilters = ['active', 'open', 'inProgress', 'completed', 'cancelled', 'all'] as const;\nexport type StatusFilter = (typeof statusFilters)[number];\n\nexport function isClosed(status: ServiceRequestStatus): boolean {\n return status === ServiceRequestStatus.completed || status === ServiceRequestStatus.cancelled;\n}\n\nexport function localDate(value: Date): string {\n const pad = (part: number) => `${part}`.padStart(2, '0');\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;\n}\n\nexport function pick<T extends string>(choices: readonly T[], value: string): T | undefined {\n return choices.find((choice) => choice === value);\n}\n","import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { DialogRef } from '@loomweaver/plugin-sdk';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport {\n ServiceRequestOrigin,\n ServiceRequestPriority,\n ServiceRequestType,\n type ServiceRequestChanges,\n type ServiceRequestResponse,\n type ServiceRequestStatus,\n} from '../api/models';\nimport { SERVICE_DESK_GATEWAY, ServiceRequestOutcome } from '../gateway/service-desk-gateway';\nimport { isClosed, localDate, pick, requestOrigins, requestPriorities, requestTypes, settableStatuses } from './vocabulary';\n\nexport interface RequestDialogData {\n readonly deskId: string;\n readonly request: ServiceRequestResponse | null;\n}\n\n@Component({\n selector: 'wa-request-dialog',\n imports: [TranslocoPipe],\n templateUrl: './request-dialog.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class RequestDialog {\n private readonly dialog = inject<DialogRef<boolean>>(DialogRef);\n private readonly gateway = inject(SERVICE_DESK_GATEWAY);\n private readonly data = this.dialog.data as RequestDialogData;\n private existing = this.data.request;\n\n protected readonly editing = this.existing !== null;\n protected readonly closed = this.existing !== null && isClosed(this.existing.status);\n protected readonly types = requestTypes;\n protected readonly priorities = requestPriorities;\n protected readonly origins = requestOrigins;\n protected readonly statuses = settableStatuses;\n\n protected readonly title = signal(this.existing?.title ?? '');\n protected readonly type = signal<ServiceRequestType>(this.existing?.type ?? ServiceRequestType.inquiry);\n protected readonly priority = signal<ServiceRequestPriority>(this.existing?.priority ?? ServiceRequestPriority.normal);\n protected readonly origin = signal<ServiceRequestOrigin>(this.existing?.origin ?? ServiceRequestOrigin.manual);\n protected readonly status = signal<ServiceRequestStatus>(this.existing?.status ?? 'open');\n protected readonly contactName = signal(this.existing?.contactName ?? '');\n protected readonly contactPhone = signal(this.existing?.contactPhone ?? '');\n protected readonly contactEmail = signal(this.existing?.contactEmail ?? '');\n protected readonly assignee = signal(this.existing?.assignee ?? '');\n protected readonly dueDate = signal(this.existing?.dueAt ? localDate(new Date(this.existing.dueAt)) : '');\n protected readonly description = signal(this.existing?.description ?? '');\n protected readonly cancellationReason = this.existing?.cancellationReason ?? null;\n protected readonly saving = signal(false);\n protected readonly problem = signal('');\n private persisted = false;\n\n protected bind(target: { set(value: string): void }, event: Event): void {\n target.set((event.target as HTMLInputElement).value);\n }\n\n protected chooseType(event: Event): void {\n this.choose(this.type, requestTypes, event);\n }\n\n protected choosePriority(event: Event): void {\n this.choose(this.priority, requestPriorities, event);\n }\n\n protected chooseOrigin(event: Event): void {\n this.choose(this.origin, requestOrigins, event);\n }\n\n protected chooseStatus(event: Event): void {\n this.choose(this.status, settableStatuses, event);\n }\n\n protected close(): void {\n this.dialog.close(this.persisted);\n }\n\n protected async save(): Promise<void> {\n if (!this.title().trim()) {\n this.problem.set('service-desk.dialog.titleRequired');\n return;\n }\n this.saving.set(true);\n try {\n const changes = this.changes();\n const outcome = this.existing\n ? await this.gateway.edit(this.data.deskId, this.existing.id, changes)\n : await this.gateway.raise(this.data.deskId, { ...changes, origin: this.origin() });\n this.settle(await this.applyStatus(outcome));\n } catch {\n this.problem.set('service-desk.errors.save');\n } finally {\n this.saving.set(false);\n }\n }\n\n private changes(): ServiceRequestChanges {\n const keptDue = this.existing?.dueAt && localDate(new Date(this.existing.dueAt)) === this.dueDate() ? this.existing.dueAt : null;\n if (keptDue) {\n return { ...this.fields(), dueAt: keptDue };\n }\n const due = this.dueDate() ? new Date(`${this.dueDate()}T12:00`) : null;\n return { ...this.fields(), dueAt: due && !Number.isNaN(due.getTime()) ? due.toISOString() : null };\n }\n\n private fields(): Omit<ServiceRequestChanges, 'dueAt'> {\n return {\n title: this.title().trim(),\n description: this.optional(this.description()),\n type: this.type(),\n priority: this.priority(),\n contactName: this.optional(this.contactName()),\n contactPhone: this.optional(this.contactPhone()),\n contactEmail: this.optional(this.contactEmail()),\n assignee: this.optional(this.assignee()),\n };\n }\n\n private async applyStatus(outcome: ServiceRequestOutcome): Promise<ServiceRequestOutcome> {\n if (outcome.kind === 'saved') {\n this.existing = outcome.request;\n this.persisted = true;\n }\n if (outcome.kind !== 'saved' || outcome.request.status === this.status()) {\n return outcome;\n }\n return this.gateway.setStatus(this.data.deskId, outcome.request.id, this.status());\n }\n\n private settle(outcome: ServiceRequestOutcome): void {\n const messages: Record<Exclude<ServiceRequestOutcome['kind'], 'saved'>, string> = {\n closed: 'service-desk.dialog.closed',\n changed: 'service-desk.dialog.changed',\n invalid: 'service-desk.dialog.invalid',\n missing: 'service-desk.dialog.missing',\n };\n if (outcome.kind === 'saved') {\n this.dialog.close(true);\n return;\n }\n this.problem.set(messages[outcome.kind]);\n }\n\n private choose<T extends string>(target: { set(value: T): void }, choices: readonly T[], event: Event): void {\n const chosen = pick(choices, (event.target as HTMLSelectElement).value);\n if (chosen) {\n target.set(chosen);\n }\n }\n\n private optional(value: string): string | null {\n return value.trim() ? value.trim() : null;\n }\n}\n","<form class=\"flex flex-col gap-4\" (submit)=\"$event.preventDefault(); save()\">\n @if (closed) {\n <p class=\"text-sm text-content-faint\" role=\"status\">\n {{ 'service-desk.dialog.closedNote' | transloco }}\n @if (cancellationReason) {\n {{ 'service-desk.dialog.reason' | transloco: { reason: cancellationReason } }}\n }\n </p>\n }\n\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.title' | transloco }}\n <input class=\"lw-field\" required [disabled]=\"closed\" [value]=\"title()\" (input)=\"bind(title, $event)\" />\n </label>\n\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.type' | transloco }}\n <select class=\"lw-field\" [disabled]=\"closed\" (change)=\"chooseType($event)\">\n @for (choice of types; track choice) {\n <option [value]=\"choice\" [selected]=\"choice === type()\">{{ 'service-desk.type.' + choice | transloco }}</option>\n }\n </select>\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.priority' | transloco }}\n <select class=\"lw-field\" [disabled]=\"closed\" (change)=\"choosePriority($event)\">\n @for (choice of priorities; track choice) {\n <option [value]=\"choice\" [selected]=\"choice === priority()\">{{ 'service-desk.priority.' + choice | transloco }}</option>\n }\n </select>\n </label>\n @if (editing) {\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.status' | transloco }}\n <select class=\"lw-field\" [disabled]=\"closed\" (change)=\"chooseStatus($event)\">\n @if (closed) {\n <option selected>{{ 'service-desk.status.' + status() | transloco }}</option>\n } @else {\n @for (choice of statuses; track choice) {\n <option [value]=\"choice\" [selected]=\"choice === status()\">{{ 'service-desk.status.' + choice | transloco }}</option>\n }\n }\n </select>\n </label>\n } @else {\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.origin' | transloco }}\n <select class=\"lw-field\" (change)=\"chooseOrigin($event)\">\n @for (choice of origins; track choice) {\n <option [value]=\"choice\" [selected]=\"choice === origin()\">{{ 'service-desk.origin.' + choice | transloco }}</option>\n }\n </select>\n </label>\n }\n </div>\n\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.contactName' | transloco }}\n <input class=\"lw-field\" [disabled]=\"closed\" [value]=\"contactName()\" (input)=\"bind(contactName, $event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.contactPhone' | transloco }}\n <input class=\"lw-field\" type=\"tel\" [disabled]=\"closed\" [value]=\"contactPhone()\" (input)=\"bind(contactPhone, $event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.contactEmail' | transloco }}\n <input class=\"lw-field\" type=\"email\" [disabled]=\"closed\" [value]=\"contactEmail()\" (input)=\"bind(contactEmail, $event)\" />\n </label>\n </div>\n\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.assignee' | transloco }}\n <input class=\"lw-field\" [disabled]=\"closed\" [value]=\"assignee()\" (input)=\"bind(assignee, $event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.due' | transloco }}\n <input class=\"lw-field\" type=\"date\" [disabled]=\"closed\" [value]=\"dueDate()\" (input)=\"bind(dueDate, $event)\" />\n </label>\n </div>\n\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'service-desk.fields.description' | transloco }}\n <textarea class=\"lw-field\" rows=\"3\" [disabled]=\"closed\" [value]=\"description()\" (input)=\"bind(description, $event)\"></textarea>\n </label>\n\n @if (problem()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ problem() | transloco }}</p>\n }\n\n <div class=\"flex justify-end gap-2\">\n <button type=\"button\" class=\"lw-btn lw-btn--default\" (click)=\"close()\">{{ (closed ? 'service-desk.dialog.close' : 'service-desk.dialog.cancel') | transloco }}</button>\n @if (!closed) {\n <button type=\"submit\" class=\"lw-btn lw-btn--primary\" [disabled]=\"saving()\">{{ 'service-desk.dialog.save' | transloco }}</button>\n }\n </div>\n</form>\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, input, output } from '@angular/core';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport type { ServiceRequestResponse } from '../api/models';\nimport { isClosed } from './vocabulary';\n\nexport interface RequestActions {\n readonly request: ServiceRequestResponse;\n readonly x: number;\n readonly y: number;\n}\n\ninterface RequestRow {\n readonly request: ServiceRequestResponse;\n readonly raised: string;\n readonly due: string | null;\n readonly closed: boolean;\n}\n\n@Component({\n selector: 'wa-request-table',\n imports: [TranslocoPipe],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './request-table.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class RequestTable {\n readonly requests = input.required<readonly ServiceRequestResponse[]>();\n readonly locale = input.required<string>();\n\n readonly requestActions = output<RequestActions>();\n\n protected readonly rows = computed<readonly RequestRow[]>(() => {\n const date = new Intl.DateTimeFormat(this.locale(), { day: '2-digit', month: '2-digit', year: 'numeric' });\n return this.requests().map((request) => ({\n request,\n raised: date.format(new Date(request.raisedAt)),\n due: request.dueAt ? date.format(new Date(request.dueAt)) : null,\n closed: isClosed(request.status),\n }));\n });\n}\n","<table class=\"w-full border-collapse text-sm\">\n <thead class=\"border-y border-border bg-surface-raised\">\n <tr>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'service-desk.table.title' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'service-desk.table.type' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'service-desk.table.priority' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'service-desk.table.status' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'service-desk.table.contact' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'service-desk.table.dates' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2\"><span class=\"sr-only\">{{ 'service-desk.table.actions' | transloco }}</span></th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.request.id) {\n <tr class=\"border-b border-border\" [class.text-content-faint]=\"row.closed\" data-testid=\"request-row\">\n <td class=\"min-w-48 px-4 py-3 font-medium text-content\" [class.line-through]=\"row.request.status === 'cancelled'\">{{ row.request.title }}</td>\n <td class=\"px-4 py-3 whitespace-nowrap\">\n <span class=\"rounded-full border border-border px-2 py-0.5 text-xs text-content\">{{ 'service-desk.type.' + row.request.type | transloco }}</span>\n </td>\n <td class=\"px-4 py-3 whitespace-nowrap\">\n <span class=\"rounded-full border border-border px-2 py-0.5 text-xs\" [class.text-negative]=\"row.request.priority === 'urgent'\" [class.font-semibold]=\"row.request.priority === 'urgent' || row.request.priority === 'high'\" data-testid=\"request-priority\">{{ 'service-desk.priority.' + row.request.priority | transloco }}</span>\n </td>\n <td class=\"px-4 py-3 whitespace-nowrap\">\n <span class=\"rounded-full border border-border px-2 py-0.5 text-xs text-content\" data-testid=\"request-status\">{{ 'service-desk.status.' + row.request.status | transloco }}</span>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"text-content\">{{ row.request.contactName ?? '–' }}</div>\n @if (row.request.contactPhone ?? row.request.contactEmail; as reach) {\n <div class=\"text-content-faint\">{{ reach }}</div>\n }\n </td>\n <td class=\"px-4 py-3 whitespace-nowrap\">\n <div class=\"text-content\">{{ row.raised }}</div>\n @if (row.due) {\n <div class=\"text-content-faint\">{{ 'service-desk.table.dueOn' | transloco: { date: row.due } }}</div>\n }\n </td>\n <td class=\"px-4 py-3 text-right whitespace-nowrap\">\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'service-desk.actions.more' | transloco\" (click)=\"requestActions.emit({ request: row.request, x: $event.clientX, y: $event.clientY })\">\n <lw-icon name=\"more\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'service-desk.actions.more' | transloco\" position=\"top\"></lw-tooltip>\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"px-4 py-8 text-center text-content-faint\">{{ 'service-desk.table.empty' | transloco }}</td>\n </tr>\n }\n </tbody>\n</table>\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, DestroyRef, effect, inject, resource, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute } from '@angular/router';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport { map } from 'rxjs';\nimport type { ServiceRequestResponse } from '../api/models';\nimport { SERVICE_DESK_GATEWAY, ServiceRequestOutcome } from '../gateway/service-desk-gateway';\nimport { serviceDeskHost } from '../plugin/service-desk-host';\nimport { activeLocale } from './active-locale';\nimport { RequestDialog, RequestDialogData } from './request-dialog';\nimport { RequestActions, RequestTable } from './request-table';\nimport { isClosed, statusFilters, type StatusFilter } from './vocabulary';\n\nconst pageSize = 25;\nconst searchDelayMs = 300;\n\n@Component({\n selector: 'wa-desk-page',\n imports: [TranslocoPipe, RequestTable],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './desk-page.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DeskPage {\n private readonly gateway = inject(SERVICE_DESK_GATEWAY);\n private readonly route = inject(ActivatedRoute);\n private searchTimer?: ReturnType<typeof setTimeout>;\n\n protected readonly locale = activeLocale();\n protected readonly filters = statusFilters;\n protected readonly deskId = toSignal(this.route.paramMap.pipe(map((params) => params.get('deskId') ?? '')), {\n initialValue: this.route.snapshot.paramMap.get('deskId') ?? '',\n });\n protected readonly text = signal('');\n protected readonly filter = signal<StatusFilter>('active');\n protected readonly offset = signal(0);\n\n protected readonly desk = resource({\n params: () => this.deskId(),\n loader: ({ params }) => this.gateway.desk(params),\n });\n\n protected readonly page = resource({\n params: () => ({ deskId: this.deskId(), text: this.text().trim(), filter: this.filter(), offset: this.offset() }),\n loader: ({ params, abortSignal }) =>\n this.gateway.requests(\n params.deskId,\n {\n text: params.text || undefined,\n ...(params.filter === 'active' ? {} : params.filter === 'all' ? { includeCancelled: true } : { status: params.filter }),\n offset: params.offset,\n limit: pageSize,\n },\n abortSignal,\n ),\n });\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.searchTimer));\n effect(() => {\n const total = this.total();\n if (this.page.hasValue() && this.offset() > 0 && this.offset() >= total) {\n this.offset.set(Math.max(0, Math.ceil(total / pageSize) - 1) * pageSize);\n }\n });\n }\n\n protected readonly total = computed(() => Number(this.page.value()?.total ?? 0));\n\n protected readonly range = computed(() => {\n const total = this.total();\n const first = total === 0 ? 0 : this.offset() + 1;\n return { first, last: Math.min(this.offset() + pageSize, total), total };\n });\n\n protected readonly hasPrevious = computed(() => this.offset() > 0);\n protected readonly hasNext = computed(() => this.offset() + pageSize < this.total());\n\n protected search(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n clearTimeout(this.searchTimer);\n this.searchTimer = setTimeout(() => {\n this.text.set(value);\n this.offset.set(0);\n }, searchDelayMs);\n }\n\n protected chooseFilter(event: Event): void {\n const chosen = statusFilters.find((filter) => filter === (event.target as HTMLSelectElement).value);\n if (chosen) {\n this.filter.set(chosen);\n this.offset.set(0);\n }\n }\n\n protected previous(): void {\n this.offset.update((offset) => Math.max(0, offset - pageSize));\n }\n\n protected next(): void {\n this.offset.update((offset) => offset + pageSize);\n }\n\n protected add(): void {\n this.openDialog({ deskId: this.deskId(), request: null }, 'service-desk.dialog.addTitle');\n }\n\n protected actions({ request, x, y }: RequestActions): void {\n const closed = isClosed(request.status);\n serviceDeskHost.ui.openMenu(\n [\n { label: closed ? 'service-desk.actions.view' : 'service-desk.actions.edit', icon: closed ? 'preview' : 'edit', run: () => this.open(request) },\n ...(closed\n ? []\n : [\n { label: 'service-desk.actions.complete', icon: 'serviceDeskComplete', run: () => void this.complete(request) },\n { label: 'service-desk.actions.cancel', icon: 'serviceDeskCancel', run: () => void this.cancel(request) },\n ]),\n { label: 'service-desk.actions.delete', icon: 'trash', run: () => void this.remove(request) },\n ],\n { x, y },\n );\n }\n\n protected open(request: ServiceRequestResponse): void {\n const closed = isClosed(request.status);\n this.openDialog({ deskId: this.deskId(), request }, closed ? 'service-desk.dialog.viewTitle' : 'service-desk.dialog.editTitle');\n }\n\n protected async complete(request: ServiceRequestResponse): Promise<void> {\n await this.attempt(async () => this.report(await this.gateway.complete(this.deskId(), request.id), 'service-desk.complete.done'));\n }\n\n protected async cancel(request: ServiceRequestResponse): Promise<void> {\n const reason = await serviceDeskHost.ui.prompt({\n title: 'service-desk.cancel.title',\n message: 'service-desk.cancel.message',\n confirmLabel: 'service-desk.cancel.confirm',\n tone: 'warning',\n });\n if (reason === null) {\n return;\n }\n await this.attempt(async () =>\n this.report(await this.gateway.cancel(this.deskId(), request.id, reason.trim() || null), 'service-desk.cancel.done'),\n );\n }\n\n protected async remove(request: ServiceRequestResponse): Promise<void> {\n const confirmed = await serviceDeskHost.ui.confirm({\n title: 'service-desk.delete.title',\n message: 'service-desk.delete.message',\n confirmLabel: 'service-desk.delete.confirm',\n tone: 'danger',\n });\n if (!confirmed) {\n return;\n }\n await this.attempt(async () => {\n await this.gateway.remove(this.deskId(), request.id);\n serviceDeskHost.ui.toast({ message: 'service-desk.delete.done', kind: 'success' });\n this.page.reload();\n });\n }\n\n private async attempt(work: () => Promise<void>): Promise<void> {\n try {\n await work();\n } catch {\n serviceDeskHost.ui.toast({ message: 'service-desk.errors.save', kind: 'error' });\n this.page.reload();\n }\n }\n\n private openDialog(data: RequestDialogData, title: string): void {\n const dialog = serviceDeskHost.ui.open<boolean>(RequestDialog, { data, title, size: 'lg', dismiss: 'explicit' });\n void dialog.closed.then((saved) => {\n if (saved) {\n serviceDeskHost.ui.toast({ message: 'service-desk.dialog.saved', kind: 'success' });\n this.page.reload();\n }\n });\n }\n\n private report(outcome: ServiceRequestOutcome, done: string): void {\n const saved = outcome.kind === 'saved';\n serviceDeskHost.ui.toast({ message: saved ? done : 'service-desk.errors.save', kind: saved ? 'success' : 'error' });\n this.page.reload();\n }\n}\n","<div class=\"flex h-full flex-col gap-4 overflow-auto p-6\">\n <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <h2 class=\"text-lg font-semibold text-content\">{{ desk.value()?.name ?? ('service-desk.title' | transloco) }}</h2>\n <div class=\"flex flex-wrap items-center gap-2\">\n <input\n type=\"search\"\n class=\"lw-field w-56\"\n [attr.aria-label]=\"'service-desk.search.label' | transloco\"\n [attr.placeholder]=\"'service-desk.search.placeholder' | transloco\"\n (input)=\"search($event)\"\n />\n <select class=\"lw-field w-64\" [attr.aria-label]=\"'service-desk.filter.label' | transloco\" (change)=\"chooseFilter($event)\">\n @for (choice of filters; track choice) {\n <option [value]=\"choice\" [selected]=\"choice === filter()\">{{ 'service-desk.filter.' + choice | transloco }}</option>\n }\n </select>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"add()\">\n <lw-icon name=\"add\" size=\"1rem\"></lw-icon>\n {{ 'service-desk.actions.add' | transloco }}\n </button>\n </div>\n </div>\n\n @if (page.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'service-desk.errors.load' | transloco }}</p>\n } @else {\n <div class=\"overflow-x-auto rounded-xl border border-border bg-surface\">\n <wa-request-table\n [requests]=\"page.value()?.items ?? []\"\n [locale]=\"locale()\"\n (requestActions)=\"actions($event)\"\n />\n </div>\n <div class=\"flex items-center justify-end gap-2 text-sm text-content-faint\">\n <span data-testid=\"page-range\">{{ 'service-desk.pager.range' | transloco: range() }}</span>\n <button type=\"button\" class=\"relative lw-btn lw-btn--default lw-btn--sm lw-btn--icon\" [disabled]=\"!hasPrevious()\" [attr.aria-label]=\"'service-desk.pager.previous' | transloco\" (click)=\"previous()\">\n <lw-icon name=\"serviceDeskPrevious\" size=\"1rem\"></lw-icon>\n </button>\n <button type=\"button\" class=\"relative lw-btn lw-btn--default lw-btn--sm lw-btn--icon\" [disabled]=\"!hasNext()\" [attr.aria-label]=\"'service-desk.pager.next' | transloco\" (click)=\"next()\">\n <lw-icon name=\"serviceDeskNext\" size=\"1rem\"></lw-icon>\n </button>\n </div>\n }\n</div>\n","const stroke = 'fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"';\n\nexport const serviceDeskIcons: Readonly<Record<string, string>> = {\n serviceDesk: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M4 13.5V7a2.5 2.5 0 0 1 2.5-2.5h11A2.5 2.5 0 0 1 20 7v6.5\"/><path d=\"M3 13.5h5l1.5 2.5h5l1.5-2.5h5V18a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"/></svg>`,\n serviceDeskComplete: `<svg viewBox=\"0 0 24 24\" ${stroke}><circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M8.5 12.5l2.5 2.5 4.5-5\"/></svg>`,\n serviceDeskCancel: `<svg viewBox=\"0 0 24 24\" ${stroke}><circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M9 9l6 6M15 9l-6 6\"/></svg>`,\n serviceDeskPrevious: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M15 5l-7 7 7 7\"/></svg>`,\n serviceDeskNext: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M9 5l7 7-7 7\"/></svg>`,\n};\n","import { Plugin } from '@loomweaver/plugin-sdk';\nimport { DeskListPage } from '../views/desk-list-page';\nimport { DeskPage } from '../views/desk-page';\nimport { serviceDeskHost } from './service-desk-host';\nimport { serviceDeskIcons } from './service-desk-icons';\nimport { deskListPath } from './service-desk-paths';\n\nexport interface ServiceDeskPluginOptions {\n readonly railItem?: boolean;\n}\n\nexport function createServiceDeskPlugin(options: ServiceDeskPluginOptions = {}): Plugin {\n return {\n manifest: {\n id: 'service-desk',\n name: 'Service desk',\n capabilities: ['contributions', 'navigation', 'ui'],\n },\n activate(ctx) {\n serviceDeskHost.bind(ctx);\n ctx.contributeIcons(serviceDeskIcons);\n ctx.registerSurface({\n id: 'service-desk.desks',\n title: 'service-desk.desks.title',\n icon: 'serviceDesk',\n routable: { path: deskListPath },\n component: DeskListPage,\n });\n ctx.registerSurface({\n id: 'service-desk.desk',\n title: 'service-desk.title',\n icon: 'serviceDesk',\n routable: { path: `${deskListPath}/:deskId` },\n component: DeskPage,\n });\n if (options.railItem) {\n ctx.registerRailItem({\n id: 'service-desk.rail',\n rail: 'primary',\n icon: 'serviceDesk',\n title: 'service-desk.desks.title',\n run: () => ctx.navigateContent(deskListPath),\n });\n }\n },\n deactivate() {\n serviceDeskHost.unbind();\n },\n };\n}\n\nexport const serviceDeskPlugin = createServiceDeskPlugin();\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\nimport type {\n DeskResponse,\n NewServiceRequest,\n SaveDeskRequest,\n ServiceDeskRequestsListParams,\n ServiceRequestCancellation,\n ServiceRequestChanges,\n ServiceRequestPage,\n ServiceRequestResponse,\n ServiceRequestStatusChange\n} from './models';\n\n\nexport type serviceDeskDesksSaveResponse200 = {\n data: DeskResponse\n status: 200\n}\n\nexport type serviceDeskDesksSaveResponse201 = {\n data: DeskResponse\n status: 201\n}\n\nexport type serviceDeskDesksSaveResponseSuccess = (serviceDeskDesksSaveResponse200 | serviceDeskDesksSaveResponse201) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksSaveResponse = (serviceDeskDesksSaveResponseSuccess)\n\nexport const getServiceDeskDesksSaveUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}`\n}\n\nexport const serviceDeskDesksSave = async (deskId: string,\n saveDeskRequest: SaveDeskRequest, options?: RequestInit): Promise<serviceDeskDesksSaveResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskDesksSaveUrl(deskId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(saveDeskRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksSaveResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksSaveResponse\n}\n\n\n\nexport type serviceDeskDesksGetResponse200 = {\n data: DeskResponse\n status: 200\n}\n\nexport type serviceDeskDesksGetResponseSuccess = (serviceDeskDesksGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksGetResponse = (serviceDeskDesksGetResponseSuccess)\n\nexport const getServiceDeskDesksGetUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}`\n}\n\nexport const serviceDeskDesksGet = async (deskId: string, options?: RequestInit): Promise<serviceDeskDesksGetResponse> => {\n\n const res = await fetch(getServiceDeskDesksGetUrl(deskId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksGetResponse\n}\n\n\n\nexport type serviceDeskDesksDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type serviceDeskDesksDeleteResponseSuccess = (serviceDeskDesksDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksDeleteResponse = (serviceDeskDesksDeleteResponseSuccess)\n\nexport const getServiceDeskDesksDeleteUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}`\n}\n\nexport const serviceDeskDesksDelete = async (deskId: string, options?: RequestInit): Promise<serviceDeskDesksDeleteResponse> => {\n\n const res = await fetch(getServiceDeskDesksDeleteUrl(deskId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksDeleteResponse\n}\n\n\n\nexport type serviceDeskDesksListResponse200 = {\n data: DeskResponse[]\n status: 200\n}\n\nexport type serviceDeskDesksListResponseSuccess = (serviceDeskDesksListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksListResponse = (serviceDeskDesksListResponseSuccess)\n\nexport const getServiceDeskDesksListUrl = () => {\n\n\n\n\n return `/service-desk/desks`\n}\n\nexport const serviceDeskDesksList = async ( options?: RequestInit): Promise<serviceDeskDesksListResponse> => {\n\n const res = await fetch(getServiceDeskDesksListUrl(),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksListResponse\n}\n\n\n\nexport type serviceDeskRequestsRaiseResponse201 = {\n data: ServiceRequestResponse\n status: 201\n}\n\nexport type serviceDeskRequestsRaiseResponseSuccess = (serviceDeskRequestsRaiseResponse201) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsRaiseResponse = (serviceDeskRequestsRaiseResponseSuccess)\n\nexport const getServiceDeskRequestsRaiseUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests`\n}\n\nexport const serviceDeskRequestsRaise = async (deskId: string,\n newServiceRequest: NewServiceRequest, options?: RequestInit): Promise<serviceDeskRequestsRaiseResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsRaiseUrl(deskId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(newServiceRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsRaiseResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsRaiseResponse\n}\n\n\n\nexport type serviceDeskRequestsListResponse200 = {\n data: ServiceRequestPage\n status: 200\n}\n\nexport type serviceDeskRequestsListResponseSuccess = (serviceDeskRequestsListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsListResponse = (serviceDeskRequestsListResponseSuccess)\n\nexport const getServiceDeskRequestsListUrl = (deskId: string,\n params?: ServiceDeskRequestsListParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/service-desk/desks/${deskId}/requests?${stringifiedParams}` : `/service-desk/desks/${deskId}/requests`\n}\n\nexport const serviceDeskRequestsList = async (deskId: string,\n params?: ServiceDeskRequestsListParams, options?: RequestInit): Promise<serviceDeskRequestsListResponse> => {\n\n const res = await fetch(getServiceDeskRequestsListUrl(deskId,params),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsListResponse\n}\n\n\n\nexport type serviceDeskRequestsGetResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsGetResponseSuccess = (serviceDeskRequestsGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsGetResponse = (serviceDeskRequestsGetResponseSuccess)\n\nexport const getServiceDeskRequestsGetUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}`\n}\n\nexport const serviceDeskRequestsGet = async (deskId: string,\n requestId: string, options?: RequestInit): Promise<serviceDeskRequestsGetResponse> => {\n\n const res = await fetch(getServiceDeskRequestsGetUrl(deskId,requestId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsGetResponse\n}\n\n\n\nexport type serviceDeskRequestsEditResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsEditResponseSuccess = (serviceDeskRequestsEditResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsEditResponse = (serviceDeskRequestsEditResponseSuccess)\n\nexport const getServiceDeskRequestsEditUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}`\n}\n\nexport const serviceDeskRequestsEdit = async (deskId: string,\n requestId: string,\n serviceRequestChanges: ServiceRequestChanges, options?: RequestInit): Promise<serviceDeskRequestsEditResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsEditUrl(deskId,requestId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(serviceRequestChanges)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsEditResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsEditResponse\n}\n\n\n\nexport type serviceDeskRequestsDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type serviceDeskRequestsDeleteResponseSuccess = (serviceDeskRequestsDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsDeleteResponse = (serviceDeskRequestsDeleteResponseSuccess)\n\nexport const getServiceDeskRequestsDeleteUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}`\n}\n\nexport const serviceDeskRequestsDelete = async (deskId: string,\n requestId: string, options?: RequestInit): Promise<serviceDeskRequestsDeleteResponse> => {\n\n const res = await fetch(getServiceDeskRequestsDeleteUrl(deskId,requestId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsDeleteResponse\n}\n\n\n\nexport type serviceDeskRequestsStatusResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsStatusResponseSuccess = (serviceDeskRequestsStatusResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsStatusResponse = (serviceDeskRequestsStatusResponseSuccess)\n\nexport const getServiceDeskRequestsStatusUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}/status`\n}\n\nexport const serviceDeskRequestsStatus = async (deskId: string,\n requestId: string,\n serviceRequestStatusChange: ServiceRequestStatusChange, options?: RequestInit): Promise<serviceDeskRequestsStatusResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsStatusUrl(deskId,requestId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(serviceRequestStatusChange)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsStatusResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsStatusResponse\n}\n\n\n\nexport type serviceDeskRequestsCompleteResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsCompleteResponseSuccess = (serviceDeskRequestsCompleteResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsCompleteResponse = (serviceDeskRequestsCompleteResponseSuccess)\n\nexport const getServiceDeskRequestsCompleteUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}/complete`\n}\n\nexport const serviceDeskRequestsComplete = async (deskId: string,\n requestId: string, options?: RequestInit): Promise<serviceDeskRequestsCompleteResponse> => {\n\n const res = await fetch(getServiceDeskRequestsCompleteUrl(deskId,requestId),\n {\n ...options,\n method: 'POST'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsCompleteResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsCompleteResponse\n}\n\n\n\nexport type serviceDeskRequestsCancelResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsCancelResponseSuccess = (serviceDeskRequestsCancelResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsCancelResponse = (serviceDeskRequestsCancelResponseSuccess)\n\nexport const getServiceDeskRequestsCancelUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}/cancel`\n}\n\nexport const serviceDeskRequestsCancel = async (deskId: string,\n requestId: string,\n serviceRequestCancellation: ServiceRequestCancellation, options?: RequestInit): Promise<serviceDeskRequestsCancelResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsCancelUrl(deskId,requestId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(serviceRequestCancellation)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsCancelResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsCancelResponse\n}\n\n\n\n","import {\n getServiceDeskDesksGetUrl,\n getServiceDeskDesksListUrl,\n getServiceDeskDesksSaveUrl,\n getServiceDeskRequestsCancelUrl,\n getServiceDeskRequestsCompleteUrl,\n getServiceDeskRequestsDeleteUrl,\n getServiceDeskRequestsEditUrl,\n getServiceDeskRequestsListUrl,\n getServiceDeskRequestsRaiseUrl,\n getServiceDeskRequestsStatusUrl,\n} from '../api/endpoints';\nimport type { DeskResponse, ServiceRequestPage, ServiceRequestResponse } from '../api/models';\nimport { ServiceDeskGateway, ServiceDeskGatewayError, ServiceRequestOutcome } from './service-desk-gateway';\n\nexport interface HttpServiceDeskGatewayOptions {\n readonly baseUrl: string;\n readonly headers?: Readonly<Record<string, string>>;\n readonly fetch?: typeof fetch;\n}\n\nconst notFound = 404;\nconst conflict = 409;\nconst badRequest = 400;\nconst closedCode = 'request-closed';\n\ninterface Problem {\n readonly code?: string;\n}\n\nexport function createHttpServiceDeskGateway(options: HttpServiceDeskGatewayOptions): ServiceDeskGateway {\n const base = options.baseUrl.replace(/\\/+$/, '');\n const run = options.fetch ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init));\n\n const send = (path: string, method: string, body?: unknown, signal?: AbortSignal): Promise<Response> =>\n run(base + path, {\n method,\n signal,\n credentials: 'same-origin',\n headers: {\n Accept: 'application/json',\n ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),\n ...options.headers,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n const read = async <T>(response: Response): Promise<T> => {\n if (!response.ok) {\n throw new ServiceDeskGatewayError(response.status);\n }\n const value: T = await response.json();\n return value;\n };\n\n const outcome = async (response: Response): Promise<ServiceRequestOutcome> => {\n if (response.ok) {\n const request: ServiceRequestResponse = await response.json();\n return { kind: 'saved', request };\n }\n if (response.status === notFound) {\n return { kind: 'missing' };\n }\n if (response.status === badRequest) {\n return { kind: 'invalid' };\n }\n if (response.status !== conflict) {\n throw new ServiceDeskGatewayError(response.status);\n }\n const problem: Problem = await response.json().catch(() => ({}));\n return problem.code === closedCode ? { kind: 'closed' } : { kind: 'changed' };\n };\n\n return {\n desks: async () => read<DeskResponse[]>(await send(getServiceDeskDesksListUrl(), 'GET')),\n desk: async (deskId) => {\n const response = await send(getServiceDeskDesksGetUrl(deskId), 'GET');\n return response.status === notFound ? null : read<DeskResponse>(response);\n },\n saveDesk: async (deskId, name) => read<DeskResponse>(await send(getServiceDeskDesksSaveUrl(deskId), 'PUT', { name })),\n requests: async (deskId, listing, signal) =>\n read<ServiceRequestPage>(await send(getServiceDeskRequestsListUrl(deskId, listing), 'GET', undefined, signal)),\n raise: async (deskId, request) => outcome(await send(getServiceDeskRequestsRaiseUrl(deskId), 'POST', request)),\n edit: async (deskId, requestId, changes) => outcome(await send(getServiceDeskRequestsEditUrl(deskId, requestId), 'PUT', changes)),\n setStatus: async (deskId, requestId, status) =>\n outcome(await send(getServiceDeskRequestsStatusUrl(deskId, requestId), 'PUT', { status })),\n complete: async (deskId, requestId) => outcome(await send(getServiceDeskRequestsCompleteUrl(deskId, requestId), 'POST')),\n cancel: async (deskId, requestId, reason) =>\n outcome(await send(getServiceDeskRequestsCancelUrl(deskId, requestId), 'POST', { reason })),\n remove: async (deskId, requestId) => {\n const response = await send(getServiceDeskRequestsDeleteUrl(deskId, requestId), 'DELETE');\n if (!response.ok && response.status !== notFound) {\n throw new ServiceDeskGatewayError(response.status);\n }\n },\n };\n}\n"],"mappings":";;;;;;;AAiCA,IAAa,0BAAb,cAA6C,MAAK;CAC3B;CAArB,YAAqB,QAAc;EACjC,MAAM,6BAA6B,OAAM,EAAG;EADzB,KAAA,SAAA;CAErB;AACD;AAED,MAAa,uBAAuB,IAAI,eAAmC,kCAAkC;AAE7G,SAAgB,0BAA0B,SAA2B;CACnE,OAAO;EAAE,SAAS;EAAsB,UAAU;CAAO;AAC3D;ACvCA,IAAM,kBAAN,MAAqB;CACX;CAER,KAAK,KAAgB;EACnB,KAAK,MAAM;CACb;CAEA,SAAM;EACJ,KAAK,MAAM;CACb;CAEA,IAAI,KAAE;EACJ,IAAI,CAAC,KAAK,KACR,MAAM,IAAI,MAAM,wCAAwC;EAE1D,OAAO,KAAK,IAAI;CAClB;CAEA,SAAS,MAAY;EACnB,KAAK,KAAK,gBAAgB,IAAI;CAChC;AACD;AAED,MAAa,kBAAkB,IAAI,gBAAe;AC3BlD,MAAa,eAAe;AAE5B,SAAgB,SAAS,QAAc;CACrC,OAAO,GAAG,aAAY,GAAI;AAC5B;ACSA,IAAa,eAAb,MAAa,aAAY;CACN,UAAU,OAAO,oBAAoB;CAEnC,QAAQ,SAAQ;EAAA,GAAA,YAAA,EAAA,WAAA,QAAA,+BAAA,CAAA;EAAG,cAAc,KAAK,QAAQ,MAAK;CAAE,CAAA;CAE9D,KAAK,QAAc;EAC3B,gBAAgB,SAAS,SAAS,MAAM,CAAC;CAC3C;CAEU,MAAM,SAAM;EACpB,MAAM,OAAO,MAAM,gBAAgB,GAAG,OAAO;GAC3C,OAAO;GACP,SAAS;GACT,cAAc;EACf,CAAA;EACD,IAAI,CAAC,MAAM,KAAI,GACb;EAEF,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,QAAQ,SAAS,OAAO,WAAU,GAAI,KAAK,KAAI,CAAE;GACzE,KAAK,KAAK,KAAK,EAAE;EACnB,QAAQ;GACN,gBAAgB,GAAG,MAAM;IAAE,SAAS;IAA8B,MAAM;GAAO,CAAE;EACnF;CACF;CAxBW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAY,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAZ,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAY,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UCbzB;EAsBA,cAAA,CAAA;GAAA,MAAA;GAAA,MDdY;GAAa,MAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAKZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EAPxB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAmB,SACpB,CAAC,aAAa;GAAC,SACf,CAAC,sBAAsB;GAAC,iBAEhB,wBAAwB;GAAM,UAAA;EAAA,CAAA;;;AEPjD,SAAgB,eAAY;CAC1B,MAAM,YAAY,OAAO,gBAAgB;CACzC,OAAO,SAAS,UAAU,cAAc,EAAE,cAAc,UAAU,cAAa,EAAE,CAAE;AACrF;ACMA,MAAa,uBAAuB;CAClC,QAAQ;CACR,WAAW;CACX,UAAU;CACV,QAAQ;CACR,OAAO;CACP,OAAO;AACC;ACPV,MAAa,yBAAyB;CACpC,KAAK;CACL,QAAQ;CACR,MAAM;CACN,QAAQ;AACA;ACLV,MAAa,uBAAuB;CAClC,MAAM;CACN,YAAY;CACZ,WAAW;CACX,WAAW;AACH;ACLV,MAAa,qBAAqB;CAChC,SAAS;CACT,MAAM;CACN,iBAAiB;CACjB,qBAAqB;CACrB,WAAW;CACX,OAAO;AACC;ACbV,MAAa,eAA8C,OAAO,OAAO,kBAAkB;AAC3F,MAAa,oBAAuD,OAAO,OAAO,sBAAsB;AACxG,MAAa,iBAAkD,OAAO,OAAO,oBAAoB;AACjG,MAAa,mBAAoD,CAAC,qBAAqB,MAAM,qBAAqB,UAAU;AAE5H,MAAa,gBAAgB;CAAC;CAAU;CAAQ;CAAc;CAAa;CAAa;AAAK;AAG7F,SAAgB,SAAS,QAA4B;CACnD,OAAO,WAAW,qBAAqB,aAAa,WAAW,qBAAqB;AACtF;AAEA,SAAgB,UAAU,OAAW;CACnC,MAAM,OAAO,SAAiB,GAAG,OAAO,SAAS,GAAG,GAAG;CACvD,OAAO,GAAG,MAAM,YAAW,EAAE,GAAI,IAAI,MAAM,SAAQ,IAAK,CAAC,EAAC,GAAI,IAAI,MAAM,QAAO,CAAE;AACnF;AAEA,SAAgB,KAAuB,SAAuB,OAAa;CACzE,OAAO,QAAQ,MAAM,WAAW,WAAW,KAAK;AAClD;ACDA,IAAa,gBAAb,MAAa,cAAa;CACP,SAAS,OAA2B,SAAS;CAC7C,UAAU,OAAO,oBAAoB;CACrC,OAAO,KAAK,OAAO;CAC5B,WAAW,KAAK,KAAK;CAEV,UAAU,KAAK,aAAa;CAC5B,SAAS,KAAK,aAAa,QAAQ,SAAS,KAAK,SAAS,MAAM;CAChE,QAAQ;CACR,aAAa;CACb,UAAU;CACV,WAAW;CAEX,QAAQ,OAAO,KAAK,UAAU,SAAS,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAC1C,OAAO,OAA2B,KAAK,UAAU,QAAQ,mBAAmB,SAAQ,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACpF,WAAW,OAA+B,KAAK,UAAU,YAAY,uBAAuB,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACnG,SAAS,OAA6B,KAAK,UAAU,UAAU,qBAAqB,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAC3F,SAAS,OAA6B,KAAK,UAAU,UAAU,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACtE,cAAc,OAAO,KAAK,UAAU,eAAe,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CACtD,eAAe,OAAO,KAAK,UAAU,gBAAgB,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CACxD,eAAe,OAAO,KAAK,UAAU,gBAAgB,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CACxD,WAAW,OAAO,KAAK,UAAU,YAAY,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAChD,UAAU,OAAO,KAAK,UAAU,QAAQ,UAAU,IAAI,KAAK,KAAK,SAAS,KAAK,CAAC,IAAI,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CACtF,cAAc,OAAO,KAAK,UAAU,eAAe,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CACtD,qBAAqB,KAAK,UAAU,sBAAsB;CAC1D,SAAS,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACtB,UAAU,OAAO,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAC/B,YAAY;CAEV,KAAK,QAAsC,OAAY;EAC/D,OAAO,IAAK,MAAM,OAA4B,KAAK;CACrD;CAEU,WAAW,OAAY;EAC/B,KAAK,OAAO,KAAK,MAAM,cAAc,KAAK;CAC5C;CAEU,eAAe,OAAY;EACnC,KAAK,OAAO,KAAK,UAAU,mBAAmB,KAAK;CACrD;CAEU,aAAa,OAAY;EACjC,KAAK,OAAO,KAAK,QAAQ,gBAAgB,KAAK;CAChD;CAEU,aAAa,OAAY;EACjC,KAAK,OAAO,KAAK,QAAQ,kBAAkB,KAAK;CAClD;CAEU,QAAK;EACb,KAAK,OAAO,MAAM,KAAK,SAAS;CAClC;CAEU,MAAM,OAAI;EAClB,IAAI,CAAC,KAAK,MAAK,CAAE,CAAC,KAAI,GAAI;GACxB,KAAK,QAAQ,IAAI,mCAAmC;GACpD;EACF;EACA,KAAK,OAAO,IAAI,IAAI;EACpB,IAAI;GACF,MAAM,UAAU,KAAK,QAAO;GAC5B,MAAM,UAAU,KAAK,WACjB,MAAM,KAAK,QAAQ,KAAK,KAAK,KAAK,QAAQ,KAAK,SAAS,IAAI,OAAO,IACnE,MAAM,KAAK,QAAQ,MAAM,KAAK,KAAK,QAAQ;IAAE,GAAG;IAAS,QAAQ,KAAK,OAAM;GAAE,CAAE;GACpF,KAAK,OAAO,MAAM,KAAK,YAAY,OAAO,CAAC;EAC7C,QAAQ;GACN,KAAK,QAAQ,IAAI,0BAA0B;EAC7C,UAAU;GACR,KAAK,OAAO,IAAI,KAAK;EACvB;CACF;CAEQ,UAAO;EACb,MAAM,UAAU,KAAK,UAAU,SAAS,UAAU,IAAI,KAAK,KAAK,SAAS,KAAK,CAAC,MAAM,KAAK,QAAO,IAAK,KAAK,SAAS,QAAQ;EAC5H,IAAI,SACF,OAAO;GAAE,GAAG,KAAK,OAAM;GAAI,OAAO;EAAO;EAE3C,MAAM,MAAM,KAAK,QAAO,oBAAK,IAAI,KAAK,GAAG,KAAK,QAAO,EAAE,OAAQ,IAAI;EACnE,OAAO;GAAE,GAAG,KAAK,OAAM;GAAI,OAAO,OAAO,CAAC,OAAO,MAAM,IAAI,QAAO,CAAE,IAAI,IAAI,YAAW,IAAK;EAAI;CAClG;CAEQ,SAAM;EACZ,OAAO;GACL,OAAO,KAAK,MAAK,CAAE,CAAC,KAAI;GACxB,aAAa,KAAK,SAAS,KAAK,YAAW,CAAE;GAC7C,MAAM,KAAK,KAAI;GACf,UAAU,KAAK,SAAQ;GACvB,aAAa,KAAK,SAAS,KAAK,YAAW,CAAE;GAC7C,cAAc,KAAK,SAAS,KAAK,aAAY,CAAE;GAC/C,cAAc,KAAK,SAAS,KAAK,aAAY,CAAE;GAC/C,UAAU,KAAK,SAAS,KAAK,SAAQ,CAAE;EACxC;CACH;CAEQ,MAAM,YAAY,SAA8B;EACtD,IAAI,QAAQ,SAAS,SAAS;GAC5B,KAAK,WAAW,QAAQ;GACxB,KAAK,YAAY;EACnB;EACA,IAAI,QAAQ,SAAS,WAAW,QAAQ,QAAQ,WAAW,KAAK,OAAM,GACpE,OAAO;EAET,OAAO,KAAK,QAAQ,UAAU,KAAK,KAAK,QAAQ,QAAQ,QAAQ,IAAI,KAAK,OAAM,CAAE;CACnF;CAEQ,OAAO,SAA8B;EAC3C,MAAM,WAA4E;GAChF,QAAQ;GACR,SAAS;GACT,SAAS;GACT,SAAS;EACV;EACD,IAAI,QAAQ,SAAS,SAAS;GAC5B,KAAK,OAAO,MAAM,IAAI;GACtB;EACF;EACA,KAAK,QAAQ,IAAI,SAAS,QAAQ,KAAK;CACzC;CAEQ,OAAyB,QAAiC,SAAuB,OAAY;EACnG,MAAM,SAAS,KAAK,SAAU,MAAM,OAA6B,KAAK;EACtE,IAAI,QACF,OAAO,IAAI,MAAM;CAErB;CAEQ,SAAS,OAAa;EAC5B,OAAO,MAAM,KAAI,IAAK,MAAM,KAAI,IAAK;CACvC;CAhIW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAb,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAa,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UCzB1B;EAmGA,cAAA,CAAA;GAAA,MAAA;GAAA,MD9EY;GAAa,MAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAIZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAa,YAAA,CAAA;EANzB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAmB,SACpB,CAAC,aAAa;GAAC,iBAEP,wBAAwB;GAAM,UAAA;EAAA,CAAA;;;AEEjD,IAAa,eAAb,MAAa,aAAY;CACd,WAAW,MAAM,SAA6C,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAC9D,SAAS,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAEjC,iBAAiB,OAAM;CAEb,OAAO,eAAqC;EAC7D,MAAM,OAAO,IAAI,KAAK,eAAe,KAAK,OAAM,GAAI;GAAE,KAAK;GAAW,OAAO;GAAW,MAAM;EAAS,CAAE;EACzG,OAAO,KAAK,SAAQ,CAAE,CAAC,KAAK,aAAa;GACvC;GACA,QAAQ,KAAK,OAAO,IAAI,KAAK,QAAQ,QAAQ,CAAC;GAC9C,KAAK,QAAQ,QAAQ,KAAK,OAAO,IAAI,KAAK,QAAQ,KAAK,CAAC,IAAI;GAC5D,QAAQ,SAAS,QAAQ,MAAM;EAChC,EAAC;CACJ,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAdS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAY,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAZ,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAY,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA,EAAA,gBAAA,iBAAA;EAAA,UAAA;EAAA,UCzBzB;EAmDA,cAAA,CAAA;GAAA,MAAA;GAAA,MD/BY;GAAa,MAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAKZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EAPxB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAkB,SACnB,CAAC,aAAa;GAAC,SACf,CAAC,sBAAsB;GAAC,iBAEhB,wBAAwB;GAAM,UAAA;EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;AEVjD,MAAM,WAAW;AACjB,MAAM,gBAAgB;AAStB,IAAa,WAAb,MAAa,SAAQ;CACF,UAAU,OAAO,oBAAoB;CACrC,QAAQ,OAAO,cAAc;CACtC;CAEW,SAAS,aAAY;CACrB,UAAU;CACV,SAAS,SAAS,KAAK,MAAM,SAAS,KAAK,KAAK,WAAW,OAAO,IAAI,QAAQ,KAAK,EAAE,CAAC,GAAG,EAC1G,cAAc,KAAK,MAAM,SAAS,SAAS,IAAI,QAAQ,KAAK,GAC7D,CAAA;CACkB,OAAO,OAAO,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACjB,SAAS,OAAqB,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACvC,SAAS,OAAO,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAElB,OAAO,SAAQ;EAAA,GAAA,YAAA,EAAA,WAAA,OAAA,+BAAA,CAAA;EAChC,cAAc,KAAK,OAAM;EACzB,SAAS,EAAE,aAAa,KAAK,QAAQ,KAAK,MAAM;CAAC,CAAA;CAGhC,OAAO,SAAQ;EAAA,GAAA,YAAA,EAAA,WAAA,OAAA,+BAAA,CAAA;EAChC,eAAe;GAAE,QAAQ,KAAK,OAAM;GAAI,MAAM,KAAK,KAAI,CAAE,CAAC,KAAI;GAAI,QAAQ,KAAK,OAAM;GAAI,QAAQ,KAAK,OAAM;EAAE;EAC9G,SAAS,EAAE,QAAQ,kBACjB,KAAK,QAAQ,SACX,OAAO,QACP;GACE,MAAM,OAAO,QAAQ;GACrB,GAAI,OAAO,WAAW,WAAW,CAAA,IAAK,OAAO,WAAW,QAAQ,EAAE,kBAAkB,KAAI,IAAK,EAAE,QAAQ,OAAO,OAAM;GACpH,QAAQ,OAAO;GACf,OAAO;EACR,GACD,WAAW;CACZ,CAAA;CAGL,cAAA;EACE,OAAO,UAAU,CAAC,CAAC,gBAAgB,aAAa,KAAK,WAAW,CAAC;EACjE,aAAY;GACV,MAAM,QAAQ,KAAK,MAAK;GACxB,IAAI,KAAK,KAAK,SAAQ,KAAM,KAAK,OAAM,IAAK,KAAK,KAAK,OAAM,KAAM,OAChE,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,QAAQ,IAAI,CAAC,IAAI,QAAQ;EAE3E,CAAC;CACH;CAEmB,QAAQ,eAAe,OAAO,KAAK,KAAK,MAAK,CAAE,EAAE,SAAS,CAAC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAE7D,QAAQ,eAAc;EACvC,MAAM,QAAQ,KAAK,MAAK;EAExB,OAAO;GAAE,OADK,UAAU,IAAI,IAAI,KAAK,OAAM,IAAK;GAChC,MAAM,KAAK,IAAI,KAAK,OAAM,IAAK,UAAU,KAAK;GAAG;EAAK;CACxE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAEiB,cAAc,eAAe,KAAK,OAAM,IAAK,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAC/C,UAAU,eAAe,KAAK,OAAM,IAAK,WAAW,KAAK,MAAK,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAE1E,OAAO,OAAY;EAC3B,MAAM,QAAS,MAAM,OAA4B;EACjD,aAAa,KAAK,WAAW;EAC7B,KAAK,cAAc,iBAAgB;GACjC,KAAK,KAAK,IAAI,KAAK;GACnB,KAAK,OAAO,IAAI,CAAC;EACnB,GAAG,aAAa;CAClB;CAEU,aAAa,OAAY;EACjC,MAAM,SAAS,cAAc,MAAM,WAAW,WAAY,MAAM,OAA6B,KAAK;EAClG,IAAI,QAAQ;GACV,KAAK,OAAO,IAAI,MAAM;GACtB,KAAK,OAAO,IAAI,CAAC;EACnB;CACF;CAEU,WAAQ;EAChB,KAAK,OAAO,QAAQ,WAAW,KAAK,IAAI,GAAG,SAAS,QAAQ,CAAC;CAC/D;CAEU,OAAI;EACZ,KAAK,OAAO,QAAQ,WAAW,SAAS,QAAQ;CAClD;CAEU,MAAG;EACX,KAAK,WAAW;GAAE,QAAQ,KAAK,OAAM;GAAI,SAAS;EAAI,GAAI,8BAA8B;CAC1F;CAEU,QAAQ,EAAE,SAAS,GAAG,KAAmB;EACjD,MAAM,SAAS,SAAS,QAAQ,MAAM;EACtC,gBAAgB,GAAG,SACjB;GACE;IAAE,OAAO,SAAS,8BAA8B;IAA6B,MAAM,SAAS,YAAY;IAAQ,WAAW,KAAK,KAAK,OAAO;GAAC;GAC7I,GAAI,SACA,CAAA,IACA,CACE;IAAE,OAAO;IAAiC,MAAM;IAAuB,WAAW,KAAK,KAAK,SAAS,OAAO;GAAC,GAC7G;IAAE,OAAO;IAA+B,MAAM;IAAqB,WAAW,KAAK,KAAK,OAAO,OAAO;GAAC,CACxG;GACL;IAAE,OAAO;IAA+B,MAAM;IAAS,WAAW,KAAK,KAAK,OAAO,OAAO;GAAC;EAC5F,GACD;GAAE;GAAG;EAAC,CAAE;CAEZ;CAEU,KAAK,SAA+B;EAC5C,MAAM,SAAS,SAAS,QAAQ,MAAM;EACtC,KAAK,WAAW;GAAE,QAAQ,KAAK,OAAM;GAAI;EAAO,GAAI,SAAS,kCAAkC,+BAA+B;CAChI;CAEU,MAAM,SAAS,SAA+B;EACtD,MAAM,KAAK,QAAQ,YAAY,KAAK,OAAO,MAAM,KAAK,QAAQ,SAAS,KAAK,OAAM,GAAI,QAAQ,EAAE,GAAG,4BAA4B,CAAC;CAClI;CAEU,MAAM,OAAO,SAA+B;EACpD,MAAM,SAAS,MAAM,gBAAgB,GAAG,OAAO;GAC7C,OAAO;GACP,SAAS;GACT,cAAc;GACd,MAAM;EACP,CAAA;EACD,IAAI,WAAW,MACb;EAEF,MAAM,KAAK,QAAQ,YACjB,KAAK,OAAO,MAAM,KAAK,QAAQ,OAAO,KAAK,OAAM,GAAI,QAAQ,IAAI,OAAO,KAAI,KAAM,IAAI,GAAG,0BAA0B,CAAC;CAExH;CAEU,MAAM,OAAO,SAA+B;EAOpD,IAAI,CAAC,MANmB,gBAAgB,GAAG,QAAQ;GACjD,OAAO;GACP,SAAS;GACT,cAAc;GACd,MAAM;EACP,CAAA,GAEC;EAEF,MAAM,KAAK,QAAQ,YAAW;GAC5B,MAAM,KAAK,QAAQ,OAAO,KAAK,OAAM,GAAI,QAAQ,EAAE;GACnD,gBAAgB,GAAG,MAAM;IAAE,SAAS;IAA4B,MAAM;GAAS,CAAE;GACjF,KAAK,KAAK,OAAM;EAClB,CAAC;CACH;CAEQ,MAAM,QAAQ,MAAyB;EAC7C,IAAI;GACF,MAAM,KAAI;EACZ,QAAQ;GACN,gBAAgB,GAAG,MAAM;IAAE,SAAS;IAA4B,MAAM;GAAO,CAAE;GAC/E,KAAK,KAAK,OAAM;EAClB;CACF;CAEQ,WAAW,MAAyB,OAAa;EAEvD,AADe,gBAAgB,GAAG,KAAc,eAAe;GAAE;GAAM;GAAO,MAAM;GAAM,SAAS;EAAU,CACxG,CAAA,CAAO,OAAO,MAAM,UAAS;GAChC,IAAI,OAAO;IACT,gBAAgB,GAAG,MAAM;KAAE,SAAS;KAA6B,MAAM;IAAS,CAAE;IAClF,KAAK,KAAK,OAAM;GAClB;EACF,CAAC;CACH;CAEQ,OAAO,SAAgC,MAAY;EACzD,MAAM,QAAQ,QAAQ,SAAS;EAC/B,gBAAgB,GAAG,MAAM;GAAE,SAAS,QAAQ,OAAO;GAA4B,MAAM,QAAQ,YAAY;EAAO,CAAE;EAClH,KAAK,KAAK,OAAM;CAClB;CArKW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAQ,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAR,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAQ,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UCvBrB;EA4CA,cAAA,CAAA;GAAA,MAAA;GAAA,MD1B2B;GAAY,UAAA;GAAA,QAAA,CAAA,YAAA,QAAA;GAAA,SAAA,CAAA,gBAAA;EAAA,GAAA;GAAA,MAAA;GAAA,MAA3B;GAAa,MAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAKZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAQ,YAAA,CAAA;EAPpB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAc,SACf,CAAC,eAAe,YAAY;GAAC,SAC7B,CAAC,sBAAsB;GAAC,iBAEhB,wBAAwB;GAAM,UAAA;EAAA,CAAA;;;;AErBjD,MAAM,SAAS;AAEf,MAAa,mBAAqD;CAChE,aAAa,4BAA4B,OAAM;CAC/C,qBAAqB,4BAA4B,OAAM;CACvD,mBAAmB,4BAA4B,OAAM;CACrD,qBAAqB,4BAA4B,OAAM;CACvD,iBAAiB,4BAA4B,OAAM;AACpD;ACGD,SAAgB,wBAAwB,UAAoC,CAAA,GAAE;CAC5E,OAAO;EACL,UAAU;GACR,IAAI;GACJ,MAAM;GACN,cAAc;IAAC;IAAiB;IAAc;GAAI;EACnD;EACD,SAAS,KAAG;GACV,gBAAgB,KAAK,GAAG;GACxB,IAAI,gBAAgB,gBAAgB;GACpC,IAAI,gBAAgB;IAClB,IAAI;IACJ,OAAO;IACP,MAAM;IACN,UAAU,EAAE,MAAM,aAAY;IAC9B,WAAW;GACZ,CAAA;GACD,IAAI,gBAAgB;IAClB,IAAI;IACJ,OAAO;IACP,MAAM;IACN,UAAU,EAAE,MAAM,GAAG,aAAY,UAAU;IAC3C,WAAW;GACZ,CAAA;GACD,IAAI,QAAQ,UACV,IAAI,iBAAiB;IACnB,IAAI;IACJ,MAAM;IACN,MAAM;IACN,OAAO;IACP,WAAW,IAAI,gBAAgB,YAAY;GAC5C,CAAA;EAEL;EACA,aAAU;GACR,gBAAgB,OAAM;EACxB;CACD;AACH;AAEA,MAAa,oBAAoB,wBAAuB;ACfxD,MAAa,8BAA8B,WAAmB;CAK5D,OAAO,uBAAuB;AAChC;AAiDA,MAAa,6BAA6B,WAAmB;CAK3D,OAAO,uBAAuB;AAChC;AA0EA,MAAa,mCAAkC;CAK7C,OAAO;AACT;AAkCA,MAAa,kCAAkC,WAAmB;CAKhE,OAAO,uBAAuB,OAAM;AACtC;AAiDA,MAAa,iCAAiC,QAC1C,WAA2C;CAC7C,MAAM,mBAAmB,IAAI,gBAAe;CAE5C,OAAO,QAAQ,UAAU,CAAA,CAAE,CAAC,CAAC,SAAS,CAAC,KAAK,WAAU;EAEpD,IAAI,UAAU,QACZ,iBAAiB,OAAO,KAAK,UAAU,OAAO,SAAS,OAAO,KAAK,CAAC;CAExE,CAAC;CAED,MAAM,oBAAoB,iBAAiB,SAAQ;CAEnD,OAAO,kBAAkB,SAAS,IAAI,uBAAuB,OAAM,YAAa,sBAAsB,uBAAuB,OAAM;AACrI;AA6EA,MAAa,iCAAiC,QAC1C,cAAsB;CAKxB,OAAO,uBAAuB,OAAM,YAAa;AACnD;AAkDA,MAAa,mCAAmC,QAC5C,cAAsB;CAKxB,OAAO,uBAAuB,OAAM,YAAa;AACnD;AAmCA,MAAa,mCAAmC,QAC5C,cAAsB;CAKxB,OAAO,uBAAuB,OAAM,YAAa,UAAS;AAC5D;AAkDA,MAAa,qCAAqC,QAC9C,cAAsB;CAKxB,OAAO,uBAAuB,OAAM,YAAa,UAAS;AAC5D;AAmCA,MAAa,mCAAmC,QAC5C,cAAsB;CAKxB,OAAO,uBAAuB,OAAM,YAAa,UAAS;AAC5D;AC7hBA,MAAM,WAAW;AACjB,MAAM,WAAW;AACjB,MAAM,aAAa;AACnB,MAAM,aAAa;AAMnB,SAAgB,6BAA6B,SAAsC;CACjF,MAAM,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;CAC/C,MAAM,MAAM,QAAQ,WAAW,OAA0B,SAAuB,MAAM,OAAO,IAAI;CAEjG,MAAM,QAAQ,MAAc,QAAgB,MAAgB,WAC1D,IAAI,OAAO,MAAM;EACf;EACA;EACA,aAAa;EACb,SAAS;GACP,QAAQ;GACR,GAAI,SAAS,SAAY,CAAA,IAAK,EAAE,gBAAgB,mBAAkB;GAClE,GAAG,QAAQ;EACZ;EACD,MAAM,SAAS,SAAY,SAAY,KAAK,UAAU,IAAI;CAC3D,CAAA;CAEH,MAAM,OAAO,OAAU,aAAkC;EACvD,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,wBAAwB,SAAS,MAAM;EAGnD,OAAO,MADgB,SAAS,KAAI;CAEtC;CAEA,MAAM,UAAU,OAAO,aAAsD;EAC3E,IAAI,SAAS,IAEX,OAAO;GAAE,MAAM;GAAS,eADsB,SAAS,KAAI;EAC5B;EAEjC,IAAI,SAAS,WAAW,UACtB,OAAO,EAAE,MAAM,UAAS;EAE1B,IAAI,SAAS,WAAW,YACtB,OAAO,EAAE,MAAM,UAAS;EAE1B,IAAI,SAAS,WAAW,UACtB,MAAM,IAAI,wBAAwB,SAAS,MAAM;EAGnD,QAAO,MADwB,SAAS,KAAI,CAAE,CAAC,aAAa,CAAA,EAAG,EACxD,CAAQ,SAAS,aAAa,EAAE,MAAM,SAAQ,IAAK,EAAE,MAAM,UAAS;CAC7E;CAEA,OAAO;EACL,OAAO,YAAY,KAAqB,MAAM,KAAK,2BAA0B,GAAI,KAAK,CAAC;EACvF,MAAM,OAAO,WAAU;GACrB,MAAM,WAAW,MAAM,KAAK,0BAA0B,MAAM,GAAG,KAAK;GACpE,OAAO,SAAS,WAAW,WAAW,OAAO,KAAmB,QAAQ;EAC1E;EACA,UAAU,OAAO,QAAQ,SAAS,KAAmB,MAAM,KAAK,2BAA2B,MAAM,GAAG,OAAO,EAAE,KAAI,CAAE,CAAC;EACpH,UAAU,OAAO,QAAQ,SAAS,WAChC,KAAyB,MAAM,KAAK,8BAA8B,QAAQ,OAAO,GAAG,OAAO,QAAW,MAAM,CAAC;EAC/G,OAAO,OAAO,QAAQ,YAAY,QAAQ,MAAM,KAAK,+BAA+B,MAAM,GAAG,QAAQ,OAAO,CAAC;EAC7G,MAAM,OAAO,QAAQ,WAAW,YAAY,QAAQ,MAAM,KAAK,8BAA8B,QAAQ,SAAS,GAAG,OAAO,OAAO,CAAC;EAChI,WAAW,OAAO,QAAQ,WAAW,WACnC,QAAQ,MAAM,KAAK,gCAAgC,QAAQ,SAAS,GAAG,OAAO,EAAE,OAAM,CAAE,CAAC;EAC3F,UAAU,OAAO,QAAQ,cAAc,QAAQ,MAAM,KAAK,kCAAkC,QAAQ,SAAS,GAAG,MAAM,CAAC;EACvH,QAAQ,OAAO,QAAQ,WAAW,WAChC,QAAQ,MAAM,KAAK,gCAAgC,QAAQ,SAAS,GAAG,QAAQ,EAAE,OAAM,CAAE,CAAC;EAC5F,QAAQ,OAAO,QAAQ,cAAa;GAClC,MAAM,WAAW,MAAM,KAAK,gCAAgC,QAAQ,SAAS,GAAG,QAAQ;GACxF,IAAI,CAAC,SAAS,MAAM,SAAS,WAAW,UACtC,MAAM,IAAI,wBAAwB,SAAS,MAAM;EAErD;CACD;AACH"}
1
+ {"version":3,"file":"weaver-apps-service-desk.mjs","names":[],"sources":["../../../../libs/service-desk/src/lib/plugin/service-desk-icons.ts","../../../../libs/service-desk/src/lib/plugin/service-desk.plugin.ts","../../../../libs/service-desk/src/lib/api/endpoints.ts","../../../../libs/service-desk/src/lib/gateway/http-service-desk-gateway.ts"],"sourcesContent":["import { serviceDeskIconNames } from './service-desk-ids';\n\nconst stroke = 'fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"';\n\nexport const serviceDeskIcons: Readonly<Record<string, string>> = {\n [serviceDeskIconNames.desk]: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M4 13.5V7a2.5 2.5 0 0 1 2.5-2.5h11A2.5 2.5 0 0 1 20 7v6.5\"/><path d=\"M3 13.5h5l1.5 2.5h5l1.5-2.5h5V18a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"/></svg>`,\n [serviceDeskIconNames.complete]: `<svg viewBox=\"0 0 24 24\" ${stroke}><circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M8.5 12.5l2.5 2.5 4.5-5\"/></svg>`,\n [serviceDeskIconNames.cancel]: `<svg viewBox=\"0 0 24 24\" ${stroke}><circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M9 9l6 6M15 9l-6 6\"/></svg>`,\n [serviceDeskIconNames.previous]: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M15 5l-7 7 7 7\"/></svg>`,\n [serviceDeskIconNames.next]: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M9 5l7 7-7 7\"/></svg>`,\n};\n","import { Plugin } from '@loomweaver/plugin-sdk';\nimport { serviceDeskHost } from './service-desk-host';\nimport { serviceDeskContributionIds, serviceDeskIconNames, serviceDeskPluginId } from './service-desk-ids';\nimport { serviceDeskIcons } from './service-desk-icons';\nimport { deskListPath } from './service-desk-paths';\n\nexport interface ServiceDeskPluginOptions {\n readonly railItem?: boolean;\n}\n\nexport function createServiceDeskPlugin(options: ServiceDeskPluginOptions = {}): Plugin {\n return {\n manifest: {\n id: serviceDeskPluginId,\n name: 'Service desk',\n capabilities: ['contributions', 'navigation', 'ui'],\n },\n activate(ctx) {\n serviceDeskHost.bind(ctx);\n ctx.contributeIcons(serviceDeskIcons);\n ctx.registerSurface({\n id: serviceDeskContributionIds.desks,\n title: 'weaver-apps-service-desk.desks.title',\n icon: serviceDeskIconNames.desk,\n routable: { path: deskListPath },\n loadComponent: () => import('../views/desk-list-page').then((module) => module.DeskListPage),\n });\n ctx.registerSurface({\n id: serviceDeskContributionIds.desk,\n title: 'weaver-apps-service-desk.title',\n icon: serviceDeskIconNames.desk,\n routable: { path: `${deskListPath}/:deskId` },\n loadComponent: () => import('../views/desk-page').then((module) => module.DeskPage),\n });\n if (options.railItem) {\n ctx.registerRailItem({\n id: serviceDeskContributionIds.rail,\n rail: 'primary',\n icon: serviceDeskIconNames.desk,\n title: 'weaver-apps-service-desk.desks.title',\n run: () => ctx.navigateContent(deskListPath),\n });\n }\n },\n deactivate() {\n serviceDeskHost.unbind();\n },\n };\n}\n\nexport const serviceDeskPlugin = createServiceDeskPlugin();\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\nimport type {\n DeskResponse,\n NewServiceRequest,\n SaveDeskRequest,\n ServiceDeskRequestsListParams,\n ServiceRequestCancellation,\n ServiceRequestChanges,\n ServiceRequestPage,\n ServiceRequestResponse,\n ServiceRequestStatusChange\n} from './models';\n\n\nexport type serviceDeskDesksSaveResponse200 = {\n data: DeskResponse\n status: 200\n}\n\nexport type serviceDeskDesksSaveResponse201 = {\n data: DeskResponse\n status: 201\n}\n\nexport type serviceDeskDesksSaveResponseSuccess = (serviceDeskDesksSaveResponse200 | serviceDeskDesksSaveResponse201) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksSaveResponse = (serviceDeskDesksSaveResponseSuccess)\n\nexport const getServiceDeskDesksSaveUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}`\n}\n\nexport const serviceDeskDesksSave = async (deskId: string,\n saveDeskRequest: SaveDeskRequest, options?: RequestInit): Promise<serviceDeskDesksSaveResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskDesksSaveUrl(deskId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(saveDeskRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksSaveResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksSaveResponse\n}\n\n\n\nexport type serviceDeskDesksGetResponse200 = {\n data: DeskResponse\n status: 200\n}\n\nexport type serviceDeskDesksGetResponseSuccess = (serviceDeskDesksGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksGetResponse = (serviceDeskDesksGetResponseSuccess)\n\nexport const getServiceDeskDesksGetUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}`\n}\n\nexport const serviceDeskDesksGet = async (deskId: string, options?: RequestInit): Promise<serviceDeskDesksGetResponse> => {\n\n const res = await fetch(getServiceDeskDesksGetUrl(deskId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksGetResponse\n}\n\n\n\nexport type serviceDeskDesksDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type serviceDeskDesksDeleteResponseSuccess = (serviceDeskDesksDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksDeleteResponse = (serviceDeskDesksDeleteResponseSuccess)\n\nexport const getServiceDeskDesksDeleteUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}`\n}\n\nexport const serviceDeskDesksDelete = async (deskId: string, options?: RequestInit): Promise<serviceDeskDesksDeleteResponse> => {\n\n const res = await fetch(getServiceDeskDesksDeleteUrl(deskId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksDeleteResponse\n}\n\n\n\nexport type serviceDeskDesksListResponse200 = {\n data: DeskResponse[]\n status: 200\n}\n\nexport type serviceDeskDesksListResponseSuccess = (serviceDeskDesksListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskDesksListResponse = (serviceDeskDesksListResponseSuccess)\n\nexport const getServiceDeskDesksListUrl = () => {\n\n\n\n\n return `/service-desk/desks`\n}\n\nexport const serviceDeskDesksList = async ( options?: RequestInit): Promise<serviceDeskDesksListResponse> => {\n\n const res = await fetch(getServiceDeskDesksListUrl(),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskDesksListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskDesksListResponse\n}\n\n\n\nexport type serviceDeskRequestsRaiseResponse201 = {\n data: ServiceRequestResponse\n status: 201\n}\n\nexport type serviceDeskRequestsRaiseResponseSuccess = (serviceDeskRequestsRaiseResponse201) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsRaiseResponse = (serviceDeskRequestsRaiseResponseSuccess)\n\nexport const getServiceDeskRequestsRaiseUrl = (deskId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests`\n}\n\nexport const serviceDeskRequestsRaise = async (deskId: string,\n newServiceRequest: NewServiceRequest, options?: RequestInit): Promise<serviceDeskRequestsRaiseResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsRaiseUrl(deskId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(newServiceRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsRaiseResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsRaiseResponse\n}\n\n\n\nexport type serviceDeskRequestsListResponse200 = {\n data: ServiceRequestPage\n status: 200\n}\n\nexport type serviceDeskRequestsListResponseSuccess = (serviceDeskRequestsListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsListResponse = (serviceDeskRequestsListResponseSuccess)\n\nexport const getServiceDeskRequestsListUrl = (deskId: string,\n params?: ServiceDeskRequestsListParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n const explodeParameters = [\"type\",\"status\",\"priority\"];\n\n if (Array.isArray(value) && explodeParameters.includes(key)) {\n value.forEach((v) => {\n normalizedParams.append(key, v === null ? 'null' : String(v));\n });\n return;\n }\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/service-desk/desks/${deskId}/requests?${stringifiedParams}` : `/service-desk/desks/${deskId}/requests`\n}\n\nexport const serviceDeskRequestsList = async (deskId: string,\n params?: ServiceDeskRequestsListParams, options?: RequestInit): Promise<serviceDeskRequestsListResponse> => {\n\n const res = await fetch(getServiceDeskRequestsListUrl(deskId,params),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsListResponse\n}\n\n\n\nexport type serviceDeskRequestsGetResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsGetResponseSuccess = (serviceDeskRequestsGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsGetResponse = (serviceDeskRequestsGetResponseSuccess)\n\nexport const getServiceDeskRequestsGetUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}`\n}\n\nexport const serviceDeskRequestsGet = async (deskId: string,\n requestId: string, options?: RequestInit): Promise<serviceDeskRequestsGetResponse> => {\n\n const res = await fetch(getServiceDeskRequestsGetUrl(deskId,requestId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsGetResponse\n}\n\n\n\nexport type serviceDeskRequestsEditResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsEditResponseSuccess = (serviceDeskRequestsEditResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsEditResponse = (serviceDeskRequestsEditResponseSuccess)\n\nexport const getServiceDeskRequestsEditUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}`\n}\n\nexport const serviceDeskRequestsEdit = async (deskId: string,\n requestId: string,\n serviceRequestChanges: ServiceRequestChanges, options?: RequestInit): Promise<serviceDeskRequestsEditResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsEditUrl(deskId,requestId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(serviceRequestChanges)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsEditResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsEditResponse\n}\n\n\n\nexport type serviceDeskRequestsDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type serviceDeskRequestsDeleteResponseSuccess = (serviceDeskRequestsDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsDeleteResponse = (serviceDeskRequestsDeleteResponseSuccess)\n\nexport const getServiceDeskRequestsDeleteUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}`\n}\n\nexport const serviceDeskRequestsDelete = async (deskId: string,\n requestId: string, options?: RequestInit): Promise<serviceDeskRequestsDeleteResponse> => {\n\n const res = await fetch(getServiceDeskRequestsDeleteUrl(deskId,requestId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsDeleteResponse\n}\n\n\n\nexport type serviceDeskRequestsStatusResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsStatusResponseSuccess = (serviceDeskRequestsStatusResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsStatusResponse = (serviceDeskRequestsStatusResponseSuccess)\n\nexport const getServiceDeskRequestsStatusUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}/status`\n}\n\nexport const serviceDeskRequestsStatus = async (deskId: string,\n requestId: string,\n serviceRequestStatusChange: ServiceRequestStatusChange, options?: RequestInit): Promise<serviceDeskRequestsStatusResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsStatusUrl(deskId,requestId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(serviceRequestStatusChange)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsStatusResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsStatusResponse\n}\n\n\n\nexport type serviceDeskRequestsCompleteResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsCompleteResponseSuccess = (serviceDeskRequestsCompleteResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsCompleteResponse = (serviceDeskRequestsCompleteResponseSuccess)\n\nexport const getServiceDeskRequestsCompleteUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}/complete`\n}\n\nexport const serviceDeskRequestsComplete = async (deskId: string,\n requestId: string, options?: RequestInit): Promise<serviceDeskRequestsCompleteResponse> => {\n\n const res = await fetch(getServiceDeskRequestsCompleteUrl(deskId,requestId),\n {\n ...options,\n method: 'POST'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsCompleteResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsCompleteResponse\n}\n\n\n\nexport type serviceDeskRequestsCancelResponse200 = {\n data: ServiceRequestResponse\n status: 200\n}\n\nexport type serviceDeskRequestsCancelResponseSuccess = (serviceDeskRequestsCancelResponse200) & {\n headers: Headers;\n};\n;\n\nexport type serviceDeskRequestsCancelResponse = (serviceDeskRequestsCancelResponseSuccess)\n\nexport const getServiceDeskRequestsCancelUrl = (deskId: string,\n requestId: string,) => {\n\n\n\n\n return `/service-desk/desks/${deskId}/requests/${requestId}/cancel`\n}\n\nexport const serviceDeskRequestsCancel = async (deskId: string,\n requestId: string,\n serviceRequestCancellation: ServiceRequestCancellation, options?: RequestInit): Promise<serviceDeskRequestsCancelResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getServiceDeskRequestsCancelUrl(deskId,requestId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(serviceRequestCancellation)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: serviceDeskRequestsCancelResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as serviceDeskRequestsCancelResponse\n}\n\n\n\n","import {\n getServiceDeskDesksGetUrl,\n getServiceDeskDesksListUrl,\n getServiceDeskDesksSaveUrl,\n getServiceDeskRequestsCancelUrl,\n getServiceDeskRequestsCompleteUrl,\n getServiceDeskRequestsDeleteUrl,\n getServiceDeskRequestsEditUrl,\n getServiceDeskRequestsListUrl,\n getServiceDeskRequestsRaiseUrl,\n getServiceDeskRequestsStatusUrl,\n} from '../api/endpoints';\nimport type { DeskResponse, ServiceRequestPage, ServiceRequestResponse } from '../api/models';\nimport { ServiceDeskGateway, ServiceDeskGatewayError, ServiceRequestOutcome } from './service-desk-gateway';\n\nexport interface HttpServiceDeskGatewayOptions {\n readonly baseUrl: string;\n readonly headers?: Readonly<Record<string, string>>;\n readonly fetch?: typeof fetch;\n}\n\nconst notFound = 404;\nconst conflict = 409;\nconst badRequest = 400;\nconst closedCode = 'request-closed';\n\ninterface Problem {\n readonly code?: string;\n}\n\nexport function createHttpServiceDeskGateway(options: HttpServiceDeskGatewayOptions): ServiceDeskGateway {\n const base = options.baseUrl.replace(/\\/+$/, '');\n const run = options.fetch ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init));\n\n const send = (path: string, method: string, body?: unknown, signal?: AbortSignal): Promise<Response> =>\n run(base + path, {\n method,\n signal,\n credentials: 'same-origin',\n headers: {\n Accept: 'application/json',\n ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),\n ...options.headers,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n const read = async <T>(response: Response): Promise<T> => {\n if (!response.ok) {\n throw new ServiceDeskGatewayError(response.status);\n }\n const value: T = await response.json();\n return value;\n };\n\n const outcome = async (response: Response): Promise<ServiceRequestOutcome> => {\n if (response.ok) {\n const request: ServiceRequestResponse = await response.json();\n return { kind: 'saved', request };\n }\n if (response.status === notFound) {\n return { kind: 'missing' };\n }\n if (response.status === badRequest) {\n return { kind: 'invalid' };\n }\n if (response.status !== conflict) {\n throw new ServiceDeskGatewayError(response.status);\n }\n const problem: Problem = await response.json().catch(() => ({}));\n return problem.code === closedCode ? { kind: 'closed' } : { kind: 'changed' };\n };\n\n return {\n desks: async () => read<DeskResponse[]>(await send(getServiceDeskDesksListUrl(), 'GET')),\n desk: async (deskId) => {\n const response = await send(getServiceDeskDesksGetUrl(deskId), 'GET');\n return response.status === notFound ? null : read<DeskResponse>(response);\n },\n saveDesk: async (deskId, name) => read<DeskResponse>(await send(getServiceDeskDesksSaveUrl(deskId), 'PUT', { name })),\n requests: async (deskId, listing, signal) =>\n read<ServiceRequestPage>(await send(getServiceDeskRequestsListUrl(deskId, listing), 'GET', undefined, signal)),\n raise: async (deskId, request) => outcome(await send(getServiceDeskRequestsRaiseUrl(deskId), 'POST', request)),\n edit: async (deskId, requestId, changes) => outcome(await send(getServiceDeskRequestsEditUrl(deskId, requestId), 'PUT', changes)),\n setStatus: async (deskId, requestId, status) =>\n outcome(await send(getServiceDeskRequestsStatusUrl(deskId, requestId), 'PUT', { status })),\n complete: async (deskId, requestId) => outcome(await send(getServiceDeskRequestsCompleteUrl(deskId, requestId), 'POST')),\n cancel: async (deskId, requestId, reason) =>\n outcome(await send(getServiceDeskRequestsCancelUrl(deskId, requestId), 'POST', { reason })),\n remove: async (deskId, requestId) => {\n const response = await send(getServiceDeskRequestsDeleteUrl(deskId, requestId), 'DELETE');\n if (!response.ok && response.status !== notFound) {\n throw new ServiceDeskGatewayError(response.status);\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -7,24 +7,6 @@
7
7
  "createConfirm": "Anlegen",
8
8
  "empty": "Es gibt noch keinen Desk."
9
9
  },
10
- "search": {
11
- "label": "Anfragen durchsuchen",
12
- "placeholder": "Titel oder Beschreibung"
13
- },
14
- "filter": {
15
- "label": "Anzeigen",
16
- "active": "Offen, in Arbeit und erledigt",
17
- "open": "Offen",
18
- "inProgress": "In Arbeit",
19
- "completed": "Erledigt",
20
- "cancelled": "Abgesagt",
21
- "all": "Alle, auch abgesagte"
22
- },
23
- "pager": {
24
- "range": "{{first}}–{{last}} von {{total}}",
25
- "previous": "Vorige Seite",
26
- "next": "Nächste Seite"
27
- },
28
10
  "table": {
29
11
  "title": "Titel",
30
12
  "type": "Typ",
@@ -33,8 +15,9 @@
33
15
  "contact": "Kontakt",
34
16
  "actions": "Aktionen",
35
17
  "empty": "Keine passenden Anfragen.",
36
- "dates": "Eingang / fällig",
37
- "dueOn": "fällig {{date}}"
18
+ "raised": "Eingang",
19
+ "due": "Fällig",
20
+ "count": "Treffer: {{count}}"
38
21
  },
39
22
  "type": {
40
23
  "inquiry": "Anfrage",
@@ -7,24 +7,6 @@
7
7
  "createConfirm": "Create",
8
8
  "empty": "There is no desk yet."
9
9
  },
10
- "search": {
11
- "label": "Search requests",
12
- "placeholder": "Title or description"
13
- },
14
- "filter": {
15
- "label": "Show",
16
- "active": "Open, in progress and completed",
17
- "open": "Open",
18
- "inProgress": "In progress",
19
- "completed": "Completed",
20
- "cancelled": "Cancelled",
21
- "all": "All, including cancelled"
22
- },
23
- "pager": {
24
- "range": "{{first}}–{{last}} of {{total}}",
25
- "previous": "Previous page",
26
- "next": "Next page"
27
- },
28
10
  "table": {
29
11
  "title": "Title",
30
12
  "type": "Type",
@@ -33,8 +15,9 @@
33
15
  "contact": "Contact",
34
16
  "actions": "Actions",
35
17
  "empty": "No requests match.",
36
- "dates": "Raised / due",
37
- "dueOn": "due {{date}}"
18
+ "raised": "Raised",
19
+ "due": "Due",
20
+ "count": "Matches: {{count}}"
38
21
  },
39
22
  "type": {
40
23
  "inquiry": "Inquiry",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weaver-apps/service-desk",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "The service-desk app's weaver for a LoomWeaver distribution: a desk's service requests, filtered and paged, raising, editing, completing, cancelling and deleting, behind a gateway the host supplies.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -8,13 +8,20 @@
8
8
  "registry": "https://registry.npmjs.org/"
9
9
  },
10
10
  "peerDependencies": {
11
+ "@ag-grid-community/locale": "^36.2.0",
11
12
  "@angular/common": "^22.2.0",
12
13
  "@angular/core": "^22.2.0",
13
14
  "@angular/router": "^22.2.0",
14
15
  "@jsverse/transloco": "^8.4.0",
15
- "@loomweaver/plugin-sdk": ">=0.20.0 <1.0.0"
16
+ "@loomweaver/plugin-sdk": ">=0.20.0 <1.0.0",
17
+ "ag-grid-angular": "^36.2.0",
18
+ "ag-grid-community": "^36.2.0"
16
19
  },
17
20
  "sideEffects": false,
21
+ "dependencies": {
22
+ "@weaver-apps/data-grid": "0.3.0",
23
+ "tslib": "^2.3.0"
24
+ },
18
25
  "module": "fesm2022/weaver-apps-service-desk.mjs",
19
26
  "typings": "types/weaver-apps-service-desk.d.ts",
20
27
  "exports": {
@@ -26,8 +33,5 @@
26
33
  "default": "./fesm2022/weaver-apps-service-desk.mjs"
27
34
  }
28
35
  },
29
- "type": "module",
30
- "dependencies": {
31
- "tslib": "^2.3.0"
32
- }
36
+ "type": "module"
33
37
  }
@@ -5,8 +5,14 @@ interface ServiceDeskPluginOptions {
5
5
  }
6
6
  export declare function createServiceDeskPlugin(options?: ServiceDeskPluginOptions): Plugin;
7
7
  export declare const serviceDeskPlugin: Plugin;
8
- export declare const deskListPath = "service-desk";
8
+ export declare const deskListPath = "weaver-apps-service-desk";
9
9
  export declare function deskPath(deskId: string): string;
10
+ export declare const serviceDeskPluginId = "weaver-apps-service-desk";
11
+ export declare const serviceDeskContributionIds: {
12
+ readonly desks: "weaver-apps-service-desk.desks";
13
+ readonly desk: "weaver-apps-service-desk.desk";
14
+ readonly rail: "weaver-apps-service-desk.rail";
15
+ };
10
16
  /**
11
17
  * Generated by orval 🍺
12
18
  * Do not edit manually.
@@ -137,19 +143,23 @@ interface NewServiceRequest {
137
143
  * OpenAPI spec version: 1.0.0
138
144
  */
139
145
  type ServiceDeskRequestsListParams = {
140
- type?: string;
141
- status?: string;
142
- priority?: string;
146
+ type?: string[];
147
+ status?: string[];
148
+ priority?: string[];
143
149
  contact?: string;
144
150
  text?: string;
145
151
  includeCancelled?: boolean;
146
152
  sort?: string;
147
153
  descending?: boolean;
148
154
  /**
155
+ * @minimum 0
156
+ * @maximum 2147483647
149
157
  * @pattern ^-?(?:0|[1-9]\d*)$
150
158
  */
151
159
  offset?: number | string;
152
160
  /**
161
+ * @minimum 1
162
+ * @maximum 100
153
163
  * @pattern ^-?(?:0|[1-9]\d*)$
154
164
  */
155
165
  limit?: number | string;
@@ -171,10 +181,8 @@ interface ServiceRequestChanges {
171
181
  * @nullable
172
182
  */
173
183
  description: string | null;
174
- /** Its kind. */
175
- type: ServiceRequestType;
176
- /** How urgent it is. */
177
- priority: ServiceRequestPriority;
184
+ type: null | ServiceRequestType;
185
+ priority: null | ServiceRequestPriority;
178
186
  /**
179
187
  * Who it is for.
180
188
  * @minLength 0