diff --git a/apps/app/src/app/bundles/skill-org-publish.ts b/apps/app/src/app/bundles/skill-org-publish.ts new file mode 100644 index 000000000..d25cd2155 --- /dev/null +++ b/apps/app/src/app/bundles/skill-org-publish.ts @@ -0,0 +1,50 @@ +import { createDenClient, readDenSettings, writeDenSettings } from "../lib/den"; + +export async function saveInstalledSkillToOpenWorkOrg(input: { + skillText: string; + skillHubId?: string | null; +}): Promise<{ skillId: string; orgId: string; orgName: string }> { + const settings = readDenSettings(); + const token = settings.authToken?.trim() ?? ""; + if (!token) { + throw new Error("Sign in to OpenWork Cloud in Settings to share with your team."); + } + + const cloudClient = createDenClient({ baseUrl: settings.baseUrl, token }); + let orgId = settings.activeOrgId?.trim() ?? ""; + let orgSlug = settings.activeOrgSlug?.trim() ?? ""; + let orgName = settings.activeOrgName?.trim() ?? ""; + + if (!orgSlug || !orgName || !orgId) { + const response = await cloudClient.listOrgs(); + const match = orgId + ? response.orgs.find((org) => org.id === orgId) + : response.orgs.find((org) => org.slug === orgSlug) ?? response.orgs[0]; + if (!match) { + throw new Error("Choose an organization in Settings -> Cloud before sharing with your team."); + } + orgId = match.id; + orgSlug = match.slug; + orgName = match.name; + writeDenSettings({ + ...settings, + baseUrl: settings.baseUrl, + authToken: token, + activeOrgId: orgId, + activeOrgSlug: orgSlug, + activeOrgName: orgName, + }); + } + + const created = await cloudClient.createOrgSkill(orgId, { + skillText: input.skillText, + shared: "org", + }); + + const hubId = input.skillHubId?.trim() ?? ""; + if (hubId) { + await cloudClient.addOrgSkillToHub(orgId, hubId, created.id); + } + + return { skillId: created.id, orgId, orgName }; +} diff --git a/apps/app/src/app/components/select-menu.tsx b/apps/app/src/app/components/select-menu.tsx new file mode 100644 index 000000000..7e9e45ed8 --- /dev/null +++ b/apps/app/src/app/components/select-menu.tsx @@ -0,0 +1,116 @@ +import { For, Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js"; +import { Check, ChevronDown } from "lucide-solid"; + +export type SelectMenuOption = { + value: string; + label: string; +}; + +type SelectMenuProps = { + options: SelectMenuOption[]; + value: string; + onChange: (value: string) => void; + disabled?: boolean; + placeholder?: string; + id?: string; + /** For pairing with a visible `