Skip to content

Commit d7c6b52

Browse files
committed
make editing skills full page
1 parent 5c3066a commit d7c6b52

11 files changed

Lines changed: 664 additions & 377 deletions

File tree

apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import { useMemo, useRef, useState } from 'react'
44
import { Chip, toast } from '@sim/emcn'
5-
import { getErrorMessage } from '@sim/utils/errors'
65
import { Check, Plus } from 'lucide-react'
76
import { usePostHog } from 'posthog-js/react'
87
import { captureEvent } from '@/lib/posthog/client'
98
import { SkillTile } from '@/app/workspace/[workspaceId]/components'
9+
import { isSkillNameConflictError } from '@/app/workspace/[workspaceId]/skills/components/utils'
1010
import type { SuggestedSkill } from '@/blocks/types'
1111
import { useCreateSkill, useSkills } from '@/hooks/queries/skills'
1212

@@ -81,7 +81,7 @@ export function IntegrationSkillsSection({
8181
} catch (error) {
8282
// A name conflict means someone already added this skill but restricted
8383
// it — retrying can never succeed, so say what to actually do.
84-
if (getErrorMessage(error, '').includes('is unavailable')) {
84+
if (isSkillNameConflictError(error)) {
8585
toast.error(
8686
`"${skill.name}" already exists in this workspace but isn't shared with you — ask a skill admin for access`
8787
)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use client'
2+
3+
import { Chip } from '@sim/emcn'
4+
import { MemberRow } from '@/components/permissions'
5+
import { DetailSection } from '@/app/workspace/[workspaceId]/components/credential-detail'
6+
import {
7+
type SkillMembersController,
8+
skillMemberLockReason,
9+
} from '@/app/workspace/[workspaceId]/skills/components/skill-members'
10+
11+
interface SkillMembersCardProps {
12+
members: SkillMembersController
13+
/** Whether the viewer is a skill admin (explicit or derived workspace admin). */
14+
isAdmin: boolean
15+
workspaceShared: boolean
16+
}
17+
18+
/**
19+
* Page-styled member roster for the skill detail page: active members with
20+
* role/remove controls, and — for admins — removed (denied) members with a
21+
* restore action. Adding people happens through the header Share action.
22+
*/
23+
export function SkillMembersCard({ members, isAdmin, workspaceShared }: SkillMembersCardProps) {
24+
return (
25+
<>
26+
<DetailSection title={`Members (${members.activeMembers.length})`}>
27+
{members.membersError ? (
28+
<span className='text-[12px] text-[var(--text-muted)]'>
29+
Couldn't load members. You may no longer have access to this skill.
30+
</span>
31+
) : members.membersLoading ? null : (
32+
<div className='flex flex-col gap-2'>
33+
{members.activeMembers.map((member) => {
34+
const lockReason = skillMemberLockReason(member, {
35+
workspaceShared,
36+
explicitAdminCount: members.explicitAdminCount,
37+
})
38+
return (
39+
<MemberRow
40+
key={member.id}
41+
member={member}
42+
lockReason={lockReason}
43+
canManage={isAdmin}
44+
roleDisabled={!isAdmin || lockReason !== null}
45+
removeDisabled={lockReason !== null}
46+
onRoleChange={(role) => members.changeMemberRole(member.userId, role)}
47+
onRemove={() => members.removeMember(member.userId)}
48+
/>
49+
)
50+
})}
51+
</div>
52+
)}
53+
</DetailSection>
54+
55+
{isAdmin && members.removedMembers.length > 0 && (
56+
<DetailSection title={`Removed (${members.removedMembers.length})`}>
57+
<div className='flex flex-col gap-2'>
58+
{members.removedMembers.map((member) => (
59+
<div key={member.id} className='flex items-center justify-between gap-2'>
60+
<span className='min-w-0 truncate text-[14px] text-[var(--text-muted)]'>
61+
{member.userName || member.userEmail || member.userId}
62+
</span>
63+
<Chip onClick={() => members.restoreMember(member.userId)} flush>
64+
Restore
65+
</Chip>
66+
</div>
67+
))}
68+
</div>
69+
</DetailSection>
70+
)}
71+
</>
72+
)
73+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { Metadata } from 'next'
2+
import { SkillDetail } from '@/app/workspace/[workspaceId]/skills/[skillId]/skill-detail'
3+
4+
export const metadata: Metadata = {
5+
title: 'Skill',
6+
}
7+
8+
export default async function SkillDetailPage({
9+
params,
10+
}: {
11+
params: Promise<{ workspaceId: string; skillId: string }>
12+
}) {
13+
const { workspaceId, skillId } = await params
14+
return <SkillDetail workspaceId={workspaceId} skillId={skillId} />
15+
}

0 commit comments

Comments
 (0)