mirror of
https://github.com/paperclipai/paperclip
synced 2026-04-25 17:25:15 +02:00
Open imported company after import
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { CompanyPortabilityPreviewResult } from "@paperclipai/shared";
|
||||
import {
|
||||
buildCompanyDashboardUrl,
|
||||
buildDefaultImportAdapterOverrides,
|
||||
buildDefaultImportSelectionState,
|
||||
buildImportSelectionCatalog,
|
||||
@@ -101,6 +102,14 @@ describe("resolveCompanyImportApplyConfirmationMode", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildCompanyDashboardUrl", () => {
|
||||
it("preserves the configured base path when building a dashboard URL", () => {
|
||||
expect(buildCompanyDashboardUrl("https://paperclip.example/app/", "PAP")).toBe(
|
||||
"https://paperclip.example/app/PAP/dashboard",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("renderCompanyImportPreview", () => {
|
||||
it("summarizes the preview with counts, selection info, and truncated examples", () => {
|
||||
const preview: CompanyPortabilityPreviewResult = {
|
||||
@@ -155,6 +164,10 @@ describe("renderCompanyImportPreview", () => {
|
||||
logoPath: null,
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
},
|
||||
sidebar: {
|
||||
agents: ["ceo"],
|
||||
projects: ["alpha"],
|
||||
},
|
||||
agents: [
|
||||
{
|
||||
slug: "ceo",
|
||||
@@ -291,16 +304,19 @@ describe("renderCompanyImportResult", () => {
|
||||
{ slug: "cto", id: "agent-2", action: "updated", name: "CTO", reason: "replace strategy" },
|
||||
{ slug: "ops", id: null, action: "skipped", name: "Ops", reason: "skip strategy" },
|
||||
],
|
||||
projects: [],
|
||||
envInputs: [],
|
||||
warnings: ["Review API keys"],
|
||||
},
|
||||
{
|
||||
targetLabel: "Imported Co (company-123)",
|
||||
companyUrl: "https://paperclip.example/PAP/dashboard",
|
||||
infoMessages: ["Using claude-local adapter"],
|
||||
},
|
||||
);
|
||||
|
||||
expect(rendered).toContain("Company");
|
||||
expect(rendered).toContain("https://paperclip.example/PAP/dashboard");
|
||||
expect(rendered).toContain("3 agents total (1 created, 1 updated, 1 skipped)");
|
||||
expect(rendered).toContain("Agent results");
|
||||
expect(rendered).toContain("Using claude-local adapter");
|
||||
@@ -350,6 +366,10 @@ describe("import selection catalog", () => {
|
||||
logoPath: "images/company-logo.png",
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
},
|
||||
sidebar: {
|
||||
agents: ["ceo"],
|
||||
projects: ["alpha"],
|
||||
},
|
||||
agents: [
|
||||
{
|
||||
slug: "ceo",
|
||||
@@ -504,6 +524,7 @@ describe("default adapter overrides", () => {
|
||||
skills: false,
|
||||
},
|
||||
company: null,
|
||||
sidebar: null,
|
||||
agents: [
|
||||
{
|
||||
slug: "legacy-agent",
|
||||
|
||||
@@ -169,7 +169,7 @@ async function requestJson<T>(url: string, init?: RequestInit): Promise<T> {
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
|
||||
function openUrl(url: string): boolean {
|
||||
export function openUrl(url: string): boolean {
|
||||
const platform = process.platform;
|
||||
try {
|
||||
if (platform === "darwin") {
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
CompanyPortabilityImportResult,
|
||||
} from "@paperclipai/shared";
|
||||
import { ApiRequestError } from "../../client/http.js";
|
||||
import { openUrl } from "../../client/board-auth.js";
|
||||
import { readZipArchive } from "./zip.js";
|
||||
import {
|
||||
addCommonClientOptions,
|
||||
@@ -654,7 +655,7 @@ export function renderCompanyImportPreview(
|
||||
|
||||
export function renderCompanyImportResult(
|
||||
result: CompanyPortabilityImportResult,
|
||||
meta: { targetLabel: string; infoMessages?: string[] },
|
||||
meta: { targetLabel: string; companyUrl?: string; infoMessages?: string[] },
|
||||
): string {
|
||||
const lines: string[] = [
|
||||
`${pc.bold("Target")} ${meta.targetLabel}`,
|
||||
@@ -662,6 +663,10 @@ export function renderCompanyImportResult(
|
||||
`${pc.bold("Agents")} ${summarizeImportAgentResults(result.agents)}`,
|
||||
];
|
||||
|
||||
if (meta.companyUrl) {
|
||||
lines.splice(1, 0, `${pc.bold("URL")} ${meta.companyUrl}`);
|
||||
}
|
||||
|
||||
appendPreviewExamples(
|
||||
lines,
|
||||
"Agent results",
|
||||
@@ -713,6 +718,15 @@ export function resolveCompanyImportApiPath(input: {
|
||||
return input.dryRun ? "/api/companies/import/preview" : "/api/companies/import";
|
||||
}
|
||||
|
||||
export function buildCompanyDashboardUrl(apiBase: string, issuePrefix: string): string {
|
||||
const url = new URL(apiBase);
|
||||
const normalizedPrefix = issuePrefix.trim().replace(/^\/+|\/+$/g, "");
|
||||
url.pathname = `${url.pathname.replace(/\/+$/, "")}/${normalizedPrefix}/dashboard`;
|
||||
url.search = "";
|
||||
url.hash = "";
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
export function resolveCompanyImportApplyConfirmationMode(input: {
|
||||
yes?: boolean;
|
||||
interactive: boolean;
|
||||
@@ -1298,6 +1312,18 @@ export function registerCompanyCommands(program: Command): void {
|
||||
if (!imported) {
|
||||
throw new Error("Import request returned no data.");
|
||||
}
|
||||
let companyUrl: string | undefined;
|
||||
if (!ctx.json) {
|
||||
try {
|
||||
const importedCompany = await ctx.api.get<Company>(`/api/companies/${imported.company.id}`);
|
||||
const issuePrefix = importedCompany?.issuePrefix?.trim();
|
||||
if (issuePrefix) {
|
||||
companyUrl = buildCompanyDashboardUrl(ctx.api.apiBase, issuePrefix);
|
||||
}
|
||||
} catch {
|
||||
companyUrl = undefined;
|
||||
}
|
||||
}
|
||||
if (ctx.json) {
|
||||
printOutput(imported, { json: true });
|
||||
} else {
|
||||
@@ -1305,10 +1331,24 @@ export function registerCompanyCommands(program: Command): void {
|
||||
"Import Result",
|
||||
renderCompanyImportResult(imported, {
|
||||
targetLabel,
|
||||
companyUrl,
|
||||
infoMessages: adapterMessages,
|
||||
}),
|
||||
{ interactive: interactiveView },
|
||||
);
|
||||
if (interactiveView && companyUrl) {
|
||||
const openImportedCompany = await p.confirm({
|
||||
message: "Open the imported company in your browser?",
|
||||
initialValue: true,
|
||||
});
|
||||
if (!p.isCancel(openImportedCompany) && openImportedCompany) {
|
||||
if (openUrl(companyUrl)) {
|
||||
p.log.info(`Opened ${companyUrl}`);
|
||||
} else {
|
||||
p.log.warn(`Could not open your browser automatically. Open this URL manually:\n${companyUrl}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
handleCommandError(err);
|
||||
|
||||
Reference in New Issue
Block a user