-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Import prisma in flows and auth * Add structure for task forms * Direct my tasks links to correct subfolder * Add rest of instructions * Use instructions dynamically in svelte:component Also fixed some things to make TS happy. * Make tables in forms sortable * Add simple queries and log results * Add comments noting which database field * Retrieve product data from database Currently grabbing all relevant fields. Once workflow backend is implemented, should change to only grab data needed based on the state of the task in the workflow. * Move arrow icons to lib/icons * Rename fields to be more meaningful * Rename instructions to align with DWKit forms * Remove unneeded query * Add note for ProductArtifacts * Clean up code for SortTable and co. * Break out artifacts query, filter on latest build --------- Co-authored-by: 7dev7urandom <[email protected]>
- Loading branch information
1 parent
eb9d160
commit 2307fae
Showing
24 changed files
with
766 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
source/SIL.AppBuilder.Portal/src/lib/icons/ArrowDownIcon.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<!-- source: https://fonts.google.com/icons --> | ||
<svg | ||
class="inline fill-current" | ||
xmlns="http://www.w3.org/2000/svg" | ||
height="24px" | ||
viewBox="0 -960 960 960" | ||
width="24px"> | ||
<path d="M480-360 280-560h400L480-360Z"/> | ||
</svg> |
9 changes: 9 additions & 0 deletions
9
source/SIL.AppBuilder.Portal/src/lib/icons/ArrowUpIcon.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<!-- source: https://fonts.google.com/icons --> | ||
<svg | ||
class="inline fill-current" | ||
xmlns="http://www.w3.org/2000/svg" | ||
height="24px" | ||
viewBox="0 -960 960 960" | ||
width="24px"> | ||
<path d="m280-400 200-200 200 200H280Z"/> | ||
</svg> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import ArrowBackIcon from './ArrowBackIcon.svelte'; | ||
import ArrowDownIcon from './ArrowDownIcon.svelte'; | ||
import HamburgerIcon from './HamburgerIcon.svelte'; | ||
import LanguageIcon from './LanguageIcon.svelte'; | ||
import ArrowUpIcon from './ArrowUpIcon.svelte'; | ||
|
||
export { ArrowBackIcon, HamburgerIcon, LanguageIcon }; | ||
export { ArrowBackIcon, ArrowDownIcon, HamburgerIcon, LanguageIcon, ArrowUpIcon }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
source/SIL.AppBuilder.Portal/src/routes/(authenticated)/tasks/[product_id]/+page.server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import type { PageServerLoad } from './$types'; | ||
import { prisma } from 'sil.appbuilder.portal.common'; | ||
|
||
type Fields = { | ||
ownerName?: string; //Product.Project.Owner.Name | ||
ownerEmail?: string; //Product.Project.Owner.Email | ||
projectName: string; //Product.Project.Name | ||
projectDescription: string; //Product.Project.Description | ||
storeDescription?: string; //Product.Store.Description | ||
listingLanguageCode?: string; //Product.StoreLanguage.Name | ||
projectURL?: string; //Product.Project.WorkflowAppProjectURL | ||
productDescription?: string; //Product.ProductDefinition.Description | ||
appType?: string; //Product.ProductDefinition.ApplicationTypes.Description | ||
projectLanguageCode?: string; //Product.Project.Language | ||
} | ||
|
||
export const load = (async ({ params, url, locals }) => { | ||
const product = await prisma.products.findUnique({ | ||
where: { | ||
Id: params.product_id | ||
}, | ||
select: { | ||
WorkflowBuildId: true, | ||
Project: { | ||
select: { | ||
Name: true, | ||
Description: true, | ||
WorkflowAppProjectUrl: true, | ||
Language: true, | ||
Owner: { | ||
select: { | ||
Name: true, | ||
Email: true | ||
} | ||
}, | ||
Reviewers: { | ||
select: { | ||
Id: true, | ||
Name: true, | ||
Email: true | ||
} | ||
} | ||
} | ||
}, | ||
Store: { | ||
select: { | ||
Description: true | ||
} | ||
}, | ||
StoreLanguage: { | ||
select: { | ||
Name: true | ||
} | ||
}, | ||
ProductDefinition: { | ||
select: { | ||
Name: true, | ||
ApplicationTypes: { | ||
select: { | ||
Description: true | ||
} | ||
} | ||
} | ||
}, | ||
} | ||
}); | ||
|
||
// later: include only when workflow state needs it | ||
const artifacts = await prisma.productArtifacts.findMany({ | ||
where: { | ||
ProductId: params.product_id, | ||
ProductBuild: { | ||
BuildId: product?.WorkflowBuildId | ||
} | ||
// later: some forms don't need all artifacts, some just need aab | ||
}, | ||
select: { | ||
ProductBuildId: true, | ||
ContentType: true, | ||
FileSize: true, | ||
Url: true, | ||
Id: true | ||
} | ||
}) | ||
|
||
return { | ||
actions: [], | ||
taskTitle: "Waiting", | ||
instructions: "waiting", | ||
//filter fields/files/reviewers based on task once workflows are implemented | ||
//possibly filter in the original query to increase database efficiency | ||
fields: { | ||
ownerName: product?.Project.Owner.Name, | ||
ownerEmail: product?.Project.Owner.Email, | ||
projectName: product?.Project.Name, | ||
projectDescription: product?.Project.Description, | ||
storeDescription: product?.Store?.Description, | ||
listingLanguageCode: product?.StoreLanguage?.Name, | ||
projectURL: product?.Project.WorkflowAppProjectUrl, | ||
productDescription: product?.ProductDefinition.Name, | ||
appType: product?.ProductDefinition.ApplicationTypes.Description, | ||
projectLanguageCode: product?.Project.Language | ||
} as Fields, | ||
files: artifacts, | ||
reviewers: product?.Project.Reviewers | ||
} | ||
}) satisfies PageServerLoad; |
140 changes: 140 additions & 0 deletions
140
source/SIL.AppBuilder.Portal/src/routes/(authenticated)/tasks/[product_id]/+page.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
<script lang="ts"> | ||
import type { PageData } from './$types'; | ||
import { instructions } from './instructions'; | ||
import SortTable from "./components/SortTable.svelte"; | ||
export let data: PageData; | ||
</script> | ||
|
||
<div class="p-5"> | ||
<form> | ||
{#if data.actions?.length} | ||
<div class="flex flex-row gap-x-3"> | ||
{#each data.actions as action} | ||
<input type="submit" class="btn" value={action}> | ||
{/each} | ||
</div> | ||
{/if} | ||
<label class="form-control"> | ||
<div class="label"> | ||
<span class="label-text">Comment</span> | ||
</div> | ||
<textarea class="textarea textarea-bordered h-24"></textarea> | ||
</label> | ||
</form> | ||
<hr class="border-t-4 my-2"> | ||
<h2> | ||
{data.taskTitle} | ||
</h2> | ||
<div> | ||
{#if data.fields.ownerName && data.fields.ownerEmail} | ||
<div class="flex flex-col gap-x-3 w-full md:flex-row"> | ||
<label class="form-control w-full md:w-2/4"> | ||
<div class="label"> | ||
<span class="label-text">User Name</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.ownerName} /> | ||
</label> | ||
<label class="form-control w-full md:w-2/4"> | ||
<div class="label"> | ||
<span class="label-text">Email</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.ownerEmail} /> | ||
</label> | ||
</div> | ||
{/if} | ||
<div class="flex flex-col gap-x-3 w-full md:flex-row"> | ||
<label class="form-control w-full md:w-2/4"> | ||
<div class="label"> | ||
<span class="label-text">Project Name</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.projectName} /> | ||
</label> | ||
<label class="form-control w-full md:w-2/4"> | ||
<div class="label"> | ||
<span class="label-text">Project Description</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.projectDescription} /> | ||
</label> | ||
</div> | ||
{#if data.fields.storeDescription} | ||
<div class="flex flex-col gap-x-3 md:flex-row"> | ||
<label class="form-control w-full md:w-2/4"> | ||
<div class="label"> | ||
<span class="label-text">Store</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.storeDescription} /> | ||
</label> | ||
{#if data.fields.listingLanguageCode} | ||
<label class="form-control w-full md:w-2/4"> | ||
<div class="label"> | ||
<span class="label-text">Store Listing Language</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.listingLanguageCode} /> | ||
</label> | ||
{/if} | ||
</div> | ||
{/if} | ||
{#if data.fields.projectURL} | ||
<label class="form-control w-full"> | ||
<div class="label"> | ||
<span class="label-text">App Project URL</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.projectURL} /> | ||
</label> | ||
{/if} | ||
{#if data.fields.productDescription && data.fields.appType && data.fields.projectLanguageCode} | ||
<label class="form-control w-full"> | ||
<div class="label"> | ||
<span class="label-text">Product</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.productDescription} /> | ||
</label> | ||
<label class="form-control w-full"> | ||
<div class="label"> | ||
<span class="label-text">Application Type</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.appType} /> | ||
</label> | ||
<label class="form-control w-full"> | ||
<div class="label"> | ||
<span class="label-text">Language Code</span> | ||
</div> | ||
<input type="text" class="input input-bordered w-full" readonly value={data.fields.projectLanguageCode} /> | ||
</label> | ||
{/if} | ||
</div> | ||
{#if data.instructions} | ||
<div class="py-2" id="instructions"> | ||
<svelte:component this={instructions[data.instructions]} /> | ||
</div> | ||
{/if} | ||
{#if data?.files?.length} | ||
<div class="overflow-x-auto max-h-96"> | ||
<h3>Files</h3> | ||
<SortTable items={data.files} /> | ||
</div> | ||
{/if} | ||
{#if data?.reviewers?.length} | ||
<div class="overflow-x-auto max-h-96"> | ||
<h3>Reviewers</h3> | ||
<SortTable items={data.reviewers} /> | ||
</div> | ||
{/if} | ||
</div> | ||
|
||
<style lang=postcss> | ||
.label-text { | ||
font-weight: bold; | ||
} | ||
/*this VVV technique allows css rules to break svelte scoping downwards*/ | ||
#instructions :global(ul) { | ||
@apply pl-10 list-disc; | ||
} | ||
#instructions :global(ol) { | ||
@apply pl-10 list-decimal; | ||
} | ||
#instructions :global(h3) { | ||
@apply text-info; | ||
} | ||
</style> |
27 changes: 27 additions & 0 deletions
27
...ortal/src/routes/(authenticated)/tasks/[product_id]/components/SortDirectionPicker.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<script lang="ts"> | ||
import { ArrowDownIcon, ArrowUpIcon } from "$lib/icons"; | ||
export let active: boolean; | ||
export let descending: boolean; | ||
//later: selecting one of these causes the relative sizes of the table headers to change, which looks really janky. I've tried fixing this, but have been unsuccessful. For now, at least it functions correctly, even if it doesn't look quite right. | ||
</script> | ||
|
||
<div class="form-control"> | ||
<label> | ||
<span class="{active? "":"hidden"}"> | ||
{#if descending} | ||
<ArrowDownIcon /> | ||
{:else} | ||
<ArrowUpIcon /> | ||
{/if} | ||
</span> | ||
<span class="label-text"><slot></slot></span> | ||
</label> | ||
</div> | ||
|
||
<style lang=postcss> | ||
label { | ||
@apply select-none cursor-pointer; | ||
} | ||
</style> |
64 changes: 64 additions & 0 deletions
64
...pBuilder.Portal/src/routes/(authenticated)/tasks/[product_id]/components/SortTable.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<script lang="ts"> | ||
import SortDirectionPicker from "./SortDirectionPicker.svelte"; | ||
export let items: {[key: string]: any}[]; | ||
let current = ""; //current field being sorted | ||
let descending = false; | ||
const handleClick = (key: string) => { | ||
if (current !== key) { | ||
// change current field | ||
descending = false; | ||
current = key; | ||
} | ||
else { | ||
if (descending) { | ||
// reset to sort default field | ||
handleClick(""); | ||
return; //don't sort twice | ||
} | ||
else { | ||
descending = true; | ||
} | ||
} | ||
// sort based on current field | ||
// if blank, sort first field | ||
const field = current || Object.keys(items[0])[0]; | ||
items = (typeof items[0][field] === 'string')? | ||
// sort strings | ||
items.sort((a, b) => { | ||
return descending ? | ||
b[field].localeCompare(a[field]): | ||
a[field].localeCompare(b[field]); | ||
}): | ||
// sort non-strings (i.e. numbers) | ||
items.sort((a, b) => { | ||
return descending? | ||
b[field] - a[field]: | ||
a[field] - b[field]; | ||
}); | ||
} | ||
</script> | ||
|
||
<table class="table"> | ||
<thead> | ||
<tr> | ||
{#each Object.keys(items[0]) as key} | ||
<th on:click={() => handleClick(key)}> | ||
<SortDirectionPicker active={current === key} bind:descending={descending}> | ||
{key} | ||
</SortDirectionPicker> | ||
</th> | ||
{/each} | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{#each items as item} | ||
<tr> | ||
{#each Object.values(item) as val} | ||
<td>{val}</td> | ||
{/each} | ||
</tr> | ||
{/each} | ||
</tbody> | ||
</table> |
Oops, something went wrong.