@laststance/claude-plugin-dashboard 0.3.0 → 0.3.2
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 +1 -0
- package/dist/app.js +346 -211
- package/dist/cli.js +3 -1
- package/dist/components/ComponentBadges.d.ts +0 -9
- package/dist/components/ComponentBadges.js +0 -33
- package/dist/components/ComponentDetail.d.ts +32 -0
- package/dist/components/ComponentDetail.js +106 -0
- package/dist/components/ComponentList.d.ts +36 -2
- package/dist/components/ComponentList.js +105 -11
- package/dist/components/HelpOverlay.js +1 -0
- package/dist/components/KeyHints.d.ts +1 -0
- package/dist/components/KeyHints.js +8 -1
- package/dist/components/PluginDetail.d.ts +16 -3
- package/dist/components/PluginDetail.js +29 -3
- package/dist/services/componentService.d.ts +10 -42
- package/dist/services/componentService.js +19 -412
- package/dist/services/components/hookService.d.ts +17 -0
- package/dist/services/components/hookService.js +45 -0
- package/dist/services/components/index.d.ts +41 -0
- package/dist/services/components/index.js +126 -0
- package/dist/services/components/markdownService.d.ts +39 -0
- package/dist/services/components/markdownService.js +147 -0
- package/dist/services/components/serverService.d.ts +28 -0
- package/dist/services/components/serverService.js +69 -0
- package/dist/services/components/skillService.d.ts +48 -0
- package/dist/services/components/skillService.js +164 -0
- package/dist/services/components/utils.d.ts +23 -0
- package/dist/services/components/utils.js +42 -0
- package/dist/services/pluginActionsService.d.ts +31 -2
- package/dist/services/pluginActionsService.js +65 -6
- package/dist/store/index.d.ts +46 -0
- package/dist/store/index.js +47 -0
- package/dist/store/slices/marketplaceSlice.d.ts +344 -0
- package/dist/store/slices/marketplaceSlice.js +152 -0
- package/dist/store/slices/pluginSlice.d.ts +1544 -0
- package/dist/store/slices/pluginSlice.js +191 -0
- package/dist/store/slices/uiSlice.d.ts +147 -0
- package/dist/store/slices/uiSlice.js +126 -0
- package/dist/tabs/DiscoverTab.d.ts +8 -2
- package/dist/tabs/DiscoverTab.js +2 -2
- package/dist/tabs/EnabledTab.d.ts +8 -2
- package/dist/tabs/EnabledTab.js +2 -2
- package/dist/tabs/ErrorsTab.js +1 -1
- package/dist/tabs/InstalledTab.d.ts +8 -2
- package/dist/tabs/InstalledTab.js +2 -2
- package/dist/types/index.d.ts +47 -4
- package/package.json +7 -2
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin state slice for plugin data and operations
|
|
3
|
+
* Handles plugin list, loading state, selection, and operations
|
|
4
|
+
*/
|
|
5
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
6
|
+
import { setTab, nextTab, prevTab } from './uiSlice.js';
|
|
7
|
+
/**
|
|
8
|
+
* Initial plugin state
|
|
9
|
+
*/
|
|
10
|
+
const initialState = {
|
|
11
|
+
plugins: [],
|
|
12
|
+
errors: [],
|
|
13
|
+
loading: true,
|
|
14
|
+
error: null,
|
|
15
|
+
selectedIndex: 0,
|
|
16
|
+
operation: 'idle',
|
|
17
|
+
operationPluginId: null,
|
|
18
|
+
confirmUninstall: false,
|
|
19
|
+
confirmUpdateAll: false,
|
|
20
|
+
updateProgress: null,
|
|
21
|
+
selectedComponentIndex: 0,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Plugin slice with reducers for all plugin-related state changes
|
|
25
|
+
*/
|
|
26
|
+
export const pluginSlice = createSlice({
|
|
27
|
+
name: 'plugins',
|
|
28
|
+
initialState,
|
|
29
|
+
reducers: {
|
|
30
|
+
/**
|
|
31
|
+
* Set the plugins list
|
|
32
|
+
*/
|
|
33
|
+
setPlugins: (state, action) => {
|
|
34
|
+
state.plugins = action.payload;
|
|
35
|
+
state.loading = false;
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* Set plugin errors
|
|
39
|
+
*/
|
|
40
|
+
setErrors: (state, action) => {
|
|
41
|
+
state.errors = action.payload;
|
|
42
|
+
},
|
|
43
|
+
/**
|
|
44
|
+
* Set loading state
|
|
45
|
+
*/
|
|
46
|
+
setLoading: (state, action) => {
|
|
47
|
+
state.loading = action.payload;
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* Set error message
|
|
51
|
+
*/
|
|
52
|
+
setError: (state, action) => {
|
|
53
|
+
state.error = action.payload;
|
|
54
|
+
state.loading = false;
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Set selected plugin index
|
|
58
|
+
*/
|
|
59
|
+
setSelectedIndex: (state, action) => {
|
|
60
|
+
state.selectedIndex = action.payload;
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* Move selection up or down
|
|
64
|
+
*/
|
|
65
|
+
moveSelection: (state, action) => {
|
|
66
|
+
const { direction, maxIndex } = action.payload;
|
|
67
|
+
if (direction === 'up') {
|
|
68
|
+
state.selectedIndex = Math.max(0, state.selectedIndex - 1);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
state.selectedIndex = Math.min(maxIndex, state.selectedIndex + 1);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* Toggle plugin enabled state
|
|
76
|
+
*/
|
|
77
|
+
togglePluginEnabled: (state, action) => {
|
|
78
|
+
const pluginId = action.payload;
|
|
79
|
+
const plugin = state.plugins.find((p) => p.id === pluginId);
|
|
80
|
+
if (plugin) {
|
|
81
|
+
plugin.isEnabled = !plugin.isEnabled;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* Update a single plugin
|
|
86
|
+
*/
|
|
87
|
+
updatePlugin: (state, action) => {
|
|
88
|
+
const index = state.plugins.findIndex((p) => p.id === action.payload.id);
|
|
89
|
+
if (index !== -1) {
|
|
90
|
+
state.plugins[index] = action.payload;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* Start a plugin operation (install/uninstall)
|
|
95
|
+
*/
|
|
96
|
+
startOperation: (state, action) => {
|
|
97
|
+
state.operation = action.payload.operation;
|
|
98
|
+
state.operationPluginId = action.payload.pluginId;
|
|
99
|
+
},
|
|
100
|
+
/**
|
|
101
|
+
* End the current operation
|
|
102
|
+
*/
|
|
103
|
+
endOperation: (state) => {
|
|
104
|
+
state.operation = 'idle';
|
|
105
|
+
state.operationPluginId = null;
|
|
106
|
+
},
|
|
107
|
+
/**
|
|
108
|
+
* Show uninstall confirmation dialog
|
|
109
|
+
*/
|
|
110
|
+
showConfirmUninstall: (state, action) => {
|
|
111
|
+
state.confirmUninstall = true;
|
|
112
|
+
state.operationPluginId = action.payload;
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* Hide uninstall confirmation dialog
|
|
116
|
+
*/
|
|
117
|
+
hideConfirmUninstall: (state) => {
|
|
118
|
+
state.confirmUninstall = false;
|
|
119
|
+
state.operationPluginId = null;
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Show update all confirmation dialog
|
|
123
|
+
*/
|
|
124
|
+
showConfirmUpdateAll: (state) => {
|
|
125
|
+
state.confirmUpdateAll = true;
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Hide update all confirmation dialog
|
|
129
|
+
*/
|
|
130
|
+
hideConfirmUpdateAll: (state) => {
|
|
131
|
+
state.confirmUpdateAll = false;
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Set bulk update progress
|
|
135
|
+
*/
|
|
136
|
+
setUpdateProgress: (state, action) => {
|
|
137
|
+
state.updateProgress = action.payload;
|
|
138
|
+
},
|
|
139
|
+
/**
|
|
140
|
+
* Clear bulk update progress
|
|
141
|
+
*/
|
|
142
|
+
clearUpdateProgress: (state) => {
|
|
143
|
+
state.updateProgress = null;
|
|
144
|
+
},
|
|
145
|
+
/**
|
|
146
|
+
* Set selected component index for component focus mode
|
|
147
|
+
*/
|
|
148
|
+
setComponentIndex: (state, action) => {
|
|
149
|
+
state.selectedComponentIndex = action.payload;
|
|
150
|
+
},
|
|
151
|
+
/**
|
|
152
|
+
* Move component selection up or down
|
|
153
|
+
*/
|
|
154
|
+
moveComponentSelection: (state, action) => {
|
|
155
|
+
const { direction, maxIndex } = action.payload;
|
|
156
|
+
if (direction === 'up') {
|
|
157
|
+
state.selectedComponentIndex = Math.max(0, state.selectedComponentIndex - 1);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
state.selectedComponentIndex = Math.min(maxIndex, state.selectedComponentIndex + 1);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
/**
|
|
164
|
+
* Reset component index when entering component mode
|
|
165
|
+
*/
|
|
166
|
+
enterComponentMode: (state) => {
|
|
167
|
+
state.selectedComponentIndex = 0;
|
|
168
|
+
},
|
|
169
|
+
/**
|
|
170
|
+
* Reset component index when exiting component mode
|
|
171
|
+
*/
|
|
172
|
+
exitComponentMode: (state) => {
|
|
173
|
+
state.selectedComponentIndex = 0;
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
extraReducers: (builder) => {
|
|
177
|
+
// Reset selectedIndex when tab changes
|
|
178
|
+
builder
|
|
179
|
+
.addCase(setTab, (state) => {
|
|
180
|
+
state.selectedIndex = 0;
|
|
181
|
+
})
|
|
182
|
+
.addCase(nextTab, (state) => {
|
|
183
|
+
state.selectedIndex = 0;
|
|
184
|
+
})
|
|
185
|
+
.addCase(prevTab, (state) => {
|
|
186
|
+
state.selectedIndex = 0;
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
export const { setPlugins, setErrors, setLoading, setError, setSelectedIndex, moveSelection, togglePluginEnabled, updatePlugin, startOperation, endOperation, showConfirmUninstall, hideConfirmUninstall, showConfirmUpdateAll, hideConfirmUpdateAll, setUpdateProgress, clearUpdateProgress, setComponentIndex, moveComponentSelection, enterComponentMode, exitComponentMode, } = pluginSlice.actions;
|
|
191
|
+
export default pluginSlice.reducer;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI state slice for application-wide UI state management
|
|
3
|
+
* Handles tabs, focus zones, dialogs, search, sort, and messages
|
|
4
|
+
*/
|
|
5
|
+
import { type PayloadAction } from '@reduxjs/toolkit';
|
|
6
|
+
import type { AppState, FocusZone } from '../../types/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* UI-specific state extracted from AppState
|
|
9
|
+
*/
|
|
10
|
+
export interface UiState {
|
|
11
|
+
activeTab: AppState['activeTab'];
|
|
12
|
+
focusZone: FocusZone;
|
|
13
|
+
showHelp: boolean;
|
|
14
|
+
searchQuery: string;
|
|
15
|
+
sortBy: AppState['sortBy'];
|
|
16
|
+
sortOrder: AppState['sortOrder'];
|
|
17
|
+
message: string | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get available focus zones for the current tab
|
|
21
|
+
* Errors tab has no search zone since it doesn't support filtering
|
|
22
|
+
* @param activeTab - The currently active tab
|
|
23
|
+
* @returns Array of available focus zones in navigation order
|
|
24
|
+
*/
|
|
25
|
+
export declare function getAvailableZones(activeTab: AppState['activeTab']): FocusZone[];
|
|
26
|
+
/**
|
|
27
|
+
* UI slice with reducers for all UI-related state changes
|
|
28
|
+
*/
|
|
29
|
+
export declare const uiSlice: import("@reduxjs/toolkit").Slice<UiState, {
|
|
30
|
+
/**
|
|
31
|
+
* Set the active tab and reset related state
|
|
32
|
+
*/
|
|
33
|
+
setTab: (state: {
|
|
34
|
+
activeTab: AppState["activeTab"];
|
|
35
|
+
focusZone: FocusZone;
|
|
36
|
+
showHelp: boolean;
|
|
37
|
+
searchQuery: string;
|
|
38
|
+
sortBy: AppState["sortBy"];
|
|
39
|
+
sortOrder: AppState["sortOrder"];
|
|
40
|
+
message: string | null;
|
|
41
|
+
}, action: PayloadAction<AppState["activeTab"]>) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Navigate to next tab
|
|
44
|
+
*/
|
|
45
|
+
nextTab: (state: {
|
|
46
|
+
activeTab: AppState["activeTab"];
|
|
47
|
+
focusZone: FocusZone;
|
|
48
|
+
showHelp: boolean;
|
|
49
|
+
searchQuery: string;
|
|
50
|
+
sortBy: AppState["sortBy"];
|
|
51
|
+
sortOrder: AppState["sortOrder"];
|
|
52
|
+
message: string | null;
|
|
53
|
+
}) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Navigate to previous tab
|
|
56
|
+
*/
|
|
57
|
+
prevTab: (state: {
|
|
58
|
+
activeTab: AppState["activeTab"];
|
|
59
|
+
focusZone: FocusZone;
|
|
60
|
+
showHelp: boolean;
|
|
61
|
+
searchQuery: string;
|
|
62
|
+
sortBy: AppState["sortBy"];
|
|
63
|
+
sortOrder: AppState["sortOrder"];
|
|
64
|
+
message: string | null;
|
|
65
|
+
}) => void;
|
|
66
|
+
/**
|
|
67
|
+
* Set the focus zone
|
|
68
|
+
*/
|
|
69
|
+
setFocusZone: (state: {
|
|
70
|
+
activeTab: AppState["activeTab"];
|
|
71
|
+
focusZone: FocusZone;
|
|
72
|
+
showHelp: boolean;
|
|
73
|
+
searchQuery: string;
|
|
74
|
+
sortBy: AppState["sortBy"];
|
|
75
|
+
sortOrder: AppState["sortOrder"];
|
|
76
|
+
message: string | null;
|
|
77
|
+
}, action: PayloadAction<FocusZone>) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Toggle help overlay visibility
|
|
80
|
+
*/
|
|
81
|
+
toggleHelp: (state: {
|
|
82
|
+
activeTab: AppState["activeTab"];
|
|
83
|
+
focusZone: FocusZone;
|
|
84
|
+
showHelp: boolean;
|
|
85
|
+
searchQuery: string;
|
|
86
|
+
sortBy: AppState["sortBy"];
|
|
87
|
+
sortOrder: AppState["sortOrder"];
|
|
88
|
+
message: string | null;
|
|
89
|
+
}) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Set the search query
|
|
92
|
+
*/
|
|
93
|
+
setSearchQuery: (state: {
|
|
94
|
+
activeTab: AppState["activeTab"];
|
|
95
|
+
focusZone: FocusZone;
|
|
96
|
+
showHelp: boolean;
|
|
97
|
+
searchQuery: string;
|
|
98
|
+
sortBy: AppState["sortBy"];
|
|
99
|
+
sortOrder: AppState["sortOrder"];
|
|
100
|
+
message: string | null;
|
|
101
|
+
}, action: PayloadAction<string>) => void;
|
|
102
|
+
/**
|
|
103
|
+
* Set sort configuration
|
|
104
|
+
*/
|
|
105
|
+
setSort: (state: {
|
|
106
|
+
activeTab: AppState["activeTab"];
|
|
107
|
+
focusZone: FocusZone;
|
|
108
|
+
showHelp: boolean;
|
|
109
|
+
searchQuery: string;
|
|
110
|
+
sortBy: AppState["sortBy"];
|
|
111
|
+
sortOrder: AppState["sortOrder"];
|
|
112
|
+
message: string | null;
|
|
113
|
+
}, action: PayloadAction<{
|
|
114
|
+
by: AppState["sortBy"];
|
|
115
|
+
order: AppState["sortOrder"];
|
|
116
|
+
}>) => void;
|
|
117
|
+
/**
|
|
118
|
+
* Set a message to display to the user
|
|
119
|
+
*/
|
|
120
|
+
setMessage: (state: {
|
|
121
|
+
activeTab: AppState["activeTab"];
|
|
122
|
+
focusZone: FocusZone;
|
|
123
|
+
showHelp: boolean;
|
|
124
|
+
searchQuery: string;
|
|
125
|
+
sortBy: AppState["sortBy"];
|
|
126
|
+
sortOrder: AppState["sortOrder"];
|
|
127
|
+
message: string | null;
|
|
128
|
+
}, action: PayloadAction<string | null>) => void;
|
|
129
|
+
/**
|
|
130
|
+
* Clear the message
|
|
131
|
+
*/
|
|
132
|
+
clearMessage: (state: {
|
|
133
|
+
activeTab: AppState["activeTab"];
|
|
134
|
+
focusZone: FocusZone;
|
|
135
|
+
showHelp: boolean;
|
|
136
|
+
searchQuery: string;
|
|
137
|
+
sortBy: AppState["sortBy"];
|
|
138
|
+
sortOrder: AppState["sortOrder"];
|
|
139
|
+
message: string | null;
|
|
140
|
+
}) => void;
|
|
141
|
+
}, "ui", "ui", import("@reduxjs/toolkit").SliceSelectors<UiState>>;
|
|
142
|
+
export declare const setTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<"enabled" | "installed" | "discover" | "marketplaces" | "errors", "ui/setTab">, nextTab: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"ui/nextTab">, prevTab: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"ui/prevTab">, setFocusZone: import("@reduxjs/toolkit").ActionCreatorWithPayload<FocusZone, "ui/setFocusZone">, toggleHelp: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"ui/toggleHelp">, setSearchQuery: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "ui/setSearchQuery">, setSort: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
143
|
+
by: AppState["sortBy"];
|
|
144
|
+
order: AppState["sortOrder"];
|
|
145
|
+
}, "ui/setSort">, setMessage: import("@reduxjs/toolkit").ActionCreatorWithPayload<string | null, "ui/setMessage">, clearMessage: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"ui/clearMessage">;
|
|
146
|
+
declare const _default: import("@reduxjs/toolkit").Reducer<UiState>;
|
|
147
|
+
export default _default;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI state slice for application-wide UI state management
|
|
3
|
+
* Handles tabs, focus zones, dialogs, search, sort, and messages
|
|
4
|
+
*/
|
|
5
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
6
|
+
/**
|
|
7
|
+
* Initial UI state
|
|
8
|
+
*/
|
|
9
|
+
const initialState = {
|
|
10
|
+
activeTab: 'enabled',
|
|
11
|
+
focusZone: 'list',
|
|
12
|
+
showHelp: false,
|
|
13
|
+
searchQuery: '',
|
|
14
|
+
sortBy: 'installs',
|
|
15
|
+
sortOrder: 'desc',
|
|
16
|
+
message: null,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Get available focus zones for the current tab
|
|
20
|
+
* Errors tab has no search zone since it doesn't support filtering
|
|
21
|
+
* @param activeTab - The currently active tab
|
|
22
|
+
* @returns Array of available focus zones in navigation order
|
|
23
|
+
*/
|
|
24
|
+
export function getAvailableZones(activeTab) {
|
|
25
|
+
if (activeTab === 'errors') {
|
|
26
|
+
return ['tabbar', 'list'];
|
|
27
|
+
}
|
|
28
|
+
return ['tabbar', 'search', 'list'];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* UI slice with reducers for all UI-related state changes
|
|
32
|
+
*/
|
|
33
|
+
export const uiSlice = createSlice({
|
|
34
|
+
name: 'ui',
|
|
35
|
+
initialState,
|
|
36
|
+
reducers: {
|
|
37
|
+
/**
|
|
38
|
+
* Set the active tab and reset related state
|
|
39
|
+
*/
|
|
40
|
+
setTab: (state, action) => {
|
|
41
|
+
state.activeTab = action.payload;
|
|
42
|
+
state.focusZone = 'list';
|
|
43
|
+
state.searchQuery = '';
|
|
44
|
+
state.message = null;
|
|
45
|
+
},
|
|
46
|
+
/**
|
|
47
|
+
* Navigate to next tab
|
|
48
|
+
*/
|
|
49
|
+
nextTab: (state) => {
|
|
50
|
+
const tabs = [
|
|
51
|
+
'enabled',
|
|
52
|
+
'installed',
|
|
53
|
+
'discover',
|
|
54
|
+
'marketplaces',
|
|
55
|
+
'errors',
|
|
56
|
+
];
|
|
57
|
+
const currentIndex = tabs.indexOf(state.activeTab);
|
|
58
|
+
const nextTab = tabs[(currentIndex + 1) % tabs.length];
|
|
59
|
+
if (nextTab) {
|
|
60
|
+
state.activeTab = nextTab;
|
|
61
|
+
}
|
|
62
|
+
state.focusZone = 'list';
|
|
63
|
+
state.searchQuery = '';
|
|
64
|
+
state.message = null;
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Navigate to previous tab
|
|
68
|
+
*/
|
|
69
|
+
prevTab: (state) => {
|
|
70
|
+
const tabs = [
|
|
71
|
+
'enabled',
|
|
72
|
+
'installed',
|
|
73
|
+
'discover',
|
|
74
|
+
'marketplaces',
|
|
75
|
+
'errors',
|
|
76
|
+
];
|
|
77
|
+
const currentIndex = tabs.indexOf(state.activeTab);
|
|
78
|
+
const prevTab = tabs[(currentIndex - 1 + tabs.length) % tabs.length];
|
|
79
|
+
if (prevTab) {
|
|
80
|
+
state.activeTab = prevTab;
|
|
81
|
+
}
|
|
82
|
+
state.focusZone = 'list';
|
|
83
|
+
state.searchQuery = '';
|
|
84
|
+
state.message = null;
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* Set the focus zone
|
|
88
|
+
*/
|
|
89
|
+
setFocusZone: (state, action) => {
|
|
90
|
+
state.focusZone = action.payload;
|
|
91
|
+
},
|
|
92
|
+
/**
|
|
93
|
+
* Toggle help overlay visibility
|
|
94
|
+
*/
|
|
95
|
+
toggleHelp: (state) => {
|
|
96
|
+
state.showHelp = !state.showHelp;
|
|
97
|
+
},
|
|
98
|
+
/**
|
|
99
|
+
* Set the search query
|
|
100
|
+
*/
|
|
101
|
+
setSearchQuery: (state, action) => {
|
|
102
|
+
state.searchQuery = action.payload;
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* Set sort configuration
|
|
106
|
+
*/
|
|
107
|
+
setSort: (state, action) => {
|
|
108
|
+
state.sortBy = action.payload.by;
|
|
109
|
+
state.sortOrder = action.payload.order;
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* Set a message to display to the user
|
|
113
|
+
*/
|
|
114
|
+
setMessage: (state, action) => {
|
|
115
|
+
state.message = action.payload;
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Clear the message
|
|
119
|
+
*/
|
|
120
|
+
clearMessage: (state) => {
|
|
121
|
+
state.message = null;
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
export const { setTab, nextTab, prevTab, setFocusZone, toggleHelp, setSearchQuery, setSort, setMessage, clearMessage, } = uiSlice.actions;
|
|
126
|
+
export default uiSlice.reducer;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* DiscoverTab component
|
|
3
3
|
* Browse all available plugins from all marketplaces
|
|
4
4
|
*/
|
|
5
|
-
import type { Plugin, AppState, FocusZone } from '../types/index.js';
|
|
5
|
+
import type { Plugin, AppState, FocusZone, ComponentDetailedInfo } from '../types/index.js';
|
|
6
6
|
interface DiscoverTabProps {
|
|
7
7
|
plugins: Plugin[];
|
|
8
8
|
selectedIndex: number;
|
|
@@ -11,6 +11,12 @@ interface DiscoverTabProps {
|
|
|
11
11
|
sortOrder: AppState['sortOrder'];
|
|
12
12
|
/** Current focus zone for keyboard navigation */
|
|
13
13
|
focusZone?: FocusZone;
|
|
14
|
+
/** Whether component focus mode is active */
|
|
15
|
+
componentFocusMode?: boolean;
|
|
16
|
+
/** Currently selected component index */
|
|
17
|
+
selectedComponentIndex?: number;
|
|
18
|
+
/** Selected component's detailed info */
|
|
19
|
+
selectedComponentDetail?: ComponentDetailedInfo | null;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* Discover tab - browse all plugins
|
|
@@ -24,5 +30,5 @@ interface DiscoverTabProps {
|
|
|
24
30
|
* focusZone="list"
|
|
25
31
|
* />
|
|
26
32
|
*/
|
|
27
|
-
export default function DiscoverTab({ plugins, selectedIndex, searchQuery, sortBy, sortOrder, focusZone, }: DiscoverTabProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export default function DiscoverTab({ plugins, selectedIndex, searchQuery, sortBy, sortOrder, focusZone, componentFocusMode, selectedComponentIndex, selectedComponentDetail, }: DiscoverTabProps): import("react/jsx-runtime").JSX.Element;
|
|
28
34
|
export {};
|
package/dist/tabs/DiscoverTab.js
CHANGED
|
@@ -20,7 +20,7 @@ import SortDropdown from '../components/SortDropdown.js';
|
|
|
20
20
|
* focusZone="list"
|
|
21
21
|
* />
|
|
22
22
|
*/
|
|
23
|
-
export default function DiscoverTab({ plugins, selectedIndex, searchQuery, sortBy, sortOrder, focusZone = 'list', }) {
|
|
23
|
+
export default function DiscoverTab({ plugins, selectedIndex, searchQuery, sortBy, sortOrder, focusZone = 'list', componentFocusMode = false, selectedComponentIndex = 0, selectedComponentDetail = null, }) {
|
|
24
24
|
const selectedPlugin = plugins[selectedIndex] ?? null;
|
|
25
|
-
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsxs(Text, { bold: true, children: ["Discover plugins (", plugins.length > 0 ? `${selectedIndex + 1}/${plugins.length}` : '0', ")"] }), _jsx(Box, { flexGrow: 1 }), _jsx(SortDropdown, { sortBy: sortBy, sortOrder: sortOrder })] }), _jsx(Box, { marginBottom: 1, children: _jsx(SearchInput, { query: searchQuery, isActive: focusZone === 'search', placeholder: "Type to search..." }) }), _jsxs(Box, { flexGrow: 1, overflow: "hidden", children: [_jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginList, { plugins: plugins, selectedIndex: selectedIndex, visibleCount: 12, isFocused: focusZone === 'list' }) }), _jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginDetail, { plugin: selectedPlugin }, selectedPlugin?.id ?? 'none') })] })] }));
|
|
25
|
+
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsxs(Text, { bold: true, children: ["Discover plugins (", plugins.length > 0 ? `${selectedIndex + 1}/${plugins.length}` : '0', ")"] }), _jsx(Box, { flexGrow: 1 }), _jsx(SortDropdown, { sortBy: sortBy, sortOrder: sortOrder })] }), _jsx(Box, { marginBottom: 1, children: _jsx(SearchInput, { query: searchQuery, isActive: focusZone === 'search', placeholder: "Type to search..." }) }), _jsxs(Box, { flexGrow: 1, overflow: "hidden", children: [_jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginList, { plugins: plugins, selectedIndex: selectedIndex, visibleCount: 12, isFocused: focusZone === 'list' }) }), _jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginDetail, { plugin: selectedPlugin, componentFocusMode: componentFocusMode, selectedComponentIndex: selectedComponentIndex, selectedComponentDetail: selectedComponentDetail }, selectedPlugin?.id ?? 'none') })] })] }));
|
|
26
26
|
}
|
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
* EnabledTab component
|
|
3
3
|
* View and manage enabled plugins (installed + enabled)
|
|
4
4
|
*/
|
|
5
|
-
import type { Plugin, FocusZone } from '../types/index.js';
|
|
5
|
+
import type { Plugin, FocusZone, ComponentDetailedInfo } from '../types/index.js';
|
|
6
6
|
interface EnabledTabProps {
|
|
7
7
|
plugins: Plugin[];
|
|
8
8
|
selectedIndex: number;
|
|
9
9
|
searchQuery?: string;
|
|
10
10
|
/** Current focus zone for keyboard navigation */
|
|
11
11
|
focusZone?: FocusZone;
|
|
12
|
+
/** Whether component focus mode is active */
|
|
13
|
+
componentFocusMode?: boolean;
|
|
14
|
+
/** Currently selected component index */
|
|
15
|
+
selectedComponentIndex?: number;
|
|
16
|
+
/** Selected component's detailed info */
|
|
17
|
+
selectedComponentDetail?: ComponentDetailedInfo | null;
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* Enabled tab - view currently active plugins
|
|
@@ -20,5 +26,5 @@ interface EnabledTabProps {
|
|
|
20
26
|
* @example
|
|
21
27
|
* <EnabledTab plugins={enabledPlugins} selectedIndex={0} searchQuery="" focusZone="list" />
|
|
22
28
|
*/
|
|
23
|
-
export default function EnabledTab({ plugins, selectedIndex, searchQuery, focusZone, }: EnabledTabProps): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export default function EnabledTab({ plugins, selectedIndex, searchQuery, focusZone, componentFocusMode, selectedComponentIndex, selectedComponentDetail, }: EnabledTabProps): import("react/jsx-runtime").JSX.Element;
|
|
24
30
|
export {};
|
package/dist/tabs/EnabledTab.js
CHANGED
|
@@ -17,10 +17,10 @@ import SearchInput from '../components/SearchInput.js';
|
|
|
17
17
|
* @example
|
|
18
18
|
* <EnabledTab plugins={enabledPlugins} selectedIndex={0} searchQuery="" focusZone="list" />
|
|
19
19
|
*/
|
|
20
|
-
export default function EnabledTab({ plugins, selectedIndex, searchQuery = '', focusZone = 'list', }) {
|
|
20
|
+
export default function EnabledTab({ plugins, selectedIndex, searchQuery = '', focusZone = 'list', componentFocusMode = false, selectedComponentIndex = 0, selectedComponentDetail = null, }) {
|
|
21
21
|
// Plugins are already filtered by parent, use directly
|
|
22
22
|
const selectedPlugin = plugins[selectedIndex] ?? null;
|
|
23
23
|
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsxs(Text, { bold: true, children: ["Enabled plugins (", plugins.length > 0 ? `${selectedIndex + 1}/${plugins.length}` : '0', ")"] }), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { dimColor: true, children: "Currently active in Claude Code" })] }), _jsx(Box, { marginBottom: 1, children: _jsx(SearchInput, { query: searchQuery, isActive: focusZone === 'search', placeholder: "Type to search enabled plugins..." }) }), _jsxs(Box, { flexGrow: 1, overflow: "hidden", children: [_jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: plugins.length === 0 ? (_jsxs(Box, { padding: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: searchQuery ? 'No matching plugins' : 'No enabled plugins' }), _jsx(Text, { dimColor: true, children: searchQuery
|
|
24
24
|
? 'Try a different search term'
|
|
25
|
-
: 'Enable plugins in the Installed tab or use /plugin enable' })] })) : (_jsx(PluginList, { plugins: plugins, selectedIndex: selectedIndex, visibleCount: 12, isFocused: focusZone === 'list' })) }), _jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginDetail, { plugin: selectedPlugin }, selectedPlugin?.id ?? 'none') })] })] }));
|
|
25
|
+
: 'Enable plugins in the Installed tab or use /plugin enable' })] })) : (_jsx(PluginList, { plugins: plugins, selectedIndex: selectedIndex, visibleCount: 12, isFocused: focusZone === 'list' })) }), _jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginDetail, { plugin: selectedPlugin, componentFocusMode: componentFocusMode, selectedComponentIndex: selectedComponentIndex, selectedComponentDetail: selectedComponentDetail }, selectedPlugin?.id ?? 'none') })] })] }));
|
|
26
26
|
}
|
package/dist/tabs/ErrorsTab.js
CHANGED
|
@@ -16,7 +16,7 @@ export default function ErrorsTab({ errors, selectedIndex }) {
|
|
|
16
16
|
const selectedError = errors[selectedIndex] ?? null;
|
|
17
17
|
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsx(Box, { marginBottom: 1, gap: 2, children: _jsxs(Text, { bold: true, color: "red", children: ["Errors (", errors.length > 0 ? `${selectedIndex + 1}/${errors.length}` : '0', ")"] }) }), _jsxs(Box, { flexGrow: 1, children: [_jsx(Box, { width: "50%", flexDirection: "column", children: errors.map((error, index) => {
|
|
18
18
|
const isSelected = index === selectedIndex;
|
|
19
|
-
return (_jsxs(Box, { paddingX: 1, children: [_jsx(Box, { width: 2, children: isSelected ? (_jsx(Text, { color: "cyan", children: '>' })) : (_jsx(Text, { children: " " })) }), _jsx(Box, { width: 2, children: _jsx(Text, { color: "red", children: "\u2717" }) }), _jsxs(Box, { flexGrow: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, color: isSelected ? 'cyan' : 'white', children: error.pluginId }), _jsx(Text, { dimColor: true, wrap: "truncate", children: error.message })] })] }, `${error.pluginId}-${index}`));
|
|
19
|
+
return (_jsxs(Box, { paddingX: 1, children: [_jsx(Box, { width: 2, children: isSelected ? (_jsx(Text, { color: "cyan", children: '>' })) : (_jsx(Text, { children: " " })) }), _jsx(Box, { width: 2, children: _jsx(Text, { color: "red", children: "\u2717" }) }), _jsxs(Box, { flexGrow: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, color: isSelected ? 'cyan' : 'white', children: error.pluginId }), _jsx(Text, { dimColor: true, wrap: "truncate", children: error.message })] })] }, `${error.pluginId}-${error.type}-${error.timestamp}-${index}`));
|
|
20
20
|
}) }), _jsx(Box, { width: "50%", flexDirection: "column", children: selectedError ? (_jsxs(Box, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "red", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "red", children: selectedError.pluginId }) }), _jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "gray", children: "Type:" }), _jsx(Text, { children: selectedError.type })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "gray", children: "Time:" }), _jsx(Text, { children: formatDate(selectedError.timestamp) })] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "Message:" }), _jsx(Text, { wrap: "wrap", children: selectedError.message })] }), selectedError.details && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "Details:" }), _jsx(Text, { dimColor: true, wrap: "wrap", children: selectedError.details })] }))] })) : (_jsx(Box, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "gray", children: _jsx(Text, { dimColor: true, children: "Select an error to view details" }) })) })] })] }));
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
* InstalledTab component
|
|
3
3
|
* View and manage installed plugins
|
|
4
4
|
*/
|
|
5
|
-
import type { Plugin, FocusZone } from '../types/index.js';
|
|
5
|
+
import type { Plugin, FocusZone, ComponentDetailedInfo } from '../types/index.js';
|
|
6
6
|
interface InstalledTabProps {
|
|
7
7
|
plugins: Plugin[];
|
|
8
8
|
selectedIndex: number;
|
|
9
9
|
searchQuery?: string;
|
|
10
10
|
/** Current focus zone for keyboard navigation */
|
|
11
11
|
focusZone?: FocusZone;
|
|
12
|
+
/** Whether component focus mode is active */
|
|
13
|
+
componentFocusMode?: boolean;
|
|
14
|
+
/** Currently selected component index */
|
|
15
|
+
selectedComponentIndex?: number;
|
|
16
|
+
/** Selected component's detailed info */
|
|
17
|
+
selectedComponentDetail?: ComponentDetailedInfo | null;
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* Installed tab - manage installed plugins
|
|
@@ -19,5 +25,5 @@ interface InstalledTabProps {
|
|
|
19
25
|
* @example
|
|
20
26
|
* <InstalledTab plugins={installedPlugins} selectedIndex={0} searchQuery="" focusZone="list" />
|
|
21
27
|
*/
|
|
22
|
-
export default function InstalledTab({ plugins, selectedIndex, searchQuery, focusZone, }: InstalledTabProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export default function InstalledTab({ plugins, selectedIndex, searchQuery, focusZone, componentFocusMode, selectedComponentIndex, selectedComponentDetail, }: InstalledTabProps): import("react/jsx-runtime").JSX.Element;
|
|
23
29
|
export {};
|
|
@@ -16,7 +16,7 @@ import SearchInput from '../components/SearchInput.js';
|
|
|
16
16
|
* @example
|
|
17
17
|
* <InstalledTab plugins={installedPlugins} selectedIndex={0} searchQuery="" focusZone="list" />
|
|
18
18
|
*/
|
|
19
|
-
export default function InstalledTab({ plugins, selectedIndex, searchQuery = '', focusZone = 'list', }) {
|
|
19
|
+
export default function InstalledTab({ plugins, selectedIndex, searchQuery = '', focusZone = 'list', componentFocusMode = false, selectedComponentIndex = 0, selectedComponentDetail = null, }) {
|
|
20
20
|
// Plugins are already filtered by parent, use directly
|
|
21
21
|
const selectedPlugin = plugins[selectedIndex] ?? null;
|
|
22
22
|
// Count enabled/disabled
|
|
@@ -24,5 +24,5 @@ export default function InstalledTab({ plugins, selectedIndex, searchQuery = '',
|
|
|
24
24
|
const disabledCount = plugins.length - enabledCount;
|
|
25
25
|
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsxs(Text, { bold: true, children: ["Installed plugins (", plugins.length > 0 ? `${selectedIndex + 1}/${plugins.length}` : '0', ")"] }), _jsx(Box, { flexGrow: 1 }), _jsxs(Box, { gap: 2, children: [_jsxs(Text, { color: "green", children: ["\u25CF ", enabledCount, " enabled"] }), _jsxs(Text, { color: "yellow", children: ["\u25D0 ", disabledCount, " disabled"] })] })] }), _jsx(Box, { marginBottom: 1, children: _jsx(SearchInput, { query: searchQuery, isActive: focusZone === 'search', placeholder: "Type to search installed plugins..." }) }), _jsxs(Box, { flexGrow: 1, overflow: "hidden", children: [_jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: plugins.length === 0 ? (_jsxs(Box, { padding: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: searchQuery ? 'No matching plugins' : 'No plugins installed' }), _jsx(Text, { dimColor: true, children: searchQuery
|
|
26
26
|
? 'Try a different search term'
|
|
27
|
-
: 'Use the Discover tab or /plugin install in Claude Code' })] })) : (_jsx(PluginList, { plugins: plugins, selectedIndex: selectedIndex, visibleCount: 12, isFocused: focusZone === 'list' })) }), _jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginDetail, { plugin: selectedPlugin }, selectedPlugin?.id ?? 'none') })] })] }));
|
|
27
|
+
: 'Use the Discover tab or /plugin install in Claude Code' })] })) : (_jsx(PluginList, { plugins: plugins, selectedIndex: selectedIndex, visibleCount: 12, isFocused: focusZone === 'list' })) }), _jsx(Box, { width: "50%", flexDirection: "column", overflow: "hidden", children: _jsx(PluginDetail, { plugin: selectedPlugin, componentFocusMode: componentFocusMode, selectedComponentIndex: selectedComponentIndex, selectedComponentDetail: selectedComponentDetail }, selectedPlugin?.id ?? 'none') })] })] }));
|
|
28
28
|
}
|