@iblai/mcp 1.0.0
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/README.md +199 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +130 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/data-layer.d.ts +8 -0
- package/dist/resources/data-layer.d.ts.map +1 -0
- package/dist/resources/data-layer.js +181 -0
- package/dist/resources/data-layer.js.map +1 -0
- package/dist/resources/guides-layout.d.ts +8 -0
- package/dist/resources/guides-layout.d.ts.map +1 -0
- package/dist/resources/guides-layout.js +235 -0
- package/dist/resources/guides-layout.js.map +1 -0
- package/dist/resources/guides-rbac.d.ts +8 -0
- package/dist/resources/guides-rbac.d.ts.map +1 -0
- package/dist/resources/guides-rbac.js +231 -0
- package/dist/resources/guides-rbac.js.map +1 -0
- package/dist/resources/guides-theme.d.ts +8 -0
- package/dist/resources/guides-theme.d.ts.map +1 -0
- package/dist/resources/guides-theme.js +183 -0
- package/dist/resources/guides-theme.js.map +1 -0
- package/dist/resources/index.d.ts +17 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +18 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/packages-overview.d.ts +8 -0
- package/dist/resources/packages-overview.d.ts.map +1 -0
- package/dist/resources/packages-overview.js +53 -0
- package/dist/resources/packages-overview.js.map +1 -0
- package/dist/resources/web-containers.d.ts +8 -0
- package/dist/resources/web-containers.d.ts.map +1 -0
- package/dist/resources/web-containers.js +122 -0
- package/dist/resources/web-containers.js.map +1 -0
- package/dist/resources/web-utils.d.ts +8 -0
- package/dist/resources/web-utils.d.ts.map +1 -0
- package/dist/resources/web-utils.js +210 -0
- package/dist/resources/web-utils.js.map +1 -0
- package/dist/tools/api-query-info.d.ts +16 -0
- package/dist/tools/api-query-info.d.ts.map +1 -0
- package/dist/tools/api-query-info.js +2398 -0
- package/dist/tools/api-query-info.js.map +1 -0
- package/dist/tools/component-info.d.ts +16 -0
- package/dist/tools/component-info.d.ts.map +1 -0
- package/dist/tools/component-info.js +1323 -0
- package/dist/tools/component-info.js.map +1 -0
- package/dist/tools/hook-info.d.ts +16 -0
- package/dist/tools/hook-info.d.ts.map +1 -0
- package/dist/tools/hook-info.js +1988 -0
- package/dist/tools/hook-info.js.map +1 -0
- package/dist/tools/index.d.ts +68 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +14 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/page-template.d.ts +28 -0
- package/dist/tools/page-template.d.ts.map +1 -0
- package/dist/tools/page-template.js +198 -0
- package/dist/tools/page-template.js.map +1 -0
- package/dist/tools/provider-setup.d.ts +24 -0
- package/dist/tools/provider-setup.d.ts.map +1 -0
- package/dist/tools/provider-setup.js +213 -0
- package/dist/tools/provider-setup.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
export const guidesLayout = {
|
|
2
|
+
uri: 'ibl://guides/layout',
|
|
3
|
+
name: 'Layout Rules and Patterns',
|
|
4
|
+
description: 'How to structure layouts for IBL apps',
|
|
5
|
+
mimeType: 'text/markdown',
|
|
6
|
+
content: `# IBL Layout Rules and Patterns
|
|
7
|
+
|
|
8
|
+
## Root Layout Structure
|
|
9
|
+
|
|
10
|
+
Every IBL app follows this root layout pattern:
|
|
11
|
+
|
|
12
|
+
\`\`\`typescript
|
|
13
|
+
// app/layout.tsx
|
|
14
|
+
import { StoreProvider } from '@/providers/store-provider';
|
|
15
|
+
import { Providers } from '@/providers';
|
|
16
|
+
import { ClientLayout } from '@/components/client-layout';
|
|
17
|
+
|
|
18
|
+
export default function RootLayout({ children }) {
|
|
19
|
+
return (
|
|
20
|
+
<html lang="en" suppressHydrationWarning>
|
|
21
|
+
<head>
|
|
22
|
+
<script src="/env.js" />
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<StoreProvider>
|
|
26
|
+
<Providers>
|
|
27
|
+
<ClientLayout>
|
|
28
|
+
{children}
|
|
29
|
+
</ClientLayout>
|
|
30
|
+
</Providers>
|
|
31
|
+
</StoreProvider>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
\`\`\`
|
|
37
|
+
|
|
38
|
+
## StoreProvider Pattern
|
|
39
|
+
|
|
40
|
+
\`\`\`typescript
|
|
41
|
+
// providers/store-provider.tsx
|
|
42
|
+
'use client';
|
|
43
|
+
|
|
44
|
+
import { useRef } from 'react';
|
|
45
|
+
import { Provider } from 'react-redux';
|
|
46
|
+
import { makeStore, AppStore } from '@/lib/store';
|
|
47
|
+
|
|
48
|
+
export function StoreProvider({ children }) {
|
|
49
|
+
const storeRef = useRef<AppStore | null>(null);
|
|
50
|
+
|
|
51
|
+
if (!storeRef.current) {
|
|
52
|
+
storeRef.current = makeStore();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return <Provider store={storeRef.current}>{children}</Provider>;
|
|
56
|
+
}
|
|
57
|
+
\`\`\`
|
|
58
|
+
|
|
59
|
+
## Providers Component
|
|
60
|
+
|
|
61
|
+
\`\`\`typescript
|
|
62
|
+
// providers/index.tsx
|
|
63
|
+
'use client';
|
|
64
|
+
|
|
65
|
+
import { AuthProvider, TenantProvider } from '@iblai/web-utils';
|
|
66
|
+
import { getTenant, getUsername, redirectToAuthSpa } from '@/lib/utils';
|
|
67
|
+
|
|
68
|
+
export function Providers({ children }) {
|
|
69
|
+
return (
|
|
70
|
+
<AuthProvider
|
|
71
|
+
skip={shouldSkipAuth(pathname)}
|
|
72
|
+
username={getUsername()}
|
|
73
|
+
token={getToken()}
|
|
74
|
+
redirectToAuthSpa={redirectToAuthSpa}
|
|
75
|
+
hasNonExpiredAuthToken={hasNonExpiredAuthToken}
|
|
76
|
+
>
|
|
77
|
+
<TenantProvider
|
|
78
|
+
currentTenant={getTenant()}
|
|
79
|
+
requestedTenant={getRequestedTenant()}
|
|
80
|
+
handleTenantSwitch={handleTenantSwitch}
|
|
81
|
+
onLoadPlatformPermissions={handlePermissions}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</TenantProvider>
|
|
85
|
+
</AuthProvider>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
## ClientLayout for Theming
|
|
91
|
+
|
|
92
|
+
\`\`\`typescript
|
|
93
|
+
// components/client-layout.tsx
|
|
94
|
+
'use client';
|
|
95
|
+
|
|
96
|
+
import { ThemeProvider } from 'next-themes';
|
|
97
|
+
import { Toaster } from '@iblai/web-containers';
|
|
98
|
+
|
|
99
|
+
export function ClientLayout({ children }) {
|
|
100
|
+
return (
|
|
101
|
+
<ThemeProvider attribute="class" defaultTheme="light">
|
|
102
|
+
{children}
|
|
103
|
+
<Toaster />
|
|
104
|
+
</ThemeProvider>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
\`\`\`
|
|
108
|
+
|
|
109
|
+
## Page Layout Components
|
|
110
|
+
|
|
111
|
+
### AppLayout (with Navigation)
|
|
112
|
+
|
|
113
|
+
\`\`\`typescript
|
|
114
|
+
// app/_components/app-layout.tsx
|
|
115
|
+
'use client';
|
|
116
|
+
|
|
117
|
+
import { NavBar } from '@/components/nav-bar';
|
|
118
|
+
import { Footer } from '@/components/footer';
|
|
119
|
+
|
|
120
|
+
const NON_AUTH_PAGES = ['/sso-login', '/version', '/error'];
|
|
121
|
+
|
|
122
|
+
export function AppLayout({ children }) {
|
|
123
|
+
const pathname = usePathname();
|
|
124
|
+
|
|
125
|
+
if (NON_AUTH_PAGES.some(p => pathname.startsWith(p))) {
|
|
126
|
+
return <>{children}</>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div className="flex min-h-screen flex-col">
|
|
131
|
+
<NavBar />
|
|
132
|
+
<main className="flex-1">{children}</main>
|
|
133
|
+
<Footer />
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
\`\`\`
|
|
138
|
+
|
|
139
|
+
### For Mentor App with Sidebar
|
|
140
|
+
|
|
141
|
+
\`\`\`typescript
|
|
142
|
+
import { SidebarProvider, SidebarInset } from '@iblai/web-containers';
|
|
143
|
+
|
|
144
|
+
<SidebarProvider>
|
|
145
|
+
<AppSidebar />
|
|
146
|
+
<SidebarInset>
|
|
147
|
+
<NavBar />
|
|
148
|
+
<main>{children}</main>
|
|
149
|
+
</SidebarInset>
|
|
150
|
+
</SidebarProvider>
|
|
151
|
+
\`\`\`
|
|
152
|
+
|
|
153
|
+
## Page Structure
|
|
154
|
+
|
|
155
|
+
\`\`\`typescript
|
|
156
|
+
// app/dashboard/page.tsx
|
|
157
|
+
import { AppLayout } from '@/app/_components/app-layout';
|
|
158
|
+
|
|
159
|
+
export default function DashboardPage() {
|
|
160
|
+
return (
|
|
161
|
+
<AppLayout>
|
|
162
|
+
<div className="container mx-auto px-4 py-8">
|
|
163
|
+
<h1 className="text-2xl font-bold">Dashboard</h1>
|
|
164
|
+
{/* Page content */}
|
|
165
|
+
</div>
|
|
166
|
+
</AppLayout>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
## Dynamic Routes
|
|
172
|
+
|
|
173
|
+
\`\`\`typescript
|
|
174
|
+
// app/platform/[tenantKey]/[mentorId]/page.tsx
|
|
175
|
+
interface PageProps {
|
|
176
|
+
params: Promise<{
|
|
177
|
+
tenantKey: string;
|
|
178
|
+
mentorId: string;
|
|
179
|
+
}>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export default async function MentorPage({ params }: PageProps) {
|
|
183
|
+
const { tenantKey, mentorId } = await params;
|
|
184
|
+
|
|
185
|
+
return <MentorChat tenantKey={tenantKey} mentorId={mentorId} />;
|
|
186
|
+
}
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
## Route Groups
|
|
190
|
+
|
|
191
|
+
Use route groups for organization without affecting URL:
|
|
192
|
+
|
|
193
|
+
\`\`\`
|
|
194
|
+
app/
|
|
195
|
+
├── (authenticated)/
|
|
196
|
+
│ ├── layout.tsx # Auth required layout
|
|
197
|
+
│ ├── dashboard/
|
|
198
|
+
│ └── settings/
|
|
199
|
+
├── (public)/
|
|
200
|
+
│ ├── layout.tsx # No auth required
|
|
201
|
+
│ └── about/
|
|
202
|
+
└── layout.tsx # Root layout
|
|
203
|
+
\`\`\`
|
|
204
|
+
|
|
205
|
+
## Loading States
|
|
206
|
+
|
|
207
|
+
\`\`\`typescript
|
|
208
|
+
// app/dashboard/loading.tsx
|
|
209
|
+
import { Skeleton } from '@iblai/web-containers';
|
|
210
|
+
|
|
211
|
+
export default function Loading() {
|
|
212
|
+
return (
|
|
213
|
+
<div className="container mx-auto px-4 py-8">
|
|
214
|
+
<Skeleton className="h-8 w-48 mb-4" />
|
|
215
|
+
<Skeleton className="h-64 w-full" />
|
|
216
|
+
</div>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
## Error Boundaries
|
|
222
|
+
|
|
223
|
+
\`\`\`typescript
|
|
224
|
+
// app/error.tsx
|
|
225
|
+
'use client';
|
|
226
|
+
|
|
227
|
+
import { ClientErrorPage } from '@iblai/web-containers/next';
|
|
228
|
+
|
|
229
|
+
export default function Error({ error, reset }) {
|
|
230
|
+
return <ClientErrorPage error={error} reset={reset} />;
|
|
231
|
+
}
|
|
232
|
+
\`\`\`
|
|
233
|
+
`,
|
|
234
|
+
};
|
|
235
|
+
//# sourceMappingURL=guides-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides-layout.js","sourceRoot":"","sources":["../../src/resources/guides-layout.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,GAAG,EAAE,qBAAqB;IAC1B,IAAI,EAAE,2BAA2B;IACjC,WAAW,EAAE,uCAAuC;IACpD,QAAQ,EAAE,eAAe;IACzB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmOV;CACA,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides-rbac.d.ts","sourceRoot":"","sources":["../../src/resources/guides-rbac.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;CAqOtB,CAAC"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
export const guidesRbac = {
|
|
2
|
+
uri: 'ibl://guides/rbac',
|
|
3
|
+
name: 'RBAC Patterns',
|
|
4
|
+
description: 'Role-Based Access Control patterns',
|
|
5
|
+
mimeType: 'text/markdown',
|
|
6
|
+
content: `# RBAC (Role-Based Access Control) Patterns
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
IBL uses a resource-based RBAC system where permissions are associated with specific resources.
|
|
11
|
+
|
|
12
|
+
## Permission Resource Format
|
|
13
|
+
|
|
14
|
+
\`\`\`
|
|
15
|
+
/platforms/{tenantKey}/#permission_name
|
|
16
|
+
/mentors/{mentorId}/#permission_name
|
|
17
|
+
\`\`\`
|
|
18
|
+
|
|
19
|
+
## Redux RBAC Slice
|
|
20
|
+
|
|
21
|
+
\`\`\`typescript
|
|
22
|
+
// features/rbac/rbac-slice.ts
|
|
23
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
24
|
+
|
|
25
|
+
export interface RbacPermissions {
|
|
26
|
+
mentors?: Record<string, unknown>;
|
|
27
|
+
mentor?: Record<string, unknown>;
|
|
28
|
+
skills?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface RbacState {
|
|
32
|
+
rbacPermissions: RbacPermissions;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const initialState: RbacState = {
|
|
36
|
+
rbacPermissions: {},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const rbacSlice = createSlice({
|
|
40
|
+
name: 'rbac',
|
|
41
|
+
initialState,
|
|
42
|
+
reducers: {
|
|
43
|
+
updateRbacPermissions: (state, action: PayloadAction<RbacPermissions>) => {
|
|
44
|
+
state.rbacPermissions = {
|
|
45
|
+
...state.rbacPermissions,
|
|
46
|
+
...action.payload,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const { updateRbacPermissions } = rbacSlice.actions;
|
|
53
|
+
export const selectRbacPermissions = (state) => state.rbac.rbacPermissions;
|
|
54
|
+
export default rbacSlice.reducer;
|
|
55
|
+
\`\`\`
|
|
56
|
+
|
|
57
|
+
## WithPermissions HOC
|
|
58
|
+
|
|
59
|
+
\`\`\`typescript
|
|
60
|
+
// hoc/withPermissions.tsx
|
|
61
|
+
import { WithPermissions as BaseWithPermissions, checkRbacPermission } from '@iblai/web-utils';
|
|
62
|
+
import { useAppSelector } from '@/lib/hooks';
|
|
63
|
+
import { selectRbacPermissions } from '@/features/rbac';
|
|
64
|
+
import { config } from '@/lib/config';
|
|
65
|
+
|
|
66
|
+
interface WithPermissionsProps {
|
|
67
|
+
rbacResource: string;
|
|
68
|
+
children: ({ hasPermission }: { hasPermission: boolean }) => React.ReactNode;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function WithPermissions({ rbacResource, children }: WithPermissionsProps) {
|
|
72
|
+
const rbacPermissions = useAppSelector(selectRbacPermissions);
|
|
73
|
+
|
|
74
|
+
// Skip RBAC if disabled in config
|
|
75
|
+
if (!config.settings.enableRBAC()) {
|
|
76
|
+
return <>{children({ hasPermission: true })}</>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<BaseWithPermissions
|
|
81
|
+
rbacResource={rbacResource}
|
|
82
|
+
rbacPermissions={rbacPermissions}
|
|
83
|
+
>
|
|
84
|
+
{children}
|
|
85
|
+
</BaseWithPermissions>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// For form field-level permissions
|
|
90
|
+
export function WithFormPermissions(props) {
|
|
91
|
+
const rbacPermissions = useAppSelector(selectRbacPermissions);
|
|
92
|
+
return (
|
|
93
|
+
<BaseWithFormPermissions
|
|
94
|
+
{...props}
|
|
95
|
+
rbacPermissions={rbacPermissions}
|
|
96
|
+
enableRBAC={config.settings.enableRBAC()}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
\`\`\`
|
|
101
|
+
|
|
102
|
+
## Usage Examples
|
|
103
|
+
|
|
104
|
+
### Conditional UI Rendering
|
|
105
|
+
|
|
106
|
+
\`\`\`typescript
|
|
107
|
+
import { WithPermissions } from '@/hoc/withPermissions';
|
|
108
|
+
|
|
109
|
+
function NavBar() {
|
|
110
|
+
return (
|
|
111
|
+
<nav>
|
|
112
|
+
<WithPermissions rbacResource={\`/platforms/\${tenantKey}/#can_view_analytics\`}>
|
|
113
|
+
{({ hasPermission }) =>
|
|
114
|
+
hasPermission && (
|
|
115
|
+
<Link href="/analytics">Analytics</Link>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
</WithPermissions>
|
|
119
|
+
|
|
120
|
+
<WithPermissions rbacResource={\`/mentors/\${mentorId}/#show_settings\`}>
|
|
121
|
+
{({ hasPermission }) =>
|
|
122
|
+
hasPermission && (
|
|
123
|
+
<Button onClick={openSettings}>Settings</Button>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
</WithPermissions>
|
|
127
|
+
</nav>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
\`\`\`
|
|
131
|
+
|
|
132
|
+
### Programmatic Permission Check
|
|
133
|
+
|
|
134
|
+
\`\`\`typescript
|
|
135
|
+
import { checkRbacPermission } from '@iblai/web-utils';
|
|
136
|
+
import { useAppSelector } from '@/lib/hooks';
|
|
137
|
+
import { selectRbacPermissions } from '@/features/rbac';
|
|
138
|
+
|
|
139
|
+
function MentorActions({ mentorId }) {
|
|
140
|
+
const rbacPermissions = useAppSelector(selectRbacPermissions);
|
|
141
|
+
|
|
142
|
+
const canEdit = checkRbacPermission(
|
|
143
|
+
rbacPermissions,
|
|
144
|
+
\`/mentors/\${mentorId}/#can_edit\`
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const canDelete = checkRbacPermission(
|
|
148
|
+
rbacPermissions,
|
|
149
|
+
\`/mentors/\${mentorId}/#can_delete\`
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<div>
|
|
154
|
+
{canEdit && <Button onClick={handleEdit}>Edit</Button>}
|
|
155
|
+
{canDelete && <Button onClick={handleDelete}>Delete</Button>}
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
\`\`\`
|
|
160
|
+
|
|
161
|
+
### Loading Permissions from Provider
|
|
162
|
+
|
|
163
|
+
\`\`\`typescript
|
|
164
|
+
// In your Providers component
|
|
165
|
+
<TenantProvider
|
|
166
|
+
onLoadPlatformPermissions={(permissions) => {
|
|
167
|
+
dispatch(updateRbacPermissions(permissions));
|
|
168
|
+
}}
|
|
169
|
+
>
|
|
170
|
+
{children}
|
|
171
|
+
</TenantProvider>
|
|
172
|
+
|
|
173
|
+
// In MentorProvider (for mentor app)
|
|
174
|
+
<MentorProvider
|
|
175
|
+
onLoadMentorsPermissions={(permissions) => {
|
|
176
|
+
dispatch(updateRbacPermissions(permissions));
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
{children}
|
|
180
|
+
</MentorProvider>
|
|
181
|
+
\`\`\`
|
|
182
|
+
|
|
183
|
+
## Common Permission Resources
|
|
184
|
+
|
|
185
|
+
### Platform Level
|
|
186
|
+
- \`/platforms/{tenantKey}/#can_view_analytics\`
|
|
187
|
+
- \`/platforms/{tenantKey}/#can_manage_users\`
|
|
188
|
+
- \`/platforms/{tenantKey}/#can_invite_users\`
|
|
189
|
+
- \`/platforms/{tenantKey}/#can_manage_groups\`
|
|
190
|
+
|
|
191
|
+
### Mentor Level
|
|
192
|
+
- \`/mentors/{mentorId}/#can_edit\`
|
|
193
|
+
- \`/mentors/{mentorId}/#can_delete\`
|
|
194
|
+
- \`/mentors/{mentorId}/#show_settings\`
|
|
195
|
+
- \`/mentors/{mentorId}/#mentor_name\`
|
|
196
|
+
- \`/mentors/{mentorId}/#profile_image\`
|
|
197
|
+
|
|
198
|
+
### Field-Level Permissions
|
|
199
|
+
|
|
200
|
+
For forms, use WithFormPermissions:
|
|
201
|
+
|
|
202
|
+
\`\`\`typescript
|
|
203
|
+
<WithFormPermissions
|
|
204
|
+
fieldName="mentor_name"
|
|
205
|
+
mentorSettings={mentorSettings}
|
|
206
|
+
>
|
|
207
|
+
{({ isEditable }) => (
|
|
208
|
+
<Input
|
|
209
|
+
disabled={!isEditable}
|
|
210
|
+
value={mentorName}
|
|
211
|
+
onChange={handleChange}
|
|
212
|
+
/>
|
|
213
|
+
)}
|
|
214
|
+
</WithFormPermissions>
|
|
215
|
+
\`\`\`
|
|
216
|
+
|
|
217
|
+
## User Type Checks
|
|
218
|
+
|
|
219
|
+
Additional to RBAC, check user types:
|
|
220
|
+
|
|
221
|
+
\`\`\`typescript
|
|
222
|
+
const isAdmin = currentTenant?.is_admin;
|
|
223
|
+
const isStudent = !isAdmin;
|
|
224
|
+
const isAnonymous = username === ANONYMOUS_USERNAME;
|
|
225
|
+
|
|
226
|
+
// Combine with RBAC
|
|
227
|
+
const canAccessFeature = isAdmin && hasRbacPermission;
|
|
228
|
+
\`\`\`
|
|
229
|
+
`,
|
|
230
|
+
};
|
|
231
|
+
//# sourceMappingURL=guides-rbac.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides-rbac.js","sourceRoot":"","sources":["../../src/resources/guides-rbac.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,GAAG,EAAE,mBAAmB;IACxB,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,oCAAoC;IACjD,QAAQ,EAAE,eAAe;IACzB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+NV;CACA,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides-theme.d.ts","sourceRoot":"","sources":["../../src/resources/guides-theme.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW;;;;;;CAqLvB,CAAC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
export const guidesTheme = {
|
|
2
|
+
uri: 'ibl://guides/theme',
|
|
3
|
+
name: 'IBL Theme Configuration',
|
|
4
|
+
description: 'Theme and styling patterns',
|
|
5
|
+
mimeType: 'text/markdown',
|
|
6
|
+
content: `# IBL Theme Configuration
|
|
7
|
+
|
|
8
|
+
## CSS Custom Properties
|
|
9
|
+
|
|
10
|
+
Import the base theme in your app:
|
|
11
|
+
|
|
12
|
+
\`\`\`typescript
|
|
13
|
+
// In your root layout or global CSS
|
|
14
|
+
import '@iblai/web-containers/styles/base.css';
|
|
15
|
+
\`\`\`
|
|
16
|
+
|
|
17
|
+
## Theme Variables
|
|
18
|
+
|
|
19
|
+
\`\`\`css
|
|
20
|
+
:root {
|
|
21
|
+
/* Primary Colors */
|
|
22
|
+
--primary: #0058cc;
|
|
23
|
+
--primary-light: #00b0ef;
|
|
24
|
+
--primary-dark: #004499;
|
|
25
|
+
--primary-foreground: #ffffff;
|
|
26
|
+
|
|
27
|
+
/* Secondary Colors */
|
|
28
|
+
--secondary: #f4f4f5;
|
|
29
|
+
--secondary-foreground: #18181b;
|
|
30
|
+
|
|
31
|
+
/* Text Colors */
|
|
32
|
+
--text-primary: #616a76;
|
|
33
|
+
--text-secondary: #71717a;
|
|
34
|
+
--text-muted: #9ca3af;
|
|
35
|
+
|
|
36
|
+
/* Status Colors */
|
|
37
|
+
--success: #22c55e;
|
|
38
|
+
--warning: #f59e0b;
|
|
39
|
+
--error: #ef4444;
|
|
40
|
+
--info: #3b82f6;
|
|
41
|
+
|
|
42
|
+
/* Background Colors */
|
|
43
|
+
--background: #ffffff;
|
|
44
|
+
--foreground: #0a0a0a;
|
|
45
|
+
--card: #ffffff;
|
|
46
|
+
--card-foreground: #0a0a0a;
|
|
47
|
+
--muted: #f4f4f5;
|
|
48
|
+
--muted-foreground: #71717a;
|
|
49
|
+
|
|
50
|
+
/* Border Colors */
|
|
51
|
+
--border: #e4e4e7;
|
|
52
|
+
--input: #e4e4e7;
|
|
53
|
+
--ring: #0058cc;
|
|
54
|
+
|
|
55
|
+
/* Border Radius */
|
|
56
|
+
--radius: 0.5rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Dark Mode */
|
|
60
|
+
.dark {
|
|
61
|
+
--background: #0a0a0a;
|
|
62
|
+
--foreground: #fafafa;
|
|
63
|
+
--card: #0a0a0a;
|
|
64
|
+
--card-foreground: #fafafa;
|
|
65
|
+
--muted: #27272a;
|
|
66
|
+
--muted-foreground: #a1a1aa;
|
|
67
|
+
--border: #27272a;
|
|
68
|
+
}
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
## Using Theme with Next-Themes
|
|
72
|
+
|
|
73
|
+
\`\`\`typescript
|
|
74
|
+
// components/client-layout.tsx
|
|
75
|
+
'use client';
|
|
76
|
+
|
|
77
|
+
import { ThemeProvider } from 'next-themes';
|
|
78
|
+
|
|
79
|
+
export function ClientLayout({ children }) {
|
|
80
|
+
return (
|
|
81
|
+
<ThemeProvider
|
|
82
|
+
attribute="class"
|
|
83
|
+
defaultTheme="light"
|
|
84
|
+
enableSystem
|
|
85
|
+
disableTransitionOnChange
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</ThemeProvider>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
\`\`\`
|
|
92
|
+
|
|
93
|
+
## Theme Toggle
|
|
94
|
+
|
|
95
|
+
\`\`\`typescript
|
|
96
|
+
import { useTheme } from 'next-themes';
|
|
97
|
+
import { Sun, Moon } from 'lucide-react';
|
|
98
|
+
import { Button } from '@iblai/web-containers';
|
|
99
|
+
|
|
100
|
+
export function ThemeToggle() {
|
|
101
|
+
const { theme, setTheme } = useTheme();
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Button
|
|
105
|
+
variant="ghost"
|
|
106
|
+
size="icon"
|
|
107
|
+
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
|
|
108
|
+
>
|
|
109
|
+
<Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
|
110
|
+
<Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
|
111
|
+
</Button>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
## Tenant-Specific Theming
|
|
117
|
+
|
|
118
|
+
Tenants can customize CSS through metadata:
|
|
119
|
+
|
|
120
|
+
\`\`\`typescript
|
|
121
|
+
// Load tenant CSS dynamically
|
|
122
|
+
const { metadata } = useTenantMetadata(tenantKey);
|
|
123
|
+
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (metadata?.skills_advanced_css) {
|
|
126
|
+
const style = document.createElement('style');
|
|
127
|
+
style.textContent = sanitizeCss(metadata.skills_advanced_css);
|
|
128
|
+
document.head.appendChild(style);
|
|
129
|
+
return () => style.remove();
|
|
130
|
+
}
|
|
131
|
+
}, [metadata]);
|
|
132
|
+
\`\`\`
|
|
133
|
+
|
|
134
|
+
## Button Variants
|
|
135
|
+
|
|
136
|
+
\`\`\`typescript
|
|
137
|
+
import { Button } from '@iblai/web-containers';
|
|
138
|
+
|
|
139
|
+
// Available variants
|
|
140
|
+
<Button variant="default">Primary</Button>
|
|
141
|
+
<Button variant="destructive">Delete</Button>
|
|
142
|
+
<Button variant="outline">Outline</Button>
|
|
143
|
+
<Button variant="secondary">Secondary</Button>
|
|
144
|
+
<Button variant="ghost">Ghost</Button>
|
|
145
|
+
<Button variant="link">Link</Button>
|
|
146
|
+
|
|
147
|
+
// Sizes
|
|
148
|
+
<Button size="sm">Small</Button>
|
|
149
|
+
<Button size="default">Default</Button>
|
|
150
|
+
<Button size="lg">Large</Button>
|
|
151
|
+
<Button size="icon"><Icon /></Button>
|
|
152
|
+
\`\`\`
|
|
153
|
+
|
|
154
|
+
## Class Merging Utility
|
|
155
|
+
|
|
156
|
+
\`\`\`typescript
|
|
157
|
+
import { cn } from '@iblai/web-containers';
|
|
158
|
+
|
|
159
|
+
// Merge classes with conflict resolution
|
|
160
|
+
<div className={cn(
|
|
161
|
+
'base-class',
|
|
162
|
+
isActive && 'active-class',
|
|
163
|
+
variant === 'primary' ? 'bg-primary' : 'bg-secondary'
|
|
164
|
+
)} />
|
|
165
|
+
\`\`\`
|
|
166
|
+
|
|
167
|
+
## Gradient Patterns
|
|
168
|
+
|
|
169
|
+
\`\`\`css
|
|
170
|
+
/* IBL gradient pattern */
|
|
171
|
+
.ibl-gradient {
|
|
172
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.ibl-text-gradient {
|
|
176
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
|
|
177
|
+
-webkit-background-clip: text;
|
|
178
|
+
-webkit-text-fill-color: transparent;
|
|
179
|
+
}
|
|
180
|
+
\`\`\`
|
|
181
|
+
`,
|
|
182
|
+
};
|
|
183
|
+
//# sourceMappingURL=guides-theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides-theme.js","sourceRoot":"","sources":["../../src/resources/guides-theme.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,GAAG,EAAE,oBAAoB;IACzB,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EAAE,4BAA4B;IACzC,QAAQ,EAAE,eAAe;IACzB,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+KV;CACA,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { packagesOverview } from './packages-overview.js';
|
|
2
|
+
import { webContainers } from './web-containers.js';
|
|
3
|
+
import { webUtils } from './web-utils.js';
|
|
4
|
+
import { dataLayer } from './data-layer.js';
|
|
5
|
+
import { guidesLayout } from './guides-layout.js';
|
|
6
|
+
import { guidesRbac } from './guides-rbac.js';
|
|
7
|
+
import { guidesTheme } from './guides-theme.js';
|
|
8
|
+
export interface Resource {
|
|
9
|
+
uri: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
mimeType: string;
|
|
13
|
+
content: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const RESOURCES: Record<string, Resource>;
|
|
16
|
+
export { packagesOverview, webContainers, webUtils, dataLayer, guidesLayout, guidesRbac, guidesTheme, };
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAQ9C,CAAC;AAEF,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,CAAC"}
|