-
Notifications
You must be signed in to change notification settings - Fork 447
Allow to override project list #3850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: allow-to-override-project-list
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -24,6 +24,15 @@ export interface ProjectDefinition { | |||||||||||||||||||||||||||||
clusters: string[]; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export type ProjectListProcessorFunction = ( | ||||||||||||||||||||||||||||||
currentProjects: ProjectDefinition[] | ||||||||||||||||||||||||||||||
) => ProjectDefinition[]; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export interface ProjectListProcessor { | ||||||||||||||||||||||||||||||
id?: string; | ||||||||||||||||||||||||||||||
processor: ProjectListProcessorFunction; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/** Define custom way to create new Projects */ | ||||||||||||||||||||||||||||||
export interface CustomCreateProject { | ||||||||||||||||||||||||||||||
id: string; | ||||||||||||||||||||||||||||||
|
@@ -49,22 +58,45 @@ export interface ProjectOverviewSection { | |||||||||||||||||||||||||||||
export interface ProjectDetailsTab { | ||||||||||||||||||||||||||||||
id: string; | ||||||||||||||||||||||||||||||
label: string; | ||||||||||||||||||||||||||||||
icon: string | ReactNode; | ||||||||||||||||||||||||||||||
icon?: string | ReactNode; | ||||||||||||||||||||||||||||||
component: (props: { project: ProjectDefinition; projectResources: KubeObject[] }) => ReactNode; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export interface ProjectsState { | ||||||||||||||||||||||||||||||
customCreateProject: Record<string, CustomCreateProject>; | ||||||||||||||||||||||||||||||
overviewSections: Record<string, ProjectOverviewSection>; | ||||||||||||||||||||||||||||||
detailsTabs: Record<string, ProjectDetailsTab>; | ||||||||||||||||||||||||||||||
projectListProcessors: ProjectListProcessor[]; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const initialState: ProjectsState = { | ||||||||||||||||||||||||||||||
customCreateProject: {}, | ||||||||||||||||||||||||||||||
detailsTabs: {}, | ||||||||||||||||||||||||||||||
overviewSections: {}, | ||||||||||||||||||||||||||||||
projectListProcessors: [], | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||
* Normalizes a project list processor by ensuring it has an 'id' and a processor function. | ||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||
function _normalizeProjectListProcessor( | ||||||||||||||||||||||||||||||
action: PayloadAction<ProjectListProcessor | ProjectListProcessorFunction> | ||||||||||||||||||||||||||||||
): ProjectListProcessor { | ||||||||||||||||||||||||||||||
let processor: ProjectListProcessor = action.payload as ProjectListProcessor; | ||||||||||||||||||||||||||||||
if (typeof action.payload === 'function') { | ||||||||||||||||||||||||||||||
processor = { | ||||||||||||||||||||||||||||||
id: `generated-id-${Date.now().toString(36)}`, | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using Date.now() for ID generation could create duplicate IDs if multiple processors are registered simultaneously. Consider using crypto.randomUUID() or a counter-based approach for guaranteed uniqueness. Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||
processor: action.payload, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (!processor.id) { | ||||||||||||||||||||||||||||||
processor.id = `generated-id-${Date.now().toString(36)}`; | ||||||||||||||||||||||||||||||
Comment on lines
+88
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using Date.now() for ID generation could create duplicate IDs if multiple processors are registered simultaneously. Consider using crypto.randomUUID() or a counter-based approach for guaranteed uniqueness.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
return processor; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const projectsSlice = createSlice({ | ||||||||||||||||||||||||||||||
name: 'projects', | ||||||||||||||||||||||||||||||
initialState, | ||||||||||||||||||||||||||||||
|
@@ -83,9 +115,22 @@ const projectsSlice = createSlice({ | |||||||||||||||||||||||||||||
addOverviewSection(state, action: PayloadAction<ProjectOverviewSection>) { | ||||||||||||||||||||||||||||||
state.overviewSections[action.payload.id] = action.payload; | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/** Register a project list processor */ | ||||||||||||||||||||||||||||||
addProjectListProcessor( | ||||||||||||||||||||||||||||||
state, | ||||||||||||||||||||||||||||||
action: PayloadAction<ProjectListProcessor | ProjectListProcessorFunction> | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
state.projectListProcessors.push(_normalizeProjectListProcessor(action)); | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export const { addCustomCreateProject, addDetailsTab, addOverviewSection } = projectsSlice.actions; | ||||||||||||||||||||||||||||||
export const { | ||||||||||||||||||||||||||||||
addCustomCreateProject, | ||||||||||||||||||||||||||||||
addDetailsTab, | ||||||||||||||||||||||||||||||
addOverviewSection, | ||||||||||||||||||||||||||||||
addProjectListProcessor, | ||||||||||||||||||||||||||||||
} = projectsSlice.actions; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export default projectsSlice.reducer; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,54 @@ | ||
# Projects customization example | ||
|
||
This plugin demonstrates how to customize projects feature | ||
This plugin demonstrates how to customize projects feature including: | ||
|
||
- Custom project creation workflows | ||
- Custom project details tabs | ||
- Custom project overview sections | ||
- Custom project list processors (extend or modify project discovery) | ||
|
||
```bash | ||
cd plugins/examples/projects | ||
npm start | ||
``` | ||
|
||
The main code for the example plugin is in [src/index.tsx](src/index.tsx). | ||
|
||
## Project List Processors | ||
|
||
The `registerProjectListProcessor` function allows plugins to extend or modify how projects are discovered and listed. Processors receive the current list of projects (from namespaces or previous processors) and can: | ||
|
||
- Add new projects from Custom Resources, external APIs, or other sources | ||
- Filter existing projects based on conditions | ||
- Modify project properties like namespaces or clusters | ||
- Completely replace the project list if needed | ||
|
||
### Key Features | ||
|
||
- **Additive by default**: Processors receive existing projects and can extend the list | ||
- **Chainable**: Multiple processors can be registered and will run in sequence | ||
- **Error handling**: Failed processors don't break the application | ||
- **Duplicate prevention**: Easy to check for existing projects by ID | ||
|
||
### Example Usage | ||
|
||
```typescript | ||
// Add new projects while keeping existing ones | ||
registerProjectListProcessor((currentProjects) => { | ||
const newProjects = [ | ||
{ | ||
id: 'my-custom-project', | ||
namespaces: ['default', 'kube-system'], | ||
clusters: ['cluster1'] | ||
} | ||
]; | ||
|
||
// Only add projects that don't already exist | ||
const existingIds = currentProjects.map(p => p.id); | ||
const projectsToAdd = newProjects.filter(p => !existingIds.includes(p.id)); | ||
|
||
return [...currentProjects, ...projectsToAdd]; | ||
}); | ||
``` | ||
|
||
This approach ensures backward compatibility while providing maximum flexibility for project customization. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug console.log statement should be removed from production code.
Copilot uses AI. Check for mistakes.