First commit
parent
4aeccb8213
commit
fb0cc822f0
Binary file not shown.
@ -0,0 +1,13 @@
|
|||||||
|
.App {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: aliceblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.WhiteWindow{
|
||||||
|
background-color: white;
|
||||||
|
border: 1px rgb(1, 1, 1, 0.1) solid;
|
||||||
|
border-radius: 10px; /* Adjust the value to control the curve */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,189 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import './App.css';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import {VersionComponent, InfoComponent} from './Components.tsx';
|
||||||
|
|
||||||
|
import { Grid, Tab, Tabs, Paper, Typography, CircularProgress } from '@mui/material';
|
||||||
|
|
||||||
|
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
|
||||||
|
let theme = createTheme({
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#049a9b',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const fetchDataSgi = async (streamlineSgiId) => {
|
||||||
|
try {
|
||||||
|
const res = await axios.get("https://cc.streamline.pt/api/applications/findOne",
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
filter: {
|
||||||
|
where: {
|
||||||
|
id: streamlineSgiId
|
||||||
|
},
|
||||||
|
include: ["modules", {
|
||||||
|
relation: "versions",
|
||||||
|
scope: {
|
||||||
|
include: "module",
|
||||||
|
order: "version DESC"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let data = res.data;
|
||||||
|
let modulesSgi = data.modules;
|
||||||
|
let versionsSgi = data.versions;
|
||||||
|
|
||||||
|
return { modulesSgi, versionsSgi }; // Return both modules and versions
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
// Handle errors if any
|
||||||
|
console.error('Error fetching data:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const fetchDataApp = async (streamlineAppId) => {
|
||||||
|
try {
|
||||||
|
const res = await axios.get("https://cc.streamline.pt/api/applications/findOne",
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
filter: {
|
||||||
|
where: {
|
||||||
|
id: streamlineAppId
|
||||||
|
},
|
||||||
|
include: ["modules", {
|
||||||
|
relation: "versions",
|
||||||
|
scope: {
|
||||||
|
include: "module",
|
||||||
|
order: "version DESC"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let data = res.data;
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
// Handle errors if any
|
||||||
|
console.error('Error fetching data:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
|
||||||
|
const streamlineSgiId = "60a288ed33320700119606f9";
|
||||||
|
const streamlineAppId = "6082b67f1e0f13001133287b";
|
||||||
|
|
||||||
|
const [value, setValue] = useState(0);
|
||||||
|
const [selectedVersion, setSelectedVersion] = useState(null);
|
||||||
|
const [modulesData, setModulesData] = useState({ modules: [], versions: [] });
|
||||||
|
const [appData, setAppData] = useState({ modules: [], versions: [] });
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
|
||||||
|
const handleChange = (event, newValue) => {
|
||||||
|
setValue(newValue);
|
||||||
|
setSelectedVersion(null); // Reset selectedVersion when switching tabs
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchModules = async () => {
|
||||||
|
try {
|
||||||
|
const { modulesSgi, versionsSgi } = await fetchDataSgi(streamlineSgiId);
|
||||||
|
setModulesData({ modules: modulesSgi, versions: versionsSgi }); // Set the modules and versions in the state
|
||||||
|
|
||||||
|
const appData = await fetchDataApp(streamlineAppId);
|
||||||
|
setAppData(appData);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching modules:', error); // Handle errors if any
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
setLoading(false); // Set loading state to false when the fetch operation is complete
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchModules(); // Call the function to fetch modules
|
||||||
|
|
||||||
|
}, [streamlineSgiId]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="App">
|
||||||
|
<Typography variant="h3" sx={{ fontWeight: 'bold', marginBottom: '10px' }}>
|
||||||
|
Histórico de versões
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
|
||||||
|
{loading ? (
|
||||||
|
// Display a loading circular progress while data is being fetched
|
||||||
|
<div sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '200%' }}>
|
||||||
|
<CircularProgress />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
) : (
|
||||||
|
<div className="WhiteWindow">
|
||||||
|
|
||||||
|
<Grid container>
|
||||||
|
|
||||||
|
{/*----TAB SELECTION AREA----------------------------------------------*/}
|
||||||
|
<Grid item md={12}>
|
||||||
|
<Tabs value={value} onChange={handleChange}>
|
||||||
|
<Tab label="SISTEMA DE GESTÃO INTEGRADO (WEB)" />
|
||||||
|
<Tab label="APLICAÇÃO MÓVEL" />
|
||||||
|
</Tabs>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/*-------INFO AREA----------------------------------------*/}
|
||||||
|
<Grid container sx={{ margin: '5px', padding: '5px', marginBottom: '20px' }}>
|
||||||
|
|
||||||
|
{/*-------HISTORICO VERSOES----------------------------------------*/}
|
||||||
|
<Grid item md={6} sx={{ padding: "10px" }}>
|
||||||
|
<Paper>
|
||||||
|
{value === 0 && <VersionComponent message={modulesData} setSelectedVersion={setSelectedVersion}/>}
|
||||||
|
{value === 1 && <VersionComponent message={appData} setSelectedVersion={setSelectedVersion} />}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/*-------MORE INFO GRIDS (Info and improvements)----------------------------------------*/}
|
||||||
|
<Grid item md={6} sx={{ padding: "10px" }}>
|
||||||
|
<Paper>
|
||||||
|
{value === 0 && <InfoComponent modules={modulesData} version={selectedVersion} />}
|
||||||
|
{value === 1 && <InfoComponent modules={appData} version={selectedVersion} />}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default App;
|
@ -0,0 +1,8 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
test('renders learn react link', () => {
|
||||||
|
render(<App />);
|
||||||
|
const linkElement = screen.getByText(/learn react/i);
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
});
|
@ -0,0 +1,383 @@
|
|||||||
|
import React, {useState} from 'react';
|
||||||
|
import './App.css';
|
||||||
|
import MultipleSelectFilter from './MultipleSelectFilter.tsx';
|
||||||
|
import MultipleSelectModule from './MultipleSelectModule.tsx';
|
||||||
|
|
||||||
|
import { Grid, TextField, List, ListItem, Divider, Card, Typography} from '@mui/material';
|
||||||
|
import { Timeline, TimelineItem, TimelineSeparator, TimelineConnector, TimelineContent, TimelineDot} from '@mui/lab';
|
||||||
|
import TimelineOppositeContent, {
|
||||||
|
timelineOppositeContentClasses,
|
||||||
|
} from '@mui/lab/TimelineOppositeContent';
|
||||||
|
|
||||||
|
import DonutLargeIcon from '@mui/icons-material/DonutLarge';
|
||||||
|
import SquareFootIcon from '@mui/icons-material/SquareFoot';
|
||||||
|
import StraightenIcon from '@mui/icons-material/Straighten';
|
||||||
|
import AccountBalanceIcon from '@mui/icons-material/AccountBalance';
|
||||||
|
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
||||||
|
import EuroIcon from '@mui/icons-material/Euro';
|
||||||
|
import PowerIcon from '@mui/icons-material/Power';
|
||||||
|
import LocalFireDepartmentIcon from '@mui/icons-material/LocalFireDepartment';
|
||||||
|
import ConstructionIcon from '@mui/icons-material/Construction';
|
||||||
|
import HeightIcon from '@mui/icons-material/Height';
|
||||||
|
|
||||||
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
|
import DynamicFeedIcon from '@mui/icons-material/DynamicFeed';
|
||||||
|
import HubIcon from '@mui/icons-material/Hub';
|
||||||
|
import InfoIcon from '@mui/icons-material/Info';
|
||||||
|
|
||||||
|
import FileCopyIcon from '@mui/icons-material/FileCopy';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
|
||||||
|
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let theme = createTheme({
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: '#049a9b',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const listItemStyle = { margin: '-15px 5px -10px 0px',};
|
||||||
|
const infoTitlesStyle = { fontWeight: 'bold', margin: '15px 0px 10px 8px', fontSize: '25px' };
|
||||||
|
const informacaoTitleStyles = {fontWeight: 'bold', margin: '0px 10px 5px 10px', fontSize: '15px' }
|
||||||
|
const informacaoContentStyle = { margin: '0px 10px 5px 10px', fontSize: '15px' }
|
||||||
|
|
||||||
|
const namesWithIcons = [
|
||||||
|
{ id: 0, name: 'Novas funcionalidade', icon: < HubIcon /> },
|
||||||
|
{ id: 1, name: 'Correção de Falhas', icon: <BuildIcon /> },
|
||||||
|
{ id: 2, name: 'Melhorias', icon: <DynamicFeedIcon /> },
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
function formatDate(myString){
|
||||||
|
const date = new Date(myString);
|
||||||
|
const year = date.getUTCFullYear() % 100; // Get the last two digits of the year
|
||||||
|
const month = (date.getUTCMonth() + 1).toString().padStart(2, '0'); // Month is zero-based
|
||||||
|
const day = date.getUTCDate().toString().padStart(2, '0');
|
||||||
|
|
||||||
|
return `${day}/${month}/${year}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function semanticVersions(myString){
|
||||||
|
// Convert from "005001010" to 5.1.10
|
||||||
|
return String(parseInt(myString.slice(0, 3)))+"."+
|
||||||
|
String(+ parseInt(myString.slice(3, 6)))+"."+
|
||||||
|
String(+ parseInt(myString.slice(6, 9)))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const getIconForModule = (myModuleName) => {
|
||||||
|
switch (myModuleName) {
|
||||||
|
case 'CORE': return <DonutLargeIcon />;
|
||||||
|
case 'FOR': return <SquareFootIcon />;
|
||||||
|
case 'IE': return <PowerIcon/>;
|
||||||
|
case 'LME':
|
||||||
|
case 'LAB': return <StraightenIcon/>;
|
||||||
|
case 'ELV': return <HeightIcon />;
|
||||||
|
case 'FIN': return <AccountBalanceIcon />;
|
||||||
|
case 'ATV': return <AccountBalanceIcon />;
|
||||||
|
case 'PAD': return <EuroIcon />;
|
||||||
|
case 'OBL':
|
||||||
|
case 'OBLER': return <WarehouseIcon/>;
|
||||||
|
case 'GAS': return <LocalFireDepartmentIcon/>;
|
||||||
|
case 'FUN': return <ConstructionIcon />;
|
||||||
|
default: return <AccountBalanceIcon />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function VersionComponent({message, setSelectedVersion, filters }) {
|
||||||
|
|
||||||
|
//Check for the tab selected --> Could be "SGI" or "Mobile"
|
||||||
|
var tabSelected = "";
|
||||||
|
if (message.name === "SGI Mobile") {tabSelected = "mobile"}
|
||||||
|
else {tabSelected = "SGI"}
|
||||||
|
|
||||||
|
// Versions (TIMELINE)
|
||||||
|
let versions = message.versions //Get all versions
|
||||||
|
const [selectedVersion, setSelectedIcon] = useState(null);
|
||||||
|
|
||||||
|
|
||||||
|
// Module (CHIP)
|
||||||
|
const moduleNames: string[] = [];
|
||||||
|
for (let i = 0; i < message.modules.length; i++){ moduleNames[i] = message.modules[i].value;}
|
||||||
|
|
||||||
|
// Filters
|
||||||
|
const [moduleFilter, setModuleFilter] = useState([]);
|
||||||
|
const [filter, setFilter] = useState([]);
|
||||||
|
|
||||||
|
|
||||||
|
// Handling of the version click
|
||||||
|
const handleIconClick = (index, data) => {
|
||||||
|
setSelectedIcon(index); // Aggiorna lo stato selectedVersion
|
||||||
|
setSelectedVersion(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle search text
|
||||||
|
const [searchText, setSearchText] = useState('');
|
||||||
|
|
||||||
|
// Function for filtering the versions by the search text
|
||||||
|
const cleanedVersions = Object.values(versions).filter((item) => {
|
||||||
|
const versionInfo = `${item.module.value} ${semanticVersions(item.version)} ${item.improvements} ${item.bugfixes} ${item.added}`;
|
||||||
|
return versionInfo.toLowerCase().includes(searchText.toLowerCase());
|
||||||
|
});
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<Card className="Versoes-Card" variant="outlined">
|
||||||
|
<Typography sx={{ fontWeight: 'bold', margin: '15px 15px 10px 15px', fontSize: '25px' }}>
|
||||||
|
Versões {tabSelected}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
id="outlined"
|
||||||
|
label="Pesquisa..."
|
||||||
|
value={searchText}
|
||||||
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
|
sx={{ width: 'calc(100% - 30px)', marginLeft: '15px', marginRight: '15px', marginBottom: '15px'}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
<Grid container sx={{ marginBottom: '10px'}}>
|
||||||
|
|
||||||
|
<Grid item sx={{marginLeft: "8px", marginTop: "-5px"}}>
|
||||||
|
<MultipleSelectModule modules={message.modules} moduleFilter={moduleFilter} setModuleFilter={setModuleFilter}></MultipleSelectModule>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item sx={{marginLeft: "8px", marginTop: "-5px", paddingRight: '5px'}}>
|
||||||
|
<MultipleSelectFilter names={namesWithIcons} filter={filter} setFilter={setFilter}></MultipleSelectFilter>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
<Timeline style={{maxHeight: '800px', overflow: 'auto'}}
|
||||||
|
sx={{[`& .${timelineOppositeContentClasses.root}`]: {flex: 0.1, },}}>
|
||||||
|
{cleanedVersions.map((item, index) => {
|
||||||
|
|
||||||
|
// Filter item by the modulew selected (module chip)
|
||||||
|
if (moduleFilter.length > 0){
|
||||||
|
if (!(moduleFilter.includes(item.module.value))){return null;}
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log("my item", item.module.value)
|
||||||
|
|
||||||
|
// Filter module by the improvement chip
|
||||||
|
if ((filter.includes(namesWithIcons[2].name)) && ((item.improvements === undefined) || (item.improvements === "")) ) {return null;}
|
||||||
|
// Filter module by the added chip
|
||||||
|
if ((filter.includes(namesWithIcons[0].name)) && ((item.added === undefined) || (item.added === ""))) {return null;}
|
||||||
|
// Filter module by the added chip
|
||||||
|
if ((filter.includes(namesWithIcons[1].name)) && ((item.bugfixes === undefined) || (item.bugfixes === ""))) {return null;}
|
||||||
|
|
||||||
|
|
||||||
|
// Return the item
|
||||||
|
return (
|
||||||
|
<TimelineItem key={index} sx={{ py: '4px' }}>
|
||||||
|
|
||||||
|
<TimelineOppositeContent color="textSecondary" sx={{ py: '22px' }}>
|
||||||
|
<Typography variant="body2" component="div">
|
||||||
|
{formatDate(item.date)}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</TimelineOppositeContent>
|
||||||
|
|
||||||
|
|
||||||
|
<TimelineSeparator>
|
||||||
|
|
||||||
|
<TimelineDot
|
||||||
|
color={selectedVersion === index ? 'warning' : 'primary'}
|
||||||
|
onClick={() => handleIconClick(index, item)}>
|
||||||
|
{getIconForModule(item.module.name)}
|
||||||
|
</TimelineDot>
|
||||||
|
|
||||||
|
<TimelineConnector sx={{ paddingTop: '22px' }} />
|
||||||
|
|
||||||
|
</TimelineSeparator>
|
||||||
|
|
||||||
|
|
||||||
|
<TimelineContent>
|
||||||
|
<Typography variant="h6" sx={{ fontSize: '18px', lineHeight: '18px', padding: '8px 0px 0px 0px' }}>
|
||||||
|
{item.module.value}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="textPrimary">
|
||||||
|
{semanticVersions(item.version)}
|
||||||
|
</Typography>
|
||||||
|
</TimelineContent>
|
||||||
|
|
||||||
|
</TimelineItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
</Timeline>
|
||||||
|
|
||||||
|
{console.log("NO VERSIOooN!", cleanedVersions.length)}
|
||||||
|
{console.log("\n\n\n\n\n\n\nYALLE!")}
|
||||||
|
|
||||||
|
|
||||||
|
</Card>
|
||||||
|
</ThemeProvider>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function InfoComponent({ modules, version: selectedVersion }) {
|
||||||
|
|
||||||
|
// If no version is selected, don't render anything
|
||||||
|
if (!selectedVersion || !selectedVersion.version) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const copyText = (text) => {
|
||||||
|
// Function that creates an icon to copy the git id
|
||||||
|
const tempInput = document.createElement('input');
|
||||||
|
tempInput.value = text;
|
||||||
|
document.body.appendChild(tempInput);
|
||||||
|
|
||||||
|
tempInput.select();
|
||||||
|
tempInput.setSelectionRange(0, 999);
|
||||||
|
|
||||||
|
document.execCommand('copy');
|
||||||
|
|
||||||
|
document.body.removeChild(tempInput);
|
||||||
|
console.log(`Copied: ${text}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
|
||||||
|
<Card variant="outlined">
|
||||||
|
<List >
|
||||||
|
<ListItem sx={listItemStyle}>
|
||||||
|
<InfoIcon></InfoIcon>
|
||||||
|
<Typography sx={infoTitlesStyle}>
|
||||||
|
Informação para versão {semanticVersions(selectedVersion.version)}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem>
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid item md={6}>
|
||||||
|
<Typography sx={informacaoTitleStyles}> Módulo </Typography>
|
||||||
|
<Typography sx={informacaoContentStyle}>
|
||||||
|
{selectedVersion.module.value}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item md={6}>
|
||||||
|
<Typography sx={informacaoTitleStyles}> Data de lançamento </Typography>
|
||||||
|
<Typography sx={informacaoContentStyle}>
|
||||||
|
{formatDate(selectedVersion.date)}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item md={12}>
|
||||||
|
<Typography sx={informacaoTitleStyles}> Revisão GIT (se aplicavel) </Typography>
|
||||||
|
<Typography sx={informacaoContentStyle}>
|
||||||
|
{selectedVersion.gitHash ?
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
{selectedVersion.gitHash}
|
||||||
|
<IconButton sx={{ transform: 'scale(0.6)', margin: '-10px 0px 0px 0px' }}
|
||||||
|
title="Copia"
|
||||||
|
onClick={() => copyText(selectedVersion.gitHash)}
|
||||||
|
>
|
||||||
|
<FileCopyIcon />
|
||||||
|
</IconButton>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
"N/D"
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
{selectedVersion.added && (
|
||||||
|
<List>
|
||||||
|
<ListItem sx={listItemStyle}>
|
||||||
|
{namesWithIcons[0].icon}
|
||||||
|
<Typography sx={infoTitlesStyle}>
|
||||||
|
|
||||||
|
Novas Funcionalidades
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<Typography sx={{ margin: '0px 0px 10px -10px', fontSize: '15px' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: selectedVersion.added }} />
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
{selectedVersion.bugfixes && (
|
||||||
|
<List>
|
||||||
|
<ListItem sx={listItemStyle}>
|
||||||
|
{namesWithIcons[1].icon}
|
||||||
|
<Typography sx={infoTitlesStyle}>
|
||||||
|
Correção de Falhas
|
||||||
|
</Typography>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<Typography sx={{ margin: '0px 0px 10px -10px', fontSize: '15px' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: selectedVersion.bugfixes }} />
|
||||||
|
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
</List>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
{selectedVersion.improvements && (
|
||||||
|
<List>
|
||||||
|
<ListItem sx={listItemStyle}>
|
||||||
|
{namesWithIcons[2].icon}
|
||||||
|
<Typography sx={infoTitlesStyle}>
|
||||||
|
Melhorias
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<Typography sx={{ margin: '0px 0px 10px -10px', fontSize: '15px' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: selectedVersion.improvements }} />
|
||||||
|
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
</List>
|
||||||
|
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {VersionComponent, InfoComponent};
|
@ -0,0 +1,73 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||||
|
import InputLabel from '@mui/material/InputLabel';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import FormControl from '@mui/material/FormControl';
|
||||||
|
import Select, { SelectChangeEvent } from '@mui/material/Select';
|
||||||
|
import Chip from '@mui/material/Chip';
|
||||||
|
import Grid from '@mui/material/Grid';
|
||||||
|
|
||||||
|
|
||||||
|
interface NameWithIcon {
|
||||||
|
name: string;
|
||||||
|
icon: JSX.Element; // Tipo di elemento per l'icona
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
names: NameWithIcon[]; // Modifica il tipo delle props per accettare nomi con icone
|
||||||
|
filter: string[]; // Aggiungi il tipo di props per l'array filter
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultipleSelectFilter: React.FC<Props> = ({ names, filter, setFilter }) => {
|
||||||
|
const [personName, setPersonName] = React.useState<string[]>([]);
|
||||||
|
|
||||||
|
const handleChange = (event: SelectChangeEvent<typeof personName>) => {
|
||||||
|
const {
|
||||||
|
target: { value },
|
||||||
|
} = event;
|
||||||
|
const selectedValues = typeof value === 'string' ? value.split(',') : value;
|
||||||
|
setPersonName(selectedValues);
|
||||||
|
setFilter(selectedValues); // Aggiorna l'array filter quando cambia la selezione
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid>
|
||||||
|
<FormControl sx={{ m: 1, minWidth: 240}} >
|
||||||
|
<InputLabel id="demo-multiple-chip-label" sx={{ marginTop: '-8px' }}>Filtra </InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="demo-multiple-chip-label"
|
||||||
|
//id="demo-multiple-chip"
|
||||||
|
multiple
|
||||||
|
size="small"
|
||||||
|
value={personName}
|
||||||
|
onChange={handleChange}
|
||||||
|
input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
|
||||||
|
renderValue={(selected) => (
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: '0.8px' }}>
|
||||||
|
{selected.map((value) => (
|
||||||
|
<Chip
|
||||||
|
key={value}
|
||||||
|
label={names.find((item) => item.name === value)?.icon}
|
||||||
|
sx={{ fontSize: '2rem'}}/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
|
||||||
|
{names.map((nameWithIcon) => (
|
||||||
|
<MenuItem key={nameWithIcon.name} value={nameWithIcon.name}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
{nameWithIcon.icon}
|
||||||
|
<span style={{ marginLeft: '10px' }}>{nameWithIcon.name}</span>
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MultipleSelectFilter;
|
@ -0,0 +1,101 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||||
|
import InputLabel from '@mui/material/InputLabel';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import FormControl from '@mui/material/FormControl';
|
||||||
|
import Select, { SelectChangeEvent } from '@mui/material/Select';
|
||||||
|
import Chip from '@mui/material/Chip';
|
||||||
|
import Grid from '@mui/material/Grid';
|
||||||
|
|
||||||
|
import DonutLargeIcon from '@mui/icons-material/DonutLarge';
|
||||||
|
import SquareFootIcon from '@mui/icons-material/SquareFoot';
|
||||||
|
import StraightenIcon from '@mui/icons-material/Straighten';
|
||||||
|
import AccountBalanceIcon from '@mui/icons-material/AccountBalance';
|
||||||
|
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
||||||
|
import EuroIcon from '@mui/icons-material/Euro';
|
||||||
|
import PowerIcon from '@mui/icons-material/Power';
|
||||||
|
import LocalFireDepartmentIcon from '@mui/icons-material/LocalFireDepartment';
|
||||||
|
import ConstructionIcon from '@mui/icons-material/Construction';
|
||||||
|
import HeightIcon from '@mui/icons-material/Height';
|
||||||
|
|
||||||
|
const getIconForModule = (moduleName) => {
|
||||||
|
switch (moduleName) {
|
||||||
|
case 'CORE': return <DonutLargeIcon />;
|
||||||
|
case 'FOR': return <SquareFootIcon />;
|
||||||
|
case 'IE': return <PowerIcon/>;
|
||||||
|
case 'LME':
|
||||||
|
case 'LAB': return <StraightenIcon/>;
|
||||||
|
case 'ELV': return <HeightIcon />;
|
||||||
|
case 'FIN': return <AccountBalanceIcon />;
|
||||||
|
case 'ATV': return <AccountBalanceIcon />;
|
||||||
|
case 'PAD': return <EuroIcon />;
|
||||||
|
case 'OBL':
|
||||||
|
case 'OBLER': return <WarehouseIcon/>;
|
||||||
|
case 'GAS': return <LocalFireDepartmentIcon/>;
|
||||||
|
case 'FUN': return <ConstructionIcon />;
|
||||||
|
default: return <AccountBalanceIcon />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
modules: { value: string }[];
|
||||||
|
moduleFilter: string[]; // Aggiungi il tipo di props per l'array filter
|
||||||
|
setModuleFilter: (filter: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultipleSelectModule: React.FC<Props> = ({ modules, moduleFilter, setModuleFilter }) => {
|
||||||
|
const [selectedModules, setSelectedModules] = React.useState<string[]>([]);
|
||||||
|
|
||||||
|
const handleChange = (event: SelectChangeEvent<typeof selectedModules>) => {
|
||||||
|
console.log("QUi--> ", event.target, event.target.value, event.target.name)
|
||||||
|
setSelectedModules(event.target.value as string[]);
|
||||||
|
|
||||||
|
const selectedValues = (event.target.value as { value: string, name: string }[]).map(module => module.value);
|
||||||
|
setModuleFilter(selectedValues); // Update moduleFilter with only the 'value' properties
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid>
|
||||||
|
<FormControl sx={{ m: 1, minWidth: 240}}>
|
||||||
|
<InputLabel id="demo-multiple-chip-label" sx={{ marginTop: '-8px' }}>Selecionar modulo</InputLabel>
|
||||||
|
<Select
|
||||||
|
fullWidth
|
||||||
|
labelId="demo-multiple-chip-label"
|
||||||
|
//id="demo-multiple-chip"
|
||||||
|
multiple
|
||||||
|
size="small"
|
||||||
|
value={selectedModules}
|
||||||
|
onChange={handleChange}
|
||||||
|
input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
|
||||||
|
renderValue={(selected) => {
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: '0.1px' }}>
|
||||||
|
{selected.map((value) => (
|
||||||
|
<Chip
|
||||||
|
key={value}
|
||||||
|
icon={getIconForModule(value.name)}
|
||||||
|
sx={{
|
||||||
|
fontSize: '2rem', backgroundColor: 'transparent'}} />
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{modules.map((modulee) => (
|
||||||
|
<MenuItem key={modulee} value={modulee}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'right' }}>
|
||||||
|
{getIconForModule(modulee.name)}
|
||||||
|
<span style={{ marginLeft: '10px' }}>{modulee.value}</span>
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MultipleSelectModule;
|
@ -0,0 +1,13 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
|
monospace;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import './index.css';
|
||||||
|
import App from './App';
|
||||||
|
import reportWebVitals from './reportWebVitals';
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
|
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();
|
@ -0,0 +1,13 @@
|
|||||||
|
const reportWebVitals = onPerfEntry => {
|
||||||
|
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||||
|
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||||
|
getCLS(onPerfEntry);
|
||||||
|
getFID(onPerfEntry);
|
||||||
|
getFCP(onPerfEntry);
|
||||||
|
getLCP(onPerfEntry);
|
||||||
|
getTTFB(onPerfEntry);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default reportWebVitals;
|
@ -0,0 +1,5 @@
|
|||||||
|
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||||
|
// allows you to do things like:
|
||||||
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
|
import '@testing-library/jest-dom';
|
Loading…
Reference in New Issue