@tscircuit/fake-snippets 0.0.115 → 0.0.117
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/.github/workflows/update-package.yml +58 -0
- package/bun.lock +4 -2
- package/dist/bundle.js +488 -467
- package/dist/index.js +5 -1
- package/fake-snippets-api/lib/db/seed.ts +6 -1
- package/fake-snippets-api/routes/api/autocomplete/create_autocomplete.ts +16 -0
- package/package.json +2 -2
- package/src/components/CmdKMenu.tsx +3 -1
- package/src/components/GithubAvatarWithFallback.tsx +1 -1
- package/src/components/organization/OrganizationHeader.tsx +6 -3
- package/src/components/organization/OrganizationMembers.tsx +53 -81
- package/src/components/package-port/CodeEditor.tsx +8 -18
- package/src/components/package-port/CodeEditorHeader.tsx +2 -2
- package/src/components/ui/role-badge.tsx +27 -0
- package/src/hooks/use-list-org-members.ts +1 -0
- package/src/hooks/use-package-by-package-name.ts +7 -2
- package/src/hooks/use-package-stars.ts +10 -9
- package/src/lib/utils/member-role.tsx +61 -0
- package/src/pages/organization-profile.tsx +1 -2
- package/src/pages/organization-settings.tsx +63 -61
- package/src/pages/release-detail.tsx +3 -2
package/dist/index.js
CHANGED
|
@@ -593,7 +593,7 @@ var seed = (db) => {
|
|
|
593
593
|
phone: "555-123-4567"
|
|
594
594
|
}
|
|
595
595
|
});
|
|
596
|
-
db.addAccount({
|
|
596
|
+
const seveibarAcc = db.addAccount({
|
|
597
597
|
github_username: "seveibar"
|
|
598
598
|
});
|
|
599
599
|
if (process.env.AUTOLOAD_PACKAGES === "true") {
|
|
@@ -2370,6 +2370,10 @@ exports.TestComponent = TestComponent;
|
|
|
2370
2370
|
github_handle: "tscircuit",
|
|
2371
2371
|
is_personal_org: true
|
|
2372
2372
|
});
|
|
2373
|
+
db.addOrganizationAccount({
|
|
2374
|
+
org_id: testOrg.org_id,
|
|
2375
|
+
account_id: seveibarAcc.account_id
|
|
2376
|
+
});
|
|
2373
2377
|
};
|
|
2374
2378
|
|
|
2375
2379
|
// fake-snippets-api/lib/package_file/generate-fs-sha.ts
|
|
@@ -18,7 +18,7 @@ export const seed = (db: DbClient) => {
|
|
|
18
18
|
phone: "555-123-4567",
|
|
19
19
|
},
|
|
20
20
|
})
|
|
21
|
-
db.addAccount({
|
|
21
|
+
const seveibarAcc = db.addAccount({
|
|
22
22
|
github_username: "seveibar",
|
|
23
23
|
})
|
|
24
24
|
|
|
@@ -1835,4 +1835,9 @@ exports.TestComponent = TestComponent;
|
|
|
1835
1835
|
github_handle: "tscircuit",
|
|
1836
1836
|
is_personal_org: true,
|
|
1837
1837
|
})
|
|
1838
|
+
|
|
1839
|
+
db.addOrganizationAccount({
|
|
1840
|
+
org_id: testOrg.org_id,
|
|
1841
|
+
account_id: seveibarAcc.account_id,
|
|
1842
|
+
})
|
|
1838
1843
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export default withRouteSpec({
|
|
5
|
+
methods: ["POST"],
|
|
6
|
+
auth: "session",
|
|
7
|
+
jsonBody: z.object({
|
|
8
|
+
prefix: z.string(),
|
|
9
|
+
suffix: z.string(),
|
|
10
|
+
}),
|
|
11
|
+
jsonResponse: z.object({
|
|
12
|
+
prediction: z.string(),
|
|
13
|
+
}),
|
|
14
|
+
})(async (req, ctx) => {
|
|
15
|
+
return ctx.json({ prediction: "{/* mock autocomplete prediction */}" })
|
|
16
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.117",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"@tscircuit/3d-viewer": "^0.0.407",
|
|
82
82
|
"@tscircuit/assembly-viewer": "^0.0.5",
|
|
83
83
|
"@tscircuit/create-snippet-url": "^0.0.8",
|
|
84
|
-
"@tscircuit/eval": "^0.0.
|
|
84
|
+
"@tscircuit/eval": "^0.0.406",
|
|
85
85
|
"@tscircuit/layout": "^0.0.29",
|
|
86
86
|
"@tscircuit/mm": "^0.0.8",
|
|
87
87
|
"@tscircuit/pcb-viewer": "^1.11.218",
|
|
@@ -208,7 +208,7 @@ const CmdKMenu = () => {
|
|
|
208
208
|
}, [allAccounts, searchQuery])
|
|
209
209
|
|
|
210
210
|
const { data: recentPackages = [] } = useQuery<Package[]>(
|
|
211
|
-
["
|
|
211
|
+
["cmdKMenuPackages", currentUser],
|
|
212
212
|
async () => {
|
|
213
213
|
if (!currentUser) return []
|
|
214
214
|
try {
|
|
@@ -226,6 +226,8 @@ const CmdKMenu = () => {
|
|
|
226
226
|
enabled: !!currentUser && !searchQuery,
|
|
227
227
|
retry: false,
|
|
228
228
|
refetchOnWindowFocus: false,
|
|
229
|
+
refetchOnMount: false,
|
|
230
|
+
cacheTime: 24 * 60 * 60 * 1000,
|
|
229
231
|
},
|
|
230
232
|
)
|
|
231
233
|
|
|
@@ -14,7 +14,7 @@ export const GithubAvatarWithFallback = ({
|
|
|
14
14
|
size?: number
|
|
15
15
|
}) => {
|
|
16
16
|
return (
|
|
17
|
-
<Avatar className={
|
|
17
|
+
<Avatar className={className}>
|
|
18
18
|
<AvatarImage
|
|
19
19
|
src={`https://github.com/${username}.png${size ? `?size=${size}` : ""}`}
|
|
20
20
|
alt={`${username || fallback} avatar`}
|
|
@@ -4,7 +4,7 @@ import { Building2, Users, Package, Lock, Globe2, Settings } from "lucide-react"
|
|
|
4
4
|
import { cn } from "@/lib/utils"
|
|
5
5
|
import { PublicOrgSchema } from "fake-snippets-api/lib/db/schema"
|
|
6
6
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
7
|
-
import { useLocation } from "wouter"
|
|
7
|
+
import { Link, useLocation } from "wouter"
|
|
8
8
|
import { useOrganization } from "@/hooks/use-organization"
|
|
9
9
|
import { GithubAvatarWithFallback } from "../GithubAvatarWithFallback"
|
|
10
10
|
|
|
@@ -97,9 +97,12 @@ export const OrganizationHeader: React.FC<OrganizationHeaderProps> = ({
|
|
|
97
97
|
|
|
98
98
|
<div className="flex-1 min-w-0">
|
|
99
99
|
<div className="flex items-center justify-between mb-3">
|
|
100
|
-
<
|
|
100
|
+
<Link
|
|
101
|
+
href={`/${organization.name}`}
|
|
102
|
+
className="font-bold text-gray-900 text-2xl md:text-3xl truncate"
|
|
103
|
+
>
|
|
101
104
|
{organization.name}
|
|
102
|
-
</
|
|
105
|
+
</Link>
|
|
103
106
|
{canManageOrg && showActions && (
|
|
104
107
|
<Button variant="outline" onClick={handleSettingsClick}>
|
|
105
108
|
<Settings className="mr-2 h-4 w-4" />
|
|
@@ -1,48 +1,26 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import { Link } from "wouter"
|
|
3
3
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
|
4
|
-
import {
|
|
5
|
-
import { Users, Crown, Shield, User, Loader2 } from "lucide-react"
|
|
4
|
+
import { Users, Loader2 } from "lucide-react"
|
|
6
5
|
import { timeAgo } from "@/lib/utils/timeAgo"
|
|
7
6
|
import { cn } from "@/lib/utils"
|
|
8
7
|
import { useListOrgMembers } from "@/hooks/use-list-org-members"
|
|
8
|
+
import { getMemberRole } from "@/lib/utils/member-role"
|
|
9
|
+
import { RoleBadge } from "@/components/ui/role-badge"
|
|
10
|
+
import { PublicOrgSchema } from "fake-snippets-api/lib/db/schema"
|
|
9
11
|
|
|
10
12
|
interface OrganizationMembersProps {
|
|
11
|
-
|
|
13
|
+
organization: PublicOrgSchema
|
|
12
14
|
className?: string
|
|
13
15
|
}
|
|
14
|
-
type MemberRole = "owner" | "admin" | "member" //todo
|
|
15
|
-
const getRoleIcon = (role: MemberRole) => {
|
|
16
|
-
switch (role) {
|
|
17
|
-
case "owner":
|
|
18
|
-
return <Crown className="h-3 w-3" />
|
|
19
|
-
case "admin":
|
|
20
|
-
return <Shield className="h-3 w-3" />
|
|
21
|
-
case "member":
|
|
22
|
-
return <User className="h-3 w-3" />
|
|
23
|
-
default:
|
|
24
|
-
return <User className="h-3 w-3" />
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const getRoleColor = (role: MemberRole) => {
|
|
29
|
-
switch (role) {
|
|
30
|
-
case "owner":
|
|
31
|
-
return "bg-yellow-100 text-yellow-800 border-yellow-200"
|
|
32
|
-
case "admin":
|
|
33
|
-
return "bg-purple-100 text-purple-800 border-purple-200"
|
|
34
|
-
case "member":
|
|
35
|
-
return "bg-gray-100 text-gray-800 border-gray-200"
|
|
36
|
-
default:
|
|
37
|
-
return "bg-gray-100 text-gray-800 border-gray-200"
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
16
|
|
|
41
17
|
export const OrganizationMembers: React.FC<OrganizationMembersProps> = ({
|
|
42
|
-
|
|
18
|
+
organization,
|
|
43
19
|
className,
|
|
44
20
|
}) => {
|
|
45
|
-
const { data: members = [], isLoading } = useListOrgMembers({
|
|
21
|
+
const { data: members = [], isLoading } = useListOrgMembers({
|
|
22
|
+
orgId: organization.org_id,
|
|
23
|
+
})
|
|
46
24
|
|
|
47
25
|
if (isLoading) {
|
|
48
26
|
return (
|
|
@@ -78,60 +56,54 @@ export const OrganizationMembers: React.FC<OrganizationMembersProps> = ({
|
|
|
78
56
|
</div>
|
|
79
57
|
|
|
80
58
|
<div className="space-y-2 sm:space-y-3">
|
|
81
|
-
{members.map((member) =>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
{members.map((member) => {
|
|
60
|
+
const role = getMemberRole(organization, member.account_id)
|
|
61
|
+
return (
|
|
62
|
+
<Link
|
|
63
|
+
key={member.account_id || member.github_username}
|
|
64
|
+
href={`/${member.github_username}`}
|
|
65
|
+
className="block"
|
|
66
|
+
>
|
|
67
|
+
<div className="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50 transition-colors cursor-pointer">
|
|
68
|
+
<div className="flex items-center gap-3 min-w-0 flex-1">
|
|
69
|
+
<Avatar className="h-10 w-10 sm:h-12 sm:w-12 flex-shrink-0">
|
|
70
|
+
<AvatarImage
|
|
71
|
+
src={`https://github.com/${member.github_username}.png`}
|
|
72
|
+
alt={`${member.github_username} avatar`}
|
|
73
|
+
/>
|
|
74
|
+
<AvatarFallback className="text-sm font-medium">
|
|
75
|
+
{member.github_username
|
|
76
|
+
.split(" ")
|
|
77
|
+
.map((word) => word[0])
|
|
78
|
+
.join("")
|
|
79
|
+
.toUpperCase()
|
|
80
|
+
.slice(0, 2)}
|
|
81
|
+
</AvatarFallback>
|
|
82
|
+
</Avatar>
|
|
103
83
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
)}
|
|
115
|
-
>
|
|
116
|
-
{getRoleIcon("admin")}
|
|
117
|
-
{"admin"}
|
|
118
|
-
</Badge>
|
|
84
|
+
<div className="min-w-0 flex-1">
|
|
85
|
+
<div className="flex items-center gap-2 mb-1">
|
|
86
|
+
<h3 className="font-medium text-gray-900 truncate">
|
|
87
|
+
{member.github_username}
|
|
88
|
+
</h3>
|
|
89
|
+
<RoleBadge role={role} />
|
|
90
|
+
</div>
|
|
91
|
+
<p className="text-sm text-gray-500 truncate">
|
|
92
|
+
@{member.github_username}
|
|
93
|
+
</p>
|
|
119
94
|
</div>
|
|
120
|
-
<p className="text-sm text-gray-500 truncate">
|
|
121
|
-
@{member.github_username}
|
|
122
|
-
</p>
|
|
123
95
|
</div>
|
|
96
|
+
{member.joined_at && (
|
|
97
|
+
<div className="text-right flex-shrink-0 hidden sm:block">
|
|
98
|
+
<p className="text-xs text-gray-500">
|
|
99
|
+
Joined {timeAgo(new Date(member.joined_at))}
|
|
100
|
+
</p>
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
124
103
|
</div>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Joined {timeAgo(new Date(member.joined_at))}
|
|
129
|
-
</p>
|
|
130
|
-
</div>
|
|
131
|
-
)}
|
|
132
|
-
</div>
|
|
133
|
-
</Link>
|
|
134
|
-
))}
|
|
104
|
+
</Link>
|
|
105
|
+
)
|
|
106
|
+
})}
|
|
135
107
|
</div>
|
|
136
108
|
|
|
137
109
|
{members.length === 0 && (
|
|
@@ -51,6 +51,7 @@ import { isHiddenFile } from "../ViewPackagePage/utils/is-hidden-file"
|
|
|
51
51
|
import { inlineCopilot } from "codemirror-copilot"
|
|
52
52
|
import { useViewTsFilesDialog } from "@/components/dialogs/view-ts-files-dialog"
|
|
53
53
|
import { Loader2 } from "lucide-react"
|
|
54
|
+
import { useAxios } from "@/hooks/use-axios"
|
|
54
55
|
|
|
55
56
|
const defaultImports = `
|
|
56
57
|
import React from "@types/react/jsx-runtime"
|
|
@@ -111,7 +112,7 @@ export const CodeEditor = ({
|
|
|
111
112
|
const highlightTimeoutRef = useRef<number | null>(null)
|
|
112
113
|
|
|
113
114
|
const { highlighter } = useShikiHighlighter()
|
|
114
|
-
|
|
115
|
+
const axios = useAxios()
|
|
115
116
|
// Get URL search params for file_path
|
|
116
117
|
const urlParams = new URLSearchParams(window.location.search)
|
|
117
118
|
const filePathFromUrl = urlParams.get("file_path")
|
|
@@ -358,23 +359,12 @@ export const CodeEditor = ({
|
|
|
358
359
|
if (aiAutocompleteEnabled) {
|
|
359
360
|
baseExtensions.push(
|
|
360
361
|
inlineCopilot(async (prefix, suffix) => {
|
|
361
|
-
const res = await
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
},
|
|
368
|
-
body: JSON.stringify({
|
|
369
|
-
prefix,
|
|
370
|
-
suffix,
|
|
371
|
-
language: "typescript",
|
|
372
|
-
}),
|
|
373
|
-
},
|
|
374
|
-
)
|
|
375
|
-
|
|
376
|
-
const { prediction } = await res.json()
|
|
377
|
-
return prediction
|
|
362
|
+
const res = await axios.post("/autocomplete/create_autocomplete", {
|
|
363
|
+
prefix,
|
|
364
|
+
suffix,
|
|
365
|
+
language: "typescript",
|
|
366
|
+
})
|
|
367
|
+
return res.data?.prediction
|
|
378
368
|
}),
|
|
379
369
|
EditorView.theme({
|
|
380
370
|
".cm-ghostText, .cm-ghostText *": {
|
|
@@ -390,12 +390,12 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
390
390
|
onClick={() => {
|
|
391
391
|
setAiAutocompleteEnabled((prev) => !prev)
|
|
392
392
|
}}
|
|
393
|
-
className={`relative group bg-transparent ${aiAutocompleteEnabled ? "text-
|
|
393
|
+
className={`relative group bg-transparent ${aiAutocompleteEnabled ? "text-black bg-white" : "text-gray-500 group-hover:text-black"}`}
|
|
394
394
|
>
|
|
395
395
|
<Bot className="h-4 w-4" />
|
|
396
396
|
{!aiAutocompleteEnabled && (
|
|
397
397
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
398
|
-
<div className="w-5 h-0.5 group-hover:bg-
|
|
398
|
+
<div className="w-5 h-0.5 group-hover:bg-black bg-gray-500 rotate-45 rounded-full" />
|
|
399
399
|
</div>
|
|
400
400
|
)}
|
|
401
401
|
</Button>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { cn } from "@/lib/utils"
|
|
2
|
+
import {
|
|
3
|
+
type MemberRole,
|
|
4
|
+
getRoleIcon,
|
|
5
|
+
getRoleColor,
|
|
6
|
+
getRoleName,
|
|
7
|
+
} from "@/lib/utils/member-role"
|
|
8
|
+
|
|
9
|
+
interface RoleBadgeProps {
|
|
10
|
+
role: MemberRole
|
|
11
|
+
className?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const RoleBadge = ({ role, className }: RoleBadgeProps) => {
|
|
15
|
+
return (
|
|
16
|
+
<div
|
|
17
|
+
className={cn(
|
|
18
|
+
"select-none inline-flex items-center gap-1 py-0.5 px-1.5 rounded text-xs font-medium flex-shrink-0",
|
|
19
|
+
getRoleColor(role),
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
>
|
|
23
|
+
{getRoleIcon(role)}
|
|
24
|
+
<span className="leading-none">{getRoleName(role)}</span>
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { useQuery } from "react-query"
|
|
1
|
+
import { useQuery, UseQueryOptions } from "react-query"
|
|
2
2
|
import { useAxios } from "@/hooks/use-axios"
|
|
3
3
|
import type { Package } from "fake-snippets-api/lib/db/schema"
|
|
4
4
|
|
|
5
|
-
export const usePackageByName = (
|
|
5
|
+
export const usePackageByName = (
|
|
6
|
+
packageName: string | null,
|
|
7
|
+
options?: UseQueryOptions<Package, Error & { status: number }>,
|
|
8
|
+
) => {
|
|
6
9
|
const axios = useAxios()
|
|
7
10
|
return useQuery<Package, Error & { status: number }>(
|
|
8
11
|
["package", packageName],
|
|
@@ -19,6 +22,8 @@ export const usePackageByName = (packageName: string | null) => {
|
|
|
19
22
|
retry: false,
|
|
20
23
|
enabled: Boolean(packageName),
|
|
21
24
|
refetchOnWindowFocus: false,
|
|
25
|
+
staleTime: 5 * 60 * 1000,
|
|
26
|
+
...options,
|
|
22
27
|
},
|
|
23
28
|
)
|
|
24
29
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useMutation, useQuery, useQueryClient } from "react-query"
|
|
2
2
|
import { useAxios } from "./use-axios"
|
|
3
|
+
import { usePackageByName } from "./use-package-by-package-name"
|
|
4
|
+
import { usePackageById } from "./use-package-by-package-id"
|
|
3
5
|
|
|
4
6
|
type PackageStarQuery = { package_id: string } | { name: string }
|
|
5
7
|
|
|
@@ -9,7 +11,11 @@ interface PackageStarResponse {
|
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export const usePackageStars = (query: PackageStarQuery | null) => {
|
|
12
|
-
const
|
|
14
|
+
const packageName = query && "name" in query ? query.name : null
|
|
15
|
+
const packageId = query && "package_id" in query ? query.package_id : null
|
|
16
|
+
const packageQuery = packageName
|
|
17
|
+
? usePackageByName(packageName)
|
|
18
|
+
: usePackageById(packageId)
|
|
13
19
|
|
|
14
20
|
return useQuery<PackageStarResponse, Error & { status: number }>(
|
|
15
21
|
["packageStars", query],
|
|
@@ -17,19 +23,14 @@ export const usePackageStars = (query: PackageStarQuery | null) => {
|
|
|
17
23
|
if (!query) {
|
|
18
24
|
throw new Error("Query is required")
|
|
19
25
|
}
|
|
20
|
-
|
|
21
|
-
const { data } = await axios.get("/packages/get", {
|
|
22
|
-
params: query,
|
|
23
|
-
})
|
|
24
|
-
|
|
25
26
|
return {
|
|
26
|
-
is_starred: data
|
|
27
|
-
star_count: data
|
|
27
|
+
is_starred: packageQuery.data?.is_starred ?? false,
|
|
28
|
+
star_count: packageQuery.data?.star_count ?? 0,
|
|
28
29
|
}
|
|
29
30
|
},
|
|
30
31
|
{
|
|
31
32
|
retry: false,
|
|
32
|
-
enabled: Boolean(query),
|
|
33
|
+
enabled: Boolean(query) && packageQuery.isSuccess,
|
|
33
34
|
},
|
|
34
35
|
)
|
|
35
36
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { PublicOrgSchema } from "fake-snippets-api/lib/db/schema"
|
|
2
|
+
import { Crown, Shield, User } from "lucide-react"
|
|
3
|
+
|
|
4
|
+
export type MemberRole = "owner" | "manager" | "member"
|
|
5
|
+
|
|
6
|
+
export const getRoleName = (role: MemberRole) => {
|
|
7
|
+
return role.charAt(0).toUpperCase() + role.slice(1)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const getMemberRole = (
|
|
11
|
+
organization: PublicOrgSchema,
|
|
12
|
+
accountId: string,
|
|
13
|
+
): MemberRole => {
|
|
14
|
+
const isOwner =
|
|
15
|
+
String(accountId).trim() === String(organization.owner_account_id).trim()
|
|
16
|
+
const isManager = Object.values(organization.user_permissions ?? {}).some(
|
|
17
|
+
Boolean,
|
|
18
|
+
)
|
|
19
|
+
if (isOwner) {
|
|
20
|
+
return "owner"
|
|
21
|
+
}
|
|
22
|
+
if (isManager) {
|
|
23
|
+
return "manager"
|
|
24
|
+
}
|
|
25
|
+
return "member"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const getRoleIcon = (role: MemberRole) => {
|
|
29
|
+
switch (role) {
|
|
30
|
+
case "owner":
|
|
31
|
+
return <Crown className="size-3" />
|
|
32
|
+
case "manager":
|
|
33
|
+
return <Shield className="size-3" />
|
|
34
|
+
case "member":
|
|
35
|
+
return <User className="size-3" />
|
|
36
|
+
default:
|
|
37
|
+
return <User className="size-3" />
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const getRoleColor = (role: MemberRole) => {
|
|
42
|
+
switch (role) {
|
|
43
|
+
case "owner":
|
|
44
|
+
return "bg-amber-100 text-amber-800 border-amber-200"
|
|
45
|
+
case "manager":
|
|
46
|
+
return "bg-blue-50 text-blue-700 border border-blue-200"
|
|
47
|
+
default:
|
|
48
|
+
return "bg-gray-100 text-gray-800 border-gray-200"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const getRoleDescription = (role: MemberRole) => {
|
|
53
|
+
switch (role) {
|
|
54
|
+
case "owner":
|
|
55
|
+
return "Full access to organization settings"
|
|
56
|
+
case "manager":
|
|
57
|
+
return "Limited administrative privileges"
|
|
58
|
+
case "member":
|
|
59
|
+
return "Standard member access"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
SelectTrigger,
|
|
15
15
|
SelectValue,
|
|
16
16
|
} from "@/components/ui/select"
|
|
17
|
-
import { useListOrgMembers } from "@/hooks/use-list-org-members"
|
|
18
17
|
import { useOrgByGithubHandle } from "@/hooks/use-org-by-github-handle"
|
|
19
18
|
import { PackageCardSkeleton } from "@/components/PackageCardSkeleton"
|
|
20
19
|
import { useApiBaseUrl } from "@/hooks/use-packages-base-api-url"
|
|
@@ -175,7 +174,7 @@ export const OrganizationProfilePageContent = ({
|
|
|
175
174
|
|
|
176
175
|
{activeTab === "members" && (
|
|
177
176
|
<div>
|
|
178
|
-
<OrganizationMembers
|
|
177
|
+
<OrganizationMembers organization={org} />
|
|
179
178
|
</div>
|
|
180
179
|
)}
|
|
181
180
|
</div>
|