diff --git a/argocd/base/statefulset.yaml b/argocd/base/statefulset.yaml index ddefd8f6..49c370be 100644 --- a/argocd/base/statefulset.yaml +++ b/argocd/base/statefulset.yaml @@ -26,7 +26,7 @@ spec: # Note: use the *dev* version of the package here, so that # PRs can deploy `primer-service` container images that have # not yet been merged to `primer` `main`. - image: ghcr.io/hackworthltd/primer-service-dev:git-248899f37edb88f2b00945097ff075c5fc0dfef6 + image: ghcr.io/hackworthltd/primer-service-dev:git-fdd5b31b4c2a0053447f303efbbc1793d9bbb10f ports: - containerPort: 8081 env: diff --git a/flake.lock b/flake.lock index 27c703a0..c9b2093d 100644 --- a/flake.lock +++ b/flake.lock @@ -1678,17 +1678,17 @@ "pre-commit-hooks-nix": "pre-commit-hooks-nix_4" }, "locked": { - "lastModified": 1686062354, - "narHash": "sha256-6A9Pg2c7QJ9v1erFysUJbGgTvKp9b2kS9GOVZfS8xLc=", + "lastModified": 1686218664, + "narHash": "sha256-qeOpNpHNcqYel4V4ItjHWrXyHyO4McGbamvjSFgYAYo=", "owner": "hackworthltd", "repo": "primer", - "rev": "248899f37edb88f2b00945097ff075c5fc0dfef6", + "rev": "fdd5b31b4c2a0053447f303efbbc1793d9bbb10f", "type": "github" }, "original": { "owner": "hackworthltd", "repo": "primer", - "rev": "248899f37edb88f2b00945097ff075c5fc0dfef6", + "rev": "fdd5b31b4c2a0053447f303efbbc1793d9bbb10f", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 9af2f2d3..389f8604 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,7 @@ # Note: don't override any of primer's Nix flake inputs, or else # we won't hit its binary cache. - primer.url = github:hackworthltd/primer/248899f37edb88f2b00945097ff075c5fc0dfef6; + primer.url = github:hackworthltd/primer/fdd5b31b4c2a0053447f303efbbc1793d9bbb10f; flake-parts.url = "github:hercules-ci/flake-parts"; }; diff --git a/src/Edit.tsx b/src/Edit.tsx index a2370759..93e01e23 100644 --- a/src/Edit.tsx +++ b/src/Edit.tsx @@ -36,6 +36,8 @@ import { Level, useUndo, useRedo, + useGetTypeOrKind, + TypeOrKind, } from "./primer-api"; import { defaultTreeReactFlowProps, @@ -82,9 +84,22 @@ const Edit = (): JSX.Element => { const AppProg = (p: { sessionId: string; initialProg: Prog }): JSX.Element => { const [prog, setProg0] = useState(p.initialProg); - const [selection, setSelection] = useState( + const [selection, setSelection0] = useState( prog.selection ); + const getTypeOrKind = useGetTypeOrKind(); + const [selectionTypeOrKind, setSelectionTypeOrKind] = useState< + TypeOrKind | undefined + >(); + const setSelection = (s: Selection | undefined) => { + s + ? getTypeOrKind + .mutateAsync({ sessionId: p.sessionId, data: s }) + .then(setSelectionTypeOrKind) + .catch((_) => setSelectionTypeOrKind(undefined)) + : setSelectionTypeOrKind(undefined); + setSelection0(s); + }; const setProg = (prog: Prog) => { setProg0(prog); setSelection(prog.selection); @@ -108,6 +123,7 @@ const AppProg = (p: { sessionId: string; initialProg: Prog }): JSX.Element => { return ( void; setProg: (p: Prog) => void; undoAvailable: boolean; @@ -297,6 +314,7 @@ const AppNoError = ({ diff --git a/src/components/PictureInPicture/index.tsx b/src/components/PictureInPicture/index.tsx index 3e76aa2f..428d405d 100644 --- a/src/components/PictureInPicture/index.tsx +++ b/src/components/PictureInPicture/index.tsx @@ -1,14 +1,21 @@ +import { InformationCircleIcon } from "@heroicons/react/24/outline"; import classNames from "classnames"; import { useRef, useState } from "react"; import { useDraggable, DragOptions } from "@neodrag/react"; import type { EvalFullProps } from "@/components/EvalFull"; -import { EvalFull } from "@/components"; +import type { SelectionInfoProps } from "@/components/SelectionInfo"; +import { EvalFull, SelectionInfo } from "@/components"; + +export type PictureInPictureTab = "Evaluation" | "Info"; export type PictureInPictureProps = { + initialTab: PictureInPictureTab; initialPosition: { x: number; y: number }; -} & EvalFullProps; +} & EvalFullProps & + SelectionInfoProps; export const PictureInPicture = (p: PictureInPictureProps): JSX.Element => { + const [currentTab, switchTab] = useState(p.initialTab); const [touchDragging, setTouchDragging] = useState(false); const draggableRef = useRef(null); @@ -25,6 +32,21 @@ export const PictureInPicture = (p: PictureInPictureProps): JSX.Element => { }; useDraggable(draggableRef, options); + const tab = (tab: PictureInPictureTab, element: JSX.Element): JSX.Element => ( + + ); + return (
{ )} >
- Evaluate +
+ {tab( + "Evaluation", +
+ Evaluation +
+ )} + {tab("Info", )} +
- + {(() => { + switch (currentTab) { + case "Evaluation": + return ; + case "Info": + return ; + } + })()}
); diff --git a/src/components/SelectionInfo/index.tsx b/src/components/SelectionInfo/index.tsx new file mode 100644 index 00000000..f8dd3c48 --- /dev/null +++ b/src/components/SelectionInfo/index.tsx @@ -0,0 +1,49 @@ +import { NodeChange, ReactFlowProvider, useReactFlow } from "reactflow"; +import { Level, TypeOrKind } from "@/primer-api"; +import { TreeReactFlowOne } from "@/components"; +import { defaultTreeReactFlowProps } from "../TreeReactFlow"; + +export type SelectionInfoProps = { + typeOrKind: TypeOrKind | undefined; + level: Level; +}; + +const TypeOrKindTree = (p: { typeOrKind: TypeOrKind; level: Level }) => { + const padding = 1.0; + const { fitView } = useReactFlow(); + const onNodesChange = (_: NodeChange[]) => { + fitView({ padding }); + }; + + return ( + + ); +}; + +export const SelectionInfo = ({ + typeOrKind, + level, +}: SelectionInfoProps): JSX.Element => { + return ( +
+ {typeOrKind && ( + <> +
+ + + +
+ + )} +
+ ); +}; + +export default SelectionInfo; diff --git a/src/components/TreeReactFlow/Flavor.ts b/src/components/TreeReactFlow/Flavor.ts index 8fc3abc4..1dabb4b0 100644 --- a/src/components/TreeReactFlow/Flavor.ts +++ b/src/components/TreeReactFlow/Flavor.ts @@ -53,6 +53,24 @@ export const flavorClasses = (flavor: NodeFlavor): string => { "hover:ring-green-primary", commonHoverClasses ); + case "KHole": + return classNames( + "border-red-tertiary ring-red-tertiary bg-white-primary", + "hover:ring-red-tertiary", + commonHoverClasses + ); + case "KType": + return classNames( + "border-grey-secondary ring-grey-secondary bg-grey-secondary", + "hover:ring-grey-secondary", + commonHoverClasses + ); + case "KFun": + return classNames( + "border-grey-secondary ring-grey-secondary bg-grey-secondary", + "hover:ring-grey-secondary", + commonHoverClasses + ); case "Lam": return classNames( "border-blue-primary ring-blue-primary bg-white-primary", @@ -200,6 +218,12 @@ export const flavorContentClasses = ( return "text-white-primary"; case "Con": return "text-blue-primary"; + case "KHole": + return "text-blue-primary"; + case "KType": + return "text-blue-primary"; + case "KFun": + return "text-blue-primary"; case "Lam": return "text-blue-primary"; case "LAM": @@ -270,6 +294,12 @@ export const flavorLabelClasses = (flavor: NodeFlavor): string => { return "font-code bg-black-primary border-black-primary text-white-primary"; case "GlobalVar": return "bg-blue-quaternary border-blue-quaternary text-white-primary"; + case "KHole": + return "font-code bg-red-tertiary border-red-tertiary text-white-primary"; + case "KType": + return "font-code bg-grey-secondary bg-grey-secondary text-white-primary"; + case "KFun": + return "font-code bg-grey-secondary bg-grey-secondary text-white-primary"; case "LocalVar": return "bg-blue-quaternary border-blue-quaternary text-white-primary"; case "Let": @@ -327,6 +357,12 @@ export const flavorEdgeClasses = (flavor: NodeFlavor): string => { return "stroke-yellow-secondary"; case "Con": return "stroke-green-primary"; + case "KHole": + return "stroke-grey-seconary"; + case "KType": + return "stroke-grey-seconary"; + case "KFun": + return "stroke-grey-seconary"; case "Lam": return "stroke-blue-primary"; case "LAM": @@ -436,6 +472,12 @@ export const flavorLabel = (flavor: NodeFlavor): string => { return "🤷🏽‍♀️"; case "PatternBind": return "Var"; + case "KType": + return "*"; + case "KHole": + return "?"; + case "KFun": + return "*→*"; } }; @@ -465,6 +507,12 @@ export const noBodyFlavorContents = (flavor: NodeFlavorNoBody): string => { return "{?}"; case "PatternWildcard": return "🤷🏽‍♀️"; + case "KType": + return "type"; + case "KHole": + return "?"; + case "KFun": + return "type constructor"; } }; diff --git a/src/components/index.ts b/src/components/index.ts index f809cd53..d7401e64 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -13,6 +13,7 @@ export { default as Branding } from "./Branding"; export { default as PictureInPicture } from "./PictureInPicture"; export { default as SearchBar } from "./SearchBar"; export { default as SelectMenu } from "./SelectMenu"; +export { default as SelectionInfo } from "./SelectionInfo"; export { default as SessionList } from "./SessionList"; export { default as SessionNameModal } from "./SessionNameModal"; export { default as SessionPreview } from "./SessionPreview"; diff --git a/src/primer-api/model/index.ts b/src/primer-api/model/index.ts index a1d349c5..751ab212 100644 --- a/src/primer-api/model/index.ts +++ b/src/primer-api/model/index.ts @@ -82,5 +82,10 @@ export * from './typeDefNodeSelectionOneOfTag'; export * from './typeDefNodeSelectionOneOfThree'; export * from './typeDefNodeSelectionOneOfThreeTag'; export * from './typeDefSelection'; +export * from './typeOrKind'; +export * from './typeOrKindOneOf'; +export * from './typeOrKindOneOfTag'; +export * from './typeOrKindOneOfThree'; +export * from './typeOrKindOneOfThreeTag'; export * from './uuid'; export * from './valCon'; \ No newline at end of file diff --git a/src/primer-api/model/nodeFlavorNoBody.ts b/src/primer-api/model/nodeFlavorNoBody.ts index 96084457..fe8d84ea 100644 --- a/src/primer-api/model/nodeFlavorNoBody.ts +++ b/src/primer-api/model/nodeFlavorNoBody.ts @@ -23,4 +23,7 @@ export const NodeFlavorNoBody = { TFun: 'TFun', TApp: 'TApp', PatternWildcard: 'PatternWildcard', + KType: 'KType', + KHole: 'KHole', + KFun: 'KFun', } as const; diff --git a/src/primer-api/model/typeOrKind.ts b/src/primer-api/model/typeOrKind.ts new file mode 100644 index 00000000..89cae292 --- /dev/null +++ b/src/primer-api/model/typeOrKind.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval v6.16.0 🍺 + * Do not edit manually. + * Primer backend API + * A backend service implementing a pedagogic functional programming language. + * OpenAPI spec version: 0.7 + */ +import type { TypeOrKindOneOf } from './typeOrKindOneOf'; +import type { TypeOrKindOneOfThree } from './typeOrKindOneOfThree'; + +export type TypeOrKind = TypeOrKindOneOf | TypeOrKindOneOfThree; diff --git a/src/primer-api/model/typeOrKindOneOf.ts b/src/primer-api/model/typeOrKindOneOf.ts new file mode 100644 index 00000000..b6de0712 --- /dev/null +++ b/src/primer-api/model/typeOrKindOneOf.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v6.16.0 🍺 + * Do not edit manually. + * Primer backend API + * A backend service implementing a pedagogic functional programming language. + * OpenAPI spec version: 0.7 + */ +import type { Tree } from './tree'; +import type { TypeOrKindOneOfTag } from './typeOrKindOneOfTag'; + +export type TypeOrKindOneOf = { + contents: Tree; + tag: TypeOrKindOneOfTag; +}; diff --git a/src/primer-api/model/typeOrKindOneOfTag.ts b/src/primer-api/model/typeOrKindOneOfTag.ts new file mode 100644 index 00000000..5affe81c --- /dev/null +++ b/src/primer-api/model/typeOrKindOneOfTag.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v6.16.0 🍺 + * Do not edit manually. + * Primer backend API + * A backend service implementing a pedagogic functional programming language. + * OpenAPI spec version: 0.7 + */ + +export type TypeOrKindOneOfTag = typeof TypeOrKindOneOfTag[keyof typeof TypeOrKindOneOfTag]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const TypeOrKindOneOfTag = { + Type: 'Type', +} as const; diff --git a/src/primer-api/model/typeOrKindOneOfThree.ts b/src/primer-api/model/typeOrKindOneOfThree.ts new file mode 100644 index 00000000..c604d74f --- /dev/null +++ b/src/primer-api/model/typeOrKindOneOfThree.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v6.16.0 🍺 + * Do not edit manually. + * Primer backend API + * A backend service implementing a pedagogic functional programming language. + * OpenAPI spec version: 0.7 + */ +import type { Tree } from './tree'; +import type { TypeOrKindOneOfThreeTag } from './typeOrKindOneOfThreeTag'; + +export type TypeOrKindOneOfThree = { + contents: Tree; + tag: TypeOrKindOneOfThreeTag; +}; diff --git a/src/primer-api/model/typeOrKindOneOfThreeTag.ts b/src/primer-api/model/typeOrKindOneOfThreeTag.ts new file mode 100644 index 00000000..22c12ed8 --- /dev/null +++ b/src/primer-api/model/typeOrKindOneOfThreeTag.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v6.16.0 🍺 + * Do not edit manually. + * Primer backend API + * A backend service implementing a pedagogic functional programming language. + * OpenAPI spec version: 0.7 + */ + +export type TypeOrKindOneOfThreeTag = typeof TypeOrKindOneOfThreeTag[keyof typeof TypeOrKindOneOfThreeTag]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const TypeOrKindOneOfThreeTag = { + Kind: 'Kind', +} as const; diff --git a/src/primer-api/primer-api.ts b/src/primer-api/primer-api.ts index 5b7d08e0..a830f5ff 100644 --- a/src/primer-api/primer-api.ts +++ b/src/primer-api/primer-api.ts @@ -35,6 +35,7 @@ import type { EvalFullResp, GlobalName, EvalFullParams, + TypeOrKind, CreateTypeDefBody } from './model' import { useCustomInstance } from '../orval/mutator/use-custom-instance'; @@ -873,6 +874,64 @@ export const useRedo = , return useMutation(mutationOptions); } +/** + * @summary Get the type/kind of a particular node + */ +export const useGetTypeOrKindHook = () => { + const getTypeOrKind = useCustomInstance(); + + return ( + sessionId: string, + selection: Selection, + ) => { + return getTypeOrKind( + {url: `/openapi/sessions/${sessionId}/selection`, method: 'post', + headers: {'Content-Type': 'application/json;charset=utf-8', }, + data: selection + }, + ); + } + } + + + +export const useGetTypeOrKindMutationOptions = , + + TContext = unknown>(options?: { mutation?:UseMutationOptions>>, TError,{sessionId: string;data: Selection}, TContext>, } +): UseMutationOptions>>, TError,{sessionId: string;data: Selection}, TContext> => { + const {mutation: mutationOptions} = options ?? {}; + + const getTypeOrKind = useGetTypeOrKindHook() + + + const mutationFn: MutationFunction>>, {sessionId: string;data: Selection}> = (props) => { + const {sessionId,data} = props ?? {}; + + return getTypeOrKind(sessionId,data,) + } + + + + + return { mutationFn, ...mutationOptions }} + + export type GetTypeOrKindMutationResult = NonNullable>>> + export type GetTypeOrKindMutationBody = Selection + export type GetTypeOrKindMutationError = ErrorType + + /** + * @summary Get the type/kind of a particular node + */ +export const useGetTypeOrKind = , + + TContext = unknown>(options?: { mutation?:UseMutationOptions>>, TError,{sessionId: string;data: Selection}, TContext>, } +) => { + + const mutationOptions = useGetTypeOrKindMutationOptions(options); + + return useMutation(mutationOptions); + } + /** * @summary Create a new type definition */