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
3 changes: 3 additions & 0 deletions static/js/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,7 @@ declare interface Window {
whitelist_countries: string[];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Inclusive naming check] reported by reviewdog 🐶
[warning] whitelist may be insensitive, use allowlist instead

whitelist_country_keys: string;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Inclusive naming check] reported by reviewdog 🐶
[warning] whitelist may be insensitive, use allowlist instead

};
SNAP_LISTING_DATA: {
DNS_VERIFICATION_TOKEN: string;
};
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef } from "react";
import { useRef } from "react";
import { Row, Col, Button } from "@canonical/react-components";

import debounce from "../../../libs/debounce";
Expand All @@ -20,20 +20,26 @@ function SaveAndPreview({
showPreview,
}: Props) {
const stickyBar = useRef<HTMLDivElement>(null);
const mainPanel = document.querySelector(".l-main") as HTMLElement;

const handleScroll = () => {
stickyBar?.current?.classList.toggle(
"sticky-shadow",
stickyBar?.current?.getBoundingClientRect()?.top === 0
);
};

useEffect(() => {
document.addEventListener("scroll", debounce(handleScroll, 10, false));
}, []);
if (mainPanel) {
mainPanel.addEventListener("scroll", debounce(handleScroll, 10, false));
}

return (
<>
<div className="snapcraft-p-sticky js-sticky-bar" ref={stickyBar}>
<div
className="snapcraft-p-sticky js-sticky-bar"
ref={stickyBar}
style={{ margin: "0 -1.5rem", padding: "0 1.5rem" }}
>
<Row>
<Col size={7}>
<p className="u-no-margin--bottom">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ type Props = {
function SectionNav({ activeTab, snapName }: Props) {
return (
<Tabs
listClassName="u-no-margin--bottom"
links={[
{
label: "Listing",
active: activeTab === "listing" || !activeTab,
href: `/${snapName}/listing`,
to: `/${snapName}/listing`,
component: Link,
},
{
label: "Builds",
Expand All @@ -28,7 +30,8 @@ function SectionNav({ activeTab, snapName }: Props) {
{
label: "Metrics",
active: activeTab === "metrics",
href: `/${snapName}/metrics`,
to: `/${snapName}/metrics`,
component: Link,
},
{
label: "Publicise",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { renderHook } from "@testing-library/react";

import useMutateListingData from "../useMutateListingData";

import { mockData } from "../../test-utils";
import { mockListingData } from "../../test-utils";

describe("useMutateListingData", () => {
test("Calls useMutatation", () => {
jest.spyOn(ReactQuery, "useMutation").mockImplementation(jest.fn());
renderHook(() =>
useMutateListingData({
data: mockData,
data: mockListingData,
dirtyFields: {},
getDefaultData: jest.fn(),
refetch: jest.fn(),
Expand Down
9 changes: 8 additions & 1 deletion static/js/publisher-pages/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import useValidationSets from "./useValidationSets";
import useValidationSet from "./useValidationSet";
import useMutateListingData from "./useMutateListingData";
import useVerified from "./useVerified";

export { useValidationSets, useValidationSet };
export {
useValidationSets,
useValidationSet,
useMutateListingData,
useVerified,
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useMutation } from "react-query";

import { addDateToFilename, getChanges } from "../utils";
import { addDateToFilename, getListingChanges } from "../utils";

import type { Data } from "../types";
import type { ListingData } from "../types";

type Options = {
data: Data;
data: ListingData;
dirtyFields: any;
getDefaultData: Function;
refetch: Function;
Expand All @@ -31,7 +31,7 @@ function useMutateListingData({
mutationFn: async (values: any) => {
const formData = new FormData();

const changes = getChanges(dirtyFields, values, data);
const changes = getListingChanges(dirtyFields, values, data);

formData.set("csrf_token", window.CSRF_TOKEN);
formData.set("snap_id", data.snap_id);
Expand Down Expand Up @@ -77,9 +77,12 @@ function useMutateListingData({
}
},
onSuccess: async () => {
setShowSuccessNotification(true);
const response = await refetch();
setShowSuccessNotification(true);
reset(getDefaultData(response.data));

const mainPanel = document.querySelector(".l-main") as HTMLElement;
mainPanel.scrollTo({ top: 0, left: 0, behavior: "smooth" });
},
});
}
Expand Down
5 changes: 5 additions & 0 deletions static/js/publisher-pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Settings from "./pages/Settings";
import ValidationSets from "./pages/ValidationSets";
import ValidationSet from "./pages/ValidationSet";
import Metrics from "./pages/Metrics";
import Listing from "./pages/Listing";

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -42,6 +43,10 @@ const router = createBrowserRouter([
path: "/:snapId/metrics",
element: <Metrics />,
},
{
path: "/:snapId/listing",
element: <Listing />,
},
],
},
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { Row, Col } from "@canonical/react-components";

import LicenseInputs from "./LicenseInputs";

import type { Data } from "../../types";
import type { ListingData } from "../../../types";

type Props = {
data: Data;
data: ListingData;
register: UseFormRegister<FieldValues>;
getValues: UseFormGetValues<FieldValues>;
setValue: UseFormSetValue<FieldValues>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import {
import PrimaryDomainInput from "./PrimaryDomainInput";
import ContactFields from "./ContactFields";

import type { Data } from "../../types";
import type { ListingData } from "../../../types";

type Props = {
data: Data;
data: ListingData;
register: UseFormRegister<FieldValues>;
control: Control<FieldValues>;
getFieldState: UseFormGetFieldState<FieldValues>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import {
import { nanoid } from "nanoid";
import { Row, Col, Modal } from "@canonical/react-components";

import { useVerified } from "../../hooks";
import { useVerified } from "../../../hooks";

import type { Data } from "../../types";
import type { ListingData } from "../../../types";

type Props = {
data: Data;
data: ListingData;
register: UseFormRegister<FieldValues>;
getFieldState: UseFormGetFieldState<FieldValues>;
getValues: UseFormGetValues<FieldValues>;
Expand All @@ -26,14 +26,14 @@ function PrimaryDomainInput({
getFieldState,
getValues,
}: Props) {
const { snapName } = useParams();
const { snapId } = useParams();
const id = nanoid();
const fieldState = getFieldState("primary_website");
const [showVerifyModal, setShowVerifyModal] = useState(false);
const { isLoading, status, data: verifiedData } = useVerified(snapName);
const { isLoading, status, data: verifiedData } = useVerified(snapId);
const domain = getValues("primary_website");
const defaultDomain = data.primary_website;
const verificationToken = `SNAPCRAFT_IO_VERIFICATION=${window.DNS_VERIFICATION_TOKEN}`;
const verificationToken = `SNAPCRAFT_IO_VERIFICATION=${window.SNAP_LISTING_DATA.DNS_VERIFICATION_TOKEN}`;

const noPathDomains = [
"github.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import "@testing-library/jest-dom";

import PrimaryDomainInput from "../PrimaryDomainInput";

import { mockData } from "../../../test-utils";
import { mockListingData } from "../../../../test-utils";

import type { Data } from "../../../types";
import type { ListingData } from "../../../../types";

window.DNS_VERIFICATION_TOKEN = "abc123";
window.SNAP_LISTING_DATA = {
DNS_VERIFICATION_TOKEN: "abc123",
};

jest.mock("react-query", () => ({
...jest.requireActual("react-query"),
Expand All @@ -38,7 +40,10 @@ const mockUseFormReturnValue = {
getValues: jest.fn().mockReturnValue("https://example.com"),
};

const renderComponent = (data: Data, defaultValues: { [key: string]: any }) => {
const renderComponent = (
data: ListingData,
defaultValues: { [key: string]: any }
) => {
const Component = () => {
const { register, getFieldState, getValues } = useForm({
defaultValues,
Expand Down Expand Up @@ -71,7 +76,9 @@ describe("PrimaryDomainInput", () => {
// @ts-ignore
useForm.mockImplementation(() => mockUseFormReturnValue);

renderComponent(mockData, { primary_website: "https://example.com" });
renderComponent(mockListingData, {
primary_website: "https://example.com",
});
expect(screen.getByText("Verified ownership")).toBeInTheDocument();
});

Expand All @@ -92,7 +99,9 @@ describe("PrimaryDomainInput", () => {
useForm.mockImplementation(() => mockUseFormReturnValue);

const user = userEvent.setup();
renderComponent(mockData, { primary_website: "https://example.com" });
renderComponent(mockListingData, {
primary_website: "https://example.com",
});
const input = screen.getByRole("textbox", { name: "Primary website:" });
await user.type(input, "https://example.comabc");
expect(input).toHaveValue("https://example.comabc");
Expand Down Expand Up @@ -120,7 +129,9 @@ describe("PrimaryDomainInput", () => {
useForm.mockImplementation(() => mockUseFormReturnValue);

const user = userEvent.setup();
renderComponent(mockData, { primary_website: "https://example.com" });
renderComponent(mockListingData, {
primary_website: "https://example.com",
});
const input = screen.getByRole("textbox", { name: "Primary website:" });
await user.clear(input);
await user.type(input, "/path");
Expand All @@ -141,7 +152,7 @@ describe("PrimaryDomainInput", () => {
useForm.mockImplementation(() => mockUseFormReturnValue);
const user = userEvent.setup();
renderComponent(
{ ...mockData, primary_website: "https://launchpad.net" },
{ ...mockListingData, primary_website: "https://launchpad.net" },
{ primary_website: "https://launchpad.net" }
);
await user.type(
Expand All @@ -166,7 +177,9 @@ describe("PrimaryDomainInput", () => {
useForm.mockImplementation(() => mockUseFormReturnValue);

const user = userEvent.setup();
renderComponent(mockData, { primary_website: "https://example.com" });
renderComponent(mockListingData, {
primary_website: "https://example.com",
});
await user.click(
screen.getByRole("button", { name: "Verified ownership" })
);
Expand All @@ -187,7 +200,9 @@ describe("PrimaryDomainInput", () => {
// @ts-ignore
useForm.mockImplementation(() => mockUseFormReturnValue);

renderComponent(mockData, { primary_website: "https://example.com" });
renderComponent(mockListingData, {
primary_website: "https://example.com",
});
expect(screen.queryByText("Verified ownership")).not.toBeInTheDocument();
expect(
screen.getByRole("button", { name: "Verify ownership" })
Expand All @@ -209,7 +224,9 @@ describe("PrimaryDomainInput", () => {
useForm.mockImplementation(() => mockUseFormReturnValue);

const user = userEvent.setup();
renderComponent(mockData, { primary_website: "https://example.com" });
renderComponent(mockListingData, {
primary_website: "https://example.com",
});
await user.click(screen.getByRole("button", { name: "Verify ownership" }));
expect(
screen.getByRole("heading", { level: 2, name: "Verify ownership" })
Expand All @@ -234,7 +251,9 @@ describe("PrimaryDomainInput", () => {
useForm.mockImplementation(() => mockUseFormReturnValue);

const user = userEvent.setup();
renderComponent(mockData, { primary_website: "https://example.com" });
renderComponent(mockListingData, {
primary_website: "https://example.com",
});
expect(
screen.getByRole("button", { name: "Verify ownership" })
).toBeDisabled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { useParams } from "react-router-dom";
import { useQuery } from "react-query";
import { Strip } from "@canonical/react-components";

import PageHeader from "../../../shared/PageHeader";
import ListingForm from "../ListingForm";
import SectionNav from "../../components/SectionNav";
import ListingForm from "./ListingForm";

function App(): JSX.Element {
const { snapName } = useParams();
function Listing(): JSX.Element {
const { snapId } = useParams();
const { data, isLoading, refetch } = useQuery({
queryKey: ["listing"],
queryFn: async () => {
const response = await fetch(`/api/${snapName}/listing`);
const response = await fetch(`/api/${snapId}/listing`);

if (!response.ok) {
throw new Error("There was a problem fetching listing data");
Expand All @@ -28,17 +28,18 @@ function App(): JSX.Element {

return (
<>
<PageHeader
snapName={snapName}
snapTitle={snapName}
activeTab="listing"
/>
<h1 className="p-heading--4">
<a href="/snaps">My snaps</a> / <a href={`/${snapId}`}>{snapId}</a> /
Listing
</h1>

<SectionNav snapName={snapId} activeTab="listing" />

{isLoading && (
<Strip shallow>
<p>
<i className="p-icon--spinner u-animation--spin"></i>&nbsp;Loading{" "}
{snapName} listing data
{snapId} listing data
</p>
</Strip>
)}
Expand All @@ -48,4 +49,4 @@ function App(): JSX.Element {
);
}

export default App;
export default Listing;
Loading
Loading