Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send mainPath and configDir on update success/failure #53

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
7 changes: 5 additions & 2 deletions src/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,16 @@ export const Panel = ({ active, api }: PanelProps) => {
},
[api]
);
const [
const {
projectId,
projectToken,
configDir,
mainPath,
updateProject,
projectUpdatingFailed,
projectIdUpdated,
clearProjectIdUpdated,
] = useProjectId();
} = useProjectId();
Copy link
Contributor

Choose a reason for hiding this comment

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

🔥 thank you for cleaning this up


// Render a hidden element when the addon panel is not active.
// Storybook's AddonPanel component does the same but it's not styleable so we don't use it.
Expand All @@ -109,6 +110,7 @@ export const Panel = ({ active, api }: PanelProps) => {
<LinkingProjectFailed
projectId={projectId}
projectToken={projectToken}
mainPath={mainPath}
configDir={configDir}
/>
);
Expand All @@ -119,6 +121,7 @@ export const Panel = ({ active, api }: PanelProps) => {
<Provider key={PANEL_ID} value={client}>
<LinkedProject
projectId={projectId}
mainPath={mainPath}
goToNext={clearProjectIdUpdated}
setAccessToken={setAccessToken}
/>
Expand Down
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ export type UpdateProjectPayload = {
};

export const PROJECT_UPDATED = `${ADDON_ID}/projectUpdated`;
export type ProjectUpdatedPayload = {
mainPath: string;
configDir: string;
};
export const PROJECT_UPDATING_FAILED = `${ADDON_ID}/projectUpdatingFailed`;
export type ProjectUpdatingFailedPayload = {
mainPath?: string;
configDir: string;
};
16 changes: 12 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { Channel } from "@storybook/channels";
// eslint-disable-next-line import/no-unresolved
import { getGitInfo, GitInfo, run } from "chromatic/node";
import { relative } from "path";
import { basename, relative } from "path";

import {
BUILD_ANNOUNCED,
Expand All @@ -12,11 +12,13 @@ import {
GitInfoPayload,
PROJECT_UPDATED,
PROJECT_UPDATING_FAILED,
ProjectUpdatedPayload,
ProjectUpdatingFailedPayload,
START_BUILD,
UPDATE_PROJECT,
UpdateProjectPayload,
} from "./constants";
import { findConfig } from "./utils/storybook.config.utils";
import { updateMain } from "./utils/updateMain";

/**
Expand Down Expand Up @@ -94,13 +96,19 @@ async function serverChannel(
async ({ projectId, projectToken: updatedProjectToken }: UpdateProjectPayload) => {
projectToken = updatedProjectToken;

const relativeConfigDir = relative(process.cwd(), configDir);
let mainPath: string;
try {
await updateMain({ configDir, projectId, projectToken });
channel.emit(PROJECT_UPDATED);
mainPath = await findConfig(configDir, "main");
await updateMain({ mainPath, projectId, projectToken });
channel.emit(PROJECT_UPDATED, {
mainPath: basename(mainPath),
configDir: relativeConfigDir,
} satisfies ProjectUpdatedPayload);
} catch (err) {
console.warn(`Failed to update your main configuration:\n\n ${err}`);
const relativeConfigDir = relative(process.cwd(), configDir);
channel.emit(PROJECT_UPDATING_FAILED, {
mainPath: mainPath && basename(mainPath),
configDir: relativeConfigDir,
} satisfies ProjectUpdatingFailedPayload);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import { action } from "@storybook/addon-actions";
import type { Meta, StoryObj } from "@storybook/react";
import { findByTestId } from "@storybook/testing-library";
import { graphql } from "msw";
import React from "react";

import { ProjectQueryQuery, SelectProjectsQueryQuery } from "../../gql/graphql";
import { SelectProjectsQueryQuery } from "../../gql/graphql";
import { storyWrapper } from "../../utils/graphQLClient";
import { playAll } from "../../utils/playAll";
import { withFigmaDesign } from "../../utils/withFigmaDesign";
import { LinkedProject } from "./LinkedProject";
import { LinkProject } from "./LinkProject";

const meta = {
Expand Down Expand Up @@ -239,35 +237,6 @@ export const SelectProjectManyProjects: Story = {
await leftDiv.scroll({ top: leftDiv.scrollHeight });
}),
};
export const Linked: Story = {
render: () => (
<LinkedProject
projectId="789"
goToNext={action("goToNext")}
setAccessToken={action("setAccessToken")}
/>
),
parameters: {
...withGraphQLQuery("ProjectQuery", (req, res, ctx) =>
res(
ctx.data({
project: {
id: "789",
name: "acme",
webUrl: "https://www.chromatic.com/builds?appId=789",
lastBuild: {
branch: "main",
number: 123,
},
},
} satisfies ProjectQueryQuery)
)
),
...withFigmaDesign(
"https://www.figma.com/file/GFEbCgCVDtbZhngULbw2gP/Visual-testing-in-Storybook?type=design&node-id=508-317094&t=435fylbu7gUQNEgq-4"
),
},
};

export const EmptyNoAccounts: Story = {
parameters: {
Expand Down
50 changes: 50 additions & 0 deletions src/screens/LinkProject/LinkedProject.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { action } from "@storybook/addon-actions";
import type { Meta, StoryObj } from "@storybook/react";
import { graphql } from "msw";

import { ProjectQueryQuery } from "../../gql/graphql";
import { storyWrapper } from "../../utils/graphQLClient";
import { withFigmaDesign } from "../../utils/withFigmaDesign";
import { LinkedProject } from "./LinkedProject";

const withGraphQLQuery = (...args: Parameters<typeof graphql.query>) => ({
msw: {
handlers: [graphql.query(...args)],
},
});

const meta = {
component: LinkedProject,
args: {
projectId: "Project:abc123",
mainPath: "main.ts",
goToNext: action("goToNext"),
setAccessToken: action("setAccessToken"),
},
decorators: [storyWrapper],
parameters: {
...withGraphQLQuery("ProjectQuery", (req, res, ctx) =>
res(
ctx.data({
project: {
id: "789",
name: "acme",
webUrl: "https://www.chromatic.com/builds?appId=789",
lastBuild: {
branch: "main",
number: 123,
},
},
} satisfies ProjectQueryQuery)
)
),
...withFigmaDesign(
"https://www.figma.com/file/GFEbCgCVDtbZhngULbw2gP/Visual-testing-in-Storybook?type=design&node-id=508-317094&t=435fylbu7gUQNEgq-4"
),
},
} satisfies Meta<typeof LinkedProject>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};
6 changes: 4 additions & 2 deletions src/screens/LinkProject/LinkedProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ const ProjectQuery = graphql(/* GraphQL */ `

export const LinkedProject = ({
projectId,
mainPath,
goToNext,
setAccessToken,
}: {
projectId: string;
mainPath: string;
goToNext: () => void;
setAccessToken: (accessToken: string | null) => void;
}) => {
Expand All @@ -62,8 +64,8 @@ export const LinkedProject = ({
<Heading>Project linked!</Heading>
<Text style={{ maxWidth: 380 }}>
The <code>projectId</code> for {data.project.name} has been added to this
Storybook&apos;s <code>main.js</code>. This will be used to sync with Chromatic.
Please commit this change to continue using this addon.
Storybook&apos;s <code>{mainPath}</code>. This will be used to sync with
Chromatic. Please commit this change to continue using this addon.
</Text>
<Button secondary onClick={() => goToNext()}>
Catch a UI change
Expand Down
6 changes: 6 additions & 0 deletions src/screens/LinkProject/LinkingProjectFailed.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};

export const WithMainPath: Story = {
args: {
mainPath: "main.ts",
},
};
4 changes: 3 additions & 1 deletion src/screens/LinkProject/LinkingProjectFailed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type LinkingProjectFailedProps = {
projectId: string;
projectToken: string;
configDir: string;
mainPath?: string;
};

const addonName = "@chromaui/addon-visual-tests";
Expand All @@ -20,6 +21,7 @@ export function LinkingProjectFailed({
projectId,
projectToken,
configDir,
mainPath,
}: LinkingProjectFailedProps) {
return (
<Sections>
Expand All @@ -32,7 +34,7 @@ export function LinkingProjectFailed({
</CenterText>
<Code>
{dedent`
// ${configDir}/main.js|ts|tsx
// ${configDir}/${mainPath ?? `main.js|ts|tsx`}

module.exports = {
// ...,
Expand Down
6 changes: 2 additions & 4 deletions src/utils/updateMain.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { readConfig, writeConfig } from "@storybook/csf-tools";

import { CHROMATIC_ADDON_NAME } from "../constants";
import { findConfig } from "./storybook.config.utils";

export async function updateMain({
projectId,
projectToken,
configDir,
mainPath,
}: {
projectId: string;
projectToken: string;
configDir: string;
mainPath: string;
}) {
const mainPath = await findConfig(configDir, "main");
const MainConfig = await readConfig(mainPath);

const addonsConfig = MainConfig.getFieldValue(["addons"]);
Expand Down
26 changes: 13 additions & 13 deletions src/utils/useProjectId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,31 @@ import React from "react";
import {
PROJECT_UPDATED,
PROJECT_UPDATING_FAILED,
ProjectUpdatedPayload,
ProjectUpdatingFailedPayload,
UPDATE_PROJECT,
UpdateProjectPayload,
} from "../constants";

const { CHROMATIC_PROJECT_ID } = process.env;

export const useProjectId = (): [
projectId: string,
projectToken: string,
configDir: string,
updateProject: (projectId: string, projectToken?: string) => void,
projectUpdatingFailed: boolean,
projectIdUpdated: boolean,
clearProjectIdUpdated: () => void
] => {
export const useProjectId = () => {
const [projectId, setProjectId] = React.useState<string | null>(CHROMATIC_PROJECT_ID);
const [projectToken, setProjectToken] = React.useState<string | null>();
const [projectIdUpdated, setProjectIdUpdated] = React.useState(false);
const [projectUpdatingFailed, setProjectUpdatingFailed] = React.useState(false);
const [mainPath, setMainPath] = React.useState<string | null>();
const [configDir, setConfigDir] = React.useState<string | null>();

const emit = useChannel({
[PROJECT_UPDATED]: () => setProjectIdUpdated(true),
[PROJECT_UPDATED]: (payload: ProjectUpdatedPayload) => {
setProjectIdUpdated(true);
setMainPath(payload.mainPath);
setConfigDir(payload.configDir);
},
[PROJECT_UPDATING_FAILED]: (payload: ProjectUpdatingFailedPayload) => {
setProjectUpdatingFailed(true);
setMainPath(payload.mainPath);
setConfigDir(payload.configDir);
},
});
Expand All @@ -42,13 +41,14 @@ export const useProjectId = (): [
setProjectId(newProjectId);
setProjectToken(newProjectToken);
};
return [
return {
projectId,
projectToken,
configDir,
mainPath,
updateProject,
projectUpdatingFailed,
projectIdUpdated,
() => setProjectIdUpdated(false),
];
clearProjectIdUpdated: () => setProjectIdUpdated(false),
};
};
Loading