@tscircuit/fake-snippets 0.0.113 → 0.0.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun-tests/fake-snippets-api/routes/packages/create.test.ts +23 -10
- package/dist/bundle.js +27 -10
- package/fake-snippets-api/routes/api/packages/create.ts +18 -9
- package/fake-snippets-api/routes/api/packages/list.ts +11 -3
- package/package.json +1 -1
- package/src/components/CmdKMenu.tsx +1 -0
- package/src/components/dialogs/new-package-save-prompt-dialog.tsx +20 -11
- package/src/components/package-port/CodeEditorHeader.tsx +1 -1
- package/src/hooks/useFileManagement.ts +11 -9
|
@@ -18,35 +18,44 @@ export default withRouteSpec({
|
|
|
18
18
|
description: z.string().optional(),
|
|
19
19
|
is_private: z.boolean().optional().default(false),
|
|
20
20
|
is_unlisted: z.boolean().optional().default(false),
|
|
21
|
+
org_id: z.string().optional(),
|
|
21
22
|
}),
|
|
22
23
|
jsonResponse: z.object({
|
|
23
24
|
package: packageSchema.optional(),
|
|
24
25
|
}),
|
|
25
26
|
})(async (req, ctx) => {
|
|
26
|
-
const { name, description, is_private, is_unlisted } = req.jsonBody
|
|
27
|
-
|
|
27
|
+
const { name, description, is_private, is_unlisted, org_id } = req.jsonBody
|
|
28
28
|
let owner_segment = name?.split("/")[0]
|
|
29
29
|
let unscoped_name = name?.split("/")[1]
|
|
30
30
|
|
|
31
31
|
if (name && !unscoped_name) {
|
|
32
|
-
|
|
32
|
+
return ctx.error(400, {
|
|
33
33
|
error_code: "invalid_package_name",
|
|
34
34
|
message:
|
|
35
35
|
"Package name must include an author segment (e.g. author/package_name)",
|
|
36
36
|
})
|
|
37
37
|
}
|
|
38
|
+
const org = ctx.db.getOrg({ org_id })
|
|
39
|
+
if (Boolean(org_id) && !Boolean(org))
|
|
40
|
+
return ctx.error(404, {
|
|
41
|
+
error_code: "org_not_found",
|
|
42
|
+
message: "Organization not found",
|
|
43
|
+
})
|
|
38
44
|
|
|
39
45
|
if (!unscoped_name) {
|
|
40
46
|
const state = ctx.db.getState()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
|
|
48
|
+
const count = org_id
|
|
49
|
+
? state.packages.filter((pkg) => pkg.owner_org_id === org_id).length
|
|
50
|
+
: state.packages.filter(
|
|
51
|
+
(pkg) => pkg.creator_account_id === ctx.auth.account_id,
|
|
52
|
+
).length
|
|
44
53
|
|
|
45
54
|
unscoped_name = `untitled-package-${count}`
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
if (!owner_segment) {
|
|
49
|
-
owner_segment = ctx.auth.github_username
|
|
58
|
+
owner_segment = org_id ? org!.org_name : ctx.auth.github_username
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
const final_name = name ?? `${owner_segment}/${unscoped_name}`
|
|
@@ -71,7 +80,7 @@ export default withRouteSpec({
|
|
|
71
80
|
)
|
|
72
81
|
|
|
73
82
|
if (!memberOrg) {
|
|
74
|
-
|
|
83
|
+
return ctx.error(403, {
|
|
75
84
|
error_code: "forbidden",
|
|
76
85
|
message:
|
|
77
86
|
"You must be a member of the organization to create a package under it",
|
|
@@ -87,7 +96,7 @@ export default withRouteSpec({
|
|
|
87
96
|
.packages.find((pkg) => pkg.name === final_name)
|
|
88
97
|
|
|
89
98
|
if (existingPackage) {
|
|
90
|
-
|
|
99
|
+
return ctx.error(400, {
|
|
91
100
|
error_code: "package_already_exists",
|
|
92
101
|
message: "A package with this name already exists",
|
|
93
102
|
})
|
|
@@ -10,6 +10,7 @@ export default withRouteSpec({
|
|
|
10
10
|
owner_github_username: z.string().optional(),
|
|
11
11
|
is_writable: z.boolean().optional(),
|
|
12
12
|
name: z.string().optional(),
|
|
13
|
+
limit: z.number().int().min(1).optional(),
|
|
13
14
|
}),
|
|
14
15
|
jsonResponse: z.object({
|
|
15
16
|
ok: z.boolean(),
|
|
@@ -25,8 +26,13 @@ export default withRouteSpec({
|
|
|
25
26
|
),
|
|
26
27
|
}),
|
|
27
28
|
})(async (req, ctx) => {
|
|
28
|
-
const {
|
|
29
|
-
|
|
29
|
+
const {
|
|
30
|
+
creator_account_id,
|
|
31
|
+
owner_github_username,
|
|
32
|
+
name,
|
|
33
|
+
is_writable,
|
|
34
|
+
limit,
|
|
35
|
+
} = req.commonParams
|
|
30
36
|
|
|
31
37
|
const auth = "auth" in ctx && ctx.auth ? ctx.auth : null
|
|
32
38
|
|
|
@@ -64,7 +70,9 @@ export default withRouteSpec({
|
|
|
64
70
|
if (name) {
|
|
65
71
|
packages = packages.filter((p) => p.name === name)
|
|
66
72
|
}
|
|
67
|
-
|
|
73
|
+
if (limit) {
|
|
74
|
+
packages = packages.slice(0, limit)
|
|
75
|
+
}
|
|
68
76
|
if (is_writable && auth) {
|
|
69
77
|
packages = packages.filter(canManagePackage)
|
|
70
78
|
}
|
package/package.json
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { createUseDialog } from "./create-use-dialog"
|
|
20
20
|
import { useListUserOrgs } from "@/hooks/use-list-user-orgs"
|
|
21
21
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
22
|
+
import { ICreatePackageProps } from "@/hooks/useFileManagement"
|
|
22
23
|
|
|
23
24
|
export const NewPackageSavePromptDialog = ({
|
|
24
25
|
open,
|
|
@@ -31,27 +32,31 @@ export const NewPackageSavePromptDialog = ({
|
|
|
31
32
|
onOpenChange: (open: boolean) => void
|
|
32
33
|
initialIsPrivate?: boolean
|
|
33
34
|
initialName?: string
|
|
34
|
-
onSave: (
|
|
35
|
-
name,
|
|
36
|
-
isPrivate,
|
|
37
|
-
orgId,
|
|
38
|
-
}: {
|
|
39
|
-
name?: string
|
|
40
|
-
isPrivate: boolean
|
|
41
|
-
orgId: string
|
|
42
|
-
}) => void
|
|
35
|
+
onSave: (props: ICreatePackageProps) => void
|
|
43
36
|
}) => {
|
|
44
37
|
const [packageName, setPackageName] = useState(initialName)
|
|
45
38
|
const session = useGlobalStore((s) => s.session)
|
|
46
39
|
const [isPrivate, setIsPrivate] = useState(initialIsPrivate)
|
|
47
40
|
const [selectedOrgId, setSelectedOrgId] = useState<string>("")
|
|
48
41
|
const { data: organizations, isLoading: orgsLoading } = useListUserOrgs()
|
|
42
|
+
|
|
43
|
+
const isOwnerPersonalOrg = useMemo(() => {
|
|
44
|
+
if (!selectedOrgId) return false
|
|
45
|
+
const selectedOrg = organizations?.find((x) => x.org_id === selectedOrgId)
|
|
46
|
+
return (
|
|
47
|
+
selectedOrg?.is_personal_org &&
|
|
48
|
+
selectedOrg?.owner_account_id == session?.account_id
|
|
49
|
+
)
|
|
50
|
+
}, [selectedOrgId, organizations, session?.github_username])
|
|
51
|
+
|
|
49
52
|
const fullPackageName = useMemo(() => {
|
|
53
|
+
if (!Boolean(packageName)) return
|
|
50
54
|
if (selectedOrgId) {
|
|
51
55
|
return `${organizations?.find((x) => x.org_id === selectedOrgId)?.name}/${packageName}`
|
|
52
56
|
}
|
|
53
57
|
return `${session?.github_username}/${packageName}`
|
|
54
58
|
}, [selectedOrgId, packageName, organizations, session?.github_username])
|
|
59
|
+
|
|
55
60
|
useEffect(() => {
|
|
56
61
|
if (organizations && organizations.length > 0 && !selectedOrgId) {
|
|
57
62
|
setSelectedOrgId(
|
|
@@ -169,9 +174,13 @@ export const NewPackageSavePromptDialog = ({
|
|
|
169
174
|
<Button
|
|
170
175
|
onClick={() => {
|
|
171
176
|
onSave({
|
|
172
|
-
name: fullPackageName
|
|
177
|
+
name: fullPackageName,
|
|
173
178
|
isPrivate,
|
|
174
|
-
|
|
179
|
+
...(isOwnerPersonalOrg
|
|
180
|
+
? {}
|
|
181
|
+
: {
|
|
182
|
+
org_id: selectedOrgId,
|
|
183
|
+
}),
|
|
175
184
|
})
|
|
176
185
|
onOpenChange(false)
|
|
177
186
|
}}
|
|
@@ -274,7 +274,7 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
274
274
|
|
|
275
275
|
return (
|
|
276
276
|
<>
|
|
277
|
-
<div className="flex items-center gap-2 px-2 border-b border-gray-200">
|
|
277
|
+
<div className="flex items-center gap-2 px-2 border-b md:py-2 border-gray-200">
|
|
278
278
|
<button
|
|
279
279
|
className={`text-gray-400 scale-90 p-0 transition-[width,opacity] duration-300 ease-in-out overflow-hidden ${
|
|
280
280
|
sidebarOpen
|
|
@@ -45,6 +45,12 @@ export interface IRenameFileResult {
|
|
|
45
45
|
fileRenamed: boolean
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
export interface ICreatePackageProps {
|
|
49
|
+
isPrivate?: boolean
|
|
50
|
+
name?: string
|
|
51
|
+
org_id?: string
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
export function useFileManagement({
|
|
49
55
|
templateCode,
|
|
50
56
|
currentPackage,
|
|
@@ -428,12 +434,8 @@ export function useFileManagement({
|
|
|
428
434
|
const savePackage = async ({
|
|
429
435
|
name,
|
|
430
436
|
isPrivate,
|
|
431
|
-
|
|
432
|
-
}: {
|
|
433
|
-
name?: string
|
|
434
|
-
isPrivate: boolean
|
|
435
|
-
orgId: string
|
|
436
|
-
}) => {
|
|
437
|
+
org_id,
|
|
438
|
+
}: ICreatePackageProps) => {
|
|
437
439
|
if (!isLoggedIn) {
|
|
438
440
|
toast({
|
|
439
441
|
title: "Not Logged In",
|
|
@@ -443,9 +445,9 @@ export function useFileManagement({
|
|
|
443
445
|
}
|
|
444
446
|
|
|
445
447
|
await createPackageMutation.mutateAsync({
|
|
446
|
-
is_private: isPrivate,
|
|
447
|
-
org_id:
|
|
448
|
-
...(name ? { name } : {}),
|
|
448
|
+
is_private: Boolean(isPrivate),
|
|
449
|
+
...(org_id ? { org_id: org_id } : {}),
|
|
450
|
+
...(name ? { name: name?.trim() } : {}),
|
|
449
451
|
})
|
|
450
452
|
}
|
|
451
453
|
|