[release] version 0.5.0-unstable25

This commit is contained in:
Yann Stepienik 2023-05-17 12:44:14 +01:00
parent 7134301f64
commit 1722f3f832
12 changed files with 129 additions and 98 deletions

View file

@ -1,13 +1,15 @@
## Version 0.5.0
- Add Terminal to containers
- Add Create Container
- Add "Create ServApp"
- Add support for importing Docker Compose
- Improved icon fetching
- Change Home background and style (especially fixing the awckward light theme)
- Fixed 2 bugs with the smart shield, that made it too strict
- Fixed issues that prevented from login in with different hostnames
- Added more infoon the shield when blocking someone
- Fixed home background image
- Added more info on the shield when blocking someone
- Fixed issue where the UI would have missing icon images
- Improved icon fetching for apps by following redirections
- Fixed Homepage showing stopped containers
- Fixed bug where you can't save changes on the URLs Screen
## Version 0.4.3
- Fix for exposing routes from the details page

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View file

@ -61,10 +61,6 @@ const RouteConfigPage = () => {
routeConfig={currentRoute}
/>
},
{
title: 'Permissions',
children: <div>WIP</div>
},
]}/>}
{!config && <div style={{textAlign: 'center'}}>

View file

@ -215,20 +215,6 @@ const ProxyManagement = () => {
disableElevation
fullWidth
onClick={() => {
if(routes.some((route, key) => {
let errors = ValidateRoute(route, config);
if (errors && errors.length > 0) {
errors = errors.map((err) => {
return `${route.Name}: ${err}`;
});
setSubmitErrors(errors);
return true;
}
})) {
return;
} else {
setSubmitErrors([]);
}
API.config.set(cleanRoutes(updateRoutes(routes))).then(() => {
setNeedSave(false);
setOpenModal(true);

View file

@ -3,7 +3,8 @@ import Back from "../../components/back";
import { Alert, Box, CircularProgress, Grid, Stack, useTheme } from "@mui/material";
import { useEffect, useState } from "react";
import * as API from "../../api";
import wallpaper from '../../assets/images/wallpaper.jpg';
import wallpaper from '../../assets/images/wallpaper2.jpg';
import wallpaperLight from '../../assets/images/wallpaper2_light.jpg';
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
import { getFaviconURL } from "../../utils/routes";
import { Link } from "react-router-dom";
@ -13,28 +14,48 @@ import IsLoggedIn from "../../isLoggedIn";
const HomeBackground = () => {
const theme = useTheme();
const isDark = theme.palette.mode === 'dark';
return (
<Box sx={{ position: 'fixed', float: 'left', overflow: 'hidden', zIndex: 0, top: 0, left: 0, right: 0, bottom: 0 }}>
<img src={wallpaper} style={{ display: 'inline' }} alt="Cosmos" width="100%" height="100%" />
<Box sx={{ position: 'fixed', float: 'left', overflow: 'hidden', zIndex: 0, top: 0, left: 0, right: 0, bottom: 0,
// gradient
// backgroundImage: isDark ?
// `linear-gradient(#371d53, #26143a)` :
// `linear-gradient(#e6d3fb, #c8b0e2)`,
}}>
<img src={isDark ? wallpaper : wallpaperLight } style={{ display: 'inline' }} alt="Cosmos" width="100%" height="100%" />
</Box>
);
};
const blockStyle = {
margin: 0,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxWidth: '78%',
verticalAlign: 'middle',
}
const HomePage = () => {
const { routeName } = useParams();
const [serveApps, setServeApps] = useState([]);
const [config, setConfig] = useState(null);
const [coStatus, setCoStatus] = useState(null);
const [containers, setContainers] = useState(null);
const theme = useTheme();
const isDark = theme.palette.mode === 'dark';
const blockStyle = {
margin: 0,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxWidth: '78%',
verticalAlign: 'middle',
}
const appColor = isDark ? {
color: 'white',
background: 'rgba(0,0,0,0.35)',
} : {
color: 'black',
background: 'rgba(255,255,255,0.35)',
}
const backColor = isDark ? '0,0,0' : '255,255,255';
const textColor = isDark ? 'white' : 'dark';
const refreshStatus = () => {
API.getStatus().then((res) => {
@ -64,18 +85,19 @@ const HomePage = () => {
<HomeBackground />
<style>
{`header {
background: rgba(0.2,0.2,0.2,0.2) !important;
border-bottom-color: rgba(0.4,0.4,0.4,0.4) !important;
color: white !important;
background: rgba(${backColor},0.3) !important;
border-bottom-color: rgba(${backColor},0.4) !important;
color: ${textColor} !important;
font-weight: bold;
}
header .MuiChip-label {
color: #eee !important;
color: ${textColor} !important;
}
header .MuiButtonBase-root {
color: #eee !important;
background: rgba(0.2,0.2,0.2,0.2) !important;
header .MuiButtonBase-root, header .MuiChip-colorDefault {
color: ${textColor} !important;
background: rgba(${backColor},0.5) !important;
}
.app {
@ -85,9 +107,15 @@ const HomePage = () => {
.app:hover {
cursor: pointer;
background: rgba(0.4,0.4,0.4,0.4) !important;
background: rgba(${backColor},0.8) !important;
transform: scale(1.05);
}
.MuiAlert-standard {
background: rgba(${backColor},0.3) !important;
color: ${textColor} !important;
font-weight: bold;
}
`}
</style>
<Stack style={{ zIndex: 2 }} spacing={1}>
@ -144,8 +172,8 @@ const HomePage = () => {
}
}
return !skip && <Grid2 item xs={12} sm={6} md={4} lg={3} xl={3} xxl={2} key={route.Name}>
<Box className='app' style={{ padding: 10, color: 'white', background: 'rgba(0,0,0,0.35)', borderRadius: 5 }}>
<Link to={getFullOrigin(route)} target="_blank" style={{ textDecoration: 'none', color: 'white' }}>
<Box className='app' style={{ padding: 10, borderRadius: 5, ...appColor }}>
<Link to={getFullOrigin(route)} target="_blank" style={{ textDecoration: 'none', ...appColor }}>
<Stack direction="row" spacing={2} alignItems="center">
<img className="loading-image" alt="" src={getFaviconURL(route)} width="64px" height="64px"/>
@ -162,7 +190,7 @@ const HomePage = () => {
{config && config.HTTPConfig.ProxyConfig.Routes.length === 0 && (
<Grid2 item xs={12} sm={12} md={12} lg={12} xl={12}>
<Box style={{ padding: 10, color: 'white', background: 'rgba(0,0,0,0.35)', borderRadius: 5 }}>
<Box style={{ padding: 10, borderRadius: 5, ...appColor }}>
<Stack direction="row" spacing={2} alignItems="center">
<div style={{ width: '100%' }}>
<h3 style={blockStyle}>No Apps</h3>

View file

@ -19,6 +19,7 @@ import VolumeContainerSetup from './volumes';
import DockerTerminal from './terminal';
import { Link } from 'react-router-dom';
import { smartDockerLogConcat, tryParseProgressLog } from '../../../utils/docker';
import { LoadingButton } from '@mui/lab';
const preStyle = {
backgroundColor: '#000',
@ -64,7 +65,9 @@ const NewDockerService = ({service, refresh}) => {
}, []);
const create = () => {
setLog([])
setLog([
'Creating Service... ',
])
API.docker.createService(service, (newlog) => {
setLog((old) => smartDockerLogConcat(old, newlog));
preRef.current.scrollTop = preRef.current.scrollHeight;
@ -75,7 +78,7 @@ const NewDockerService = ({service, refresh}) => {
});
}
const needsRestart = service && service.service && service.service.some((c) => {
const needsRestart = service && service.services && Object.values(service.services).some((c) => {
return c.routes && c.routes.length > 0;
});
@ -83,13 +86,14 @@ const NewDockerService = ({service, refresh}) => {
<MainCard title="Create Service">
<RestartModal openModal={openModal} setOpenModal={setOpenModal} />
<Stack spacing={1}>
{!isDone && <Button
{!isDone && <LoadingButton
onClick={create}
variant="contained"
color="primary"
fullWidth
loading={log.length && !isDone}
startIcon={<PlusCircleOutlined />}
>Create</Button>}
>Create</LoadingButton>}
{isDone && <Stack spacing={1}>
<Alert severity="success">Service Created!</Alert>
{needsRestart && <Alert severity="warning">Cosmos needs to be restarted to apply changes to the URLs</Alert>}

View file

@ -1,7 +1,7 @@
import * as React from 'react';
import MainCard from '../../../components/MainCard';
import RestartModal from '../../config/users/restart';
import { Alert, Button, Chip, Divider, Stack, useMediaQuery } from '@mui/material';
import { Alert, Button, Checkbox, Chip, Divider, Stack, useMediaQuery } from '@mui/material';
import HostChip from '../../../components/hostChip';
import { RouteMode, RouteSecurity } from '../../../components/routeComponents';
import { getFaviconURL } from '../../../utils/routes';
@ -56,7 +56,7 @@ const NewDockerServiceForm = () => {
});
let service = {
Services: {
services: {
container_name : {
container_name: containerInfo.Name,
image: containerInfo.Config.Image,
@ -72,7 +72,7 @@ const NewDockerServiceForm = () => {
acc[cur] = {};
return acc;
}, {}),
Routes: [containerInfo.Route]
routes: containerInfo.CreateRoute ? [containerInfo.Route] : [],
}
},
}
@ -164,40 +164,53 @@ const NewDockerServiceForm = () => {
{
title: 'URL',
disabled: maxTab < 1,
children: <Stack spacing={2}><RouteManagement TargetContainer={containerInfo}
routeConfig={{
Target: "http://"+containerInfo.Name.replace('/', '') + ":",
Mode: "SERVAPP",
Name: containerInfo.Name.replace('/', ''),
Description: "Expose " + containerInfo.Name.replace('/', '') + " to the internet",
UseHost: true,
Host: getHostnameFromName(containerInfo.Name),
UsePathPrefix: false,
PathPrefix: '',
CORSOrigin: '',
StripPathPrefix: false,
AuthEnabled: false,
Timeout: 14400000,
ThrottlePerMinute: 10000,
BlockCommonBots: true,
SmartShield: {
Enabled: true,
}
}}
routeNames={[]}
setRouteConfig={(newRoute) => {
const newValues = {
...containerInfo,
Route: newRoute,
}
setContainerInfo(newValues);
}}
up={() => {}}
down={() => {}}
deleteRoute={() => {}}
noControls
lockTarget
/>{nav()}</Stack>
children: <Stack spacing={2}>
<MainCard style={{ maxWidth: '1000px', width: '100%', margin: '', position: 'relative' }}>
<Checkbox
checked={containerInfo.CreateRoute}
onChange={(e) => {
const newValues = {
...containerInfo,
CreateRoute: e.target.checked,
}
setContainerInfo(newValues);
}}
/>Create a URL to access this ServApp
</MainCard>
{containerInfo.CreateRoute && <RouteManagement TargetContainer={containerInfo}
routeConfig={{
Target: "http://"+containerInfo.Name.replace('/', '') + ":",
Mode: "SERVAPP",
Name: containerInfo.Name.replace('/', ''),
Description: "Expose " + containerInfo.Name.replace('/', '') + " to the internet",
UseHost: true,
Host: getHostnameFromName(containerInfo.Name),
UsePathPrefix: false,
PathPrefix: '',
CORSOrigin: '',
StripPathPrefix: false,
AuthEnabled: false,
Timeout: 14400000,
ThrottlePerMinute: 10000,
BlockCommonBots: true,
SmartShield: {
Enabled: true,
}
}}
routeNames={[]}
setRouteConfig={(newRoute) => {
const newValues = {
...containerInfo,
Route: newRoute,
}
setContainerInfo(newValues);
}}
up={() => {}}
down={() => {}}
deleteRoute={() => {}}
noControls
lockTarget
/>}{nav()}</Stack>
},
{
title: 'Network',

View file

@ -123,7 +123,7 @@ const ContainerOverview = ({ containerInfo, config, refresh }) => {
disabled={isUpdating}
onChange={(e) => {
setIsUpdating(true);
API.docker.secure(Name, e.target.checked).then(() => {
API.docker.secure(Name.replace('/', ''), e.target.checked).then(() => {
setTimeout(() => {
refreshAll();
}, 3000);
@ -137,7 +137,7 @@ const ContainerOverview = ({ containerInfo, config, refresh }) => {
disabled={isUpdating}
onChange={(e) => {
setIsUpdating(true);
API.docker.autoUpdate(Name, e.target.checked).then(() => {
API.docker.autoUpdate(Name.replace('/', ''), e.target.checked).then(() => {
setTimeout(() => {
refreshAll();
}, 3000);

View file

@ -226,7 +226,7 @@ const ServeApps = () => {
})}
</Stack>
</Stack>
{isUpdating[app.Id] ? <div>
{isUpdating[app.Names[0].replace('/', '')] ? <div>
<CircularProgress color="inherit" />
</div>
:
@ -239,14 +239,15 @@ const ServeApps = () => {
checked={app.Labels['cosmos-force-network-secured'] === 'true'}
disabled={app.State !== 'running'}
onChange={(e) => {
setIsUpdatingId(app.Id, true);
API.docker.secure(app.Id, e.target.checked).then(() => {
const name = app.Names[0].replace('/', '');
setIsUpdatingId(name, true);
API.docker.secure(name, e.target.checked).then(() => {
setTimeout(() => {
setIsUpdatingId(app.Id, false);
setIsUpdatingId(name, false);
refreshServeApps();
}, 3000);
}).catch(() => {
setIsUpdatingId(app.Id, false);
setIsUpdatingId(name, false);
refreshServeApps();
})
}}
@ -257,14 +258,15 @@ const ServeApps = () => {
checked={app.Labels['cosmos-auto-update'] === 'true'}
disabled={app.State !== 'running'}
onChange={(e) => {
setIsUpdatingId(app.Id, true);
API.docker.autoUpdate(app.Id, e.target.checked).then(() => {
const name = app.Names[0].replace('/', '');
setIsUpdatingId(name, true);
API.docker.autoUpdate(name, e.target.checked).then(() => {
setTimeout(() => {
setIsUpdatingId(app.Id, false);
setIsUpdatingId(name, false);
refreshServeApps();
}, 3000);
}).catch(() => {
setIsUpdatingId(app.Id, false);
setIsUpdatingId(name, false);
refreshServeApps();
})
}}

View file

@ -1,6 +1,6 @@
{
"name": "cosmos-server",
"version": "0.5.0-unstable24",
"version": "0.5.0-unstable25",
"description": "",
"main": "test-server.js",
"bugs": {