module federation

This commit is contained in:
2025-08-26 20:32:13 -04:00
parent a7d5425124
commit 2772dcc966
46 changed files with 52051 additions and 103 deletions

View File

@ -5,3 +5,4 @@ REACT_APP_VERSION=1.0.0
# Development settings
GENERATE_SOURCEMAP=true
SKIP_PREFLIGHT_CHECK=true

View File

@ -1,3 +1,4 @@
dist
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies

View File

@ -0,0 +1,50 @@
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
devServer: {
port: 3001,
historyApiFallback: true,
},
webpack: {
plugins: {
add: [
new ModuleFederationPlugin({
name: 'kms',
filename: 'remoteEntry.js',
exposes: {
'./App': './src/federated/KMSApp',
'./SearchProvider': './src/federated/SearchProvider',
},
shared: {
react: {
singleton: true,
requiredVersion: '^19.1.1'
},
'react-dom': {
singleton: true,
requiredVersion: '^19.1.1'
},
'react-router-dom': {
singleton: true,
requiredVersion: '^7.8.2'
},
antd: {
singleton: true,
requiredVersion: '^5.27.1'
},
axios: {
singleton: true
}
},
}),
],
},
configure: (webpackConfig) => ({
...webpackConfig,
output: {
...webpackConfig.output,
publicPath: "auto",
},
}),
},
};

File diff suppressed because it is too large Load Diff

View File

@ -23,11 +23,16 @@
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@craco/craco": "^7.1.0",
"craco-module-federation": "^1.1.0",
"webpack": "^5.96.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject"
},
"eslintConfig": {
"extends": [

View File

@ -0,0 +1,24 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter as Router } from 'react-router-dom';
import { ConfigProvider, theme } from 'antd';
import App from './App';
import './App.css';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<ConfigProvider
theme={{
algorithm: theme.defaultAlgorithm,
}}
>
<Router>
<App />
</Router>
</ConfigProvider>
</React.StrictMode>
);

View File

@ -0,0 +1,120 @@
import React from 'react';
import { Routes, Route, Navigate, useNavigate } from 'react-router-dom';
import { Layout, Menu, theme } from 'antd';
import {
DashboardOutlined,
AppstoreOutlined,
KeyOutlined,
UserOutlined,
AuditOutlined,
ExperimentOutlined,
} from '@ant-design/icons';
import { useState, useEffect } from 'react';
import Dashboard from '../components/Dashboard';
import Applications from '../components/Applications';
import Tokens from '../components/Tokens';
import Users from '../components/Users';
import Audit from '../components/Audit';
import TokenTester from '../components/TokenTester';
import TokenTesterCallback from '../components/TokenTesterCallback';
import { AuthProvider, useAuth } from '../contexts/AuthContext';
import Login from '../components/Login';
const { Sider, Content } = Layout;
const KMSAppContent: React.FC = () => {
const [collapsed, setCollapsed] = useState(false);
const { user } = useAuth();
const navigate = useNavigate();
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
if (!user) {
return <Login />;
}
const menuItems = [
{
key: '/kms',
icon: <DashboardOutlined />,
label: 'Dashboard',
},
{
key: '/kms/applications',
icon: <AppstoreOutlined />,
label: 'Applications',
},
{
key: '/kms/tokens',
icon: <KeyOutlined />,
label: 'Tokens',
},
{
key: '/kms/token-tester',
icon: <ExperimentOutlined />,
label: 'Token Tester',
},
{
key: '/kms/users',
icon: <UserOutlined />,
label: 'Users',
},
{
key: '/kms/audit',
icon: <AuditOutlined />,
label: 'Audit Log',
},
];
return (
<Layout style={{ height: '100%', minHeight: '600px' }}>
<Sider trigger={null} collapsible collapsed={collapsed} width={200}>
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['/kms']}
items={menuItems}
onClick={({ key }) => {
navigate(key);
}}
style={{ height: '100%', borderRight: 0 }}
/>
</Sider>
<Layout style={{ background: colorBgContainer }}>
<Content
style={{
margin: '16px',
padding: 24,
minHeight: 280,
background: colorBgContainer,
borderRadius: borderRadiusLG,
overflow: 'auto',
}}
>
<Routes>
<Route path="/kms" element={<Dashboard />} />
<Route path="/kms/applications" element={<Applications />} />
<Route path="/kms/tokens" element={<Tokens />} />
<Route path="/kms/token-tester" element={<TokenTester />} />
<Route path="/kms/token-tester/callback" element={<TokenTesterCallback />} />
<Route path="/kms/users" element={<Users />} />
<Route path="/kms/audit" element={<Audit />} />
<Route path="*" element={<Navigate to="/kms" replace />} />
</Routes>
</Content>
</Layout>
</Layout>
);
};
const KMSApp: React.FC = () => {
return (
<AuthProvider>
<KMSAppContent />
</AuthProvider>
);
};
export default KMSApp;

View File

@ -0,0 +1,64 @@
import { apiService, Application, PaginatedResponse } from '../services/apiService';
interface SearchResult {
id: string;
title: string;
description?: string;
appId: string;
action?: () => void;
}
export const kmsSearchProvider = async (query: string): Promise<SearchResult[]> => {
const results: SearchResult[] = [];
try {
// Search applications
const applicationsResponse: PaginatedResponse<Application> = await apiService.getApplications();
applicationsResponse.data
.filter((app: Application) =>
app.app_id.toLowerCase().includes(query.toLowerCase()) ||
(app.owner?.name && app.owner.name.toLowerCase().includes(query.toLowerCase()))
)
.forEach((app: Application) => {
results.push({
id: `app-${app.app_id}`,
title: app.app_id,
description: `Application owned by ${app.owner?.name || 'Unknown'}`,
appId: 'KMS',
action: () => {
window.location.hash = '/kms/applications';
}
});
});
// Add quick actions
const quickActions = [
{ key: 'applications', title: 'Applications', path: '/kms/applications' },
{ key: 'tokens', title: 'Tokens', path: '/kms/tokens' },
{ key: 'users', title: 'Users', path: '/kms/users' },
{ key: 'audit', title: 'Audit Log', path: '/kms/audit' },
{ key: 'dashboard', title: 'Dashboard', path: '/kms' },
];
quickActions
.filter(action => action.title.toLowerCase().includes(query.toLowerCase()))
.forEach(action => {
results.push({
id: `quick-${action.key}`,
title: action.title,
description: `Navigate to ${action.title}`,
appId: 'KMS',
action: () => {
window.location.hash = action.path;
}
});
});
} catch (error) {
console.error('KMS search error:', error);
}
return results.slice(0, 10); // Limit results
};
export default kmsSearchProvider;

View File

@ -1,19 +1,3 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import('./bootstrap');
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
export {};