Skip to content
Open
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
156 changes: 152 additions & 4 deletions src/commands/context/get.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Value } from "../../rendering/react/components/Value.js";
import { usePromise } from "@mittwald/react-use-promise";
import { Note } from "../../rendering/react/components/Note.js";
import { Box, Text } from "ink";
import { Set } from "./set.js";
import { Set as SetCommand } from "./set.js";
import { RenderJson } from "../../rendering/react/json/RenderJson.js";
import { useRenderContext } from "../../rendering/react/context.js";
import { LocalFilename } from "../../rendering/react/components/LocalFilename.js";
Expand All @@ -14,6 +14,12 @@ import Context, {
ContextValue,
ContextValueSource,
} from "../../lib/context/Context.js";
import {
fetchProjectOverview,
formatOverviewEntry,
ProjectOverview,
resolveProjectContext,
} from "../../lib/context/projectOverview.js";

const ContextSourceValue: FC<{ source: ContextValueSource }> = ({ source }) => {
switch (source.type) {
Expand Down Expand Up @@ -75,9 +81,122 @@ const ContextSource: FC<{ source: ContextValueSource }> = ({ source }) => {
);
};

const ProjectOverviewSection: FC<{ overview: ProjectOverview }> = ({
overview,
}) => {
const stackDisplayById = new Map(
overview.stacks.map((stack) => [stack.id, stack.shortId ?? ""]),
);

if (overview.unavailableReason) {
return (
<Note marginBottom={1}>
Project overview is unavailable: {overview.unavailableReason}
</Note>
);
}

const rows: Record<string, ReactNode> = {
Project: (
<Text>
<Value>{overview.projectName ?? overview.projectId}</Value>{" "}
<Text color="gray">
({overview.projectShortId ?? overview.projectId}, resolved from{" "}
{overview.resolvedFrom ?? "project-id"})
</Text>
</Text>
),
};

rows["Apps"] =
overview.apps.length > 0 ? (
<Box flexDirection="column">
{overview.apps.map((app) => (
<Box key={app.installationId} flexDirection="column" marginBottom={1}>
<Text color="green">
{formatOverviewEntry({
shortId: app.installationShortId,
name: app.appName,
status: `installed at ${app.installationPath}`,
id: app.installationId,
})}
</Text>
{app.linkedDatabases.length > 0 ? (
app.linkedDatabases.map((db) => (
<Text
key={`${app.installationId}-${db.databaseId}-${db.purpose}`}
color="gray"
>
database {db.purpose}: {db.name ?? db.databaseId} ({db.kind})
</Text>
))
) : (
<Text color="gray">no linked databases</Text>
)}
</Box>
))}
</Box>
) : (
<Text color="gray">none found in this project</Text>
);

rows["Stacks"] =
overview.stacks.length > 0 ? (
<Box flexDirection="column">
<Text>
<Value>{overview.stacks.length}</Value> total
</Text>
{overview.stacks.slice(0, 5).map((stack) => (
<Text key={stack.id} color="gray">
{formatOverviewEntry({
shortId: stack.shortId,
name: stack.description ?? "stack",
status: `${stack.services} services, ${stack.volumes} volumes`,
id: stack.id,
})}
</Text>
))}
</Box>
) : (
<Text color="gray">none found in this project</Text>
);

rows["Containers"] =
overview.containers.length > 0 ? (
<Box flexDirection="column">
<Text>
<Value>{overview.containers.length}</Value> total
</Text>
{overview.containers.slice(0, 8).map((container) => {
const stackShortId = container.stackId
? (stackDisplayById.get(container.stackId) ?? "")
: "";
const stackSuffix = container.stackId
? ` | stack ${stackShortId}`
: "";

return (
<Text key={container.id} color="gray">
{formatOverviewEntry({
shortId: container.shortId,
name: container.name,
status: `${container.status}${stackSuffix}`,
id: container.id,
})}
</Text>
);
})}
</Box>
) : (
<Text color="gray">none found in this project</Text>
);

return <SingleResult title="Project context overview" rows={rows} />;
};

const GetContext: FC<{ ctx: Context }> = ({ ctx }) => {
const rows: Record<string, ReactNode> = {};
const { renderAsJson } = useRenderContext();
const { renderAsJson, apiClient } = useRenderContext();
const values: Record<string, ContextValue | undefined> = {};

let hasTerraformSource = false;
Expand Down Expand Up @@ -109,15 +228,44 @@ const GetContext: FC<{ ctx: Context }> = ({ ctx }) => {
}
}

const projectIdFromContext = values["project-id"]?.value;
const appInstallationId = values["installation-id"]?.value;

const resolvedProject = usePromise(
(
contextProjectId: string | undefined,
installationId: string | undefined,
) => resolveProjectContext(apiClient, contextProjectId, installationId),
[projectIdFromContext, appInstallationId],
);

const overview = usePromise(
Comment thread
gandie marked this conversation as resolved.
(resolvedProjectContext: {
projectId?: string;
resolvedFrom?: "project-id" | "installation-id";
unavailableReason?: string;
}): Promise<ProjectOverview> =>
fetchProjectOverview(apiClient, resolvedProjectContext),
[resolvedProject],
);

if (renderAsJson) {
return <RenderJson name={"context"} data={values} />;
return (
<>
<RenderJson name={"context"} data={values} />
<RenderJson name={"projectOverview"} data={overview} />
</>
);
}

return (
<Box flexDirection="column">
<Box marginBottom={1}>
<SingleResult title="Current CLI context" rows={rows} />
</Box>
<Box marginBottom={1}>
<ProjectOverviewSection overview={overview} />
</Box>
{hasTerraformSource && <TerraformHint />}
{hasDDEVSource && <DDEVHint />}
{hasDotfileSource && <DotfileHint />}
Expand Down Expand Up @@ -156,7 +304,7 @@ const ContextSetHint: FC = () => (

export class Get extends RenderBaseCommand<typeof Get> {
static summary = "Print an overview of currently set context parameters";
static description = Set.description;
static description = SetCommand.description;
static flags = { ...RenderBaseCommand.buildFlags() };

protected render(): ReactNode {
Expand Down
Loading
Loading