@terasky/backstage-plugin-ai-rules 1.6.0 → 1.8.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/config.d.ts +11 -9
- package/dist/alpha.esm.js +30 -0
- package/dist/alpha.esm.js.map +1 -1
- package/dist/api/AiRulesClient.esm.js +27 -19
- package/dist/api/AiRulesClient.esm.js.map +1 -1
- package/dist/api/types.esm.js.map +1 -1
- package/dist/components/AgentConfigsComponent/AgentConfigsComponent.esm.js +91 -0
- package/dist/components/AgentConfigsComponent/AgentConfigsComponent.esm.js.map +1 -0
- package/dist/components/AgentSkillsComponent/AgentSkillsComponent.esm.js +225 -0
- package/dist/components/AgentSkillsComponent/AgentSkillsComponent.esm.js.map +1 -0
- package/dist/components/AiInstructionsComponent/AiInstructionsComponent.esm.js +13 -3
- package/dist/components/AiInstructionsComponent/AiInstructionsComponent.esm.js.map +1 -1
- package/dist/components/AiRulesComponent/AiRulesComponent.esm.js +327 -248
- package/dist/components/AiRulesComponent/AiRulesComponent.esm.js.map +1 -1
- package/dist/components/IgnoreFilesComponent/IgnoreFilesComponent.esm.js +86 -0
- package/dist/components/IgnoreFilesComponent/IgnoreFilesComponent.esm.js.map +1 -0
- package/dist/components/MCPServersComponent/MCPServersComponent.esm.js +5 -1
- package/dist/components/MCPServersComponent/MCPServersComponent.esm.js.map +1 -1
- package/dist/hooks/useAgentConfigs.esm.js +38 -0
- package/dist/hooks/useAgentConfigs.esm.js.map +1 -0
- package/dist/hooks/useAiRules.esm.js +13 -1
- package/dist/hooks/useAiRules.esm.js.map +1 -1
- package/dist/hooks/useIgnoreFiles.esm.js +38 -0
- package/dist/hooks/useIgnoreFiles.esm.js.map +1 -0
- package/dist/hooks/useSkills.esm.js +38 -0
- package/dist/hooks/useSkills.esm.js.map +1 -0
- package/dist/index.d.ts +142 -5
- package/dist/index.esm.js +3 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/plugin.esm.js +24 -0
- package/dist/plugin.esm.js.map +1 -1
- package/dist/types.esm.js +7 -0
- package/dist/types.esm.js.map +1 -1
- package/package.json +11 -11
|
@@ -1,23 +1,64 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useMemo, useCallback } from 'react';
|
|
2
3
|
import { useAiRules } from '../../hooks/useAiRules.esm.js';
|
|
3
|
-
import { InfoCard, Progress, EmptyState, MarkdownContent } from '@backstage/core-components';
|
|
4
|
-
import {
|
|
4
|
+
import { InfoCard, Progress, EmptyState, MarkdownContent, CodeSnippet } from '@backstage/core-components';
|
|
5
|
+
import { Typography, FormControlLabel, Checkbox, Button, TextField, Card, CardContent, Tooltip, makeStyles, useTheme, Accordion, AccordionSummary, Chip, IconButton, AccordionDetails, Snackbar } from '@material-ui/core';
|
|
6
|
+
import { ToggleButtonGroup, ToggleButton } from '@material-ui/lab';
|
|
5
7
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
6
8
|
import CodeIcon from '@material-ui/icons/Code';
|
|
7
9
|
import LaunchIcon from '@material-ui/icons/Launch';
|
|
10
|
+
import FileCopyIcon from '@material-ui/icons/FileCopy';
|
|
11
|
+
import GetAppIcon from '@material-ui/icons/GetApp';
|
|
8
12
|
import { AIRuleType } from '../../types.esm.js';
|
|
9
13
|
|
|
10
14
|
const isAIRulesAvailable = (entity) => {
|
|
11
15
|
const sourceAnnotation = entity.metadata?.annotations?.["backstage.io/source-location"] || "";
|
|
12
16
|
return sourceAnnotation.startsWith("url:");
|
|
13
17
|
};
|
|
18
|
+
const RULE_TYPE_COLORS = {
|
|
19
|
+
[AIRuleType.CURSOR]: "#0066CC",
|
|
20
|
+
[AIRuleType.COPILOT]: "#6F42C1",
|
|
21
|
+
[AIRuleType.CLINE]: "#28A745",
|
|
22
|
+
[AIRuleType.CLAUDE_CODE]: "#FF6B35",
|
|
23
|
+
[AIRuleType.WINDSURF]: "#00B4D8",
|
|
24
|
+
[AIRuleType.ROO_CODE]: "#6610F2",
|
|
25
|
+
[AIRuleType.CODEX]: "#10A37F",
|
|
26
|
+
[AIRuleType.GEMINI]: "#4285F4",
|
|
27
|
+
[AIRuleType.AMAZON_Q]: "#FF9900",
|
|
28
|
+
[AIRuleType.CONTINUE]: "#1A73E8",
|
|
29
|
+
[AIRuleType.AIDER]: "#E83E8C"
|
|
30
|
+
};
|
|
31
|
+
const RULE_TYPE_DISPLAY_NAMES = {
|
|
32
|
+
[AIRuleType.CURSOR]: "Cursor",
|
|
33
|
+
[AIRuleType.COPILOT]: "Copilot",
|
|
34
|
+
[AIRuleType.CLINE]: "Cline",
|
|
35
|
+
[AIRuleType.CLAUDE_CODE]: "Claude Code",
|
|
36
|
+
[AIRuleType.WINDSURF]: "Windsurf",
|
|
37
|
+
[AIRuleType.ROO_CODE]: "Roo Code",
|
|
38
|
+
[AIRuleType.CODEX]: "OpenAI Codex",
|
|
39
|
+
[AIRuleType.GEMINI]: "Gemini CLI",
|
|
40
|
+
[AIRuleType.AMAZON_Q]: "Amazon Q",
|
|
41
|
+
[AIRuleType.CONTINUE]: "Continue",
|
|
42
|
+
[AIRuleType.AIDER]: "Aider"
|
|
43
|
+
};
|
|
44
|
+
const RULE_TYPE_DISPLAY_ORDER = [
|
|
45
|
+
AIRuleType.CURSOR,
|
|
46
|
+
AIRuleType.CLAUDE_CODE,
|
|
47
|
+
AIRuleType.COPILOT,
|
|
48
|
+
AIRuleType.CLINE,
|
|
49
|
+
AIRuleType.WINDSURF,
|
|
50
|
+
AIRuleType.ROO_CODE,
|
|
51
|
+
AIRuleType.CODEX,
|
|
52
|
+
AIRuleType.GEMINI,
|
|
53
|
+
AIRuleType.AMAZON_Q,
|
|
54
|
+
AIRuleType.CONTINUE,
|
|
55
|
+
AIRuleType.AIDER
|
|
56
|
+
];
|
|
14
57
|
const useStyles = makeStyles((theme) => ({
|
|
15
58
|
root: {
|
|
16
59
|
"& .MuiAccordion-root": {
|
|
17
60
|
marginBottom: theme.spacing(1),
|
|
18
|
-
"&:before": {
|
|
19
|
-
display: "none"
|
|
20
|
-
}
|
|
61
|
+
"&:before": { display: "none" }
|
|
21
62
|
}
|
|
22
63
|
},
|
|
23
64
|
filterSection: {
|
|
@@ -26,6 +67,10 @@ const useStyles = makeStyles((theme) => ({
|
|
|
26
67
|
backgroundColor: theme.palette.background.default,
|
|
27
68
|
borderRadius: theme.shape.borderRadius
|
|
28
69
|
},
|
|
70
|
+
searchBar: {
|
|
71
|
+
marginBottom: theme.spacing(2),
|
|
72
|
+
width: "100%"
|
|
73
|
+
},
|
|
29
74
|
ruleCard: {
|
|
30
75
|
marginBottom: theme.spacing(1),
|
|
31
76
|
border: `1px solid ${theme.palette.divider}`
|
|
@@ -40,7 +85,14 @@ const useStyles = makeStyles((theme) => ({
|
|
|
40
85
|
display: "flex",
|
|
41
86
|
alignItems: "center",
|
|
42
87
|
gap: theme.spacing(1),
|
|
43
|
-
flex: 1
|
|
88
|
+
flex: 1,
|
|
89
|
+
overflow: "hidden"
|
|
90
|
+
},
|
|
91
|
+
ruleHeaderActions: {
|
|
92
|
+
display: "flex",
|
|
93
|
+
alignItems: "center",
|
|
94
|
+
gap: theme.spacing(0.5),
|
|
95
|
+
flexShrink: 0
|
|
44
96
|
},
|
|
45
97
|
ruleType: {
|
|
46
98
|
textTransform: "uppercase",
|
|
@@ -52,9 +104,7 @@ const useStyles = makeStyles((theme) => ({
|
|
|
52
104
|
borderRadius: theme.shape.borderRadius,
|
|
53
105
|
overflow: "auto",
|
|
54
106
|
maxHeight: "300px",
|
|
55
|
-
"& > *": {
|
|
56
|
-
backgroundColor: "transparent !important"
|
|
57
|
-
}
|
|
107
|
+
"& > *": { backgroundColor: "transparent !important" }
|
|
58
108
|
},
|
|
59
109
|
ruleMetadata: {
|
|
60
110
|
display: "flex",
|
|
@@ -64,88 +114,34 @@ const useStyles = makeStyles((theme) => ({
|
|
|
64
114
|
},
|
|
65
115
|
statsContainer: {
|
|
66
116
|
display: "flex",
|
|
117
|
+
flexWrap: "wrap",
|
|
67
118
|
gap: theme.spacing(2),
|
|
68
|
-
marginBottom: theme.spacing(2)
|
|
119
|
+
marginBottom: theme.spacing(2),
|
|
120
|
+
alignItems: "center"
|
|
69
121
|
},
|
|
70
122
|
statCard: {
|
|
71
|
-
minWidth: "
|
|
123
|
+
minWidth: "100px",
|
|
72
124
|
textAlign: "center"
|
|
73
125
|
},
|
|
74
|
-
emptyStateIcon: {
|
|
75
|
-
fontSize: "4rem",
|
|
76
|
-
color: theme.palette.grey[400]
|
|
77
|
-
},
|
|
78
126
|
filterContainer: {
|
|
79
127
|
display: "flex",
|
|
80
128
|
flexWrap: "wrap",
|
|
81
|
-
"& > *": {
|
|
82
|
-
marginRight: theme.spacing(1)
|
|
83
|
-
}
|
|
129
|
+
"& > *": { marginRight: theme.spacing(1) }
|
|
84
130
|
},
|
|
85
131
|
applyFilterButton: {
|
|
86
132
|
marginTop: theme.spacing(1)
|
|
133
|
+
},
|
|
134
|
+
viewToggle: {
|
|
135
|
+
marginBottom: theme.spacing(1)
|
|
136
|
+
},
|
|
137
|
+
exportButton: {
|
|
138
|
+
marginLeft: "auto"
|
|
87
139
|
}
|
|
88
140
|
}));
|
|
89
|
-
const
|
|
90
|
-
const colors = {
|
|
91
|
-
[AIRuleType.CURSOR]: "#0066CC",
|
|
92
|
-
[AIRuleType.COPILOT]: "#6F42C1",
|
|
93
|
-
[AIRuleType.CLINE]: "#28A745",
|
|
94
|
-
[AIRuleType.CLAUDE_CODE]: "#FF6B35"
|
|
95
|
-
};
|
|
96
|
-
return /* @__PURE__ */ jsx(CodeIcon, { style: { color: colors[type] } });
|
|
97
|
-
};
|
|
98
|
-
const renderFrontmatter = (theme, frontmatter) => {
|
|
99
|
-
if (!frontmatter || Object.keys(frontmatter).length === 0) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
const filteredEntries = Object.entries(frontmatter).filter(
|
|
103
|
-
([key]) => !["description", "globs"].includes(key)
|
|
104
|
-
);
|
|
105
|
-
if (filteredEntries.length === 0) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
return /* @__PURE__ */ jsxs("div", { style: {
|
|
109
|
-
marginBottom: "16px",
|
|
110
|
-
padding: "16px",
|
|
111
|
-
backgroundColor: theme.palette.type === "dark" ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)",
|
|
112
|
-
borderRadius: "8px",
|
|
113
|
-
border: `1px solid ${theme.palette.type === "dark" ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.12)"}`
|
|
114
|
-
}, children: [
|
|
115
|
-
/* @__PURE__ */ jsx(Typography, { variant: "subtitle2", style: {
|
|
116
|
-
marginBottom: "12px",
|
|
117
|
-
fontWeight: "bold",
|
|
118
|
-
color: theme.palette.text.secondary,
|
|
119
|
-
textTransform: "uppercase",
|
|
120
|
-
letterSpacing: "0.5px"
|
|
121
|
-
}, children: "Metadata" }),
|
|
122
|
-
filteredEntries.map(([key, value], index) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: index < filteredEntries.length - 1 ? "12px" : "0" }, children: [
|
|
123
|
-
/* @__PURE__ */ jsxs(Typography, { variant: "body2", style: {
|
|
124
|
-
fontWeight: "bold",
|
|
125
|
-
textTransform: "capitalize",
|
|
126
|
-
color: theme.palette.primary.main,
|
|
127
|
-
marginBottom: "4px"
|
|
128
|
-
}, children: [
|
|
129
|
-
key,
|
|
130
|
-
":"
|
|
131
|
-
] }),
|
|
132
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", style: {
|
|
133
|
-
lineHeight: "1.5",
|
|
134
|
-
marginLeft: "8px",
|
|
135
|
-
color: theme.palette.text.primary
|
|
136
|
-
}, children: Array.isArray(value) ? value.join(", ") : String(value) })
|
|
137
|
-
] }, key))
|
|
138
|
-
] });
|
|
139
|
-
};
|
|
140
|
-
const parseCursorContent = (content) => {
|
|
141
|
-
return manualParseFrontmatter(content);
|
|
142
|
-
};
|
|
141
|
+
const parseCursorContent = (content) => manualParseFrontmatter(content);
|
|
143
142
|
const manualParseFrontmatter = (content) => {
|
|
144
143
|
if (!content.trim().startsWith("---")) {
|
|
145
|
-
return {
|
|
146
|
-
frontmatter: void 0,
|
|
147
|
-
content
|
|
148
|
-
};
|
|
144
|
+
return { frontmatter: void 0, content };
|
|
149
145
|
}
|
|
150
146
|
try {
|
|
151
147
|
const lines = content.split("\n");
|
|
@@ -156,12 +152,7 @@ const manualParseFrontmatter = (content) => {
|
|
|
156
152
|
break;
|
|
157
153
|
}
|
|
158
154
|
}
|
|
159
|
-
if (frontmatterEndIndex === -1) {
|
|
160
|
-
return {
|
|
161
|
-
frontmatter: void 0,
|
|
162
|
-
content
|
|
163
|
-
};
|
|
164
|
-
}
|
|
155
|
+
if (frontmatterEndIndex === -1) return { frontmatter: void 0, content };
|
|
165
156
|
const frontmatterLines = lines.slice(1, frontmatterEndIndex);
|
|
166
157
|
const contentLines = lines.slice(frontmatterEndIndex + 1);
|
|
167
158
|
const frontmatter = {};
|
|
@@ -178,143 +169,207 @@ const manualParseFrontmatter = (content) => {
|
|
|
178
169
|
frontmatter: Object.keys(frontmatter).length > 0 ? frontmatter : void 0,
|
|
179
170
|
content: contentLines.join("\n").trim()
|
|
180
171
|
};
|
|
181
|
-
} catch (
|
|
182
|
-
return {
|
|
183
|
-
frontmatter: void 0,
|
|
184
|
-
content
|
|
185
|
-
};
|
|
172
|
+
} catch (_e) {
|
|
173
|
+
return { frontmatter: void 0, content };
|
|
186
174
|
}
|
|
187
175
|
};
|
|
188
176
|
const constructFileUrl = (gitUrl, filePath) => {
|
|
189
177
|
const cleanGitUrl = gitUrl.replace(/\/+$/, "");
|
|
190
|
-
if (cleanGitUrl.includes("github.com")) {
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
if (cleanGitUrl.includes("gitlab.com")) {
|
|
194
|
-
return `${cleanGitUrl}/-/blob/main/${filePath}`;
|
|
195
|
-
}
|
|
178
|
+
if (cleanGitUrl.includes("github.com")) return `${cleanGitUrl}/blob/main/${filePath}`;
|
|
179
|
+
if (cleanGitUrl.includes("gitlab.com")) return `${cleanGitUrl}/-/blob/main/${filePath}`;
|
|
196
180
|
return `${cleanGitUrl}/blob/main/${filePath}`;
|
|
197
181
|
};
|
|
182
|
+
const RuleTypeIcon = ({ type }) => /* @__PURE__ */ jsx(CodeIcon, { style: { color: RULE_TYPE_COLORS[type] ?? "#888", flexShrink: 0 } });
|
|
183
|
+
const renderFrontmatter = (theme, frontmatter) => {
|
|
184
|
+
if (!frontmatter || Object.keys(frontmatter).length === 0) return null;
|
|
185
|
+
const filteredEntries = Object.entries(frontmatter).filter(
|
|
186
|
+
([key]) => !["description", "globs"].includes(key)
|
|
187
|
+
);
|
|
188
|
+
if (filteredEntries.length === 0) return null;
|
|
189
|
+
return /* @__PURE__ */ jsxs("div", { style: {
|
|
190
|
+
marginBottom: 16,
|
|
191
|
+
padding: 16,
|
|
192
|
+
backgroundColor: theme.palette.type === "dark" ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)",
|
|
193
|
+
borderRadius: 8,
|
|
194
|
+
border: `1px solid ${theme.palette.type === "dark" ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.12)"}`
|
|
195
|
+
}, children: [
|
|
196
|
+
/* @__PURE__ */ jsx(Typography, { variant: "subtitle2", style: { marginBottom: 12, fontWeight: "bold", color: theme.palette.text.secondary, textTransform: "uppercase", letterSpacing: "0.5px" }, children: "Metadata" }),
|
|
197
|
+
filteredEntries.map(([key, value], index) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: index < filteredEntries.length - 1 ? 12 : 0 }, children: [
|
|
198
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body2", style: { fontWeight: "bold", textTransform: "capitalize", color: theme.palette.primary.main, marginBottom: 4 }, children: [
|
|
199
|
+
key,
|
|
200
|
+
":"
|
|
201
|
+
] }),
|
|
202
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", style: { lineHeight: "1.5", marginLeft: 8, color: theme.palette.text.primary }, children: Array.isArray(value) ? value.join(", ") : String(value) })
|
|
203
|
+
] }, key))
|
|
204
|
+
] });
|
|
205
|
+
};
|
|
206
|
+
const RuleContentViewer = ({ content }) => {
|
|
207
|
+
const styles = useStyles();
|
|
208
|
+
const [view, setView] = useState("rendered");
|
|
209
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
210
|
+
/* @__PURE__ */ jsxs(
|
|
211
|
+
ToggleButtonGroup,
|
|
212
|
+
{
|
|
213
|
+
size: "small",
|
|
214
|
+
value: view,
|
|
215
|
+
exclusive: true,
|
|
216
|
+
onChange: (_e, v) => {
|
|
217
|
+
if (v) setView(v);
|
|
218
|
+
},
|
|
219
|
+
className: styles.viewToggle,
|
|
220
|
+
children: [
|
|
221
|
+
/* @__PURE__ */ jsx(ToggleButton, { value: "rendered", children: "Rendered" }),
|
|
222
|
+
/* @__PURE__ */ jsx(ToggleButton, { value: "raw", children: "Raw" })
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
),
|
|
226
|
+
view === "rendered" ? /* @__PURE__ */ jsx("div", { className: styles.ruleContent, children: /* @__PURE__ */ jsx(MarkdownContent, { content }) }) : /* @__PURE__ */ jsx(CodeSnippet, { text: content, language: "markdown" })
|
|
227
|
+
] });
|
|
228
|
+
};
|
|
229
|
+
const CopyButton = ({ content }) => {
|
|
230
|
+
const [open, setOpen] = useState(false);
|
|
231
|
+
const handleCopy = useCallback((e) => {
|
|
232
|
+
e.stopPropagation();
|
|
233
|
+
navigator.clipboard.writeText(content).then(() => setOpen(true));
|
|
234
|
+
}, [content]);
|
|
235
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
236
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Copy content", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: handleCopy, children: /* @__PURE__ */ jsx(FileCopyIcon, { fontSize: "small" }) }) }),
|
|
237
|
+
/* @__PURE__ */ jsx(
|
|
238
|
+
Snackbar,
|
|
239
|
+
{
|
|
240
|
+
open,
|
|
241
|
+
autoHideDuration: 2e3,
|
|
242
|
+
onClose: () => setOpen(false),
|
|
243
|
+
message: "Copied to clipboard",
|
|
244
|
+
anchorOrigin: { vertical: "bottom", horizontal: "center" }
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
] });
|
|
248
|
+
};
|
|
249
|
+
const GenericRuleAccordion = ({
|
|
250
|
+
rule,
|
|
251
|
+
label
|
|
252
|
+
}) => {
|
|
253
|
+
const styles = useStyles();
|
|
254
|
+
const theme = useTheme();
|
|
255
|
+
return /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
|
|
256
|
+
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
|
|
257
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
|
|
258
|
+
/* @__PURE__ */ jsx(RuleTypeIcon, { type: rule.type }),
|
|
259
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: rule.title || rule.fileName }),
|
|
260
|
+
/* @__PURE__ */ jsx(Chip, { label: label ?? rule.type, size: "small", className: styles.ruleType }),
|
|
261
|
+
rule.mode && /* @__PURE__ */ jsx(Chip, { label: `Mode: ${rule.mode}`, size: "small", variant: "outlined" }),
|
|
262
|
+
rule.alwaysApply !== void 0 && /* @__PURE__ */ jsx(Chip, { label: rule.alwaysApply ? "Always Apply" : "On Demand", size: "small", variant: "outlined" }),
|
|
263
|
+
rule.applyTo && /* @__PURE__ */ jsx(Chip, { label: `Applies to: ${rule.applyTo}`, size: "small", variant: "outlined" })
|
|
264
|
+
] }),
|
|
265
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderActions, children: [
|
|
266
|
+
/* @__PURE__ */ jsx(CopyButton, { content: rule.content }),
|
|
267
|
+
rule.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: (e) => {
|
|
268
|
+
e.stopPropagation();
|
|
269
|
+
window.open(constructFileUrl(rule.gitUrl, rule.filePath), "_blank");
|
|
270
|
+
}, children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" }) }) })
|
|
271
|
+
] })
|
|
272
|
+
] }) }),
|
|
273
|
+
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
274
|
+
/* @__PURE__ */ jsx("div", { className: styles.ruleMetadata, children: /* @__PURE__ */ jsx(Chip, { label: `Path: ${rule.filePath}`, size: "small", variant: "outlined" }) }),
|
|
275
|
+
rule.frontmatter && renderFrontmatter(theme, rule.frontmatter),
|
|
276
|
+
/* @__PURE__ */ jsx(RuleContentViewer, { content: rule.content })
|
|
277
|
+
] }) })
|
|
278
|
+
] });
|
|
279
|
+
};
|
|
198
280
|
const RuleComponent = ({ rule }) => {
|
|
199
281
|
const styles = useStyles();
|
|
200
282
|
const theme = useTheme();
|
|
201
|
-
const renderCursorRule = (
|
|
202
|
-
const { frontmatter, content } = parseCursorContent(
|
|
283
|
+
const renderCursorRule = (r) => {
|
|
284
|
+
const { frontmatter, content } = parseCursorContent(r.content);
|
|
203
285
|
return /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
|
|
204
286
|
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
|
|
205
287
|
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
|
|
206
|
-
/* @__PURE__ */ jsx(RuleTypeIcon, { type:
|
|
207
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h6", children:
|
|
208
|
-
/* @__PURE__ */ jsx(Chip, { label:
|
|
288
|
+
/* @__PURE__ */ jsx(RuleTypeIcon, { type: r.type }),
|
|
289
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: r.fileName }),
|
|
290
|
+
/* @__PURE__ */ jsx(Chip, { label: r.type, size: "small", className: styles.ruleType }),
|
|
209
291
|
frontmatter?.description && /* @__PURE__ */ jsx(Typography, { variant: "body2", style: { marginLeft: 8, color: theme.palette.text.secondary }, children: frontmatter.description })
|
|
210
292
|
] }),
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
{
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
},
|
|
219
|
-
children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" })
|
|
220
|
-
}
|
|
221
|
-
) })
|
|
293
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderActions, children: [
|
|
294
|
+
/* @__PURE__ */ jsx(CopyButton, { content }),
|
|
295
|
+
r.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: (e) => {
|
|
296
|
+
e.stopPropagation();
|
|
297
|
+
window.open(constructFileUrl(r.gitUrl, r.filePath), "_blank");
|
|
298
|
+
}, children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" }) }) })
|
|
299
|
+
] })
|
|
222
300
|
] }) }),
|
|
223
301
|
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
224
302
|
/* @__PURE__ */ jsxs("div", { className: styles.ruleMetadata, children: [
|
|
225
|
-
/* @__PURE__ */ jsx(Chip, { label: `Path: ${
|
|
303
|
+
/* @__PURE__ */ jsx(Chip, { label: `Path: ${r.filePath}`, size: "small", variant: "outlined" }),
|
|
226
304
|
frontmatter?.globs && /* @__PURE__ */ jsx(Chip, { label: `Globs: ${Array.isArray(frontmatter.globs) ? frontmatter.globs.join(", ") : frontmatter.globs}`, size: "small", variant: "outlined" })
|
|
227
305
|
] }),
|
|
228
306
|
renderFrontmatter(theme, frontmatter),
|
|
229
|
-
/* @__PURE__ */ jsx(
|
|
230
|
-
] }) })
|
|
231
|
-
] });
|
|
232
|
-
};
|
|
233
|
-
const renderCopilotRule = (rule2) => {
|
|
234
|
-
const ruleNumber = rule2.order || (rule2.fileName.match(/Rule (\d+)/) || [])[1] || rule2.id.split("-").pop();
|
|
235
|
-
return /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
|
|
236
|
-
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
|
|
237
|
-
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
|
|
238
|
-
/* @__PURE__ */ jsx(RuleTypeIcon, { type: rule2.type }),
|
|
239
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: rule2.title || `Copilot Rule #${ruleNumber}` }),
|
|
240
|
-
/* @__PURE__ */ jsx(Chip, { label: rule2.type, size: "small", className: styles.ruleType }),
|
|
241
|
-
rule2.applyTo && /* @__PURE__ */ jsx(
|
|
242
|
-
Chip,
|
|
243
|
-
{
|
|
244
|
-
label: `Applies to: ${rule2.applyTo}`,
|
|
245
|
-
size: "small",
|
|
246
|
-
variant: "outlined",
|
|
247
|
-
style: { marginLeft: 8 }
|
|
248
|
-
}
|
|
249
|
-
)
|
|
250
|
-
] }),
|
|
251
|
-
rule2.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(
|
|
252
|
-
IconButton,
|
|
253
|
-
{
|
|
254
|
-
size: "small",
|
|
255
|
-
onClick: (e) => {
|
|
256
|
-
e.stopPropagation();
|
|
257
|
-
window.open(constructFileUrl(rule2.gitUrl, rule2.filePath), "_blank");
|
|
258
|
-
},
|
|
259
|
-
children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" })
|
|
260
|
-
}
|
|
261
|
-
) })
|
|
262
|
-
] }) }),
|
|
263
|
-
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
264
|
-
/* @__PURE__ */ jsxs("div", { className: styles.ruleMetadata, children: [
|
|
265
|
-
/* @__PURE__ */ jsx(Chip, { label: `Path: ${rule2.filePath}`, size: "small", variant: "outlined" }),
|
|
266
|
-
rule2.frontmatter && renderFrontmatter(theme, rule2.frontmatter)
|
|
267
|
-
] }),
|
|
268
|
-
/* @__PURE__ */ jsx("div", { className: styles.ruleContent, children: /* @__PURE__ */ jsx(MarkdownContent, { content: rule2.content }) })
|
|
307
|
+
/* @__PURE__ */ jsx(RuleContentViewer, { content })
|
|
269
308
|
] }) })
|
|
270
309
|
] });
|
|
271
310
|
};
|
|
272
|
-
const
|
|
311
|
+
const renderCopilotRule = (r) => /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
|
|
273
312
|
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
|
|
274
313
|
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
|
|
275
|
-
/* @__PURE__ */ jsx(RuleTypeIcon, { type:
|
|
276
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h6", children:
|
|
277
|
-
/* @__PURE__ */ jsx(Chip, { label:
|
|
314
|
+
/* @__PURE__ */ jsx(RuleTypeIcon, { type: r.type }),
|
|
315
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: r.title || r.fileName }),
|
|
316
|
+
/* @__PURE__ */ jsx(Chip, { label: r.type, size: "small", className: styles.ruleType }),
|
|
317
|
+
r.applyTo && /* @__PURE__ */ jsx(Chip, { label: `Applies to: ${r.applyTo}`, size: "small", variant: "outlined", style: { marginLeft: 8 } })
|
|
278
318
|
] }),
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
},
|
|
287
|
-
children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" })
|
|
288
|
-
}
|
|
289
|
-
) })
|
|
319
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderActions, children: [
|
|
320
|
+
/* @__PURE__ */ jsx(CopyButton, { content: r.content }),
|
|
321
|
+
r.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: (e) => {
|
|
322
|
+
e.stopPropagation();
|
|
323
|
+
window.open(constructFileUrl(r.gitUrl, r.filePath), "_blank");
|
|
324
|
+
}, children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" }) }) })
|
|
325
|
+
] })
|
|
290
326
|
] }) }),
|
|
291
327
|
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
292
|
-
/* @__PURE__ */
|
|
293
|
-
|
|
328
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleMetadata, children: [
|
|
329
|
+
/* @__PURE__ */ jsx(Chip, { label: `Path: ${r.filePath}`, size: "small", variant: "outlined" }),
|
|
330
|
+
r.frontmatter && renderFrontmatter(theme, r.frontmatter)
|
|
331
|
+
] }),
|
|
332
|
+
/* @__PURE__ */ jsx(RuleContentViewer, { content: r.content })
|
|
294
333
|
] }) })
|
|
295
334
|
] });
|
|
296
|
-
const
|
|
335
|
+
const renderClineRule = (r) => /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
|
|
297
336
|
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
|
|
298
337
|
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
|
|
299
|
-
/* @__PURE__ */ jsx(RuleTypeIcon, { type:
|
|
300
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h6", children:
|
|
301
|
-
/* @__PURE__ */ jsx(Chip, { label:
|
|
338
|
+
/* @__PURE__ */ jsx(RuleTypeIcon, { type: r.type }),
|
|
339
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: r.title || r.fileName }),
|
|
340
|
+
/* @__PURE__ */ jsx(Chip, { label: r.type, size: "small", className: styles.ruleType })
|
|
302
341
|
] }),
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
{
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
},
|
|
311
|
-
children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" })
|
|
312
|
-
}
|
|
313
|
-
) })
|
|
342
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderActions, children: [
|
|
343
|
+
/* @__PURE__ */ jsx(CopyButton, { content: r.content }),
|
|
344
|
+
r.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: (e) => {
|
|
345
|
+
e.stopPropagation();
|
|
346
|
+
window.open(constructFileUrl(r.gitUrl, r.filePath), "_blank");
|
|
347
|
+
}, children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" }) }) })
|
|
348
|
+
] })
|
|
314
349
|
] }) }),
|
|
315
350
|
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
316
|
-
/* @__PURE__ */ jsx("div", { className: styles.ruleMetadata, children: /* @__PURE__ */ jsx(Chip, { label: `Path: ${
|
|
317
|
-
/* @__PURE__ */ jsx(
|
|
351
|
+
/* @__PURE__ */ jsx("div", { className: styles.ruleMetadata, children: /* @__PURE__ */ jsx(Chip, { label: `Path: ${r.filePath}`, size: "small", variant: "outlined" }) }),
|
|
352
|
+
/* @__PURE__ */ jsx(RuleContentViewer, { content: r.content })
|
|
353
|
+
] }) })
|
|
354
|
+
] });
|
|
355
|
+
const renderClaudeCodeRule = (r) => /* @__PURE__ */ jsxs(Accordion, { className: styles.ruleCard, children: [
|
|
356
|
+
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsxs("div", { className: styles.ruleHeader, children: [
|
|
357
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderContent, children: [
|
|
358
|
+
/* @__PURE__ */ jsx(RuleTypeIcon, { type: r.type }),
|
|
359
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", children: r.title || r.fileName }),
|
|
360
|
+
/* @__PURE__ */ jsx(Chip, { label: "claude-code", size: "small", className: styles.ruleType })
|
|
361
|
+
] }),
|
|
362
|
+
/* @__PURE__ */ jsxs("div", { className: styles.ruleHeaderActions, children: [
|
|
363
|
+
/* @__PURE__ */ jsx(CopyButton, { content: r.content }),
|
|
364
|
+
r.gitUrl && /* @__PURE__ */ jsx(Tooltip, { title: "Open file in repository", children: /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: (e) => {
|
|
365
|
+
e.stopPropagation();
|
|
366
|
+
window.open(constructFileUrl(r.gitUrl, r.filePath), "_blank");
|
|
367
|
+
}, children: /* @__PURE__ */ jsx(LaunchIcon, { fontSize: "small" }) }) })
|
|
368
|
+
] })
|
|
369
|
+
] }) }),
|
|
370
|
+
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
371
|
+
/* @__PURE__ */ jsx("div", { className: styles.ruleMetadata, children: /* @__PURE__ */ jsx(Chip, { label: `Path: ${r.filePath}`, size: "small", variant: "outlined" }) }),
|
|
372
|
+
/* @__PURE__ */ jsx(RuleContentViewer, { content: r.content })
|
|
318
373
|
] }) })
|
|
319
374
|
] });
|
|
320
375
|
switch (rule.type) {
|
|
@@ -327,51 +382,73 @@ const RuleComponent = ({ rule }) => {
|
|
|
327
382
|
case AIRuleType.CLINE:
|
|
328
383
|
return renderClineRule(rule);
|
|
329
384
|
default:
|
|
330
|
-
return
|
|
385
|
+
return /* @__PURE__ */ jsx(GenericRuleAccordion, { rule });
|
|
331
386
|
}
|
|
332
387
|
};
|
|
388
|
+
const exportRulesToMarkdown = (rules) => {
|
|
389
|
+
const lines = ["# AI Coding Rules Export\n"];
|
|
390
|
+
const grouped = {};
|
|
391
|
+
for (const rule of rules) {
|
|
392
|
+
if (!grouped[rule.type]) grouped[rule.type] = [];
|
|
393
|
+
grouped[rule.type].push(rule);
|
|
394
|
+
}
|
|
395
|
+
for (const type of RULE_TYPE_DISPLAY_ORDER) {
|
|
396
|
+
const typeRules = grouped[type];
|
|
397
|
+
if (!typeRules || typeRules.length === 0) continue;
|
|
398
|
+
lines.push(`## ${RULE_TYPE_DISPLAY_NAMES[type]}
|
|
399
|
+
`);
|
|
400
|
+
for (const rule of typeRules) {
|
|
401
|
+
const title = rule.title || rule.fileName;
|
|
402
|
+
lines.push(`### ${title}
|
|
403
|
+
`);
|
|
404
|
+
lines.push(`_File: \`${rule.filePath}\`_
|
|
405
|
+
`);
|
|
406
|
+
lines.push(`${rule.content}
|
|
407
|
+
`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const blob = new Blob([lines.join("\n")], { type: "text/markdown" });
|
|
411
|
+
const url = URL.createObjectURL(blob);
|
|
412
|
+
const a = document.createElement("a");
|
|
413
|
+
a.href = url;
|
|
414
|
+
a.download = "ai-rules-export.md";
|
|
415
|
+
a.click();
|
|
416
|
+
URL.revokeObjectURL(url);
|
|
417
|
+
};
|
|
333
418
|
const AIRulesComponent = ({ title = "AI Coding Rules" } = {}) => {
|
|
334
|
-
const { rulesByType, loading, error, hasGitUrl, totalRules, allowedRuleTypes, selectedRuleTypes, setSelectedRuleTypes, applyFilters, resetFilters, hasUnappliedChanges, hasSearched } = useAiRules();
|
|
419
|
+
const { rulesByType, rules, loading, error, hasGitUrl, totalRules, allowedRuleTypes, selectedRuleTypes, setSelectedRuleTypes, applyFilters, resetFilters, hasUnappliedChanges, hasSearched } = useAiRules();
|
|
335
420
|
const styles = useStyles();
|
|
336
|
-
const
|
|
337
|
-
const formatRuleTypeName = (type) =>
|
|
338
|
-
switch (type) {
|
|
339
|
-
case AIRuleType.CURSOR:
|
|
340
|
-
return "Cursor";
|
|
341
|
-
case AIRuleType.CLAUDE_CODE:
|
|
342
|
-
return "Claude Code";
|
|
343
|
-
case AIRuleType.COPILOT:
|
|
344
|
-
return "Copilot";
|
|
345
|
-
case AIRuleType.CLINE:
|
|
346
|
-
return "Cline";
|
|
347
|
-
}
|
|
348
|
-
};
|
|
421
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
422
|
+
const formatRuleTypeName = (type) => RULE_TYPE_DISPLAY_NAMES[type] ?? type;
|
|
349
423
|
const handleTypeToggle = (type, checked) => {
|
|
350
424
|
const newTypes = checked ? [...selectedRuleTypes, type] : selectedRuleTypes.filter((t) => t !== type);
|
|
351
425
|
setSelectedRuleTypes(newTypes);
|
|
352
426
|
};
|
|
427
|
+
const filteredRulesByType = useMemo(() => {
|
|
428
|
+
if (!searchQuery.trim()) return rulesByType;
|
|
429
|
+
const q = searchQuery.toLowerCase();
|
|
430
|
+
const filtered = {};
|
|
431
|
+
for (const type of RULE_TYPE_DISPLAY_ORDER) {
|
|
432
|
+
const typeRules = (rulesByType[type] || []).filter((rule) => {
|
|
433
|
+
const r = rule;
|
|
434
|
+
return rule.content?.toLowerCase().includes(q) || rule.fileName?.toLowerCase().includes(q) || r.title?.toLowerCase().includes(q) || r.description?.toLowerCase().includes(q);
|
|
435
|
+
});
|
|
436
|
+
if (typeRules.length > 0) filtered[type] = typeRules;
|
|
437
|
+
}
|
|
438
|
+
return filtered;
|
|
439
|
+
}, [rulesByType, searchQuery]);
|
|
440
|
+
const filteredTotal = useMemo(
|
|
441
|
+
() => Object.values(filteredRulesByType).reduce((sum, arr) => sum + (arr?.length ?? 0), 0),
|
|
442
|
+
[filteredRulesByType]
|
|
443
|
+
);
|
|
353
444
|
if (loading) {
|
|
354
445
|
return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(Progress, {}) });
|
|
355
446
|
}
|
|
356
447
|
if (!hasGitUrl) {
|
|
357
|
-
return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(
|
|
358
|
-
EmptyState,
|
|
359
|
-
{
|
|
360
|
-
missing: "content",
|
|
361
|
-
title: "No Git Repository",
|
|
362
|
-
description: "This component doesn't have a Git source URL configured."
|
|
363
|
-
}
|
|
364
|
-
) });
|
|
448
|
+
return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(EmptyState, { missing: "content", title: "No Git Repository", description: "This component doesn't have a Git source URL configured." }) });
|
|
365
449
|
}
|
|
366
450
|
if (error) {
|
|
367
|
-
return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(
|
|
368
|
-
EmptyState,
|
|
369
|
-
{
|
|
370
|
-
missing: "content",
|
|
371
|
-
title: "Error Loading Rules",
|
|
372
|
-
description: error
|
|
373
|
-
}
|
|
374
|
-
) });
|
|
451
|
+
return /* @__PURE__ */ jsx(InfoCard, { title, children: /* @__PURE__ */ jsx(EmptyState, { missing: "content", title: "Error Loading Rules", description: error }) });
|
|
375
452
|
}
|
|
376
453
|
return /* @__PURE__ */ jsxs(InfoCard, { title, className: styles.root, children: [
|
|
377
454
|
/* @__PURE__ */ jsxs("div", { className: styles.filterSection, children: [
|
|
@@ -379,28 +456,13 @@ const AIRulesComponent = ({ title = "AI Coding Rules" } = {}) => {
|
|
|
379
456
|
/* @__PURE__ */ jsx("div", { className: styles.filterContainer, children: allowedRuleTypes.map((type) => /* @__PURE__ */ jsx(
|
|
380
457
|
FormControlLabel,
|
|
381
458
|
{
|
|
382
|
-
control: /* @__PURE__ */ jsx(
|
|
383
|
-
Checkbox,
|
|
384
|
-
{
|
|
385
|
-
checked: selectedRuleTypes.includes(type),
|
|
386
|
-
onChange: (e) => handleTypeToggle(type, e.target.checked)
|
|
387
|
-
}
|
|
388
|
-
),
|
|
459
|
+
control: /* @__PURE__ */ jsx(Checkbox, { checked: selectedRuleTypes.includes(type), onChange: (e) => handleTypeToggle(type, e.target.checked) }),
|
|
389
460
|
label: formatRuleTypeName(type)
|
|
390
461
|
},
|
|
391
462
|
type
|
|
392
463
|
)) }),
|
|
393
464
|
/* @__PURE__ */ jsxs("div", { className: styles.applyFilterButton, children: [
|
|
394
|
-
/* @__PURE__ */ jsx(
|
|
395
|
-
Button,
|
|
396
|
-
{
|
|
397
|
-
variant: "contained",
|
|
398
|
-
color: "primary",
|
|
399
|
-
onClick: applyFilters,
|
|
400
|
-
disabled: !hasUnappliedChanges,
|
|
401
|
-
children: "Apply Filter"
|
|
402
|
-
}
|
|
403
|
-
),
|
|
465
|
+
/* @__PURE__ */ jsx(Button, { variant: "contained", color: "primary", onClick: applyFilters, disabled: !hasUnappliedChanges, children: "Apply Filter" }),
|
|
404
466
|
hasUnappliedChanges && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", style: { marginTop: 8 }, children: 'You have unsaved filter changes. Click "Apply Filter" to update the results.' }),
|
|
405
467
|
!hasUnappliedChanges && selectedRuleTypes.length === 0 && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", style: { marginTop: 8 }, children: "Select at least one rule type to search for AI rules." })
|
|
406
468
|
] })
|
|
@@ -411,32 +473,48 @@ const AIRulesComponent = ({ title = "AI Coding Rules" } = {}) => {
|
|
|
411
473
|
missing: "content",
|
|
412
474
|
title: "No AI Rules Found",
|
|
413
475
|
description: "No AI rules were found in this repository for the selected rule types.",
|
|
414
|
-
action: /* @__PURE__ */ jsx(
|
|
415
|
-
Button,
|
|
416
|
-
{
|
|
417
|
-
variant: "outlined",
|
|
418
|
-
onClick: resetFilters,
|
|
419
|
-
children: "Reset Filters"
|
|
420
|
-
}
|
|
421
|
-
)
|
|
476
|
+
action: /* @__PURE__ */ jsx(Button, { variant: "outlined", onClick: resetFilters, children: "Reset Filters" })
|
|
422
477
|
}
|
|
423
478
|
) : totalRules > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
479
|
+
/* @__PURE__ */ jsx(
|
|
480
|
+
TextField,
|
|
481
|
+
{
|
|
482
|
+
className: styles.searchBar,
|
|
483
|
+
variant: "outlined",
|
|
484
|
+
size: "small",
|
|
485
|
+
label: "Search rules",
|
|
486
|
+
placeholder: "Search by name, title, or content\u2026",
|
|
487
|
+
value: searchQuery,
|
|
488
|
+
onChange: (e) => setSearchQuery(e.target.value)
|
|
489
|
+
}
|
|
490
|
+
),
|
|
424
491
|
/* @__PURE__ */ jsxs("div", { className: styles.statsContainer, children: [
|
|
425
492
|
/* @__PURE__ */ jsx(Card, { className: styles.statCard, children: /* @__PURE__ */ jsxs(CardContent, { children: [
|
|
426
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", children: totalRules }),
|
|
427
|
-
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "Total Rules" })
|
|
493
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", children: searchQuery ? filteredTotal : totalRules }),
|
|
494
|
+
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: searchQuery ? "Matching" : "Total Rules" })
|
|
428
495
|
] }) }),
|
|
429
|
-
|
|
430
|
-
const typeRules = rulesByType[type] || [];
|
|
496
|
+
RULE_TYPE_DISPLAY_ORDER.map((type) => {
|
|
497
|
+
const typeRules = (searchQuery ? filteredRulesByType : rulesByType)[type] || [];
|
|
431
498
|
if (typeRules.length === 0) return null;
|
|
432
499
|
return /* @__PURE__ */ jsx(Card, { className: styles.statCard, children: /* @__PURE__ */ jsxs(CardContent, { children: [
|
|
433
500
|
/* @__PURE__ */ jsx(Typography, { variant: "h4", children: typeRules.length }),
|
|
434
501
|
/* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: formatRuleTypeName(type) })
|
|
435
502
|
] }) }, type);
|
|
436
|
-
})
|
|
503
|
+
}),
|
|
504
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Download all rules as Markdown", children: /* @__PURE__ */ jsx(
|
|
505
|
+
Button,
|
|
506
|
+
{
|
|
507
|
+
variant: "outlined",
|
|
508
|
+
size: "small",
|
|
509
|
+
startIcon: /* @__PURE__ */ jsx(GetAppIcon, {}),
|
|
510
|
+
className: styles.exportButton,
|
|
511
|
+
onClick: () => exportRulesToMarkdown(rules),
|
|
512
|
+
children: "Export"
|
|
513
|
+
}
|
|
514
|
+
) })
|
|
437
515
|
] }),
|
|
438
|
-
|
|
439
|
-
const typeRules = rulesByType[type] || [];
|
|
516
|
+
RULE_TYPE_DISPLAY_ORDER.map((type) => {
|
|
517
|
+
const typeRules = (searchQuery ? filteredRulesByType : rulesByType)[type] || [];
|
|
440
518
|
if (typeRules.length === 0) return null;
|
|
441
519
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
442
520
|
/* @__PURE__ */ jsxs(Typography, { variant: "h5", gutterBottom: true, style: { marginTop: 16 }, children: [
|
|
@@ -447,7 +525,8 @@ const AIRulesComponent = ({ title = "AI Coding Rules" } = {}) => {
|
|
|
447
525
|
] }),
|
|
448
526
|
typeRules.map((rule) => /* @__PURE__ */ jsx(RuleComponent, { rule }, rule.id))
|
|
449
527
|
] }, type);
|
|
450
|
-
})
|
|
528
|
+
}),
|
|
529
|
+
searchQuery && filteredTotal === 0 && /* @__PURE__ */ jsx(EmptyState, { missing: "content", title: "No matching rules", description: `No rules match "${searchQuery}". Clear the search to show all rules.` })
|
|
451
530
|
] }) : /* @__PURE__ */ jsx("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "textSecondary", children: 'Select rule types above and click "Apply Filter" to search for AI coding rules in this repository.' }) })
|
|
452
531
|
] });
|
|
453
532
|
};
|