latest
This commit is contained in:
39
package-lock.json
generated
39
package-lock.json
generated
@@ -8,13 +8,14 @@
|
|||||||
"name": "log",
|
"name": "log",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.3",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@mui/icons-material": "^5.15.20",
|
"@material-ui/icons": "^4.11.3",
|
||||||
"@mui/material": "^5.15.20",
|
"@mui/icons-material": "^5.17.1",
|
||||||
|
"@mui/material": "^5.17.1",
|
||||||
"@mui/styles": "^5.16.4",
|
"@mui/styles": "^5.16.4",
|
||||||
"@mui/x-charts": "^7.6.2",
|
"@mui/x-charts": "^7.6.2",
|
||||||
"@mui/x-data-grid": "^7.6.2",
|
"@mui/x-data-grid": "^7.6.2",
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
"ajv-keywords": "^3.5.2",
|
"ajv-keywords": "^3.5.2",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
"chart.js": "^4.4.9",
|
"chart.js": "^4.4.9",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"mdb-react-ui-kit": "^7.1.0",
|
"mdb-react-ui-kit": "^7.1.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@@ -3764,6 +3766,29 @@
|
|||||||
"integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
|
"integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@material-ui/icons": {
|
||||||
|
"version": "4.11.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz",
|
||||||
|
"integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.4.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@material-ui/core": "^4.0.0",
|
||||||
|
"@types/react": "^16.8.6 || ^17.0.0",
|
||||||
|
"react": "^16.8.0 || ^17.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mui/core-downloads-tracker": {
|
"node_modules/@mui/core-downloads-tracker": {
|
||||||
"version": "5.17.1",
|
"version": "5.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.17.1.tgz",
|
||||||
@@ -9931,6 +9956,12 @@
|
|||||||
"webpack": "^4.0.0 || ^5.0.0"
|
"webpack": "^4.0.0 || ^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/filelist": {
|
"node_modules/filelist": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -3,13 +3,14 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.3",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@mui/icons-material": "^5.15.20",
|
"@material-ui/icons": "^4.11.3",
|
||||||
"@mui/material": "^5.15.20",
|
"@mui/icons-material": "^5.17.1",
|
||||||
|
"@mui/material": "^5.17.1",
|
||||||
"@mui/styles": "^5.16.4",
|
"@mui/styles": "^5.16.4",
|
||||||
"@mui/x-charts": "^7.6.2",
|
"@mui/x-charts": "^7.6.2",
|
||||||
"@mui/x-data-grid": "^7.6.2",
|
"@mui/x-data-grid": "^7.6.2",
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
"ajv-keywords": "^3.5.2",
|
"ajv-keywords": "^3.5.2",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
"chart.js": "^4.4.9",
|
"chart.js": "^4.4.9",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"mdb-react-ui-kit": "^7.1.0",
|
"mdb-react-ui-kit": "^7.1.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|||||||
@@ -1,117 +1,160 @@
|
|||||||
|
// import axios from 'axios';
|
||||||
|
|
||||||
|
// // Use the same environment variable name consistently
|
||||||
|
// const BASE_URL = process.env.REACT_APP_API_BASE_URL;
|
||||||
|
// console.log('API Base URL:', BASE_URL);
|
||||||
|
// // Enhanced token service
|
||||||
|
// export const getToken = () => {
|
||||||
|
// // Check multiple possible storage locations
|
||||||
|
// return localStorage.getItem('token') ||
|
||||||
|
// sessionStorage.getItem('token') ||
|
||||||
|
// document.cookie.split('; ').find(row => row.startsWith('token='))?.split('=')[1];
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const apiClient = axios.create({
|
||||||
|
// baseURL: BASE_URL,
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json',
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Enhanced request interceptor
|
||||||
|
// apiClient.interceptors.request.use(
|
||||||
|
// (config) => {
|
||||||
|
// const token = getToken();
|
||||||
|
// if (token) {
|
||||||
|
// config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
|
// // Add debug logging
|
||||||
|
// console.debug('[API] Request with token:', {
|
||||||
|
// url: config.url,
|
||||||
|
// headers: config.headers
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// console.warn('[API] No token available for request:', config.url);
|
||||||
|
// }
|
||||||
|
// return config;
|
||||||
|
// },
|
||||||
|
// (error) => {
|
||||||
|
// console.error('[API] Request interceptor error:', error);
|
||||||
|
// return Promise.reject(error);
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // Enhanced response interceptor
|
||||||
|
// apiClient.interceptors.response.use(
|
||||||
|
// (response) => {
|
||||||
|
// console.debug('[API] Successful response:', {
|
||||||
|
// url: response.config.url,
|
||||||
|
// status: response.status,
|
||||||
|
// data: response.data
|
||||||
|
// });
|
||||||
|
// return response;
|
||||||
|
// },
|
||||||
|
// (error) => {
|
||||||
|
// const originalRequest = error.config;
|
||||||
|
|
||||||
|
// // Debug logging
|
||||||
|
// console.error('[API] Error response:', {
|
||||||
|
// url: originalRequest.url,
|
||||||
|
// status: error.response?.status,
|
||||||
|
// data: error.response?.data
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Handle 401 specifically
|
||||||
|
// if (error.response?.status === 401 && !originalRequest._retry) {
|
||||||
|
// originalRequest._retry = true;
|
||||||
|
// console.warn('[API] Attempting token refresh...');
|
||||||
|
// // Add your token refresh logic here if needed
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return Promise.reject(error);
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // API methods
|
||||||
|
// const apiService = {
|
||||||
|
// get: (url, params, options = {}) =>
|
||||||
|
// apiClient.get(url, { ...options, params }).catch(handleError),
|
||||||
|
|
||||||
|
// post: (url, body = {}, options = {}) =>
|
||||||
|
// apiClient.post(url, body, options).catch(handleError),
|
||||||
|
|
||||||
|
// put: (url, body = {}, options = {}) =>
|
||||||
|
// apiClient.put(url, body, options).catch(handleError),
|
||||||
|
|
||||||
|
// delete: (url, options = {}) =>
|
||||||
|
// apiClient.delete(url, options).catch(handleError),
|
||||||
|
|
||||||
|
// // Add patch if needed
|
||||||
|
// patch: (url, body = {}, options = {}) =>
|
||||||
|
// apiClient.patch(url, body, options).catch(handleError)
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Enhanced error handler
|
||||||
|
// const handleError = (error) => {
|
||||||
|
// // Your existing error handling logic
|
||||||
|
// // ...
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Specific API endpoints
|
||||||
|
// export const getSubmenuItems = async (id) => {
|
||||||
|
// try {
|
||||||
|
// const response = await apiService.get(`/api1/submenu1/${id}`);
|
||||||
|
// return response.data;
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Error fetching submenu items:', error);
|
||||||
|
// throw error; // Re-throw for component-level handling
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Export the configured service
|
||||||
|
// export default apiService;
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { getToken } from '../../src/utils/tokenService';
|
|
||||||
|
|
||||||
const BASE_URL = process.env.REACT_APP_API_BASE_URL;
|
const BASE_URL = process.env.REACT_APP_API_BASE_URL ;
|
||||||
|
|
||||||
const apiClient = axios.create({
|
const apiService = axios.create({
|
||||||
baseURL: BASE_URL,
|
baseURL: BASE_URL,
|
||||||
headers: {
|
timeout: 30000,
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
// Add a request interceptor to include Authorization header
|
|
||||||
apiClient.interceptors.request.use(
|
// Request interceptor for auth token
|
||||||
|
apiService.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
const token = getToken();
|
const token = localStorage.getItem('authToken');
|
||||||
if (token) {
|
if (token) {
|
||||||
console.log("token: ",token);
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
config.headers['Authorization'] = `Bearer ${token}`;
|
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => Promise.reject(error)
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generic error handler function
|
// Response interceptor
|
||||||
const handleError = (error) => {
|
apiService.interceptors.response.use(
|
||||||
let errorMessage = 'An unknown error occurred';
|
(response) => response,
|
||||||
console.error('Error Details:', error);
|
(error) => {
|
||||||
|
if (error.response?.status === 401) {
|
||||||
if (error.response) {
|
localStorage.removeItem('authToken');
|
||||||
// HTTP errors
|
window.location.href = '/login';
|
||||||
switch (error.response.status) {
|
|
||||||
case 401:
|
|
||||||
errorMessage = 'Unauthorized - Please login again.';
|
|
||||||
break;
|
|
||||||
case 403:
|
|
||||||
errorMessage = 'Forbidden - Access denied.';
|
|
||||||
break;
|
|
||||||
case 404:
|
|
||||||
errorMessage = 'Service not found.';
|
|
||||||
break;
|
|
||||||
case 408:
|
|
||||||
errorMessage = 'Request timed out.';
|
|
||||||
break;
|
|
||||||
case 500:
|
|
||||||
errorMessage = 'Internal server error.';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errorMessage = `Unexpected error: ${error.response.statusText || 'Server Error'}`;
|
|
||||||
}
|
}
|
||||||
} else if (error.request) {
|
return Promise.reject(error);
|
||||||
// No response received
|
|
||||||
errorMessage = 'No response from server. Please check your connection.';
|
|
||||||
} else {
|
|
||||||
// Other errors
|
|
||||||
errorMessage = error.message || 'An unexpected error occurred.';
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return Promise.reject(errorMessage); // Return error message as rejected promise
|
// Add downloadFile method
|
||||||
|
apiService.downloadFile = async (url, data) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.post(url, data, {
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define the reusable methods
|
export default apiService;
|
||||||
// const apiService = {
|
|
||||||
// get: (url, params) =>
|
|
||||||
// apiClient
|
|
||||||
// .get(url, { params: params || {} })
|
|
||||||
// .catch(handleError), // Attach error handler
|
|
||||||
// post: (url, body = {}) =>
|
|
||||||
// apiClient
|
|
||||||
// .post(url, body)
|
|
||||||
// .catch(handleError), // Attach error handler
|
|
||||||
// put: (url, body = {}) =>
|
|
||||||
// apiClient
|
|
||||||
// .put(url, body)
|
|
||||||
// .catch(handleError), // Attach error handler
|
|
||||||
// delete: (url) =>
|
|
||||||
// apiClient
|
|
||||||
// .delete(url)
|
|
||||||
// .catch(handleError), // Attach error handler
|
|
||||||
// };
|
|
||||||
|
|
||||||
const apiService = {
|
|
||||||
get: (url, params) =>
|
|
||||||
apiClient
|
|
||||||
.get(url, { params: params || {} })
|
|
||||||
.catch(handleError), // Attach error handler
|
|
||||||
|
|
||||||
post: (url, body = {}, options = {}) =>
|
|
||||||
apiClient
|
|
||||||
.post(url, body, options) // Pass options such as headers
|
|
||||||
.catch(handleError), // Attach error handler
|
|
||||||
|
|
||||||
put: (url, body = {}, options = {}) =>
|
|
||||||
apiClient
|
|
||||||
.put(url, body, options) // Pass options such as headers
|
|
||||||
.catch(handleError), // Attach error handler
|
|
||||||
|
|
||||||
delete: (url, options = {}) =>
|
|
||||||
apiClient
|
|
||||||
.delete(url, options) // Pass options such as headers
|
|
||||||
.catch(handleError), // Attach error handler
|
|
||||||
};
|
|
||||||
// Add at the bottom of APIService.js
|
|
||||||
|
|
||||||
export const getSubmenuItems = async (id) => {
|
|
||||||
const response = await apiService.get(`/api1/submenu1/${id}`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
export const addSubmenuItem = async (menuId, submenuData) => {
|
|
||||||
const response = await apiService.post(`/api1/menu/${menuId}/submenu`, submenuData);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
export const updateMenuItem = (id, formData) => apiService.put(`/api1/submenu1/${id}`, formData);
|
|
||||||
export const deleteMenuItem = (id) => apiService.delete(`/api1/menu/${id}`);
|
|
||||||
|
|
||||||
|
|
||||||
export default apiService;
|
|
||||||
22
src/ApiServices/AddReportSQLBuilderAPI.js
Normal file
22
src/ApiServices/AddReportSQLBuilderAPI.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export const addSQLReport = async (formData) => {
|
||||||
|
try {
|
||||||
|
const token = localStorage.getItem('authToken');
|
||||||
|
const response = await axios.post(
|
||||||
|
`${process.env.REACT_APP_API_BASE_URL}/Rpt_builder2/Rpt_builder2`,
|
||||||
|
formData,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error adding SQL report:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
17
src/ApiServices/DeleteReportSQLAPI.js
Normal file
17
src/ApiServices/DeleteReportSQLAPI.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import apiService from '../APIRequestService/APIServices';
|
||||||
|
|
||||||
|
|
||||||
|
export const deleteReportSQL = async (id) => {
|
||||||
|
if (!id) {
|
||||||
|
throw new Error("ID is required for deletion.");
|
||||||
|
}
|
||||||
|
const BASE_URL = `${process.env.REACT_APP_API_BASE_URL}/Rpt_builder2/Rpt_builder2/${id}`;
|
||||||
|
try {
|
||||||
|
const response = await apiService.delete(BASE_URL);
|
||||||
|
console.log("Delete response:", response.data);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in API call:", error.response || error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
134
src/ApiServices/ReportBuilderService.js
Normal file
134
src/ApiServices/ReportBuilderService.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import apiService from '../APIRequestService/APIServices';
|
||||||
|
|
||||||
|
const API_BASE_URL = 'api';
|
||||||
|
|
||||||
|
const ReportBuilderService = {
|
||||||
|
getById: (id) => apiService.get(`${API_BASE_URL}/edit-report/${id}`),
|
||||||
|
|
||||||
|
buildReport: (id) => {
|
||||||
|
const params = { id };
|
||||||
|
return apiService.get(`${API_BASE_URL}/build_report`, params);
|
||||||
|
},
|
||||||
|
|
||||||
|
getAll: (moduleId, page = 0, size = 1000) => {
|
||||||
|
const params = { page, size, moduleId };
|
||||||
|
return apiService.get(`${API_BASE_URL}/report-builder-by-id`, params);
|
||||||
|
},
|
||||||
|
|
||||||
|
create: (fbHeader, moduleId) => {
|
||||||
|
const params = { moduleId };
|
||||||
|
return apiService.post(`${API_BASE_URL}/report-builder`, fbHeader, { params });
|
||||||
|
},
|
||||||
|
|
||||||
|
createservicereport: (fbHeader, moduleId) => {
|
||||||
|
const params = { moduleId };
|
||||||
|
return apiService.post(`${API_BASE_URL}/report-builder_service`, fbHeader, { params });
|
||||||
|
},
|
||||||
|
|
||||||
|
createQuery: (reportId) => {
|
||||||
|
const params = { reportId };
|
||||||
|
return apiService.post(`${API_BASE_URL}/add-master-query`, {}, { params });
|
||||||
|
},
|
||||||
|
|
||||||
|
update: (id, functionRegister) => {
|
||||||
|
return apiService.put(`${API_BASE_URL}/add-master-query/${id}`, functionRegister);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateservicereport: (id, functionRegister) => {
|
||||||
|
return apiService.put(`${API_BASE_URL}/updatereport/${id}`, functionRegister);
|
||||||
|
},
|
||||||
|
|
||||||
|
getMasterQuery: (id) => apiService.get(`${API_BASE_URL}/master-query/${id}`),
|
||||||
|
|
||||||
|
getMasterData: (query) => {
|
||||||
|
const params = { sql_query: query };
|
||||||
|
return apiService.get(`${API_BASE_URL}/master-query-data`, params);
|
||||||
|
},
|
||||||
|
|
||||||
|
report2: (serviceName) => apiService.post(`${API_BASE_URL}/add-report`, serviceName),
|
||||||
|
|
||||||
|
saveq: (data) => apiService.post('FndQuery/query', data),
|
||||||
|
|
||||||
|
getall: () => apiService.get('FndQuery/query'),
|
||||||
|
|
||||||
|
getreportdata: (apiName) => {
|
||||||
|
const url = `${API_BASE_URL}/${apiName}`;
|
||||||
|
return apiService.get(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
getDatabase: () => apiService.get('SqlworkbenchSqlcont/sql'),
|
||||||
|
|
||||||
|
getTableListn: (val) => apiService.get(`Table_list/${val}`), // table list
|
||||||
|
|
||||||
|
getcolListn: (val, val1) => apiService.get(`Table_list/${val}/${val1}`), // column list
|
||||||
|
|
||||||
|
getColumnList: (tableSchema, tables) => {
|
||||||
|
const params = { str: tables.join(',') };
|
||||||
|
return apiService.get(`${API_BASE_URL}/AllTable_list/${tableSchema}`, { params });
|
||||||
|
},
|
||||||
|
|
||||||
|
getAllColumnsFromAllTables: (tableNames) => {
|
||||||
|
// If tableNames is an array, join it with commas
|
||||||
|
const tables = Array.isArray(tableNames) ? tableNames.join(',') : tableNames;
|
||||||
|
return apiService.get(`Alias_Table_list/${tables}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
getcollist: (table) => apiService.get(`fndMenu/loadcolumn/${table}`),
|
||||||
|
|
||||||
|
createdb: (data) => apiService.post('SqlworkbenchSqlcont/sql', data),
|
||||||
|
|
||||||
|
updateSqlModel: (id, sqlModel) => apiService.put(`SqlworkbenchSqlcont/sql/${id}`, sqlModel),
|
||||||
|
|
||||||
|
getSqlModelById: (id) => apiService.get(`SqlworkbenchSqlcont/sql/${id}`),
|
||||||
|
|
||||||
|
deleteSqlModel: (id) => apiService.delete(`SqlworkbenchSqlcont/sql/${id}`),
|
||||||
|
|
||||||
|
getallentity: () => apiService.get(`${API_BASE_URL}/report-builder`),
|
||||||
|
|
||||||
|
saveData: (data) => apiService.post('Rpt_builder/Rpt_builder', data),
|
||||||
|
|
||||||
|
getDetails: () => apiService.get('Rpt_builder/Rpt_builder'),
|
||||||
|
|
||||||
|
getDetailsById: (id) => apiService.get(`Rpt_builder/Rpt_builder/${id}`),
|
||||||
|
|
||||||
|
deleteById: (id) => apiService.delete(`Rpt_builder/Rpt_builder/${id}`),
|
||||||
|
|
||||||
|
updateData: (data, id) => apiService.put(`Rpt_builder/Rpt_builder/${id}`, data),
|
||||||
|
|
||||||
|
saverbData: (data) => apiService.post('Rpt_builder2/Rpt_builder2', data),
|
||||||
|
|
||||||
|
getrbDetails: () => apiService.get('Rpt_builder2/Rpt_builder2'),
|
||||||
|
|
||||||
|
getrbDetailsById: (id) => apiService.get(`Rpt_builder2/Rpt_builder2/${id}`),
|
||||||
|
|
||||||
|
deletrbById: (id) => apiService.delete(`Rpt_builder2/Rpt_builder2/${id}`),
|
||||||
|
|
||||||
|
updaterbData: (data, id) => apiService.put(`Rpt_builder2/Rpt_builder2/${id}`, data),
|
||||||
|
|
||||||
|
updaterbLineData: (data, id) => apiService.put(`Rpt_builder2_lines/update/${id}`, data),
|
||||||
|
|
||||||
|
getrbLineDetailsById: (id) => apiService.get(`Rpt_builder2_lines/Rpt_builder2_lines/${id}`),
|
||||||
|
|
||||||
|
getStdParamById: (id) => apiService.get(`Rpt_builder2/html/build_report2/${id}`),
|
||||||
|
|
||||||
|
getcolumnDetailsByurl: (url) => apiService.get(`Rpt_builder2_lines/geturlkeybyurl?url=${url}`),
|
||||||
|
|
||||||
|
getAllDetailsByurl: (url) => apiService.get(`Rpt_builder2_lines/fetch_data_url?url=${url}`),
|
||||||
|
|
||||||
|
downloadFile: async (format, dataList, name) => {
|
||||||
|
const url = `${API_BASE_URL}/rbbuilder/fileconverter/downloadFile/${format}`;
|
||||||
|
try {
|
||||||
|
const fileData = await apiService.post(url, dataList, { responseType: 'blob' });
|
||||||
|
const blob = new Blob([fileData], { type: 'application/octet-stream' });
|
||||||
|
const fileName = name ? `${name}.${format}` : `download.${format}`;
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = window.URL.createObjectURL(blob);
|
||||||
|
link.download = fileName;
|
||||||
|
link.click();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading file:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReportBuilderService;
|
||||||
49
src/ApiServices/ReportRunnerAPI.js
Normal file
49
src/ApiServices/ReportRunnerAPI.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import apiService from '../APIRequestService/APIServices';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
|
// Function to run a specific report
|
||||||
|
export const runReport = async (reportId) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.get(`Rpt_builder2/Rpt_builder2/${reportId}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error running report:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to fetch all reports
|
||||||
|
export const fetchAllReportsApi = async () => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.get('Rpt_builder2/Rpt_builder2');
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching reports:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to fetch standard parameters
|
||||||
|
export const fetchStandardParameters = async (url) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.get(`Rpt_builder2_lines/fetch_data_url?url=${encodeURIComponent(url)}`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching parameters:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// File download function
|
||||||
|
export const downloadFile = async (format, dataList, name) => {
|
||||||
|
try {
|
||||||
|
const blob = await apiService.downloadFile(
|
||||||
|
`rbbuilder/fileconverter/downloadFile/${format}`,
|
||||||
|
dataList
|
||||||
|
);
|
||||||
|
saveAs(blob, `${name}.${format}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading file:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
21
src/ApiServices/ReportSQLBuilderAPI.js
Normal file
21
src/ApiServices/ReportSQLBuilderAPI.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// src/api/ReportSqlBuilderApi.js
|
||||||
|
|
||||||
|
import apiService from '../APIRequestService/APIServices';// Assuming apiService is in the same directory
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const BASE_URL = `${process.env.REACT_APP_API_BASE_URL}/Rpt_builder2/Rpt_builder2`;
|
||||||
|
console.log("BASE_URL:", BASE_URL); // Log the base URL for debugging
|
||||||
|
const ReportSqlBuilderApi = {
|
||||||
|
fetchUserDetails: async () => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.get(BASE_URL);
|
||||||
|
return response.data; // Return only the data part of the response
|
||||||
|
} catch (error) {
|
||||||
|
throw error; // Let the error be handled by the calling component
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReportSqlBuilderApi;
|
||||||
|
|
||||||
0
src/ApiServices/SQLWorksheetAPI.js
Normal file
0
src/ApiServices/SQLWorksheetAPI.js
Normal file
23
src/ApiServices/SystemparameterApi.js
Normal file
23
src/ApiServices/SystemparameterApi.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import apiService from '../APIRequestService/APIService';
|
||||||
|
|
||||||
|
export const getSysParameter = async (id) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.get(`/sysparam/getSysParams/${id}`);
|
||||||
|
return response.data; // Return only the data part of the response
|
||||||
|
} catch (error) {
|
||||||
|
throw error; // Let the error be handled by the calling component
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addSysParameter = async (formdata) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.put(`/sysparam/updateSysParams/${1}`,formdata);
|
||||||
|
console.log("add response data ",response.data)
|
||||||
|
return response.data; // Return only the data part of the response
|
||||||
|
} catch (error) {
|
||||||
|
throw error; // Let the error be handled by the calling component
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
16
src/ApiServices/UpdateReportSQLBuilderAPI.js
Normal file
16
src/ApiServices/UpdateReportSQLBuilderAPI.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import apiService from '../APIRequestService/APIServices';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const UpdateReportSQLBuilder = async (id,formData) => {
|
||||||
|
const BASE_URL = `${process.env.REACT_APP_API_BASE_URL}/Rpt_builder2/Rpt_builder2/${id}`;
|
||||||
|
try {
|
||||||
|
const response = await apiService.put(BASE_URL, formData);
|
||||||
|
console.log("update response: ",response.data);
|
||||||
|
|
||||||
|
return response.data; // Return only the data part of the response
|
||||||
|
} catch (error) {
|
||||||
|
throw error; // Let the error be handled by the calling component
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/ApiServices/reportBaseUrlAddAPI.js
Normal file
24
src/ApiServices/reportBaseUrlAddAPI.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// reportBaseUrlAddAPI.js
|
||||||
|
import apiService from '../APIRequestService/APIServices';
|
||||||
|
|
||||||
|
// Function to handle the Add API request
|
||||||
|
export const addReport = async (formData) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.post('/Rpt_builder2/Rpt_builder2', formData);
|
||||||
|
|
||||||
|
console.log("add Report response: ",response)
|
||||||
|
return response; // Return the response to handle success in the component
|
||||||
|
} catch (error) {
|
||||||
|
throw error; // Re-throw error to handle it in the calling component
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to fetch keys from URL
|
||||||
|
export const getKeysFromUrl = async (url) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.get(`/api/report-builder/columns`, { url });
|
||||||
|
return response; // Return the response for further processing
|
||||||
|
} catch (error) {
|
||||||
|
throw error; // Re-throw error to handle it in the calling component
|
||||||
|
}
|
||||||
|
};
|
||||||
35
src/ApiServices/reportBaseUrlAllAPI.js
Normal file
35
src/ApiServices/reportBaseUrlAllAPI.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
// Create axios instance
|
||||||
|
const apiService = axios.create({
|
||||||
|
baseURL: process.env.REACT_APP_API_BASE_URL,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add request interceptor to inject the token
|
||||||
|
apiService.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
const token = localStorage.getItem('authToken');
|
||||||
|
if (token) {
|
||||||
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add response interceptor to handle 401 errors
|
||||||
|
apiService.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
if (error.response?.status === 401) {
|
||||||
|
// Handle token expiration (e.g., redirect to login)
|
||||||
|
localStorage.removeItem('authToken');
|
||||||
|
window.location.href = '/login';
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default apiService;
|
||||||
12
src/ApiServices/reportBaseUrlDeleteAPI.js
Normal file
12
src/ApiServices/reportBaseUrlDeleteAPI.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import apiService from '../APIRequestService/APIServices';
|
||||||
|
|
||||||
|
|
||||||
|
export const deleteReport = async (reportId) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.delete(`/Rpt_builder2/Rpt_builder2/${reportId}`);
|
||||||
|
console.log(response.data);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
16
src/ApiServices/reportBaseUrlEditAPI.js
Normal file
16
src/ApiServices/reportBaseUrlEditAPI.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import apiService from '../APIRequestService/APIServices';
|
||||||
|
|
||||||
|
const editReport = async (id, payload) => {
|
||||||
|
try {
|
||||||
|
const response = await apiService.put(`Rpt_builder2_lines/update/${id}`, payload);
|
||||||
|
console.log("Edit api report base url ", response.data)
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in editReport:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
editReport,
|
||||||
|
};
|
||||||
42
src/App.js
42
src/App.js
@@ -37,6 +37,8 @@ import DashboardNewAdd from "./components/dashboardnew/dashboardadd/dashboardbui
|
|||||||
import DashboardNewEdit from "./components/dashboardnew/editdashboard/editformdashboard";
|
import DashboardNewEdit from "./components/dashboardnew/editdashboard/editformdashboard";
|
||||||
import EditNewDash from "./components/dashboardnew/editdashboard/editdashboard";
|
import EditNewDash from "./components/dashboardnew/editdashboard/editdashboard";
|
||||||
import SubMenuMaintenance from "./components/Dashboard/sub menu/submenumaintanence";
|
import SubMenuMaintenance from "./components/Dashboard/sub menu/submenumaintanence";
|
||||||
|
import ReportRunnerAll from "./components/Dashboard/reports/reportrunnerall";
|
||||||
|
import ReportBuilderSQL from "./components/Dashboard/reports/reportbuildersql";
|
||||||
const theme = createTheme({
|
const theme = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
primary: {
|
primary: {
|
||||||
@@ -65,22 +67,22 @@ const App = () => {
|
|||||||
draggable
|
draggable
|
||||||
pauseOnHover
|
pauseOnHover
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
|
|
||||||
{/* Main dashboard route */}
|
{/* Main dashboard route */}
|
||||||
<Route path="/dashboard" element={<Dashboard />}>
|
<Route path="/dashboard/*" element={<Dashboard />}>
|
||||||
<Route index element={<HomePage />} />
|
<Route index element={<HomePage />} />
|
||||||
|
|
||||||
{/* Setup section with all maintenance routes */}
|
{/* Setup section with all maintenance routes */}
|
||||||
<Route path="setup" element={<Setup />}>
|
<Route path="setup" element={<Setup />}>
|
||||||
<Route index element={<div>Select a setup option from the menu</div>} />
|
<Route index element={<div>Select a setup option from the menu</div>} />
|
||||||
<Route path="user-maintenance" element={<UserMaintenance />} />
|
<Route path="user-maintenance" element={<UserMaintenance />} />
|
||||||
<Route path="user-group-maintenance" element={<UserGroupMaintenance />} />
|
<Route path="user-group-maintenance" element={<UserGroupMaintenance />} />
|
||||||
<Route path="menu-maintenance" element={<MenuMaintenance />} />
|
<Route path="menu-maintenance" element={<MenuMaintenance />} />
|
||||||
<Route path="sub-menu-maintenance/:menuItemId" element={<SubMenuMaintenance />} />
|
<Route path="sub-menu-maintenance/:menuItemId" element={<SubMenuMaintenance/>} />
|
||||||
|
|
||||||
<Route path="menu-access-control" element={<MenuAccessControl />} />
|
<Route path="menu-access-control" element={<MenuAccessControl />} />
|
||||||
<Route path="system-parameters" element={<SystemParameters />} />
|
<Route path="system-parameters" element={<SystemParameters />} />
|
||||||
<Route path="access-type" element={<AccessType />} />
|
<Route path="access-type" element={<AccessType />} />
|
||||||
@@ -90,23 +92,25 @@ const App = () => {
|
|||||||
{/* Additional components */}
|
{/* Additional components */}
|
||||||
<Route path="code-extension" element={<CodeExtension />} />
|
<Route path="code-extension" element={<CodeExtension />} />
|
||||||
<Route path="dynamic-table" element={<DynamicTable />} />
|
<Route path="dynamic-table" element={<DynamicTable />} />
|
||||||
|
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="dashboard-runner-all" element={<DashboardRunnerAll />} />
|
<Route path="dashboard-runner-all" element={<DashboardRunnerAll/>}/>
|
||||||
<Route path="dashboard-new-all" element={<DashboardNewAll />} />
|
<Route path="dashboard-new-all" element={<DashboardNewAll/>}/>
|
||||||
<Route path="dashboard-new-add" element={<DashboardNewAdd />} />
|
<Route path="dashboard-new-add" element={<DashboardNewAdd/>}/>
|
||||||
<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="reports" element={<Report />} />
|
||||||
<Route path="reports" element={<Report />} />
|
<Route path="user-report" element={<ReportBuilderSQL />} />
|
||||||
<Route path="about" element={<About />} />
|
{/* <Route path="reports" element={<ReportRunnerAll />} /> */}
|
||||||
<Route path="profile" element={<Profile />} />
|
<Route path="about" element={<About />} />
|
||||||
|
<Route path="profile" element={<Profile />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* buildercomponents */}
|
{/* buildercomponents */}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Route path="*" element={<Navigate to="/" replace />} />
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { getToken } from '../../../utils/tokenService';
|
|||||||
|
|
||||||
// Create axios instance with base configuration
|
// Create axios instance with base configuration
|
||||||
const apiClient = axios.create({
|
const apiClient = axios.create({
|
||||||
baseURL: process.env.REACT_APP_API_URL || 'http://157.66.191.31:33730/back/',
|
baseURL: process.env.REACT_APP_API_URL ,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add request interceptor to inject token
|
// Add request interceptor to inject token
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import ApiRegistery from "./ApiRegistery/ApiRegistery";
|
|||||||
import TokenRegistery from "./TokenRegistery/TokenRegistery";
|
import TokenRegistery from "./TokenRegistery/TokenRegistery";
|
||||||
import HomePage from "./HomePage";
|
import HomePage from "./HomePage";
|
||||||
import Setup from "./Setup";
|
import Setup from "./Setup";
|
||||||
import Report from "./reports/Report";
|
// import Report from "./reports/Report";
|
||||||
import SequenceGenerator from "./document sequence/sequencegenerator";
|
import SequenceGenerator from "./document sequence/sequencegenerator";
|
||||||
import About from "./dropdown/about";
|
import About from "./dropdown/about";
|
||||||
import Profile from "./dropdown/profile";
|
import Profile from "./dropdown/profile";
|
||||||
@@ -61,7 +61,9 @@ import DashboardNewEdit from "../dashboardnew/editdashboard/editformdashboard";
|
|||||||
import EditNewDash from "../dashboardnew/editdashboard/editdashboard";
|
import EditNewDash from "../dashboardnew/editdashboard/editdashboard";
|
||||||
import DashboardRunner from "../dashboardnew/dashboardrunner/dashboardrunner";
|
import DashboardRunner from "../dashboardnew/dashboardrunner/dashboardrunner";
|
||||||
import SubMenuMaintenance from "./sub menu/submenumaintanence";
|
import SubMenuMaintenance from "./sub menu/submenumaintanence";
|
||||||
|
import ReportRunnerAll from "./reports/reportrunnerall";
|
||||||
|
import Report from "./reports/Report";
|
||||||
|
import ReportBuilderSQL from "./reports/reportbuildersql";
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -585,7 +587,8 @@ const Dashboard = () => {
|
|||||||
<Route path="document-sequence" element={<SequenceGenerator />} />
|
<Route path="document-sequence" element={<SequenceGenerator />} />
|
||||||
<Route path="sub-menu-maintenance/:menuItemId" element={<SubMenuMaintenance/>} />
|
<Route path="sub-menu-maintenance/:menuItemId" element={<SubMenuMaintenance/>} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="reports" element={<Report />} />
|
<Route path="reports" element={<Report/>} />
|
||||||
|
<Route path="user-report" element={<ReportBuilderSQL/>} />
|
||||||
<Route path="about" element={<About/>} />
|
<Route path="about" element={<About/>} />
|
||||||
<Route path="profile" element={<Profile/>} />
|
<Route path="profile" element={<Profile/>} />
|
||||||
<Route path="dashboard-runner-all" element={<DashboardRunnerAll/>}/>
|
<Route path="dashboard-runner-all" element={<DashboardRunnerAll/>}/>
|
||||||
|
|||||||
@@ -1,32 +1,50 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
const Card = ({ report }) => {
|
import { toast } from "react-toastify";
|
||||||
return (
|
import "react-toastify/dist/ReactToastify.css";
|
||||||
<div className="bg-white border border-gray-300 rounded-lg shadow-md p-6 m-4 cursor-pointer transition-transform transform hover:scale-105 hover:shadow-lg flex flex-col items-center justify-center text-center">
|
import {
|
||||||
<h2 className="text-lg font-semibold mb-2">{report.reportName}</h2>
|
Container,
|
||||||
<p className="text-gray-600 mb-2">{report.description}</p>
|
Grid,
|
||||||
<p className="text-gray-600 mb-2">
|
Card,
|
||||||
Active: {report.active ? "Yes" : "No"}
|
CardHeader,
|
||||||
</p>
|
CardContent,
|
||||||
<p className="text-gray-600">Is SQL: {report.isSql ? "Yes" : "No"}</p>
|
Typography,
|
||||||
</div>
|
CircularProgress,
|
||||||
);
|
Alert,
|
||||||
};
|
Paper,
|
||||||
|
Button,
|
||||||
// Define the API base URL using the environment variable
|
Avatar,
|
||||||
const api = process.env.REACT_APP_API_BASE_URL;
|
Chip,
|
||||||
|
Box,
|
||||||
|
IconButton,
|
||||||
|
Divider
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
AddCircleOutline,
|
||||||
|
Storage as Database,
|
||||||
|
Link as LinkIcon,
|
||||||
|
CheckCircle,
|
||||||
|
Cancel,
|
||||||
|
MoreVert,
|
||||||
|
AccessTime
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
const Report = () => {
|
const Report = () => {
|
||||||
const [reports, setReports] = useState([]);
|
const [reports, setReports] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const api = process.env.REACT_APP_API_BASE_URL;
|
||||||
|
console.log("API Base URL:", api);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const token = localStorage.getItem("authToken");
|
const token = localStorage.getItem("authToken");
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
console.error("No auth token found. Redirecting to login.");
|
setError("No auth token found. Please login.");
|
||||||
// You can redirect to the login page here if needed
|
toast.error("Authentication required");
|
||||||
|
navigate("/login");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,37 +56,276 @@ const Report = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Failed to fetch data");
|
throw new Error(response.status === 401 ? "Session expired" : "Failed to fetch data");
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setReports(data);
|
setReports(data);
|
||||||
setLoading(false);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching data:", error);
|
console.error("Error fetching data:", error);
|
||||||
|
setError(error.message);
|
||||||
|
if (error.message === "Session expired") {
|
||||||
|
toast.error("Session expired. Please login again.");
|
||||||
|
navigate("/login");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchData();
|
fetchData();
|
||||||
}, []);
|
}, [api, navigate]);
|
||||||
|
|
||||||
|
const goToAddSQLReport = () => {
|
||||||
|
navigate("/dashboard/user-report");
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToAddURLReport = () => {
|
||||||
|
navigate("/admin/reportbuild2all");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCardClick = (report) => {
|
||||||
|
if (report.isSql) {
|
||||||
|
navigate(`/admin/report-runner1/${report.id}`, {
|
||||||
|
state: { reportId: report.id, reportData: report }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigate(`/admin/report-runner2/${report.id}`, {
|
||||||
|
state: { reportId: report.id, reportData: report }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-100 p-4 flex flex-col items-center">
|
<Container maxWidth="xl" sx={{ py: 4 }}>
|
||||||
<div className="mb-6">
|
{/* Header Section */}
|
||||||
<h1 className="text-3xl font-semibold text-gray-700">Reports</h1>
|
<Paper elevation={2} sx={{
|
||||||
</div>
|
p: 3,
|
||||||
{loading ? (
|
mb: 4,
|
||||||
<p className="text-gray-700">Loading...</p>
|
display: 'flex',
|
||||||
) : (
|
justifyContent: 'space-between',
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
|
alignItems: 'center',
|
||||||
{reports.map((report) => (
|
borderRadius: '12px'
|
||||||
<Card key={report.id} report={report} />
|
}}>
|
||||||
))}
|
<Typography variant="h4" color="primary" sx={{ fontWeight: 'bold' }}>
|
||||||
</div>
|
All Reports
|
||||||
|
</Typography>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddCircleOutline />}
|
||||||
|
onClick={goToAddSQLReport}
|
||||||
|
sx={{ mr: 2 }}
|
||||||
|
>
|
||||||
|
Report Builder SQL
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddCircleOutline />}
|
||||||
|
onClick={goToAddURLReport}
|
||||||
|
>
|
||||||
|
Report Builder URL
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
{/* Loading State */}
|
||||||
|
{loading && (
|
||||||
|
<Grid container justifyContent="center" sx={{ py: 8 }}>
|
||||||
|
<CircularProgress size={60} />
|
||||||
|
</Grid>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
{/* Error State */}
|
||||||
|
{error && !loading && (
|
||||||
|
<Alert severity="error" sx={{ mb: 4 }}>
|
||||||
|
{error}
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Reports Grid */}
|
||||||
|
{!loading && reports.length > 0 && (
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
{reports.map((report) => (
|
||||||
|
<Grid item xs={12} sm={6} md={4} lg={3} key={report.id}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
cursor: 'pointer',
|
||||||
|
transition: 'transform 0.3s, box-shadow 0.3s',
|
||||||
|
'&:hover': {
|
||||||
|
transform: 'translateY(-8px)',
|
||||||
|
boxShadow: 6
|
||||||
|
},
|
||||||
|
borderRadius: '16px',
|
||||||
|
overflow: 'hidden'
|
||||||
|
}}
|
||||||
|
onClick={() => handleCardClick(report)}
|
||||||
|
>
|
||||||
|
{/* Card Header with Gradient */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
background: report.isSql
|
||||||
|
? 'linear-gradient(135deg, #f5f7fa 0%,rgb(198, 218, 255) 100%)'
|
||||||
|
: 'linear-gradient(135deg, #fff9f0 0%,rgb(217, 204, 255) 100%)',
|
||||||
|
height: '60px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
mr: 2,
|
||||||
|
borderRadius: '10px',
|
||||||
|
bgcolor: report.isSql ? 'rgba(65, 105, 225, 0.15)' : 'rgba(255, 165, 0, 0.15)',
|
||||||
|
color: report.isSql ? '#4169E1' : '#FF8C00'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{report.isSql ? <Database /> : <LinkIcon />}
|
||||||
|
</Avatar>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle2"
|
||||||
|
sx={{
|
||||||
|
color: report.isSql ? '#4169E1' : '#FF8C00',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{report.isSql ? "SQL Report" : "URL Report"}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Status Chip */}
|
||||||
|
<Chip
|
||||||
|
label={report.active ? "Active" : "Inactive"}
|
||||||
|
size="small"
|
||||||
|
color={report.active ? "success" : "error"}
|
||||||
|
icon={report.active ? <CheckCircle fontSize="small" /> : <Cancel fontSize="small" />}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: report.active ? 'rgba(40, 167, 69, 0.1)' : 'rgba(220, 53, 69, 0.1)',
|
||||||
|
color: report.active ? '#28a745' : '#dc3545',
|
||||||
|
px: 1,
|
||||||
|
py: 0.5
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Card Content */}
|
||||||
|
<CardContent sx={{ flexGrow: 1, p: 3 }}>
|
||||||
|
<Typography
|
||||||
|
gutterBottom
|
||||||
|
variant="h6"
|
||||||
|
component="div"
|
||||||
|
noWrap
|
||||||
|
sx={{
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: 'text.primary',
|
||||||
|
mb: 2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{report.reportName}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{
|
||||||
|
display: '-webkit-box',
|
||||||
|
WebkitLineClamp: 2,
|
||||||
|
WebkitBoxOrient: 'vertical',
|
||||||
|
overflow: 'hidden',
|
||||||
|
minHeight: '40px',
|
||||||
|
lineHeight: 1.5,
|
||||||
|
fontSize: '0.9rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{report.description || "No description available"}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
|
||||||
|
{/* Card Footer */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
borderTop: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
backgroundColor: 'background.default'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<AccessTime fontSize="small" sx={{ mr: 1, color: 'text.secondary' }} />
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
Updated: {new Date(report.updatedAt).toLocaleDateString()}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'action.hover',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'action.selected'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
// Add menu functionality here
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVert fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Empty State */}
|
||||||
|
{!loading && reports.length === 0 && !error && (
|
||||||
|
<Paper sx={{
|
||||||
|
p: 4,
|
||||||
|
textAlign: 'center',
|
||||||
|
borderRadius: '12px'
|
||||||
|
}}>
|
||||||
|
<Typography variant="h6" gutterBottom>
|
||||||
|
No reports available
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
|
||||||
|
Create your first report by clicking one of the "Add Report" buttons
|
||||||
|
</Typography>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddCircleOutline />}
|
||||||
|
onClick={goToAddSQLReport}
|
||||||
|
sx={{ mr: 2 }}
|
||||||
|
>
|
||||||
|
Add SQL Report
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddCircleOutline />}
|
||||||
|
onClick={goToAddURLReport}
|
||||||
|
>
|
||||||
|
Add URL Report
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Report;
|
export default Report;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,15 +2,45 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
import "react-toastify/dist/ReactToastify.css";
|
||||||
import { fetchAllReportsApi } from '../../../APIServices/ReportRunnerAPI';
|
import { fetchAllReportsApi } from '../../../ApiServices/ReportRunnerAPI';
|
||||||
|
import {
|
||||||
|
Container,
|
||||||
|
Grid,
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardContent,
|
||||||
|
CardActions,
|
||||||
|
Typography,
|
||||||
|
Button,
|
||||||
|
CircularProgress,
|
||||||
|
Alert,
|
||||||
|
Dialog,
|
||||||
|
DialogTitle,
|
||||||
|
DialogContent,
|
||||||
|
DialogActions,
|
||||||
|
Avatar,
|
||||||
|
IconButton,
|
||||||
|
Chip,
|
||||||
|
Divider,
|
||||||
|
Paper
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
AddCircleOutline,
|
||||||
|
Link,
|
||||||
|
Storage as Database,
|
||||||
|
MoreVert,
|
||||||
|
AccessTime,
|
||||||
|
Delete,
|
||||||
|
CheckCircle,
|
||||||
|
Cancel
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
const ReportRunnerAll = () => {
|
const ReportRunnerAll = () => {
|
||||||
const [gridData, setGridData] = useState([]);
|
const [gridData, setGridData] = useState([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [rowSelected, setRowSelected] = useState(null);
|
const [rowSelected, setRowSelected] = useState(null);
|
||||||
const [modalDelete, setModalDelete] = useState(false);
|
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
||||||
const [reports, setReports] = useState([]);
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@@ -23,16 +53,12 @@ const ReportRunnerAll = () => {
|
|||||||
try {
|
try {
|
||||||
const data = await fetchAllReportsApi();
|
const data = await fetchAllReportsApi();
|
||||||
console.log("Fetched all reports:", data);
|
console.log("Fetched all reports:", data);
|
||||||
|
|
||||||
setGridData(data);
|
setGridData(data);
|
||||||
setReports(data);
|
if (data.length === 0) setError("No data available");
|
||||||
|
|
||||||
if (data.length === 0) {
|
|
||||||
setError("No data available");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error while fetching reports:", error);
|
console.error("Error while fetching reports:", error);
|
||||||
setError("Error fetching data.");
|
setError("Error fetching data.");
|
||||||
|
toast.error("Failed to load reports");
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -42,170 +68,196 @@ const ReportRunnerAll = () => {
|
|||||||
const goToAdd2 = () => navigate("/admin/reportbuild2all");
|
const goToAdd2 = () => navigate("/admin/reportbuild2all");
|
||||||
|
|
||||||
const goToRunner = (report) => {
|
const goToRunner = (report) => {
|
||||||
console.log("at time of navigating reportID: ",report.id, " report: ",report);
|
|
||||||
if (report.isSql) {
|
if (report.isSql) {
|
||||||
navigate(`/admin/report-runner1/${report.id}`,{ state: { reportId: report.id, reportData: report}});
|
navigate(`/admin/report-runner1/${report.id}`, {
|
||||||
|
state: { reportId: report.id, reportData: report }
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
navigate(`/admin/report-runner2/${report.id}`,{ state: { reportId: report.id, reportData: report}});
|
navigate(`/admin/report-runner2/${report.id}`, {
|
||||||
|
state: { reportId: report.id, reportData: report }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (id) => {
|
const handleDelete = async (id) => {
|
||||||
setModalDelete(false);
|
setOpenDeleteDialog(false);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/report-builder/${id}`, { method: "DELETE" });
|
const response = await fetch(`/api/report-builder/${id}`, {
|
||||||
|
method: "DELETE"
|
||||||
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
toast.success("Deleted successfully");
|
toast.success("Report deleted successfully");
|
||||||
fetchAllReports();
|
fetchAllReports();
|
||||||
} else {
|
} else {
|
||||||
toast.error("Error deleting data.");
|
throw new Error("Failed to delete");
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
toast.error("Error deleting data.");
|
toast.error("Error deleting report");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDeleteModal = (row) => {
|
const openDeleteModal = (row) => {
|
||||||
setRowSelected(row);
|
setRowSelected(row);
|
||||||
setModalDelete(true);
|
setOpenDeleteDialog(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid p-4">
|
<Container maxWidth="xl" sx={{ py: 4 }}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="d-flex justify-content-between align-items-center mb-4">
|
<Paper elevation={2} sx={{ p: 3, mb: 4, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<h3 className="m-0"><strong>All Reports</strong></h3>
|
<Typography variant="h4" color="primary">
|
||||||
|
<Database sx={{ verticalAlign: 'middle', mr: 1 }} />
|
||||||
|
All Reports
|
||||||
|
</Typography>
|
||||||
<div>
|
<div>
|
||||||
<button className="btn btn-primary me-2" onClick={goToAdd}>
|
<Button
|
||||||
<i className="bi bi-plus me-1"></i> Report Builder SQL
|
variant="contained"
|
||||||
</button>
|
startIcon={<AddCircleOutline />}
|
||||||
<button className="btn btn-primary" onClick={goToAdd2}>
|
onClick={goToAdd}
|
||||||
<i className="bi bi-plus me-1"></i> Report Builder URL
|
sx={{ mr: 2 }}
|
||||||
</button>
|
>
|
||||||
|
SQL Report
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<Link />}
|
||||||
|
onClick={goToAdd2}
|
||||||
|
>
|
||||||
|
URL Report
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Paper>
|
||||||
|
|
||||||
{/* Loading Spinner */}
|
{/* Loading state */}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="alert alert-info d-flex align-items-center mt-3">
|
<Grid container justifyContent="center" sx={{ py: 8 }}>
|
||||||
<div className="spinner-border me-2" role="status"></div>
|
<CircularProgress size={60} />
|
||||||
Loading...
|
</Grid>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
|
{/* Error state */}
|
||||||
|
{error && !isLoading && (
|
||||||
|
<Alert severity="error" sx={{ mb: 4 }}>
|
||||||
|
{error}
|
||||||
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Report Cards */}
|
{/* Report Cards */}
|
||||||
{!isLoading && gridData.length > 0 && (
|
{!isLoading && gridData.length > 0 && (
|
||||||
<div className="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4 g-4">
|
<Grid container spacing={3}>
|
||||||
{gridData.map((report, index) => (
|
{gridData.map((report, index) => (
|
||||||
<div className="col" key={index}>
|
<Grid item xs={12} sm={6} md={4} lg={3} key={index}>
|
||||||
<div
|
<Card
|
||||||
className="card h-100 shadow-sm border-0"
|
sx={{
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
cursor: 'pointer',
|
||||||
|
transition: 'transform 0.3s, box-shadow 0.3s',
|
||||||
|
'&:hover': {
|
||||||
|
transform: 'translateY(-8px)',
|
||||||
|
boxShadow: 6
|
||||||
|
}
|
||||||
|
}}
|
||||||
onClick={() => goToRunner(report)}
|
onClick={() => goToRunner(report)}
|
||||||
style={{ cursor: 'pointer' }}
|
|
||||||
>
|
>
|
||||||
{/* Card Header */}
|
{/* Card Header */}
|
||||||
<div
|
<CardHeader
|
||||||
className={`card-header d-flex justify-content-between align-items-center ${report.isSql ? 'bg-primary bg-opacity-10' : 'bg-warning bg-opacity-10'}`}
|
avatar={
|
||||||
>
|
<Avatar sx={{
|
||||||
<div className="d-flex align-items-center">
|
bgcolor: report.isSql ? 'primary.light' : 'secondary.light',
|
||||||
<div className={`me-2 p-2 rounded ${report.isSql ? 'bg-primary bg-opacity-25' : 'bg-warning bg-opacity-25'}`}>
|
color: report.isSql ? 'primary.main' : 'secondary.main'
|
||||||
<i className={`bi ${report.isSql ? 'bi-database' : 'bi-link-45deg'} ${report.isSql ? 'text-primary' : 'text-warning'}`}></i>
|
}}>
|
||||||
</div>
|
{report.isSql ? <Database /> : <Link />}
|
||||||
<span className={`fw-semibold ${report.isSql ? 'text-primary' : 'text-warning'}`}>
|
</Avatar>
|
||||||
{report.isSql == null ? "N/A" : report.isSql ? "SQL Report" : "URL Report"}
|
}
|
||||||
</span>
|
action={
|
||||||
</div>
|
<Chip
|
||||||
<span className={`badge ${report.active ? 'bg-success' : 'bg-danger'}`}>
|
label={report.active ? "Active" : "Inactive"}
|
||||||
{report.active ? "Active" : "Inactive"}
|
size="small"
|
||||||
</span>
|
color={report.active ? "success" : "error"}
|
||||||
</div>
|
icon={report.active ? <CheckCircle fontSize="small" /> : <Cancel fontSize="small" />}
|
||||||
|
sx={{ ml: 1 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={
|
||||||
|
<Typography variant="subtitle1" color="text.secondary">
|
||||||
|
{report.isSql ? "SQL Report" : "URL Report"}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
bgcolor: report.isSql ? 'primary.50' : 'secondary.50',
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: 'divider'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Card Body */}
|
{/* Card Content */}
|
||||||
<div className="card-body">
|
<CardContent sx={{ flexGrow: 1 }}>
|
||||||
<h5 className="card-title fw-bold text-truncate" title={report.reportName}>
|
<Typography gutterBottom variant="h6" component="div" noWrap>
|
||||||
{report.reportName}
|
{report.reportName}
|
||||||
</h5>
|
</Typography>
|
||||||
<p
|
<Typography variant="body2" color="text.secondary" sx={{
|
||||||
className="card-text text-muted"
|
display: '-webkit-box',
|
||||||
style={{
|
WebkitLineClamp: 2,
|
||||||
display: '-webkit-box',
|
WebkitBoxOrient: 'vertical',
|
||||||
WebkitLineClamp: '2',
|
overflow: 'hidden',
|
||||||
WebkitBoxOrient: 'vertical',
|
minHeight: '40px'
|
||||||
overflow: 'hidden',
|
}}>
|
||||||
height: '42px'
|
|
||||||
}}
|
|
||||||
title={report.description}
|
|
||||||
>
|
|
||||||
{report.description || "No description available"}
|
{report.description || "No description available"}
|
||||||
</p>
|
</Typography>
|
||||||
</div>
|
</CardContent>
|
||||||
|
|
||||||
{/* Card Footer */}
|
{/* Card Footer */}
|
||||||
<div className="card-footer bg-light">
|
<Divider />
|
||||||
<div className="d-flex justify-content-between align-items-center">
|
<CardActions sx={{ justifyContent: 'space-between', p: 2 }}>
|
||||||
<small className="text-muted">
|
<Typography variant="caption" color="text.secondary" sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<i className="bi bi-clock me-1"></i>
|
<AccessTime fontSize="small" sx={{ mr: 0.5 }} />
|
||||||
Updated: {new Date(report.updatedAt).toLocaleDateString()}
|
Updated: {new Date(report.updatedAt).toLocaleDateString()}
|
||||||
</small>
|
</Typography>
|
||||||
<button
|
<IconButton
|
||||||
className="btn btn-sm btn-outline-secondary"
|
size="small"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
openDeleteModal(report);
|
openDeleteModal(report);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i className="bi bi-three-dots"></i>
|
<MoreVert />
|
||||||
</button>
|
</IconButton>
|
||||||
</div>
|
</CardActions>
|
||||||
</div>
|
</Card>
|
||||||
</div>
|
</Grid>
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Error */}
|
{/* Delete Dialog */}
|
||||||
{error && <div className="alert alert-danger mt-3">{error}</div>}
|
<Dialog
|
||||||
|
open={openDeleteDialog}
|
||||||
{/* Delete Modal */}
|
onClose={() => setOpenDeleteDialog(false)}
|
||||||
{modalDelete && (
|
>
|
||||||
<div className="modal show d-block" tabIndex="-1" style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
|
<DialogTitle>Delete Confirmation</DialogTitle>
|
||||||
<div className="modal-dialog">
|
<DialogContent>
|
||||||
<div className="modal-content">
|
<Typography>
|
||||||
<div className="modal-header">
|
Are you sure you want to delete the report?
|
||||||
<h5 className="modal-title">Delete Confirmation</h5>
|
</Typography>
|
||||||
<button
|
<Typography variant="subtitle1" sx={{ mt: 1 }}>
|
||||||
type="button"
|
{rowSelected?.reportName}
|
||||||
className="btn-close"
|
</Typography>
|
||||||
onClick={() => setModalDelete(false)}
|
</DialogContent>
|
||||||
></button>
|
<DialogActions>
|
||||||
</div>
|
<Button onClick={() => setOpenDeleteDialog(false)}>Cancel</Button>
|
||||||
<div className="modal-body">
|
<Button
|
||||||
<p>Are you sure you want to delete the report?</p>
|
onClick={() => handleDelete(rowSelected?.id)}
|
||||||
<h6>{rowSelected?.reportName}</h6>
|
color="error"
|
||||||
</div>
|
startIcon={<Delete />}
|
||||||
<div className="modal-footer">
|
>
|
||||||
<button
|
Delete
|
||||||
type="button"
|
</Button>
|
||||||
className="btn btn-secondary"
|
</DialogActions>
|
||||||
onClick={() => setModalDelete(false)}
|
</Dialog>
|
||||||
>
|
</Container>
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-danger"
|
|
||||||
onClick={() => handleDelete(rowSelected.id)}
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user