Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

Commit

Permalink
DEVPROD-834: Allow defining multiple metadata links
Browse files Browse the repository at this point in the history
  • Loading branch information
minnakt committed Jan 18, 2024
1 parent d4c9fa2 commit 3623f0d
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 108 deletions.
67 changes: 46 additions & 21 deletions cypress/integration/projectSettings/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,62 @@ import { clickSave } from "../../utils";

describe("Plugins", () => {
const patchPage = "version/5ecedafb562343215a7ff297";
it("Should set an external link to render on patch metadata panel and then unset it to revert the changes", () => {
// Set the external link
cy.visit(getPluginsRoute(projectUseRepoEnabled));
cy.dataCy("requesters-input").click();
cy.getInputByLabel("Commits").check({ force: true });

const addMetadataLink = (metadataLink: {
displayName: string;
url: string;
}) => {
cy.contains("button", "Add metadata link").scrollIntoView();
cy.contains("button", "Add metadata link").click();
cy.dataCy("requesters-input").first().click();
cy.getInputByLabel("Patches").check({ force: true });
cy.dataCy("requesters-input").click();
cy.dataCy("display-name-input").type("An external link");
cy.dataCy("url-template-input").type("https://example.com/{version_id}", {
cy.dataCy("requesters-input").first().click();
cy.dataCy("display-name-input").first().type(metadataLink.displayName);
cy.dataCy("url-template-input").first().type(metadataLink.url, {
parseSpecialCharSequences: false,
});
};

it("Should be able to set external links to render on patch metadata panel", () => {
// Add external links.
cy.visit(getPluginsRoute(projectUseRepoEnabled));
addMetadataLink({
displayName: "An external link 1",
url: "https://example-1.com/{version_id}",
});
addMetadataLink({
displayName: "An external link 2",
url: "https://example-2.com/{version_id}",
});
cy.dataCy("save-settings-button").scrollIntoView();
clickSave();

cy.visit(patchPage);
cy.dataCy("external-link").contains("An external link");
cy.dataCy("external-link").should(
"have.attr",
"href",
"https://example.com/5ecedafb562343215a7ff297",
);
cy.dataCy("external-link").should("have.length", 2);
cy.dataCy("external-link").last().contains("An external link 1");
cy.dataCy("external-link")
.last()
.should(
"have.attr",
"href",
"https://example-1.com/5ecedafb562343215a7ff297",
);
cy.dataCy("external-link").first().contains("An external link 2");
cy.dataCy("external-link")
.first()
.should(
"have.attr",
"href",
"https://example-2.com/5ecedafb562343215a7ff297",
);

// Unset the external link
// Remove external links.
cy.visit(getPluginsRoute(projectUseRepoEnabled));
cy.dataCy("requesters-input").click();
cy.getInputByLabel("Commits").uncheck({ force: true });
cy.getInputByLabel("Patches").uncheck({ force: true });
cy.dataCy("requesters-input").click();
cy.dataCy("display-name-input").clear();
cy.dataCy("url-template-input").clear();
cy.dataCy("delete-item-button").first().click();
cy.dataCy("delete-item-button").first().click();
cy.dataCy("save-settings-button").scrollIntoView();
clickSave();

cy.visit(patchPage);
cy.dataCy("external-link").should("not.exist");
});
Expand Down
2 changes: 1 addition & 1 deletion src/components/SpruceForm/Widgets/MultiSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const MultiSelect: React.FC<EnumSpruceWidgetProps> = ({
hasStyling={false}
/>
</Dropdown>
{rawErrors.length > 0 && <Error>{rawErrors.join(", ")}</Error>}
{rawErrors?.length > 0 && <Error>{rawErrors?.join(", ")}</Error>}
</Container>
</ElementWrapper>
);
Expand Down
42 changes: 22 additions & 20 deletions src/pages/projectSettings/tabs/PluginsTab/PluginsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const PluginsTab: React.FC<TabProps> = ({
const validate = ((formData, errors) => {
const {
buildBaronSettings: { ticketSearchProjects },
externalLinks: { metadataPanelLink },
externalLinks,
} = formData;

// if a search project is defined, a create project must be defined, and vice versa
Expand All @@ -63,27 +63,29 @@ const validate = ((formData, errors) => {
);
}

const displayNameDefined = metadataPanelLink.displayName.trim() !== "";
const urlTemplateDefined = metadataPanelLink.urlTemplate.trim() !== "";
const requestersDefined = metadataPanelLink.requesters.length > 0;
externalLinks.forEach((link, idx) => {
const displayNameDefined = link.displayName.trim() !== "";
const urlTemplateDefined = link.urlTemplate.trim() !== "";
const requestersDefined = link.requesters.length > 0;

if (displayNameDefined || urlTemplateDefined || requestersDefined) {
if (!displayNameDefined) {
errors.externalLinks.metadataPanelLink.displayName.addError(
"You must specify a display name.",
);
if (displayNameDefined || urlTemplateDefined || requestersDefined) {
if (!displayNameDefined) {
errors.externalLinks[idx].displayName.addError(
"You must specify a display name.",
);
}
if (!urlTemplateDefined) {
errors.externalLinks[idx].urlTemplate.addError(
"You must specify a URL template.",
);
}
if (!requestersDefined) {
errors.externalLinks[idx].requesters.addError(
"You must specify requesters.",
);
}
}
if (!urlTemplateDefined) {
errors.externalLinks.metadataPanelLink.urlTemplate.addError(
"You must specify a URL template.",
);
}
if (!requestersDefined) {
errors.externalLinks.metadataPanelLink.requesters.addError(
"You must specify requesters.",
);
}
}
});

return errors;
}) satisfies ValidateProps<PluginsFormState>;
78 changes: 43 additions & 35 deletions src/pages/projectSettings/tabs/PluginsTab/getFormSchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,38 +178,38 @@ export const getFormSchema = (
},
},
externalLinks: {
type: "object" as "object",
title: "Metadata Link",
properties: {
metadataPanelLink: {
type: "object" as "object",
title: "",
description:
"Add a URL to the metadata panel for versions with the specified requester. Include {version_id} in the URL template and it will be replaced by an actual version ID.",
properties: {
requesters: {
type: "array" as "array",
title: "Requesters",
uniqueItems: true,
items: {
type: "string" as "string",
anyOf: requesters.map((r) => ({
type: "string" as "string",
title: r.label,
enum: [r.value],
})),
},
},
displayName: {
type: "string" as "string",
title: "Display name",
maxLength: 40,
},
urlTemplate: {
type: "array" as "array",
title: "Metadata Links",
items: {
type: "object" as "object",
properties: {
requesters: {
type: "array" as "array",
title: "Requesters",
uniqueItems: true,
items: {
type: "string" as "string",
title: "URL template",
format: "validURLTemplate",
anyOf: requesters.map((r) => ({
type: "string" as "string",
title: r.label,
enum: [r.value],
})),
},
default: [],
},
displayName: {
type: "string" as "string",
title: "Display name",
default: "",
minLength: 1,
maxLength: 40,
},
urlTemplate: {
type: "string" as "string",
title: "URL template",
default: "",
minLength: 1,
format: "validURLTemplate",
},
},
},
Expand Down Expand Up @@ -292,18 +292,26 @@ export const getFormSchema = (
},
externalLinks: {
"ui:rootFieldId": "externalLinks",
"ui:ObjectFieldTemplate": CardFieldTemplate,
metadataPanelLink: {
"ui:placeholder": "No metadata links are defined.",
"ui:description":
"Add URLs to the metadata panel for versions with the specified requester.",
"ui:addButtonText": "Add metadata link",
"ui:orderable": false,
"ui:useExpandableCard": true,
items: {
"ui:displayTitle": "New Metadata Link",
requesters: {
"ui:widget": widgets.MultiSelectWidget,
"ui:data-cy": "requesters-input",
},
displayName: {
"ui:data-cy": "display-name-input",
},
urlTemplate: {
"ui:placeholder": "https://example.com/{version_id}",
"ui:data-cy": "url-template-input",
},
displayName: {
"ui:data-cy": "display-name-input",
"ui:description":
"Include {version_id} in the URL template and it will be replaced by an actual version ID.",
},
},
},
Expand Down
44 changes: 34 additions & 10 deletions src/pages/projectSettings/tabs/PluginsTab/transformers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,20 @@ const projectForm: PluginsFormState = {
secret: null,
},
},
externalLinks: {
metadataPanelLink: {
externalLinks: [
{
requesters: ["gitter_request", "patch_request"],
displayName: "a link display name",
urlTemplate: "https:/a-link-template-{version_id}.com",
displayTitle: "a link display name",
urlTemplate: "https://a-link-template-{version_id}.com",
},
},
{
requesters: ["ad_hoc"],
displayName: "periodic build link",
displayTitle: "periodic build link",
urlTemplate: "https://periodic-build-{version_id}.com",
},
],
};

const projectResult: Pick<ProjectSettingsInput, "projectRef"> = {
Expand All @@ -71,7 +78,12 @@ const projectResult: Pick<ProjectSettingsInput, "projectRef"> = {
{
requesters: ["gitter_request", "patch_request"],
displayName: "a link display name",
urlTemplate: "https:/a-link-template-{version_id}.com",
urlTemplate: "https://a-link-template-{version_id}.com",
},
{
requesters: ["ad_hoc"],
displayName: "periodic build link",
urlTemplate: "https://periodic-build-{version_id}.com",
},
],
},
Expand Down Expand Up @@ -107,13 +119,20 @@ const repoForm: PluginsFormState = {
secret: "secret",
},
},
externalLinks: {
metadataPanelLink: {
externalLinks: [
{
requesters: ["gitter_request", "patch_request"],
displayName: "a link display name",
urlTemplate: "https:/a-link-template-{version_id}.com",
displayTitle: "a link display name",
urlTemplate: "https://a-link-template-{version_id}.com",
},
},
{
requesters: ["ad_hoc"],
displayName: "periodic build link",
displayTitle: "periodic build link",
urlTemplate: "https://periodic-build-{version_id}.com",
},
],
};

const repoResult: Pick<RepoSettingsInput, "projectRef"> = {
Expand All @@ -136,7 +155,12 @@ const repoResult: Pick<RepoSettingsInput, "projectRef"> = {
{
requesters: ["gitter_request", "patch_request"],
displayName: "a link display name",
urlTemplate: "https:/a-link-template-{version_id}.com",
urlTemplate: "https://a-link-template-{version_id}.com",
},
{
requesters: ["ad_hoc"],
displayName: "periodic build link",
urlTemplate: "https://periodic-build-{version_id}.com",
},
],
},
Expand Down
20 changes: 12 additions & 8 deletions src/pages/projectSettings/tabs/PluginsTab/transformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@ export const gqlToForm = ((data) => {
secret: projectRef?.taskAnnotationSettings?.fileTicketWebhook?.secret,
},
},
externalLinks: {
metadataPanelLink: {
requesters: projectRef?.externalLinks?.[0].requesters ?? [],
displayName: projectRef?.externalLinks?.[0].displayName ?? "",
urlTemplate: projectRef?.externalLinks?.[0].urlTemplate ?? "",
},
},
externalLinks:
projectRef?.externalLinks?.map((e) => ({
...e,
displayTitle: e.displayName,
})) ?? [],
};
}) satisfies GqlToFormFunction<Tab>;

Expand All @@ -72,7 +70,13 @@ export const formToGql = ((
.map(({ displayText, field }) => ({ field, displayText }))
.filter((str) => !!str),
},
externalLinks: [externalLinks.metadataPanelLink],
externalLinks: externalLinks.map(
({ displayName, requesters, urlTemplate }) => ({
requesters,
displayName,
urlTemplate,
}),
),
};

return { projectRef };
Expand Down
13 changes: 6 additions & 7 deletions src/pages/projectSettings/tabs/PluginsTab/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ export interface PluginsFormState {
secret: string;
};
};
externalLinks: {
metadataPanelLink: {
requesters: string[];
displayName: string;
urlTemplate: string;
};
};
externalLinks: Array<{
displayTitle: string;
requesters: string[];
displayName: string;
urlTemplate: string;
}>;
}

export type TabProps = {
Expand Down
Loading

0 comments on commit 3623f0d

Please sign in to comment.