diff --git a/src/lib/bullmq.ts b/src/lib/bullmq.ts index cbee147bef..18ce0f7d94 100644 --- a/src/lib/bullmq.ts +++ b/src/lib/bullmq.ts @@ -52,6 +52,9 @@ export enum JobType { Email_ProjectImportReport = 'Project Import Report', // Svelte Project SSE SvelteSSE_UpdateProject = 'Update Project', + SvelteSSE_UpdateProjectGroups = 'Update Project Groups', + SvelteSSE_UpdateProjectOrg = 'Update Project Org', + SvelteSSE_UpdateProjectProducts = 'Update Project Products', SvelteSSE_UpdateUserTasks = 'Update UserTasks' } diff --git a/src/lib/icons/index.ts b/src/lib/icons/index.ts index f9affb23cc..eff5018555 100644 --- a/src/lib/icons/index.ts +++ b/src/lib/icons/index.ts @@ -1,4 +1,3 @@ -import type { Prisma } from '@prisma/client'; import type { Locale as DefaultLocale } from '$lib/paraglide/runtime'; import { ApplicationType, @@ -11,7 +10,7 @@ import { WorkflowType } from '$lib/prisma'; import { ProductActionType } from '$lib/products'; -import type { ValidI13nKey } from '$lib/utils'; +import type { Action } from '$lib/projects/components/ProjectActionEntry.svelte'; import { ProductType, WorkflowAction } from '$lib/workflowTypes'; export function getActionIcon(type: ProductActionType) { @@ -94,7 +93,7 @@ export function getFlagIcon( } } -export function getProductIcon(type: ProductType) { +export function getProductIcon(type?: ProductType) { switch (type) { case ProductType.Web: return 'mdi:web'; @@ -105,19 +104,17 @@ export function getProductIcon(type: ProductType) { } } -export function getProjectActionIcon( - args: Prisma.ProjectActionsGetPayload<{ select: { ActionType: true; Action: true; Value: true } }> -) { - switch (args.ActionType) { +export function getProjectActionIcon(args: Pick) { + switch (args.T) { case ProjectActionType.Archival: - switch (args.Action as ValidI13nKey) { + switch (args.A) { case ProjectActionString.Archive: return Icons.Archive; default: return Icons.ReactivateProject; } case ProjectActionType.Access: - switch (args.Action.replace(/Project /, '')) { + switch (args.A.replace(/Project /, '')) { case 'Upload': return 'material-symbols:upload'; case 'Download': @@ -126,35 +123,35 @@ export function getProjectActionIcon( return Icons.Star; } case ProjectActionType.OwnerGroup: - switch (args.Action as ValidI13nKey) { + switch (args.A) { case ProjectActionString.AssignGroup: return Icons.AddGroup; default: return Icons.AddUser; } case ProjectActionType.Product: - switch (args.Action as ValidI13nKey) { + switch (args.A) { case ProjectActionString.AddProduct: return Icons.AddProduct; default: return Icons.Trash; } case ProjectActionType.Author: - switch (args.Action as ValidI13nKey) { + switch (args.A) { case ProjectActionString.AddAuthor: return Icons.AddAuthor; default: return Icons.Trash; } case ProjectActionType.Reviewer: - switch (args.Action as ValidI13nKey) { + switch (args.A) { case ProjectActionString.AddReviewer: return Icons.AddReviewer; default: return Icons.Trash; } case ProjectActionType.EditField: - switch (args.Value as ValidI13nKey) { + switch (args.V) { case ProjectActionValue.AutoPublishOn: return Icons.RefreshOn; case ProjectActionValue.AutoPublishOff: @@ -175,7 +172,7 @@ export function getProjectActionIcon( return Icons.Edit; } case ProjectActionType.Creation: - switch (args.Action) { + switch (args.A) { case ProjectActionString.CreateProject: return Icons.AddProject; default: @@ -227,9 +224,9 @@ export function getTransitionIcon( return getActionIcon(ProductActionType.CancelWorkflow); case ProductTransitionType.ProjectAccess: return getProjectActionIcon({ - ActionType: ProjectActionType.Access, - Action: command ?? '', - Value: null + T: ProjectActionType.Access, + A: command ?? '', + V: null }); case ProductTransitionType.Migration: return Icons.Transfer; diff --git a/src/lib/organizations/components/StoreListDisplay.svelte b/src/lib/organizations/components/StoreListDisplay.svelte index ad2a46566b..f6389461ac 100644 --- a/src/lib/organizations/components/StoreListDisplay.svelte +++ b/src/lib/organizations/components/StoreListDisplay.svelte @@ -6,13 +6,17 @@ > import type { Prisma } from '@prisma/client'; import type { Snippet } from 'svelte'; + import { page } from '$app/state'; import Tooltip from '$lib/components/Tooltip.svelte'; import DataDisplayBox from '$lib/components/settings/DataDisplayBox.svelte'; import { Icons, getStoreIcon } from '$lib/icons'; import IconContainer from '$lib/icons/IconContainer.svelte'; import { m } from '$lib/paraglide/messages'; + import { getLocale } from '$lib/paraglide/runtime'; import { StoreType, displayStoreGPTitle } from '$lib/prisma'; import type { ValidI13nKey } from '$lib/utils'; + import { isSuperAdmin } from '$lib/utils/roles'; + import { byName } from '$lib/utils/sorting'; interface Props { editable: boolean; @@ -21,9 +25,10 @@ getTitle: (store: Store) => string; extra?: Snippet<[Store]>; showDescription?: boolean; + users?: (Prisma.OrganizationsGetPayload<{ select: { Name: true } }> & { Products: number })[]; } - let { editable, editLink, store, getTitle, extra, showDescription }: Props = $props(); + let { editable, editLink, store, getTitle, extra, showDescription, users }: Props = $props(); const missingGPTitle = $derived( store.StoreTypeId === StoreType.GooglePlay && editable && !store.GooglePlayTitle @@ -55,6 +60,17 @@ snippet: missingGPTitle ? gpTitleError : undefined } ] + : []), + ...(users?.length && isSuperAdmin(page.data.session!.user.roles) + ? [ + { + key: 'org_title' as ValidI13nKey, + value: users + .toSorted((a, b) => byName(a, b, getLocale())) + .map((u) => `${u.Name} (${u.Products})`) + .join(', ') + } + ] : []) ]} > diff --git a/src/lib/products/components/BuildArtifacts.svelte b/src/lib/products/components/BuildArtifacts.svelte index ca670ea5f2..71c36951f7 100644 --- a/src/lib/products/components/BuildArtifacts.svelte +++ b/src/lib/products/components/BuildArtifacts.svelte @@ -69,9 +69,9 @@ linkToBuildEngine( buildEngineUrl, { - BuildEngineJobId: 0, - CurrentBuildId: build.BuildEngineBuildId, - CurrentReleaseId: null + J: 0, + CB: build.BuildEngineBuildId, + CR: null }, WorkflowState.Product_Build ), diff --git a/src/lib/products/components/ProductDetails.svelte b/src/lib/products/components/ProductDetails.svelte index a1b7d8666e..3c5527e431 100644 --- a/src/lib/products/components/ProductDetails.svelte +++ b/src/lib/products/components/ProductDetails.svelte @@ -5,56 +5,14 @@ (document.getElementById('modal' + productId) as HTMLDialogElement)?.showModal?.(); } - export type Transition = Prisma.ProductTransitionsGetPayload<{ - select: { - Id: true; - TransitionType: true; - InitialState: true; - WorkflowType: true; - AllowedUserNames: true; - Command: true; - Comment: true; - DateTransition: true; - User: { select: { Id: true; Name: true } }; - QueueRecords: { - select: { - Queue: true; - JobId: true; - JobType: true; - }; - }; - }; - }>; - export interface Props { - product: Prisma.ProductsGetPayload<{ - select: { - Id: true; - BuildEngineJobId: true; - CurrentBuildId: true; - CurrentReleaseId: true; - ProductBuilds: { - select: { - BuildEngineBuildId: true; - TransitionId: true; - }; - }; - ProductPublications: { - select: { - BuildEngineReleaseId: true; - TransitionId: true; - }; - }; - }; - }> & { BuildEngineUrl?: string }; - transitions: Transition[]; + product: MinifiedProductDetails; projectActions?: Action[]; } -{#snippet transitionType(transition: (typeof transitions)[0], showRecs: boolean)} - {#if transition.TransitionType === ProductTransitionType.Activity} +{#snippet transitionType(transition: MinifiedProductDetails['PT'][number], showRecs: boolean)} + {#if transition.T === ProductTransitionType.Activity} {@html formatBuildEngineLink( linkToBuildEngine( - (transition.DateTransition && - transition.InitialState && - isBackground(transition.InitialState as WorkflowState)) || - showRecs - ? product.BuildEngineUrl + (transition.D && transition.S && isBackground(transition.S as WorkflowState)) || showRecs + ? product.BE : undefined, getBuildOrPub(transition), - transition.InitialState as WorkflowState + transition.S as WorkflowState ), - transition.InitialState ?? '' + transition.S ?? '' )} {:else} {@const icon = getTransitionIcon( - transition.TransitionType, - transition.WorkflowType ?? 1, - transition.Command ?? transition.InitialState?.match(/(Download|Upload)/)?.at(1) ?? null + transition.T, + transition.W ?? 1, + transition.Cd ?? transition.S?.match(/(Download|Upload)/)?.at(1) ?? null )} {#if icon}   {/if} - {#if transition.TransitionType === ProductTransitionType.ProjectAccess} - {transition.InitialState} - {:else if isLandmark(transition.TransitionType)} - {stateString(transition.WorkflowType ?? 1, transition.TransitionType)} + {#if transition.T === ProductTransitionType.ProjectAccess} + {transition.S} + {:else if isLandmark(transition.T)} + {stateString(transition.W ?? 1, transition.T)} {:else} {m.transitions_types({ - type: transition.TransitionType as ProductTransitionType, + type: transition.T as ProductTransitionType, workflowType: '' })} {/if} {/if} {/snippet} -{#snippet queueRecords(trans: Transition)} - {@const records = trans.QueueRecords} +{#snippet queueRecords(trans: MinifiedProductDetails['PT'][number])} + {@const records = trans.QR}
{m.products_jobRecords()} ({records.length})
{/snippet} - +