Skip to content
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
33 changes: 33 additions & 0 deletions apps/apollo-vertex/app/templates/solution-tests/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,39 @@ render the dumb `SolutionTestsView`, which takes all data and callbacks via
props. It must still be wrapped in `SolutionTestsProvider` (the view reads
`config` from context via `useSolutionTestsConfig`), as the preview above does.

## Saving a subject as a test

Alongside the full-page view, the package exports a standalone `SaveAsTestButton`
for the inverse flow: letting a user promote the subject they're looking at (a
loan, claim, invoice, …) into a new Solution Test from that subject's own page.
It's presentational — you own the placement and wire it to the `useCreateTest`
hook, which POSTs the subject id to the `solution-tests/create` action through
the same `triggerBaseUrl` / `getToken` plumbing as the other writes.
Comment thread
frankkluijtmans marked this conversation as resolved.

```tsx
"use client";

import {
SaveAsTestButton,
useCreateTest,
} from "@/components/ui/solution-tests";

function SaveSubjectAsTest({ subjectId }: { subjectId: string }) {
const createTest = useCreateTest();
return (
<SaveAsTestButton
isSaving={createTest.isPending}
isSaved={createTest.isSuccess}
onSave={() => createTest.mutate(subjectId)}
/>
);
}
```

Both must sit inside a `SolutionTestsProvider` (the hook resolves the write
actions from context). The button takes `isSaved`, `isSaving`, `onSave`, and an
optional `disabled`, and renders its own saving / saved states.

## Installation

```bash
Expand Down
2 changes: 2 additions & 0 deletions apps/apollo-vertex/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@
"runs_in_progress": "Runs in progress",
"russian": "Russian",
"save_and_rerun": "Save & re-run",
"save_as_solution_test": "Save as solution test",
"saved_as_solution_test": "Saved as solution test",
Comment thread
frankkluijtmans marked this conversation as resolved.
"score": "Score",
"score_trend": "Score trend",
"scroll_to_bottom": "Scroll to bottom",
Expand Down
2 changes: 1 addition & 1 deletion apps/apollo-vertex/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
5 changes: 5 additions & 0 deletions apps/apollo-vertex/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,11 @@
"type": "registry:ui",
"target": "components/ui/solution-tests/index.ts"
},
{
"path": "registry/solution-tests/save-as-test-button.tsx",
"type": "registry:ui",
"target": "components/ui/solution-tests/save-as-test-button.tsx"
},
{
"path": "registry/solution-tests/solution-tests-view.tsx",
"type": "registry:ui",
Expand Down
2 changes: 2 additions & 0 deletions apps/apollo-vertex/registry/solution-tests/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
export interface SolutionTestsActions {
/** Run the given tests, or all active Ready tests when omitted. */
runTests(testIds?: string[]): Promise<void>;
/** Create a solution test from a subject (the backend keys it as `subject_id`). */
createTest(subjectId: string): Promise<void>;
deleteTest(testId: string): Promise<void>;
forceStopBatch(batchId: string): Promise<void>;
forceStopRun(runId: string): Promise<void>;
Expand Down
1 change: 1 addition & 0 deletions apps/apollo-vertex/registry/solution-tests/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const AUTOMATION_FUNCTIONS_SLUG = "automation-functions";

/** `automation-functions` RPC paths. */
export const AUTOMATION_FUNCTION_PATH = {
createTest: "/solution-tests/create",
deleteTest: "/solution-tests/delete",
forceStopBatch: "/solution-tests/force-stop-batch",
forceStopRun: "/solution-tests/force-stop",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ export function createSolutionTestActions(
auth: { userToken: token },
}));
},
createTest(subjectId: string): Promise<void> {
return callFn(AUTOMATION_FUNCTION_PATH.createTest, {
subject_id: subjectId,
});
},
deleteTest(testId: string): Promise<void> {
return callFn(AUTOMATION_FUNCTION_PATH.deleteTest, {
solution_test_id: testId,
Expand Down
1 change: 1 addition & 0 deletions apps/apollo-vertex/registry/solution-tests/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
export {
useSolutionTests,
useRunTests,
useCreateTest,
useToggleTestActive,
useDeleteTest,
} from "./use-solution-tests";
Expand Down
2 changes: 2 additions & 0 deletions apps/apollo-vertex/registry/solution-tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
export { SolutionTests } from "./solution-tests";
export { SolutionTestsView } from "./solution-tests-view";
export type { SolutionTestsViewProps } from "./solution-tests-view";
export { SaveAsTestButton } from "./save-as-test-button";
export {
SolutionTestsProvider,
useSolutionTestsContext,
Expand All @@ -35,6 +36,7 @@ export {
useBaselineJobs,
useRunResults,
useRunTests,
useCreateTest,
useToggleTestActive,
useDeleteTest,
useForceStopBatch,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import { Check, FlaskConical } from "lucide-react";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";

interface SaveAsTestButtonProps {
isSaved: boolean;
isSaving: boolean;
onSave: () => void;
disabled?: boolean;
}

/** Presentational button for saving the current subject as a solution test. */
export const SaveAsTestButton = ({
isSaved,
isSaving,
onSave,
disabled = false,
}: SaveAsTestButtonProps) => {
const { t } = useTranslation();
return (
<Button
type="button"
variant="outline"
disabled={disabled || isSaving || isSaved}
onClick={onSave}
>
Comment thread
Copilot marked this conversation as resolved.
{isSaved ? (
<Check className="size-4" />
) : isSaving ? (
<Spinner className="size-4" />
) : (
<FlaskConical className="size-4" />
)}
{isSaved ? t("saved_as_solution_test") : t("save_as_solution_test")}
</Button>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ export function useRunTests(): MutationHook<{ testIds?: string[] }> {
});
}

/** Create a solution test from a subject id (e.g. a loan). */
export function useCreateTest(): MutationHook<string> {
const actions = useSolutionTestsActions();
const testsCollection = useSolutionTestCollection(ENTITY.tests);
return useMutation({
mutationFn: async (subjectId: string) => {
await actions.createTest(subjectId);
await testsCollection.utils.refetch();
},
});
}
Comment thread
Copilot marked this conversation as resolved.

/**
* Toggle a test's active flag. Unlike the other writes this isn't an API
* trigger — it's a direct field update on the `UiPathSTTests` collection, so it
Expand Down
Loading