diff --git a/src/lib/utils/wave/types/waveProgram.ts b/src/lib/utils/wave/types/waveProgram.ts index 9d9b7089c..74575134d 100644 --- a/src/lib/utils/wave/types/waveProgram.ts +++ b/src/lib/utils/wave/types/waveProgram.ts @@ -137,6 +137,7 @@ export const waveProgramRepoWithDetailsDtoSchema = z.object({ pointsUsed: z.number().int(), pointsBudget: z.number().int().nullable(), pointsRemaining: z.number().int().nullable(), + pointsBudgetOverride: z.number().int().nullable().optional(), pointsMultiplier: z.number().int().optional(), repo: z.object({ stargazersCount: z.number().int().nullable().optional(), diff --git a/src/lib/utils/wave/wavePrograms.ts b/src/lib/utils/wave/wavePrograms.ts index 5b08ad86a..133a6f28c 100644 --- a/src/lib/utils/wave/wavePrograms.ts +++ b/src/lib/utils/wave/wavePrograms.ts @@ -184,6 +184,36 @@ export async function unfeatureWaveProgramRepo( }); } +export async function setRepoBudgetOverride( + f = fetch, + waveProgramId: string, + orgRepoId: string, + pointsBudget: number, +) { + await authenticatedCall( + f, + `/api/wave-programs/${waveProgramId}/repos/${orgRepoId}/budget-override`, + { + method: 'PUT', + body: JSON.stringify({ pointsBudget }), + }, + ); +} + +export async function removeRepoBudgetOverride( + f = fetch, + waveProgramId: string, + orgRepoId: string, +) { + await authenticatedCall( + f, + `/api/wave-programs/${waveProgramId}/repos/${orgRepoId}/budget-override`, + { + method: 'DELETE', + }, + ); +} + export async function addIssueToWaveProgram( f = fetch, waveProgramId: string, diff --git a/src/routes/(pages)/wave/(base-layout)/admin/repos/+layout.ts b/src/routes/(pages)/wave/(base-layout)/admin/repos/+layout.ts index f57398683..f557a4e0b 100644 --- a/src/routes/(pages)/wave/(base-layout)/admin/repos/+layout.ts +++ b/src/routes/(pages)/wave/(base-layout)/admin/repos/+layout.ts @@ -9,8 +9,9 @@ export const load = async ({ parent, fetch, depends }) => { const canManageTags = user.permissions?.includes('manageTags'); const canFeatureRepos = user.permissions?.includes('featureWaveRepos'); + const canManagePoints = user.permissions?.includes('managePoints'); - if (!canManageTags && !canFeatureRepos) { + if (!canManageTags && !canFeatureRepos && !canManagePoints) { throw redirect(302, '/wave/admin'); } @@ -24,5 +25,6 @@ export const load = async ({ parent, fetch, depends }) => { tags, canManageTags: !!canManageTags, canFeatureRepos: !!canFeatureRepos, + canManagePoints: !!canManagePoints, }; }; diff --git a/src/routes/(pages)/wave/(base-layout)/admin/repos/components/budget-override-modal.svelte b/src/routes/(pages)/wave/(base-layout)/admin/repos/components/budget-override-modal.svelte new file mode 100644 index 000000000..780b7070d --- /dev/null +++ b/src/routes/(pages)/wave/(base-layout)/admin/repos/components/budget-override-modal.svelte @@ -0,0 +1,113 @@ + + + + + diff --git a/src/routes/(pages)/wave/(base-layout)/admin/repos/repos/+page.svelte b/src/routes/(pages)/wave/(base-layout)/admin/repos/repos/+page.svelte index 1ecb67aca..daecc3abf 100644 --- a/src/routes/(pages)/wave/(base-layout)/admin/repos/repos/+page.svelte +++ b/src/routes/(pages)/wave/(base-layout)/admin/repos/repos/+page.svelte @@ -19,6 +19,8 @@ import type { Pagination } from '$lib/utils/wave/types/pagination'; import ManageRepoTagsModal from '../components/manage-repo-tags-modal.svelte'; import FeatureRepoModal from '../components/feature-repo-modal.svelte'; + import BudgetOverrideModal from '../components/budget-override-modal.svelte'; + import Coin from '$lib/components/icons/Coin.svelte'; let { data } = $props(); @@ -26,6 +28,7 @@ let wavePrograms = $derived(data.wavePrograms); let canManageTags = $derived(data.canManageTags); let canFeatureRepos = $derived(data.canFeatureRepos); + let canManagePoints = $derived(data.canManagePoints); let waveProgramId = $derived(data.waveProgramId); let repos = $derived(data.repos); @@ -123,6 +126,14 @@ }); } + function openBudgetOverrideModal(repo: WaveProgramRepoWithDetailsDto) { + modal.show(BudgetOverrideModal, undefined, { + repo, + waveProgramId: waveProgramId!, + onChanged: reloadPage, + }); + } + async function handleUnfeature(repo: WaveProgramRepoWithDetailsDto) { await doWithConfirmationModal( `Remove featured status from ${repo.repo.gitHubRepoFullName}?`, @@ -196,6 +207,18 @@ > {/if} {/if} + + {#if canManagePoints} + + {/if} {/snippet}