Added UI to guide you to fixing unconfigured integrations

This commit is contained in:
Matt Aitken
2023-07-06 11:56:17 +01:00
parent be6741a4a8
commit bee77051e7
5 changed files with 98 additions and 34 deletions
+30 -6
View File
@@ -18,6 +18,7 @@ import { runStatusTitle } from "../runs/RunStatuses";
import { ProjectJob, useProject } from "~/hooks/useProject";
import { useOrganization } from "~/hooks/useOrganizations";
import { JobRunStatus } from "~/models/job.server";
import { cn } from "~/utils/cn";
export function JobsTable({
jobs,
@@ -46,7 +47,12 @@ export function JobsTable({
jobs.map((job) => {
const path = jobPath(organization, project, job);
return (
<TableRow key={job.id}>
<TableRow
key={job.id}
className={cn(
job.hasIntegrationsRequiringAction && "bg-rose-500/30"
)}
>
<TableCell to={path}>
<span className="flex items-center gap-2">
<NamedIcon name={job.event.icon} className="h-8 w-8" />
@@ -79,12 +85,30 @@ export function JobsTable({
<SimpleTooltip
key={integration.key}
button={
<NamedIcon
name={integration.icon}
className="h-6 w-6"
/>
<div className="relative">
<NamedIcon
name={integration.icon}
className="h-6 w-6"
/>
{integration.setupStatus === "MISSING_FIELDS" && (
<NamedIcon
name="error"
className="absolute -left-1 -top-1 h-4 w-4"
/>
)}
</div>
}
content={
<div>
<p className="mb-1 text-rose-400">
{integration.setupStatus === "MISSING_FIELDS" &&
"This integration requires configuration"}
</p>
<p>
{integration.title}: {integration.key}
</p>
</div>
}
content={`${integration.title}: ${integration.key}`}
/>
))}
</TableCell>
@@ -57,6 +57,7 @@ export class ProjectPresenter {
select: {
slug: true,
definition: true,
setupStatus: true,
},
},
},
@@ -169,6 +170,7 @@ export class ProjectPresenter {
key: integration.key,
title: integration.integration.slug,
icon: integration.integration.definition.id,
setupStatus: integration.integration.setupStatus,
})
);
@@ -197,6 +199,9 @@ export class ProjectPresenter {
source: eventSpecification.source,
},
integrations,
hasIntegrationsRequiringAction: integrations.some(
(i) => i.setupStatus === "MISSING_FIELDS"
),
lastRun,
properties,
};
@@ -21,7 +21,7 @@ import { useProject } from "~/hooks/useProject";
import { cn } from "~/utils/cn";
import { Handle } from "~/utils/handle";
import useWindowSize from "react-use/lib/useWindowSize";
import { docsPath } from "~/utils/pathBuilder";
import { docsPath, projectIntegrationsPath } from "~/utils/pathBuilder";
export const handle: Handle = {
breadcrumb: {
@@ -83,6 +83,19 @@ export default function Page() {
)}
>
<div>
{project.jobs.length > 0 &&
project.jobs.some(
(j) => j.hasIntegrationsRequiringAction
) && (
<Callout
variant="error"
to={projectIntegrationsPath(organization, project)}
className="mb-2"
>
Some of your Jobs have Integrations that have not been
configured.
</Callout>
)}
<div className="mb-2 flex items-center justify-between gap-x-2">
{project.jobs.length === 0 ? (
<Header2>Jobs</Header2>
@@ -390,7 +390,7 @@ function IntegrationsWithMissingFields({
<div className="mb-6">
<Header2 className="mb-2 flex items-center gap-1">
<NamedIcon name="error" className="h-5 w-5" />
Integrations with missing details
Integrations requiring configuration
</Header2>
<Table>
@@ -9,8 +9,13 @@ import { RunListPresenter } from "~/presenters/RunListPresenter.server";
import { requireUserId } from "~/services/session.server";
import { cn } from "~/utils/cn";
import { Handle } from "~/utils/handle";
import { JobParamsSchema } from "~/utils/pathBuilder";
import { JobParamsSchema, projectIntegrationsPath } from "~/utils/pathBuilder";
import { ListPagination } from "./ListPagination";
import { Callout } from "~/components/primitives/Callout";
import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import { useJob } from "~/hooks/useJob";
import simplur from "simplur";
export const DirectionSchema = z.union([
z.literal("forward"),
@@ -56,34 +61,51 @@ export default function Page() {
const { list } = useTypedLoaderData<typeof loader>();
const navigation = useNavigation();
const isLoading = navigation.state !== "idle";
const organization = useOrganization();
const project = useProject();
const job = useJob();
return (
<Help defaultOpen={list.runs.length === 0}>
{(open) => (
<div
className={cn(
"grid h-fit gap-4",
open ? "grid-cols-2" : "grid-cols-1"
)}
<>
{job.hasIntegrationsRequiringAction && (
<Callout
variant="error"
to={projectIntegrationsPath(organization, project)}
className="mb-2"
>
<div>
<div className="mb-2 flex items-center justify-end gap-x-2">
<ListPagination list={list} />
<HelpTrigger title="How do I run my Job?" />
</div>
<RunsTable
total={list.runs.length}
hasFilters={false}
runs={list.runs}
isLoading={isLoading}
/>
<ListPagination list={list} className="mt-2 justify-end" />
</div>
<HelpContent title="How to run your Job">
<HowToRunYourJob />
</HelpContent>
</div>
{simplur`This Job has ${
job.integrations.filter((j) => j.setupStatus === "MISSING_FIELDS")
.length
} Integration[|s] that [has|have] not been configured.`}
</Callout>
)}
</Help>
<Help defaultOpen={list.runs.length === 0}>
{(open) => (
<div
className={cn(
"grid h-fit gap-4",
open ? "grid-cols-2" : "grid-cols-1"
)}
>
<div>
<div className="mb-2 flex items-center justify-end gap-x-2">
<ListPagination list={list} />
<HelpTrigger title="How do I run my Job?" />
</div>
<RunsTable
total={list.runs.length}
hasFilters={false}
runs={list.runs}
isLoading={isLoading}
/>
<ListPagination list={list} className="mt-2 justify-end" />
</div>
<HelpContent title="How to run your Job">
<HowToRunYourJob />
</HelpContent>
</div>
)}
</Help>
</>
);
}