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

Separate running/latest build from viewed stories #69

Merged
merged 22 commits into from
Sep 4, 2023
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"dependencies": {
"@storybook/csf-tools": "7.4.0",
"@storybook/design-system": "^7.15.15",
"chromatic": "6.24.0",
"chromatic": "7.1.0-canary.3",
"date-fns": "^2.30.0",
"pluralize": "^8.0.0",
"ts-dedent": "^2.2.0",
Expand Down
62 changes: 16 additions & 46 deletions src/Panel.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import { logger } from "@storybook/client-logger";
import { Spinner } from "@storybook/design-system";
import type { API } from "@storybook/manager-api";
import { useChannel, useStorybookState } from "@storybook/manager-api";
// eslint-disable-next-line import/no-unresolved
import { GitInfo } from "chromatic/node";
import React, { useCallback, useState } from "react";

import {
ADDON_ID,
BUILD_ANNOUNCED,
BUILD_STARTED,
DEV_BUILD_ID_KEY,
GIT_INFO,
GitInfoPayload,
PANEL_ID,
RUNNING_BUILD,
RunningBuildPayload,
START_BUILD,
} from "./constants";
import { Authentication } from "./screens/Authentication/Authentication";
import { LinkedProject } from "./screens/LinkProject/LinkedProject";
import { LinkingProjectFailed } from "./screens/LinkProject/LinkingProjectFailed";
import { LinkProject } from "./screens/LinkProject/LinkProject";
import { VisualTests } from "./screens/VisualTests/VisualTests";
import { useAddonState } from "./useAddonState/manager";
import { client, Provider, useAccessToken } from "./utils/graphQLClient";
import { StatusUpdate } from "./utils/testsToStatusUpdate";
import { useProjectId } from "./utils/useProjectId";
Expand All @@ -29,50 +28,15 @@ interface PanelProps {
api: API;
}

const {
GIT_USER_EMAIL,
GIT_USER_EMAIL_HASH,
GIT_BRANCH,
GIT_SLUG,
GIT_COMMIT,
GIT_UNCOMMITTED_HASH,
} = process.env;
const initialGitInfo: GitInfoPayload = {
userEmail: GIT_USER_EMAIL,
userEmailHash: GIT_USER_EMAIL_HASH,
branch: GIT_BRANCH,
commit: GIT_COMMIT,
slug: GIT_SLUG,
uncommittedHash: GIT_UNCOMMITTED_HASH,
};

logger.debug("Initial Git info:", initialGitInfo);

const storedBuildId = localStorage.getItem(DEV_BUILD_ID_KEY);

export const Panel = ({ active, api }: PanelProps) => {
const [accessToken, setAccessToken] = useAccessToken();
const { storyId } = useStorybookState();

const [isStarting, setIsStarting] = useState(false);
const [lastBuildId, setLastBuildId] = useState(storedBuildId);
const [gitInfo, setGitInfo] = useState(initialGitInfo);

const emit = useChannel(
{
[START_BUILD]: () => setIsStarting(true),
[BUILD_STARTED]: () => setIsStarting(false),
[BUILD_ANNOUNCED]: (buildId: string) => {
setLastBuildId(buildId);
localStorage.setItem(DEV_BUILD_ID_KEY, buildId);
},
[GIT_INFO]: (info: GitInfoPayload) => {
setGitInfo(info);
logger.debug("Updated Git info:", info);
},
},
[]
);
const [gitInfo] = useAddonState<GitInfoPayload>(GIT_INFO);
const [runningBuild] = useAddonState<RunningBuildPayload>(RUNNING_BUILD);
ghengeveld marked this conversation as resolved.
Show resolved Hide resolved
const emit = useChannel({});

const updateBuildStatus = useCallback(
(update: StatusUpdate) => {
Expand All @@ -81,6 +45,7 @@ export const Panel = ({ active, api }: PanelProps) => {
[api]
);
const {
loading: projectInfoLoading,
projectId,
projectToken,
configDir,
Expand All @@ -98,6 +63,11 @@ export const Panel = ({ active, api }: PanelProps) => {
// Render the Authentication flow if the user is not signed in.
if (!accessToken) return <Authentication key={PANEL_ID} setAccessToken={setAccessToken} />;

// Momentarily wait on addonState (should be very fast)
if (projectInfoLoading || !gitInfo) {
return <Spinner />;
}

if (!projectId)
return (
<Provider key={PANEL_ID} value={client}>
Expand Down Expand Up @@ -128,14 +98,14 @@ export const Panel = ({ active, api }: PanelProps) => {
</Provider>
);
}

return (
<Provider key={PANEL_ID} value={client}>
<VisualTests
projectId={projectId}
gitInfo={gitInfo}
isStarting={isStarting}
lastDevBuildId={lastBuildId}
startDevBuild={() => isStarting || emit(START_BUILD)}
runningBuild={runningBuild}
startDevBuild={() => emit(START_BUILD)}
setAccessToken={setAccessToken}
updateBuildStatus={updateBuildStatus}
storyId={storyId}
Expand Down
19 changes: 6 additions & 13 deletions src/Tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,20 @@ import { useChannel } from "@storybook/manager-api";
import React, { useState } from "react";

import { RunTestsButton } from "./components/RunTestsButton";
import { BUILD_STARTED, START_BUILD, TOOL_ID } from "./constants";
import { RUNNING_BUILD, RunningBuildPayload, START_BUILD, TOOL_ID } from "./constants";
import { useAddonState } from "./useAddonState/manager";
import { useAccessToken } from "./utils/graphQLClient";
import { useProjectId } from "./utils/useProjectId";

export const Tool = () => {
const [isStarting, setIsStarting] = useState(false);
const { projectId } = useProjectId();
const [accessToken] = useAccessToken();
const isLoggedIn = !!accessToken;

const emit = useChannel(
{
[START_BUILD]: () => setIsStarting(true),
[BUILD_STARTED]: () => setIsStarting(false),
},
[]
);

const startBuild = () => {
emit(START_BUILD);
};
const [runningBuild] = useAddonState<RunningBuildPayload>(RUNNING_BUILD);
const emit = useChannel({});
const startBuild = () => emit(START_BUILD);

const isStarting = ["initializing"].includes(runningBuild?.step);
return <RunTestsButton key={TOOL_ID} {...{ isStarting, projectId, isLoggedIn, startBuild }} />;
};
46 changes: 28 additions & 18 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { GitInfo } from "chromatic/node";
import type { GitInfo, TaskName } from "chromatic/node";

export const {
CHROMATIC_INDEX_URL,
Expand All @@ -15,24 +15,34 @@ export const ACCESS_TOKEN_KEY = `${ADDON_ID}/access-token/${CHROMATIC_BASE_URL}`
export const DEV_BUILD_ID_KEY = `${ADDON_ID}/dev-build-id`;

export const GIT_INFO = `${ADDON_ID}/gitInfo`;
export type GitInfoPayload = Omit<GitInfo, "committedAt" | "committerEmail" | "committerName">;
export const START_BUILD = `${ADDON_ID}/startBuild`;
export const BUILD_ANNOUNCED = `${ADDON_ID}/buildAnnounced`;
export const BUILD_STARTED = `${ADDON_ID}/buildStarted`;
export type GitInfoPayload = Omit<GitInfo, "committerEmail" | "committerName">;

export const UPDATE_PROJECT = `${ADDON_ID}/updateProject`;
export type UpdateProjectPayload = {
projectId: string;
projectToken: string;
export const PROJECT_INFO = `${ADDON_ID}/projectInfo`;
export type ProjectInfoPayload = {
projectId?: string;
projectToken?: string;
written?: boolean;
configDir?: string;
mainPath?: string;
};

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;
// The CLI may have other steps that we don't respond to, so we just ignore updates
// to those steps and focus on the ones we know.
type KnownTask = Extract<TaskName, "initialize" | "build" | "upload" | "verify" | "snapshot">;
export function isKnownTask(task: TaskName): task is KnownTask {
return ["initialize", "build", "upload", "verify", "snapshot"].includes(task);
}

export const START_BUILD = `${ADDON_ID}/startBuild`;
export const RUNNING_BUILD = `${ADDON_ID}/runningBuild`;
export type RunningBuildPayload = {
// Possibly this should be a type exported by the CLI -- these correspond to tasks
/** The step of the build process we have reached */
step: KnownTask | "complete";
/** The id of the build, available after the initialize step */
id?: string;
/** progress pertains to the current step, and may not be set */
progress?: number;
/** total pertains to the current step, and may not be set */
total?: number;
};
Loading