Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,816 changes: 1,267 additions & 549 deletions openapi/extensions-v2.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/components/ConfirmDeleteDialog.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface Props {
description: string;
confirmText: string;
intentField?: { name: string; value: string };
formAction?: string;
submitLabel?: string;
}

Expand All @@ -16,6 +17,7 @@ const {
description,
confirmText,
intentField,
formAction,
submitLabel = 'Delete',
} = Astro.props;
---
Expand All @@ -28,7 +30,7 @@ const {
onclick="if (arguments[0].target === this) this.close()"
onclose="this.querySelector('form').reset(); this.querySelector('[data-confirm-submit]').disabled = true;"
>
<form method="POST">
<form method="POST" action={formAction}>
{
intentField && (
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ interface Props {

const { developer, extension, error } = Astro.props;
const isEdit = Boolean(extension);
// A release is required, same as a brand new extension, whenever there's
// nothing already published to carry through — an extension can reach this
// form with no releases yet (rejected and never resubmitted).
const requireRelease = !isEdit || extension!.releases.length === 0;
---

{
Expand Down Expand Up @@ -250,38 +254,43 @@ const isEdit = Boolean(extension);

<fieldset class="fieldset space-y-4">
<legend>
{isEdit ? 'Add a new release (optional)' : 'Initial release'}
{
requireRelease
? 'Initial release'
: 'Add a new release (optional)'
}
</legend>
<div class="field">
<label for="version_tag">
Version Tag {!isEdit && <span class="text-destructive">*</span>}
Version Tag{' '}
{requireRelease && <span class="text-destructive">*</span>}
</label>
<input
class="input"
type="text"
id="version_tag"
name="version_tag"
required={!isEdit}
required={requireRelease}
placeholder="1.0.0"
/>
</div>
<div class="field">
<label for="release_date">
Release Date{' '}
{!isEdit && <span class="text-destructive">*</span>}
{requireRelease && <span class="text-destructive">*</span>}
</label>
<input
class="input"
type="date"
id="release_date"
name="release_date"
required={!isEdit}
required={requireRelease}
/>
</div>
<div class="field">
<label for="download_url">
Download URL{' '}
{!isEdit && <span class="text-destructive">*</span>}
{requireRelease && <span class="text-destructive">*</span>}
</label>
<div class="input-group">
<span data-align="start" class="text-muted-foreground">
Expand All @@ -291,7 +300,7 @@ const isEdit = Boolean(extension);
type="text"
id="download_url"
name="download_url"
required={!isEdit}
required={requireRelease}
/>
</div>
</div>
Expand All @@ -312,14 +321,14 @@ const isEdit = Boolean(extension);
<div class="field">
<label for="min_fossbilling_version">
Minimum FOSSBilling Version{' '}
{!isEdit && <span class="text-destructive">*</span>}
{requireRelease && <span class="text-destructive">*</span>}
</label>
<input
class="input"
type="text"
id="min_fossbilling_version"
name="min_fossbilling_version"
required={!isEdit}
required={requireRelease}
placeholder="1.0.0"
/>
</div>
Expand Down
151 changes: 107 additions & 44 deletions src/lib/api/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
deleteDevelopersMe,
deleteExtensionsById,
getDevelopers,
getDevelopersById,
getDevelopersByIdHistory,
Expand All @@ -9,9 +10,10 @@ import {
getDevelopersUnapproved,
getExtensions,
getExtensionsById,
getExtensionsByIdRevisions,
getExtensionsMine,
getSubmissionsMine,
getSubmissionsQueue,
getExtensionsMineById,
getModerationExtensions,
getUsersMe,
patchUsersMe,
postDevelopersByIdApprove,
Expand All @@ -23,11 +25,12 @@ import {
postDevelopersClaimsByIdReject,
postDevelopersMeReverify,
postDevelopersTransfersAccept,
postSubmissions,
postSubmissionsByIdApprove,
postSubmissionsByIdReject,
postExtensions,
postExtensionsByIdRevisionsByRevisionIdApprove,
postExtensionsByIdRevisionsByRevisionIdReject,
deleteUsersMe,
putDevelopersMe,
putExtensionsById,
putUsersMeIdentity,
type Developer,
type DeveloperApproval,
Expand All @@ -37,21 +40,25 @@ import {
type DeveloperTransfer,
type Error as ApiErrorBody,
type Extension,
type ExtensionCreate,
type ExtensionListItem,
type ExtensionListResponse,
type ExtensionRevision,
type ExtensionUpdate,
type GetExtensionsByIdRevisionsData,
type GetExtensionsByIdRevisionsResponse,
type GetExtensionsData,
type GetExtensionsMineData,
type GetSubmissionsMineResponse,
type GetSubmissionsMineData,
type GetSubmissionsQueueData,
type GetSubmissionsQueueResponse,
type GetModerationExtensionsData,
type GetModerationExtensionsResponse,
type OwnedDeveloperProfile,
type OwnedExtension,
type OwnedExtensionListItem,
type OwnedExtensionListResponse,
type PendingDeveloperClaim,
type User,
type UserIdentityInput,
type PutDevelopersMeData,
type Submission,
type SubmissionPayload,
} from '@/lib/api/generated/extensions-v2';
import {
createClient,
Expand All @@ -66,8 +73,10 @@ export const MAX_API_PAGE_LIMIT = 100;

type ExtensionListQuery = NonNullable<GetExtensionsData['query']>;
type ExtensionMineQuery = NonNullable<GetExtensionsMineData['query']>;
type SubmissionPageQuery = NonNullable<GetSubmissionsMineData['query']>;
type SubmissionQueueQuery = NonNullable<GetSubmissionsQueueData['query']>;
type RevisionHistoryQuery = NonNullable<
GetExtensionsByIdRevisionsData['query']
>;
type ModerationQueueQuery = NonNullable<GetModerationExtensionsData['query']>;

export type ExtensionCatalogueFilters = Pick<
ExtensionListQuery,
Expand All @@ -79,19 +88,21 @@ export type ExtensionMineFilters = Pick<
'type' | 'limit' | 'cursor'
>;

export type SubmissionPageOptions = Pick<
SubmissionPageQuery,
export type RevisionHistoryOptions = Pick<
RevisionHistoryQuery,
'cursor' | 'limit'
>;

export type SubmissionPage = GetSubmissionsMineResponse;
export type SubmissionQueuePage = GetSubmissionsQueueResponse;
export type DeveloperProfileInput = NonNullable<PutDevelopersMeData['body']>;
export type SubmissionStatus = Exclude<
SubmissionQueueQuery['status'],
undefined
export type ModerationQueueOptions = Pick<
ModerationQueueQuery,
'cursor' | 'limit'
>;

export type RevisionHistoryPage = GetExtensionsByIdRevisionsResponse;
export type ModerationQueuePage = GetModerationExtensionsResponse;
export type DeveloperProfileInput = NonNullable<PutDevelopersMeData['body']>;
export type RevisionStatus = Exclude<ModerationQueueQuery['status'], undefined>;

export type AccountUser = User;
export type IdentitySyncInput = UserIdentityInput;
export type OwnedDeveloper = OwnedDeveloperProfile;
Expand All @@ -104,11 +115,15 @@ export type {
DeveloperProfile,
DeveloperTransfer,
Extension,
ExtensionCreate,
ExtensionListItem,
ExtensionListResponse,
ExtensionRevision,
ExtensionUpdate,
OwnedExtension,
OwnedExtensionListItem,
OwnedExtensionListResponse,
PendingDeveloperClaim,
Submission,
SubmissionPayload,
};

export class ApiRequestError extends Error {
Expand Down Expand Up @@ -219,9 +234,9 @@ async function unwrap<T>(result: {
}

function pageQuery(
options: SubmissionPageOptions = {},
): NonNullable<GetSubmissionsMineData['query']> {
const query: NonNullable<GetSubmissionsMineData['query']> = {
options: RevisionHistoryOptions | ModerationQueueOptions = {},
): { limit: number; cursor?: string } {
const query: { limit: number; cursor?: string } = {
limit: clampApiPageLimit(options.limit),
};

Expand Down Expand Up @@ -334,55 +349,103 @@ export function createApiClient(env: ApplicationEnv, subject: string) {

listMyExtensions: async (
options: ExtensionMineFilters = {},
): Promise<ExtensionListResponse> =>
): Promise<OwnedExtensionListResponse> =>
unwrap(
await getExtensionsMine({
client,
query: mineExtensionQuery(options),
}),
),

submitExtension: async (payload: SubmissionPayload) =>
(await unwrap(await postSubmissions({ client, body: payload }))).result,
getMyExtension: async (id: string): Promise<OwnedExtension> =>
(
await unwrap(
await getExtensionsMineById({
client,
path: { id },
}),
)
).result,

createExtension: async (payload: ExtensionCreate) =>
(
await unwrap(
await postExtensions({
client,
body: payload,
}),
)
).result,

listMySubmissions: async (
options: SubmissionPageOptions = {},
): Promise<SubmissionPage> =>
updateExtension: async (id: string, payload: ExtensionUpdate) =>
(
await unwrap(
await putExtensionsById({
client,
path: { id },
body: payload,
}),
)
).result,

withdrawExtension: async (id: string) =>
(
await unwrap(
await deleteExtensionsById({
client,
path: { id },
}),
)
).result,

listExtensionRevisions: async (
id: string,
options: RevisionHistoryOptions = {},
): Promise<RevisionHistoryPage> =>
unwrap(
await getSubmissionsMine({
await getExtensionsByIdRevisions({
client,
path: { id },
query: pageQuery(options),
}),
),

listQueue: async (
status: SubmissionStatus = 'pending',
options: SubmissionPageOptions = {},
): Promise<SubmissionQueuePage> =>
listModerationQueue: async (
status: RevisionStatus = 'pending',
options: ModerationQueueOptions = {},
): Promise<ModerationQueuePage> =>
unwrap(
await getSubmissionsQueue({
await getModerationExtensions({
client,
query: { status, ...pageQuery(options) },
}),
),

approveSubmission: async (id: string, reviewNote?: string) =>
approveRevision: async (
extensionId: string,
revisionId: string,
reviewNote?: string,
) =>
(
await unwrap(
await postSubmissionsByIdApprove({
await postExtensionsByIdRevisionsByRevisionIdApprove({
client,
path: { id },
path: { id: extensionId, revisionId },
...(reviewNote ? { body: { review_note: reviewNote } } : {}),
}),
)
).result,

rejectSubmission: async (id: string, reviewNote: string) =>
rejectRevision: async (
extensionId: string,
revisionId: string,
reviewNote: string,
) =>
(
await unwrap(
await postSubmissionsByIdReject({
await postExtensionsByIdRevisionsByRevisionIdReject({
client,
path: { id },
path: { id: extensionId, revisionId },
body: { review_note: reviewNote },
}),
)
Expand Down
Loading