Compare commits

...

No commits in common. "saksham" and "main" have entirely different histories.

12 changed files with 443 additions and 25183 deletions

3
.env Normal file
View File

@ -0,0 +1,3 @@
GENERATE_SOURCEMAP=false
REACT_APP_API_URL=http://157.66.191.31:33730/back/

12
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,12 @@
name: Autocloser
on: [issues]
jobs:
autoclose:
runs-on: ubuntu-latest
steps:
- name: Issue auto-closer
uses: roots/issue-closer-action@v1.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-close-message: "@${issue.user.login} this issue was automatically closed because it did not follow our rules:\n\n<pre>\n\n\n\nIMPORTANT: Please use the following link to create a new issue:\n\nhttps://www.creative-tim.com/new-issue/argon-dashboard-react\n\n**If your issue was not created using the app above, it will be closed immediately.**\n\n\n\nLove Creative Tim? Do you need Angular, React, Vuejs or HTML? You can visit:\n👉 https://www.creative-tim.com/bundles\n👉 https://www.creative-tim.com\n\n\n</pre>\n\n"
issue-pattern: (\#\#\# Version([\S\s.*]*?)\#\#\# Reproduction link([\S\s.*]*?)\#\#\# Operating System([\S\s.*]*?)\#\#\# Device([\S\s.*]*?)\#\#\# Browser & Version([\S\s.*]*?)\#\#\# Steps to reproduce([\S\s.*]*?)\#\#\# What is expected([\S\s.*]*?)\#\#\# What is actually happening([\S\s.*]*?)---([\S\s.*]*?)\#\#\# Solution([\S\s.*]*?)\#\#\# Additional comments([\S\s.*]*?)\<\!-- generated by creative-tim-issues\. DO NOT REMOVE --\>)|(\#\#\# What is your enhancement([\S\s.*]*?)\<\!-- generated by creative-tim-issues\. DO NOT REMOVE --\>)

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
<<<<<<< HEAD
/build
/node_modules
package-lock.json
/build
=======
node_modules/
node_modules/
/build
package-lock.json
>>>>>>> 1c0592d (commit new code)
.eslintcache

3
.npmrc Normal file
View File

@ -0,0 +1,3 @@
legacy-peer-deps=true
auto-install-peers=true
strict-peer-dependencies=false

25036
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
"homepage": "https://demos.creative-tim.com/argon-dashboard-react/", "homepage": "https://demos.creative-tim.com/argon-dashboard-react/",
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"build": "cross-env PUBLIC_URL=/ react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject", "eject": "react-scripts eject",
"install:clean": "rm -rf node_modules/ && rm -rf package-lock.json && npm install && npm start", "install:clean": "rm -rf node_modules/ && rm -rf package-lock.json && npm install && npm start",
@ -71,6 +71,7 @@
"classnames": "2.3.2", "classnames": "2.3.2",
"cors-anywhere": "^0.4.4", "cors-anywhere": "^0.4.4",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
"moment": "2.29.4", "moment": "2.29.4",
"multiselect-react-dropdown": "^2.0.25", "multiselect-react-dropdown": "^2.0.25",
"nouislider": "15.4.0", "nouislider": "15.4.0",

View File

@ -21,6 +21,7 @@ export const fetchAllReportsApi = async () => {
try { try {
const response = await apiService.get('/Rpt_builder2/Rpt_builder2'); // API call to fetch all reports const response = await apiService.get('/Rpt_builder2/Rpt_builder2'); // API call to fetch all reports
console.log("Fetch all reports response:", response.data); console.log("Fetch all reports response:", response.data);
return response.data; // Assuming response data comes in `data` field return response.data; // Assuming response data comes in `data` field
} catch (error) { } catch (error) {
console.error("Error while fetching all reports:", error); console.error("Error while fetching all reports:", error);

View File

@ -93,7 +93,7 @@ const App = () => {
<AdminLayout /> <AdminLayout />
</ProtectedRoute> </ProtectedRoute>
}> }>
<Route path="regform" element={<Regform />} /> {/* <Route path="regform" element={<Regform />} /> */}
<Route path="error404" element={<Error404 />} /> <Route path="error404" element={<Error404 />} />
<Route path="resetpassword" element={<ResetPassword />} /> <Route path="resetpassword" element={<ResetPassword />} />
@ -137,12 +137,13 @@ const App = () => {
<Route path="dashboard-new-edit/:id" element={<DashboardNewEdit/>}/> <Route path="dashboard-new-edit/:id" element={<DashboardNewEdit/>}/>
<Route path="edit-new-dash/:id" element={<EditNewDash/>}/> <Route path="edit-new-dash/:id" element={<EditNewDash/>}/>
<Route path="dashrunner/:id" element={<DashboardRunner/>}/> <Route path="dashrunner/:id" element={<DashboardRunner/>}/>
{/* <Route path="test" element={<Regform />} /> */}
{/* buildercomponents */} {/* buildercomponents */}
</Route> </Route>
<Route path="/auth/*" element={<AuthLayout />}> <Route path="/auth/*" element={<AuthLayout />}>
<Route path="login" element={<Login />} /> <Route path="login" element={<Login />} />
<Route path="register" element={<Register />} /> <Route path="register" element={<Register />} />

View File

@ -1,11 +1,11 @@
// ProtectedRoute.js
import React from "react"; import React from "react";
import { Navigate } from "react-router-dom"; import { Navigate } from "react-router-dom";
import { getToken } from "utils/tokenService"; import { getToken } from "utils/tokenService";
const ProtectedRoute = ({ children }) => { const ProtectedRoute = ({ children }) => {
console.log(`token for checking whether authenticated: ${getToken()}`); const isAuthenticated = getToken() !== null;
const isAuthenticated = getToken() !== null; // Check if user is authenticated
return isAuthenticated ? children : <Navigate to="/auth/login" replace />; return isAuthenticated ? children : <Navigate to="/auth/login" replace />;
}; };
export default ProtectedRoute; export default ProtectedRoute;

View File

@ -57,7 +57,7 @@ function AccessTypeManagement() {
useEffect(() => { useEffect(() => {
const fetchAccessTypes = async () => { const fetchAccessTypes = async () => {
const apiUrl = `${process.env.REACT_APP_API_URL}api/getAllAccessTypes`; const apiUrl = `${process.env.REACT_APP_API_URL}token/access_type/Accesstype`;
const token = localStorage.getItem("authToken"); const token = localStorage.getItem("authToken");
if (!token) { if (!token) {

View File

@ -20,31 +20,31 @@ function TOKENRegistry() {
id: "", id: "",
tokenName: "", tokenName: "",
tokenValue: "", tokenValue: "",
isActive: true isActive: true,
scopes: []
}); });
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [recordsPerPage, setRecordsPerPage] = useState(10); const [recordsPerPage, setRecordsPerPage] = useState(10);
// Add to your state: const [visibleColumns, setVisibleColumns] = useState({
const [visibleColumns, setVisibleColumns] = useState({ id: true,
id: true, tokenName: true,
tokenName: true, tokenValue: true,
tokenValue: true, scopes: true,
scopes: true, isActive: true,
isActive: true, actions: true
actions: true });
});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [selectedScope, setSelectedScope] = useState("");
const [selectedScopes, setSelectedScopes] = useState([]); const [selectedScopes, setSelectedScopes] = useState([]);
const [availableScopes] = useState([ const [availableScopes] = useState([
{ value: 'read', label: 'Read Access' }, { value: 'read', label: 'Read Access' },
{ value: 'write', label: 'Write Access' }, { value: 'write', label: 'Write Access' },
{ value: 'delete', label: 'Delete Access' }, { value: 'delete', label: 'Delete Access' },
{ value: 'admin', label: 'Admin Access' }, { value: 'admin', label: 'Admin Access' },
]); ]);
useEffect(() => { useEffect(() => {
fetchTokens(); fetchTokens();
}, []); }, []);
@ -95,6 +95,7 @@ const [visibleColumns, setVisibleColumns] = useState({
setShowGenerateTokenModal(false); setShowGenerateTokenModal(false);
setGeneratedToken(""); setGeneratedToken("");
setNewTokenName(""); setNewTokenName("");
setSelectedScopes([]);
}; };
const handleRecordsPerPageChange = (number) => { const handleRecordsPerPageChange = (number) => {
@ -135,9 +136,10 @@ const [visibleColumns, setVisibleColumns] = useState({
} }
}; };
const openModal = (token = { id: "", tokenName: "", tokenValue: "", isActive: false }) => { const openModal = (token = { id: "", tokenName: "", tokenValue: "", isActive: false, scopes: [] }) => {
setIsEditing(!!token.id); setIsEditing(!!token.id);
setCurrentToken(token); setCurrentToken(token);
setSelectedScopes(token.scopes || []);
setShowAddEditModal(true); setShowAddEditModal(true);
}; };
@ -153,24 +155,35 @@ const [visibleColumns, setVisibleColumns] = useState({
} }
}; };
const generateNewToken = async () => { const addScope = () => {
if (!newTokenName.trim()) { if (selectedScope && !selectedScopes.includes(selectedScope)) {
toast.error("Please enter a token name"); setSelectedScopes([...selectedScopes, selectedScope]);
return; setSelectedScope("");
} }
};
try { const removeScope = (scopeToRemove) => {
const data = await tokenRegistryAPI.generateToken({ setSelectedScopes(selectedScopes.filter(scope => scope !== scopeToRemove));
name: newTokenName, };
scopes: selectedScopes
}); const generateNewToken = async () => {
setGeneratedToken(data.tokenValue); if (!newTokenName.trim()) {
toast.success("Token generated successfully!"); toast.error("Please enter a token name");
fetchTokens(); return;
} catch (error) { }
handleApiError(error, "generate token");
} try {
}; const data = await tokenRegistryAPI.generateToken({
name: newTokenName,
scopes: selectedScopes
});
setGeneratedToken(data.tokenValue);
toast.success("Token generated successfully!");
fetchTokens();
} catch (error) {
handleApiError(error, "generate token");
}
};
return ( return (
<div style={{ marginTop: "1rem" }}> <div style={{ marginTop: "1rem" }}>
@ -305,6 +318,21 @@ const [visibleColumns, setVisibleColumns] = useState({
> >
{token.isActive ? "Active" : "Inactive"} {token.isActive ? "Active" : "Inactive"}
</span> </span>
) : key === "scopes" ? (
<div>
{token.scopes && token.scopes.map(scope => {
const scopeInfo = availableScopes.find(s => s.value === scope);
return (
<span
key={scope}
className="badge bg-primary me-1 mb-1"
style={{ fontSize: '0.8rem', padding: '3px 6px' }}
>
{scopeInfo?.label || scope}
</span>
);
})}
</div>
) : ( ) : (
token[key] token[key]
)} )}
@ -383,93 +411,245 @@ const [visibleColumns, setVisibleColumns] = useState({
</PaginationItem> </PaginationItem>
</Pagination> </Pagination>
{/* Add/Edit Token Modal */} {/* Generate Token Modal */}
<Modal show={showGenerateTokenModal} onHide={handleClose}> <Modal show={showGenerateTokenModal} onHide={handleClose}>
<Modal.Header> <Modal.Header>
<Modal.Title>Generate New Token</Modal.Title> <Modal.Title>Generate New Token</Modal.Title>
<FontAwesomeIcon <FontAwesomeIcon
icon={faTimes} icon={faTimes}
size="lg" size="lg"
onClick={handleClose} onClick={handleClose}
style={{ style={{
position: "absolute", position: "absolute",
top: "25px", top: "25px",
right: "25px", right: "25px",
cursor: "pointer", cursor: "pointer",
}} }}
/> />
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
<Form> <Form>
<Form.Group controlId="formNewTokenName" className="mb-3"> <Form.Group controlId="formNewTokenName" className="mb-3">
<Form.Label>Token Name</Form.Label> <Form.Label>Token Name</Form.Label>
<Form.Control <Form.Control
type="text" type="text"
value={newTokenName} value={newTokenName}
onChange={(e) => setNewTokenName(e.target.value)} onChange={(e) => setNewTokenName(e.target.value)}
required required
className="custom-hover-border" className="custom-hover-border"
placeholder="Enter a name for the new token" placeholder="Enter a name for the new token"
/> />
</Form.Group> </Form.Group>
<Form.Group controlId="formTokenScopes" className="mb-3"> <Form.Group controlId="formTokenScopes" className="mb-3">
<Form.Label>Token Scopes</Form.Label> <Form.Label>Token Scopes</Form.Label>
<Form.Select <div className="d-flex">
multiple <Form.Select
value={selectedScopes} value={selectedScope}
onChange={(e) => { onChange={(e) => setSelectedScope(e.target.value)}
const options = [...e.target.options]; className="custom-hover-border me-2"
const selectedValues = options >
.filter(option => option.selected) <option value="">Select a scope</option>
.map(option => option.value); {availableScopes.map(scope => (
setSelectedScopes(selectedValues); <option key={scope.value} value={scope.value}>
}} {scope.label}
className="custom-hover-border" </option>
style={{ height: 'auto' }} ))}
> </Form.Select>
{availableScopes.map(scope => ( <Button
<option key={scope.value} value={scope.value}> variant="outline-primary"
{scope.label} onClick={addScope}
</option> disabled={!selectedScope}
))} >
</Form.Select> Add Scope
<Form.Text className="text-muted"> </Button>
Select the permissions this token should have (hold Ctrl/Cmd to select multiple) </div>
</Form.Text> <Form.Text className="text-muted">
</Form.Group> Select and add the permissions this token should have
</Form.Text>
{/* Display selected scopes as chips */}
{selectedScopes.length > 0 && (
<div className="mt-2">
{selectedScopes.map(scope => {
const scopeInfo = availableScopes.find(s => s.value === scope);
return (
<span
key={scope}
className="badge bg-primary me-2 mb-2"
style={{ fontSize: '0.9rem', padding: '5px 10px' }}
>
{scopeInfo?.label || scope}
<FontAwesomeIcon
icon={faTimes}
className="ms-2"
style={{ cursor: 'pointer' }}
onClick={() => removeScope(scope)}
/>
</span>
);
})}
</div>
)}
</Form.Group>
{generatedToken && ( {generatedToken && (
<Form.Group controlId="formGeneratedToken" className="mb-3"> <Form.Group controlId="formGeneratedToken" className="mb-3">
<Form.Label>Generated Token</Form.Label> <Form.Label>Generated Token</Form.Label>
<Form.Control <Form.Control
as="textarea" as="textarea"
rows={3} rows={3}
value={generatedToken} value={generatedToken}
readOnly readOnly
className="custom-hover-border" className="custom-hover-border"
/> />
<Form.Text className="text-muted"> <Form.Text className="text-muted">
Copy this token and store it securely. You won't be able to see it again. Copy this token and store it securely. You won't be able to see it again.
</Form.Text> </Form.Text>
</Form.Group> </Form.Group>
)} )}
<Modal.Footer> <Modal.Footer>
<Button variant="secondary" onClick={handleClose}> <Button variant="secondary" onClick={handleClose}>
Close Close
</Button> </Button>
<Button <Button
variant="primary" variant="primary"
onClick={generateNewToken} onClick={generateNewToken}
disabled={!newTokenName.trim()} disabled={!newTokenName.trim()}
> >
Generate Token Generate Token
</Button> </Button>
</Modal.Footer> </Modal.Footer>
</Form> </Form>
</Modal.Body> </Modal.Body>
</Modal> </Modal>
{/* Add/Edit Token Modal */}
<Modal show={showAddEditModal} onHide={handleClose}>
<Modal.Header>
<Modal.Title>{isEditing ? "Edit Token" : "Add Token"}</Modal.Title>
<FontAwesomeIcon
icon={faTimes}
size="lg"
onClick={handleClose}
style={{
position: "absolute",
top: "25px",
right: "25px",
cursor: "pointer",
}}
/>
</Modal.Header>
<Modal.Body>
<Form onSubmit={handleSubmit}>
<Form.Group controlId="formTokenName" className="mb-3">
<Form.Label>Token Name</Form.Label>
<Form.Control
type="text"
name="tokenName"
value={currentToken.tokenName}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formTokenValue" className="mb-3">
<Form.Label>Token Value</Form.Label>
<Form.Control
type="text"
name="tokenValue"
value={currentToken.tokenValue}
onChange={handleInputChange}
required
className="custom-hover-border"
/>
</Form.Group>
<Form.Group controlId="formTokenScopes" className="mb-3">
<Form.Label>Token Scopes</Form.Label>
<div className="d-flex">
<Form.Select
value={selectedScope}
onChange={(e) => setSelectedScope(e.target.value)}
className="custom-hover-border me-2"
>
<option value="">Select a scope</option>
{availableScopes.map(scope => (
<option key={scope.value} value={scope.value}>
{scope.label}
</option>
))}
</Form.Select>
<Button
variant="outline-primary"
onClick={() => {
if (selectedScope && !currentToken.scopes.includes(selectedScope)) {
setCurrentToken(prev => ({
...prev,
scopes: [...prev.scopes, selectedScope]
}));
setSelectedScope("");
}
}}
disabled={!selectedScope}
>
Add Scope
</Button>
</div>
<Form.Text className="text-muted">
Select and add the permissions this token should have
</Form.Text>
{/* Display selected scopes as chips */}
{currentToken.scopes && currentToken.scopes.length > 0 && (
<div className="mt-2">
{currentToken.scopes.map(scope => {
const scopeInfo = availableScopes.find(s => s.value === scope);
return (
<span
key={scope}
className="badge bg-primary me-2 mb-2"
style={{ fontSize: '0.9rem', padding: '5px 10px' }}
>
{scopeInfo?.label || scope}
<FontAwesomeIcon
icon={faTimes}
className="ms-2"
style={{ cursor: 'pointer' }}
onClick={() => {
setCurrentToken(prev => ({
...prev,
scopes: prev.scopes.filter(s => s !== scope)
}));
}}
/>
</span>
);
})}
</div>
)}
</Form.Group>
<Form.Group controlId="formActive" className="mb-3">
<Form.Check
type="checkbox"
label="Active?"
name="isActive"
checked={currentToken.isActive}
onChange={handleInputChange}
className="custom-checkbox"
/>
</Form.Group>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" type="submit">
{isEditing ? "Update Token" : "Add Token"}
</Button>
</Modal.Footer>
</Form>
</Modal.Body>
</Modal>
</div> </div>
)} )}
</div> </div>

View File

@ -1,4 +1,4 @@
import { useState } from "react"; import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
@ -7,20 +7,86 @@ import {
MenuItem, MenuItem,
SubMenu, SubMenu,
} from "react-pro-sidebar"; } from "react-pro-sidebar";
import { FaChevronLeft, FaChevronRight, FaDatabase, FaExclamationCircle } from "react-icons/fa"; import { FaChevronLeft, FaChevronRight, FaDatabase, FaExclamationCircle, FaCircle } from "react-icons/fa";
import { fetchMenuItems, getSubmenuItems } from "../../APIServices/MenuMaintenanceAPI";
import "../Sidebar/Sidebar.css"; import "../Sidebar/Sidebar.css";
const Sidebar = (props) => { const Sidebar = (props) => {
const [collapsed, setCollapsed] = useState(true); const [collapsed, setCollapsed] = useState(true);
const [menuItems, setMenuItems] = useState([]);
const [subMenuItems, setSubMenuItems] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => {
const loadMenuData = async () => {
try {
const mainMenuItems = await fetchMenuItems();
setMenuItems(mainMenuItems);
const subMenuPromises = mainMenuItems.map(item =>
getSubmenuItems(item.menuItemId)
.then(subItems => subItems || [])
.catch(() => [])
);
const subMenus = await Promise.all(subMenuPromises);
const subMenuMap = {};
mainMenuItems.forEach((item, index) => {
subMenuMap[item.menuItemId] = subMenus[index];
});
setSubMenuItems(subMenuMap);
} catch (err) {
console.error("Failed to load menu data:", err);
setError(err.message);
} finally {
setLoading(false);
}
};
loadMenuData();
}, []);
const toggleSidebar = () => { const toggleSidebar = () => {
setCollapsed(!collapsed); setCollapsed(!collapsed);
if (props.onSidebarToggle) { props.onSidebarToggle?.(!collapsed);
props.onSidebarToggle(!collapsed); };
const validatePath = (path) => {
if (!path || path === "#" || path === "null" || path === "undefined") {
return false;
}
return true;
};
const safeNavigate = (path) => {
if (!validatePath(path)) {
navigate("/admin/error404");
return;
}
// Ensure path starts with /admin/
const adminPath = path.startsWith("/admin/") ? path : `/admin/${path.replace(/^\//, '')}`;
try {
navigate(adminPath);
} catch (error) {
console.error(`Navigation failed:`, error);
navigate("/admin/error404");
} }
}; };
const getIconComponent = (iconName) => {
switch (iconName) {
case "fa-database": return <FaDatabase />;
case "fa-exclamation-circle": return <FaExclamationCircle />;
default: return <FaCircle />;
}
};
if (loading) return <div className="sidebar-wrapper">Loading...</div>;
if (error) return <div className="sidebar-wrapper">Error: {error}</div>;
return ( return (
<div className="sidebar-wrapper"> <div className="sidebar-wrapper">
<ProSidebar <ProSidebar
@ -41,21 +107,38 @@ const Sidebar = (props) => {
</div> </div>
<Menu> <Menu>
<SubMenu label="Transactions" icon={<FaExclamationCircle />}> {menuItems.map((menuItem) => {
<MenuItem onClick={() => navigate("/admin/regform")}> const subItems = subMenuItems[menuItem.menuItemId] || [];
Regform
</MenuItem> if (subItems.length > 0) {
<MenuItem onClick={() => navigate("/admin/error404")}> return (
Additional container <SubMenu
</MenuItem> key={menuItem.menuItemId}
</SubMenu> label={menuItem.menuItemDesc}
icon={getIconComponent(menuItem.main_menu_icon_name)}
<MenuItem >
icon={<FaDatabase />} {subItems.map((subItem) => (
onClick={() => navigate("/admin/error404")} <MenuItem
> key={subItem.menuItemId}
Masters onClick={() => safeNavigate(subItem.main_menu_action_name)}
</MenuItem> >
{subItem.menuItemDesc}
</MenuItem>
))}
</SubMenu>
);
}
return (
<MenuItem
key={menuItem.menuItemId}
icon={getIconComponent(menuItem.main_menu_icon_name)}
onClick={() => safeNavigate(menuItem.main_menu_action_name)}
>
{menuItem.menuItemDesc}
</MenuItem>
);
})}
</Menu> </Menu>
</ProSidebar> </ProSidebar>
</div> </div>
@ -71,4 +154,4 @@ Sidebar.propTypes = {
onSidebarToggle: PropTypes.func, onSidebarToggle: PropTypes.func,
}; };
export default Sidebar; export default Sidebar;