@industry-theme/repository-composition-panels 0.1.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/LICENSE +21 -0
- package/README.md +536 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/mocks/panelContext.d.ts +24 -0
- package/dist/mocks/panelContext.d.ts.map +1 -0
- package/dist/panels/GitChangesPanel.d.ts +24 -0
- package/dist/panels/GitChangesPanel.d.ts.map +1 -0
- package/dist/panels/GitChangesPanel.stories.d.ts +73 -0
- package/dist/panels/GitChangesPanel.stories.d.ts.map +1 -0
- package/dist/panels.bundle.js +8107 -0
- package/dist/panels.bundle.js.map +1 -0
- package/dist/tools/index.d.ts +32 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools.bundle.js +106 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +100 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Your Name
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# Panel Extension Starter
|
|
2
|
+
|
|
3
|
+
A starter template for building panel extensions compatible with `@principal-ade/panel-framework-core`. This template follows the [Panel Extension Store Specification V2](https://github.com/principal-ade/panel-framework/blob/main/PANEL_EXTENSION_STORE_SPECIFICATION_V2.md) and provides everything you need to create, build, and publish custom panels.
|
|
4
|
+
|
|
5
|
+
## What is a Panel Extension?
|
|
6
|
+
|
|
7
|
+
Panel extensions are React components distributed via NPM that can be dynamically loaded into panel-compatible host applications. They provide a standardized way to extend application functionality through a plugin-like architecture.
|
|
8
|
+
|
|
9
|
+
### Key Features
|
|
10
|
+
|
|
11
|
+
- **NPM Distribution**: Published and installed like any NPM package
|
|
12
|
+
- **Multi-Panel Support**: Single package can export multiple related panels
|
|
13
|
+
- **Framework Integration**: Full access to host application context, actions, and events
|
|
14
|
+
- **Type Safety**: Complete TypeScript support with comprehensive type definitions
|
|
15
|
+
- **Dependency Sharing**: Shared dependencies (React, ReactDOM) provided by host
|
|
16
|
+
- **Self-Contained**: Unique dependencies bundled within the panel
|
|
17
|
+
|
|
18
|
+
## Getting Started
|
|
19
|
+
|
|
20
|
+
### 1. Clone or Use This Template
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Clone the starter
|
|
24
|
+
git clone https://github.com/your-org/panel-starter.git my-panel-extension
|
|
25
|
+
cd my-panel-extension
|
|
26
|
+
|
|
27
|
+
# Install dependencies
|
|
28
|
+
bun install
|
|
29
|
+
# or: npm install
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Customize Your Package
|
|
33
|
+
|
|
34
|
+
Update `package.json` with your information:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"name": "@your-org/your-panel-name",
|
|
39
|
+
"description": "Your panel description",
|
|
40
|
+
"author": "Your Name",
|
|
41
|
+
"keywords": ["panel-extension"],
|
|
42
|
+
"repository": {
|
|
43
|
+
"url": "git+https://github.com/your-org/your-panel-name.git"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. Develop Your Panel
|
|
49
|
+
|
|
50
|
+
Edit `src/panels/ExamplePanel.tsx` or create new panel components:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import React from 'react';
|
|
54
|
+
import type { PanelComponentProps } from '../types';
|
|
55
|
+
|
|
56
|
+
export const MyPanel: React.FC<PanelComponentProps> = ({
|
|
57
|
+
context,
|
|
58
|
+
actions,
|
|
59
|
+
events,
|
|
60
|
+
}) => {
|
|
61
|
+
return (
|
|
62
|
+
<div>
|
|
63
|
+
<h1>My Custom Panel</h1>
|
|
64
|
+
<p>Repository: {context.repositoryPath}</p>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 4. Register Your Panels
|
|
71
|
+
|
|
72
|
+
Update `src/index.tsx` to export your panel definitions:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { MyPanel } from './panels/MyPanel';
|
|
76
|
+
|
|
77
|
+
export const panels = [
|
|
78
|
+
{
|
|
79
|
+
id: 'your-org.my-panel',
|
|
80
|
+
name: 'My Panel',
|
|
81
|
+
icon: '🚀',
|
|
82
|
+
description: 'My custom panel',
|
|
83
|
+
component: MyPanel,
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 5. Develop with Storybook
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Start Storybook for interactive development
|
|
92
|
+
bun run storybook
|
|
93
|
+
|
|
94
|
+
# Build Storybook for deployment
|
|
95
|
+
bun run build-storybook
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Storybook will open at `http://localhost:6006` with:
|
|
99
|
+
|
|
100
|
+
- Interactive component documentation
|
|
101
|
+
- Multiple panel states and examples
|
|
102
|
+
- Live prop editing
|
|
103
|
+
- Code snippets
|
|
104
|
+
|
|
105
|
+
### 6. Build and Test
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Development mode (watch for changes)
|
|
109
|
+
bun run dev
|
|
110
|
+
|
|
111
|
+
# Build for production
|
|
112
|
+
bun run build
|
|
113
|
+
|
|
114
|
+
# Type checking
|
|
115
|
+
bun run typecheck
|
|
116
|
+
|
|
117
|
+
# Linting
|
|
118
|
+
bun run lint
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Project Structure
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
panel-starter/
|
|
125
|
+
├── src/
|
|
126
|
+
│ ├── panels/
|
|
127
|
+
│ │ ├── ExamplePanel.tsx # Your panel components
|
|
128
|
+
│ │ └── ExamplePanel.stories.tsx # Storybook stories
|
|
129
|
+
│ ├── types/
|
|
130
|
+
│ │ └── index.ts # TypeScript type definitions
|
|
131
|
+
│ ├── mocks/
|
|
132
|
+
│ │ └── panelContext.tsx # Mock providers for Storybook
|
|
133
|
+
│ ├── Introduction.mdx # Storybook introduction
|
|
134
|
+
│ └── index.tsx # Main entry - export panels array
|
|
135
|
+
├── .storybook/
|
|
136
|
+
│ ├── main.ts # Storybook configuration
|
|
137
|
+
│ └── preview.ts # Storybook preview config
|
|
138
|
+
├── dist/
|
|
139
|
+
│ └── panels.bundle.js # Built output (generated)
|
|
140
|
+
├── package.json # Package configuration
|
|
141
|
+
├── tsconfig.json # TypeScript config
|
|
142
|
+
├── vite.config.ts # Build configuration
|
|
143
|
+
├── eslint.config.js # Linting rules
|
|
144
|
+
└── README.md # This file
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Panel Component API
|
|
148
|
+
|
|
149
|
+
### PanelComponentProps
|
|
150
|
+
|
|
151
|
+
Every panel component receives these props:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
interface PanelComponentProps {
|
|
155
|
+
// Access to shared data and state
|
|
156
|
+
context: PanelContextValue;
|
|
157
|
+
|
|
158
|
+
// Actions for host interaction
|
|
159
|
+
actions: PanelActions;
|
|
160
|
+
|
|
161
|
+
// Event system for inter-panel communication
|
|
162
|
+
events: PanelEventEmitter;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Context
|
|
167
|
+
|
|
168
|
+
Access repository data and state:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
const { context } = props;
|
|
172
|
+
|
|
173
|
+
// Repository information
|
|
174
|
+
context.repositoryPath; // Current repository path
|
|
175
|
+
context.repository; // Repository metadata
|
|
176
|
+
|
|
177
|
+
// Data slices
|
|
178
|
+
context.gitStatus; // Git status information
|
|
179
|
+
context.fileTree; // File tree structure
|
|
180
|
+
context.markdownFiles; // Markdown files list
|
|
181
|
+
|
|
182
|
+
// State management
|
|
183
|
+
context.loading; // Loading state
|
|
184
|
+
context.refresh(); // Refresh data
|
|
185
|
+
context.hasSlice('git'); // Check slice availability
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Actions
|
|
189
|
+
|
|
190
|
+
Interact with the host application:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
const { actions } = props;
|
|
194
|
+
|
|
195
|
+
// File operations
|
|
196
|
+
actions.openFile?.('path/to/file.ts');
|
|
197
|
+
actions.openGitDiff?.('path/to/file.ts', 'unstaged');
|
|
198
|
+
|
|
199
|
+
// Navigation
|
|
200
|
+
actions.navigateToPanel?.('panel-id');
|
|
201
|
+
|
|
202
|
+
// Notifications
|
|
203
|
+
actions.notifyPanels?.(event);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Events
|
|
207
|
+
|
|
208
|
+
Subscribe to and emit panel events:
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
const { events } = props;
|
|
212
|
+
|
|
213
|
+
// Subscribe to events
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
const unsubscribe = events.on('file:opened', (event) => {
|
|
216
|
+
console.log('File opened:', event.payload);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
return unsubscribe; // Cleanup
|
|
220
|
+
}, [events]);
|
|
221
|
+
|
|
222
|
+
// Emit events
|
|
223
|
+
events.emit({
|
|
224
|
+
type: 'custom:event',
|
|
225
|
+
source: 'my-panel',
|
|
226
|
+
timestamp: Date.now(),
|
|
227
|
+
payload: { data: 'value' },
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Panel Definition
|
|
232
|
+
|
|
233
|
+
Each panel must be defined with metadata:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
interface PanelDefinition {
|
|
237
|
+
id: string; // Unique ID (e.g., 'org.panel-name')
|
|
238
|
+
name: string; // Display name
|
|
239
|
+
icon?: string; // Icon (emoji or URL)
|
|
240
|
+
version?: string; // Version (defaults to package.json)
|
|
241
|
+
author?: string; // Author (defaults to package.json)
|
|
242
|
+
description?: string; // Short description
|
|
243
|
+
component: React.FC; // The panel component
|
|
244
|
+
|
|
245
|
+
// Optional lifecycle hooks
|
|
246
|
+
onMount?: (context) => void | Promise<void>;
|
|
247
|
+
onUnmount?: (context) => void | Promise<void>;
|
|
248
|
+
onDataChange?: (slice, data) => void;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Lifecycle Hooks
|
|
253
|
+
|
|
254
|
+
### Per-Panel Hooks
|
|
255
|
+
|
|
256
|
+
Called for individual panels:
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
{
|
|
260
|
+
id: 'my-panel',
|
|
261
|
+
component: MyPanel,
|
|
262
|
+
|
|
263
|
+
onMount: async (context) => {
|
|
264
|
+
console.log('Panel mounted');
|
|
265
|
+
if (context.hasSlice('git')) {
|
|
266
|
+
await context.refresh();
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
onUnmount: async (context) => {
|
|
271
|
+
console.log('Panel unmounting');
|
|
272
|
+
// Cleanup logic
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
onDataChange: (slice, data) => {
|
|
276
|
+
console.log(`Data changed: ${slice}`, data);
|
|
277
|
+
},
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Package-Level Hooks
|
|
282
|
+
|
|
283
|
+
Called once for the entire package:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
export const onPackageLoad = async () => {
|
|
287
|
+
console.log('Package loaded');
|
|
288
|
+
// Initialize shared resources
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export const onPackageUnload = async () => {
|
|
292
|
+
console.log('Package unloading');
|
|
293
|
+
// Cleanup shared resources
|
|
294
|
+
};
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Building and Publishing
|
|
298
|
+
|
|
299
|
+
### Build Configuration
|
|
300
|
+
|
|
301
|
+
The build process (via Vite) automatically:
|
|
302
|
+
|
|
303
|
+
- Externalizes React and ReactDOM (provided by host)
|
|
304
|
+
- Bundles all other dependencies
|
|
305
|
+
- Generates TypeScript declarations
|
|
306
|
+
- Creates source maps
|
|
307
|
+
- Outputs to `dist/panels.bundle.js`
|
|
308
|
+
|
|
309
|
+
### Local Testing
|
|
310
|
+
|
|
311
|
+
Link your panel locally for testing:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
# In your panel directory
|
|
315
|
+
bun run build
|
|
316
|
+
bun link
|
|
317
|
+
|
|
318
|
+
# In your host application
|
|
319
|
+
bun link @your-org/your-panel-name
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Publishing to NPM
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
# Build the package
|
|
326
|
+
bun run build
|
|
327
|
+
|
|
328
|
+
# Verify the output
|
|
329
|
+
ls -la dist/
|
|
330
|
+
|
|
331
|
+
# Publish to NPM
|
|
332
|
+
npm publish --access public
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Installing in Host Application
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# In the host application
|
|
339
|
+
npm install @your-org/your-panel-name
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
The host application will automatically discover your panel by the `panel-extension` keyword in `package.json`.
|
|
343
|
+
|
|
344
|
+
## Best Practices
|
|
345
|
+
|
|
346
|
+
### 1. Namespaced Panel IDs
|
|
347
|
+
|
|
348
|
+
Use reverse domain notation for panel IDs:
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
id: 'com.company.feature-panel'; // ✅ Good
|
|
352
|
+
id: 'my-panel'; // ❌ Bad (collision risk)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### 2. Error Handling
|
|
356
|
+
|
|
357
|
+
Always handle errors gracefully:
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
const [error, setError] = useState(null);
|
|
361
|
+
|
|
362
|
+
useEffect(() => {
|
|
363
|
+
const loadData = async () => {
|
|
364
|
+
try {
|
|
365
|
+
if (!context.hasSlice('git')) {
|
|
366
|
+
throw new Error('Git data not available');
|
|
367
|
+
}
|
|
368
|
+
// Use data...
|
|
369
|
+
} catch (err) {
|
|
370
|
+
setError(err);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
loadData();
|
|
374
|
+
}, [context]);
|
|
375
|
+
|
|
376
|
+
if (error) {
|
|
377
|
+
return <div>Error: {error.message}</div>;
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### 3. Loading States
|
|
382
|
+
|
|
383
|
+
Show loading indicators:
|
|
384
|
+
|
|
385
|
+
```tsx
|
|
386
|
+
if (context.loading || context.isSliceLoading('git')) {
|
|
387
|
+
return <div>Loading...</div>;
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### 4. Cleanup Subscriptions
|
|
392
|
+
|
|
393
|
+
Always unsubscribe from events:
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
useEffect(() => {
|
|
397
|
+
const unsubscribe = events.on('event:type', handler);
|
|
398
|
+
return unsubscribe; // Cleanup on unmount
|
|
399
|
+
}, [events]);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 5. Type Safety
|
|
403
|
+
|
|
404
|
+
Use provided types for type safety:
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
import type { PanelComponentProps, GitStatus } from './types';
|
|
408
|
+
|
|
409
|
+
const MyPanel: React.FC<PanelComponentProps> = ({ context }) => {
|
|
410
|
+
const gitStatus: GitStatus = context.gitStatus;
|
|
411
|
+
// ...
|
|
412
|
+
};
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Available Data Slices
|
|
416
|
+
|
|
417
|
+
Panels can access these data slices from the host:
|
|
418
|
+
|
|
419
|
+
| Slice | Type | Description |
|
|
420
|
+
| ---------- | ---------------- | ---------------------------- |
|
|
421
|
+
| `git` | `GitStatus` | Git repository status |
|
|
422
|
+
| `markdown` | `MarkdownFile[]` | Markdown files in repository |
|
|
423
|
+
| `fileTree` | `FileTree` | File system tree structure |
|
|
424
|
+
| `packages` | `PackageLayer[]` | Package dependencies |
|
|
425
|
+
| `quality` | `QualityMetrics` | Code quality metrics |
|
|
426
|
+
|
|
427
|
+
Check availability before use:
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
if (context.hasSlice('git') && !context.isSliceLoading('git')) {
|
|
431
|
+
// Use git data
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Event Types
|
|
436
|
+
|
|
437
|
+
Standard panel events:
|
|
438
|
+
|
|
439
|
+
| Event | Description | Payload |
|
|
440
|
+
| -------------------- | ------------------ | ---------------------- |
|
|
441
|
+
| `file:opened` | File was opened | `{ filePath: string }` |
|
|
442
|
+
| `file:saved` | File was saved | `{ filePath: string }` |
|
|
443
|
+
| `file:deleted` | File was deleted | `{ filePath: string }` |
|
|
444
|
+
| `git:status-changed` | Git status changed | `GitStatus` |
|
|
445
|
+
| `git:commit` | Git commit made | `{ hash: string }` |
|
|
446
|
+
| `git:branch-changed` | Branch changed | `{ branch: string }` |
|
|
447
|
+
| `panel:focus` | Panel gained focus | `{ panelId: string }` |
|
|
448
|
+
| `panel:blur` | Panel lost focus | `{ panelId: string }` |
|
|
449
|
+
| `data:refresh` | Data was refreshed | `{ slices: string[] }` |
|
|
450
|
+
|
|
451
|
+
## Dependencies
|
|
452
|
+
|
|
453
|
+
### Peer Dependencies (Required)
|
|
454
|
+
|
|
455
|
+
These are provided by the host application:
|
|
456
|
+
|
|
457
|
+
- `react` >= 19.0.0
|
|
458
|
+
- `react-dom` >= 19.0.0
|
|
459
|
+
|
|
460
|
+
### Optional Peer Dependencies
|
|
461
|
+
|
|
462
|
+
- `@principal-ade/panel-framework-core` - For advanced panel features
|
|
463
|
+
|
|
464
|
+
### Bundled Dependencies
|
|
465
|
+
|
|
466
|
+
Include any libraries unique to your panel:
|
|
467
|
+
|
|
468
|
+
```json
|
|
469
|
+
{
|
|
470
|
+
"dependencies": {
|
|
471
|
+
"lodash": "^4.17.21",
|
|
472
|
+
"date-fns": "^2.29.0",
|
|
473
|
+
"your-custom-lib": "^1.0.0"
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
These will be bundled into your panel output.
|
|
479
|
+
|
|
480
|
+
## Troubleshooting
|
|
481
|
+
|
|
482
|
+
### Panel Not Discovered
|
|
483
|
+
|
|
484
|
+
Ensure `package.json` has:
|
|
485
|
+
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"keywords": ["panel-extension"],
|
|
489
|
+
"main": "dist/panels.bundle.js"
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Build Errors
|
|
494
|
+
|
|
495
|
+
Check that peer dependencies are externalized in `vite.config.ts`:
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
external: ['react', 'react-dom'];
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Type Errors
|
|
502
|
+
|
|
503
|
+
Ensure TypeScript can find types:
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
bun run typecheck
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Runtime Errors
|
|
510
|
+
|
|
511
|
+
Check browser console and ensure:
|
|
512
|
+
|
|
513
|
+
- Panel ID is unique
|
|
514
|
+
- Required exports are present (`panels` array)
|
|
515
|
+
- Component is a valid React component
|
|
516
|
+
|
|
517
|
+
## Resources
|
|
518
|
+
|
|
519
|
+
- [Panel Extension Store Specification V2](https://github.com/principal-ade/panel-framework/blob/main/PANEL_EXTENSION_STORE_SPECIFICATION_V2.md)
|
|
520
|
+
- [Panel Framework Core](https://github.com/principal-ade/panel-framework-core)
|
|
521
|
+
- [Example Implementations](https://github.com/principal-ade/example-panels)
|
|
522
|
+
|
|
523
|
+
## License
|
|
524
|
+
|
|
525
|
+
MIT © Your Name
|
|
526
|
+
|
|
527
|
+
## Contributing
|
|
528
|
+
|
|
529
|
+
Contributions welcome! Please read the contributing guidelines first.
|
|
530
|
+
|
|
531
|
+
## Support
|
|
532
|
+
|
|
533
|
+
For issues and questions:
|
|
534
|
+
|
|
535
|
+
- [GitHub Issues](https://github.com/your-org/your-panel-name/issues)
|
|
536
|
+
- [Discussions](https://github.com/your-org/your-panel-name/discussions)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { GitChangesPanel, GitChangesPanelPreview } from './panels/GitChangesPanel';
|
|
2
|
+
export type { GitChangesPanelProps } from './panels/GitChangesPanel';
|
|
3
|
+
export type { GitStatus, GitChangeSelectionStatus, GitFileStatus, FileTree, } from './types';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACnF,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAGrE,YAAY,EACV,SAAS,EACT,wBAAwB,EACxB,aAAa,EACb,QAAQ,GACT,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PanelComponentProps, PanelContextValue, PanelActions, PanelEventEmitter } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Mock Panel Context for Storybook
|
|
5
|
+
*/
|
|
6
|
+
export declare const createMockContext: (overrides?: Partial<PanelContextValue>) => PanelContextValue;
|
|
7
|
+
/**
|
|
8
|
+
* Mock Panel Actions for Storybook
|
|
9
|
+
*/
|
|
10
|
+
export declare const createMockActions: (overrides?: Partial<PanelActions>) => PanelActions;
|
|
11
|
+
/**
|
|
12
|
+
* Mock Event Emitter for Storybook
|
|
13
|
+
*/
|
|
14
|
+
export declare const createMockEvents: () => PanelEventEmitter;
|
|
15
|
+
/**
|
|
16
|
+
* Mock Panel Props Provider
|
|
17
|
+
* Wraps components with mock context and ThemeProvider for Storybook
|
|
18
|
+
*/
|
|
19
|
+
export declare const MockPanelProvider: React.FC<{
|
|
20
|
+
children: (props: PanelComponentProps) => React.ReactNode;
|
|
21
|
+
contextOverrides?: Partial<PanelContextValue>;
|
|
22
|
+
actionsOverrides?: Partial<PanelActions>;
|
|
23
|
+
}>;
|
|
24
|
+
//# sourceMappingURL=panelContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panelContext.d.ts","sourceRoot":"","sources":["../../src/mocks/panelContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EAIlB,MAAM,UAAU,CAAC;AA+BlB;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,YAAY,OAAO,CAAC,iBAAiB,CAAC,KACrC,iBAiHF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,YAAY,OAAO,CAAC,YAAY,CAAC,KAChC,YAkBD,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAO,iBAwCnC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC;IACvC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1D,gBAAgB,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1C,CAMA,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type FileTree } from '@principal-ai/repository-abstraction';
|
|
3
|
+
import type { GitStatus, GitChangeSelectionStatus } from '../types';
|
|
4
|
+
export interface GitChangesPanelProps {
|
|
5
|
+
/** Git status data with categorized file paths */
|
|
6
|
+
gitStatus: GitStatus;
|
|
7
|
+
/** Optional file tree for "Full Tree" view mode */
|
|
8
|
+
fileTree?: FileTree | null;
|
|
9
|
+
/** Root path for the repository (used for building file trees) */
|
|
10
|
+
rootPath?: string;
|
|
11
|
+
/** Whether git status is currently loading */
|
|
12
|
+
isLoading?: boolean;
|
|
13
|
+
/** Callback when a file is clicked */
|
|
14
|
+
onFileClick?: (filePath: string, status?: GitChangeSelectionStatus) => void;
|
|
15
|
+
/** Message to display when there are no changes */
|
|
16
|
+
emptyMessage?: string;
|
|
17
|
+
/** Message to display while loading */
|
|
18
|
+
loadingMessage?: string;
|
|
19
|
+
/** Currently selected file path */
|
|
20
|
+
selectedFile?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const GitChangesPanel: React.FC<GitChangesPanelProps>;
|
|
23
|
+
export declare const GitChangesPanelPreview: React.FC;
|
|
24
|
+
//# sourceMappingURL=GitChangesPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitChangesPanel.d.ts","sourceRoot":"","sources":["../../src/panels/GitChangesPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAGjF,OAAO,EAAwB,KAAK,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAC3F,OAAO,KAAK,EAAE,SAAS,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,SAAS,EAAE,SAAS,CAAC;IACrB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sCAAsC;IACtC,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC5E,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAqQ1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAiD1C,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { GitChangesPanelPreview } from './GitChangesPanel';
|
|
3
|
+
import type { GitStatus } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* GitChangesPanel displays git status changes in a file tree format.
|
|
6
|
+
* It supports two view modes: "Full Tree" (complete file structure) and "Changes Only" (modified files only).
|
|
7
|
+
*/
|
|
8
|
+
declare const meta: {
|
|
9
|
+
title: string;
|
|
10
|
+
component: import("react").FC<import("./GitChangesPanel").GitChangesPanelProps>;
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: string;
|
|
13
|
+
docs: {
|
|
14
|
+
description: {
|
|
15
|
+
component: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
tags: string[];
|
|
20
|
+
decorators: ((Story: import("storybook/internal/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
|
|
21
|
+
gitStatus: GitStatus;
|
|
22
|
+
fileTree?: (import("@principal-ai/repository-abstraction").FileTree | null) | undefined;
|
|
23
|
+
rootPath?: string | undefined;
|
|
24
|
+
isLoading?: boolean | undefined;
|
|
25
|
+
onFileClick?: ((filePath: string, status?: import("..").GitChangeSelectionStatus) => void) | undefined;
|
|
26
|
+
emptyMessage?: string | undefined;
|
|
27
|
+
loadingMessage?: string | undefined;
|
|
28
|
+
selectedFile?: string | undefined;
|
|
29
|
+
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
30
|
+
};
|
|
31
|
+
export default meta;
|
|
32
|
+
type Story = StoryObj<typeof meta>;
|
|
33
|
+
/**
|
|
34
|
+
* Default panel with various git changes
|
|
35
|
+
*/
|
|
36
|
+
export declare const Default: Story;
|
|
37
|
+
/**
|
|
38
|
+
* Loading state
|
|
39
|
+
*/
|
|
40
|
+
export declare const Loading: Story;
|
|
41
|
+
/**
|
|
42
|
+
* No changes - clean working directory
|
|
43
|
+
*/
|
|
44
|
+
export declare const NoChanges: Story;
|
|
45
|
+
/**
|
|
46
|
+
* Only staged changes
|
|
47
|
+
*/
|
|
48
|
+
export declare const OnlyStaged: Story;
|
|
49
|
+
/**
|
|
50
|
+
* Only unstaged modifications
|
|
51
|
+
*/
|
|
52
|
+
export declare const OnlyUnstaged: Story;
|
|
53
|
+
/**
|
|
54
|
+
* Only untracked files
|
|
55
|
+
*/
|
|
56
|
+
export declare const OnlyUntracked: Story;
|
|
57
|
+
/**
|
|
58
|
+
* Only deleted files
|
|
59
|
+
*/
|
|
60
|
+
export declare const OnlyDeleted: Story;
|
|
61
|
+
/**
|
|
62
|
+
* Many changes - stress test
|
|
63
|
+
*/
|
|
64
|
+
export declare const ManyChanges: Story;
|
|
65
|
+
/**
|
|
66
|
+
* With selected file
|
|
67
|
+
*/
|
|
68
|
+
export declare const WithSelectedFile: Story;
|
|
69
|
+
/**
|
|
70
|
+
* Preview component - shown in panel switcher
|
|
71
|
+
*/
|
|
72
|
+
export declare const Preview: StoryObj<typeof GitChangesPanelPreview>;
|
|
73
|
+
//# sourceMappingURL=GitChangesPanel.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitChangesPanel.stories.d.ts","sourceRoot":"","sources":["../../src/panels/GitChangesPanel.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAmB,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;GAGG;AACH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;gDAgBA,CAAC;;;;;CAM6B,CAAC;AAEzC,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AA6BnC;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,KAQrB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,KAcxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,KAc1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,KAe3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,KAczB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,KAazB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,OAAO,sBAAsB,CAQ3D,CAAC"}
|