[release] v0.7.0-unstable

This commit is contained in:
Yann Stepienik 2023-06-08 20:55:16 +01:00
parent 6c170e5145
commit e69c81fe7a
4 changed files with 142 additions and 22 deletions

View file

@ -1,7 +1,7 @@
// material-ui // material-ui
import * as React from 'react'; import * as React from 'react';
import { Alert, Button, Stack, Typography } from '@mui/material'; import { Alert, Button, FormLabel, Stack, Typography } from '@mui/material';
import { WarningOutlined, PlusCircleOutlined, CopyOutlined, ExclamationCircleOutlined, SyncOutlined, UserOutlined, KeyOutlined, ArrowUpOutlined, FileZipOutlined } from '@ant-design/icons'; import { WarningOutlined, PlusCircleOutlined, CopyOutlined, ExclamationCircleOutlined, SyncOutlined, UserOutlined, KeyOutlined, ArrowUpOutlined, FileZipOutlined, ArrowDownOutlined } from '@ant-design/icons';
import Table from '@mui/material/Table'; import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody'; import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell'; import TableCell from '@mui/material/TableCell';
@ -63,20 +63,68 @@ const preStyle = {
marginRight: '0', marginRight: '0',
} }
const DockerComposeImport = ({ refresh }) => { const getHostnameFromName = (name) => {
return name.replace('/', '').replace(/_/g, '-').replace(/[^a-zA-Z0-9-]/g, '').toLowerCase().replace(/\s/g, '-') + '.' + window.location.origin.split('://')[1]
}
const DockerComposeImport = ({ refresh, dockerComposeInit, installer, defaultName }) => {
const [step, setStep] = useState(0); const [step, setStep] = useState(0);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [openModal, setOpenModal] = useState(false); const [openModal, setOpenModal] = useState(false);
const [dockerCompose, setDockerCompose] = useState(''); const [dockerCompose, setDockerCompose] = useState(dockerComposeInit || '');
const [service, setService] = useState({}); const [service, setService] = useState({});
const [ymlError, setYmlError] = useState(''); const [ymlError, setYmlError] = useState('');
const [serviceName, setServiceName] = useState(defaultName || 'my-service');
const [hostnames, setHostnames] = useState([]);
useEffect(() => { useEffect(() => {
if(!openModal) {
return;
}
setYmlError('');
if (dockerCompose === '') { if (dockerCompose === '') {
return; return;
} }
setYmlError(''); let isJson = dockerCompose.trim().startsWith('{') && dockerCompose.trim().endsWith('}');
// if Json
if (isJson) {
try {
let doc = JSON.parse(dockerCompose);
if(installer) {
doc = JSON.parse(dockerCompose.replace(/\{\{self\}\}/gi, serviceName));
// check hostnames for each service
let hostnames = [];
if(doc.services)
Object.keys(doc.services).forEach((key) => {
if (doc.services[key].routes) {
let routeId = 0;
doc.services[key].routes.forEach((route) => {
if (route.useHost) {
let newRoute = Object.assign({}, route);
if(route.useHost === true) {
newRoute.host = getHostnameFromName(key + (routeId > 0 ? '-' + routeId : ''))
}
hostnames.push(newRoute);
}
});
}
});
setHostnames(hostnames);
}
setService(doc);
} catch (e) {
setYmlError(e.message);
}
}
else {
// if Yml
let doc; let doc;
let newService = {}; let newService = {};
try { try {
@ -89,7 +137,6 @@ const DockerComposeImport = ({ refresh }) => {
} }
} }
// convert to the proper format // convert to the proper format
if (doc.services) { if (doc.services) {
Object.keys(doc.services).forEach((key) => { Object.keys(doc.services).forEach((key) => {
@ -231,20 +278,51 @@ const DockerComposeImport = ({ refresh }) => {
} }
setService(doc); setService(doc);
}, [dockerCompose]); }
}, [openModal, dockerCompose]);
useEffect(() => {
if(!openModal) {
return;
}
try {
if (installer) {
let doc = JSON.parse(dockerCompose.replace(/\{\{self\}\}/gi, serviceName));
if(doc.services)
Object.keys(doc.services).forEach((key) => {
if (doc.services[key].routes) {
doc.services[key].routes.forEach((route, index) => {
doc.services[key].routes[index] = {
...hostnames[index],
name: route.name,
description: route.description,
};
});
}
});
setService(doc);
}
} catch (e) {
setYmlError(e.message);
return;
}
}, [openModal, installer, serviceName, hostnames]);
return <> return <>
<Dialog open={openModal} onClose={() => setOpenModal(false)}> <Dialog open={openModal} onClose={() => setOpenModal(false)} >
<DialogTitle>Import Docker Compose</DialogTitle> <DialogTitle>{installer ? "Installation" : "Import Compose File"}</DialogTitle>
<DialogContent> <DialogContent style={{width: '800px', maxWidth: '100%'}}>
<DialogContentText> <DialogContentText>
{step === 0 && <Stack spacing={2}> {step === 0 && !installer && <><Stack spacing={2}>
<Alert severity="warning" icon={<WarningOutlined />}> <Alert severity="warning" icon={<WarningOutlined />}>
This is an experimental feature. It is recommended to use with caution. Please report any issue you find! This is an experimental feature. It is recommended to use with caution. Please report any issue you find!
</Alert> </Alert>
<UploadButtons <UploadButtons
accept='.yml,.yaml' accept='.yml,.yaml,.json'
OnChange={(e) => { OnChange={(e) => {
const file = e.target.files[0]; const file = e.target.files[0];
const reader = new FileReader(); const reader = new FileReader();
@ -261,7 +339,7 @@ const DockerComposeImport = ({ refresh }) => {
<TextField <TextField
multiline multiline
placeholder='Paste your docker-compose.yml here or use the file upload button.' placeholder='Paste your docker-compose.yml / cosmos-compose.json here or use the file upload button.'
fullWidth fullWidth
value={dockerCompose} value={dockerCompose}
onChange={(e) => setDockerCompose(e.target.value)} onChange={(e) => setDockerCompose(e.target.value)}
@ -272,7 +350,29 @@ const DockerComposeImport = ({ refresh }) => {
} }
}} }}
rows={20}></TextField> rows={20}></TextField>
</Stack>} </Stack></>}
{step === 0 && installer && <><Stack spacing={2}>
<div style={{ color: 'red' }}>
{ymlError}
</div>
{!ymlError && (<><FormLabel>Choose your service name</FormLabel>
<TextField label="Service Name" value={serviceName} onChange={(e) => setServiceName(e.target.value)} />
{hostnames.map((hostname, index) => {
return <>
<FormLabel>Choose URL for {hostname.name}</FormLabel>
<div style={{ opacity: 0.9, fontSize: '0.8em', textDecoration: 'italic'}}
>{hostname.description}</div>
<TextField key={index} label="Hostname" value={hostname.host} onChange={(e) => {
const newHostnames = [...hostnames];
newHostnames[index].host = e.target.value;
setHostnames(newHostnames);
}} />
</>
})}
</>)}
</Stack></>}
{step === 1 && <Stack spacing={2}> {step === 1 && <Stack spacing={2}>
<NewDockerService service={service} refresh={refresh} /> <NewDockerService service={service} refresh={refresh} />
</Stack>} </Stack>}
@ -284,8 +384,8 @@ const DockerComposeImport = ({ refresh }) => {
setStep(0); setStep(0);
setDockerCompose(''); setDockerCompose('');
setYmlError(''); setYmlError('');
}}>Close</Button> }}>Cancel</Button>
<Button onClick={() => { <Button disabled={!dockerCompose || ymlError} onClick={() => {
if (step === 0) { if (step === 0) {
setStep(1); setStep(1);
} else { } else {
@ -301,10 +401,10 @@ const DockerComposeImport = ({ refresh }) => {
<ResponsiveButton <ResponsiveButton
color="primary" color="primary"
onClick={() => setOpenModal(true)} onClick={() => setOpenModal(true)}
variant="outlined" variant={(installer ? "contained" : "outlined")}
startIcon={<ArrowUpOutlined />} startIcon={(installer ? <ArrowDownOutlined /> : <ArrowUpOutlined />)}
> >
Import Docker Compose {installer ? 'Install' : 'Import Compose File'}
</ResponsiveButton> </ResponsiveButton>
</>; </>;
}; };

View file

@ -91,6 +91,7 @@ const NewDockerService = ({service, refresh}) => {
variant="contained" variant="contained"
color="primary" color="primary"
fullWidth fullWidth
className='shinyButton'
loading={log.length && !isDone} loading={log.length && !isDone}
startIcon={<PlusCircleOutlined />} startIcon={<PlusCircleOutlined />}
>Create</LoadingButton>} >Create</LoadingButton>}
@ -110,7 +111,11 @@ const NewDockerService = ({service, refresh}) => {
} }
</Stack>} </Stack>}
<pre style={preStyle} ref={preRef}> <pre style={preStyle} ref={preRef}>
{!log.length && JSON.stringify(service, false ,2)} {!log.length && `
# You are about to create the following service(s):
${JSON.stringify(service, false ,2)}`
}
{log.map((l) => { {log.map((l) => {
return <div>{tryParseProgressLog(l)}</div> return <div>{tryParseProgressLog(l)}</div>
})} })}

View file

@ -1,6 +1,6 @@
{ {
"name": "cosmos-server", "name": "cosmos-server",
"version": "0.6.4", "version": "0.7.0-unstable",
"description": "", "description": "",
"main": "test-server.js", "main": "test-server.js",
"bugs": { "bugs": {

View file

@ -379,6 +379,21 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
Tty: container.Tty, Tty: container.Tty,
OpenStdin: container.StdinOpen, OpenStdin: container.StdinOpen,
} }
// check if there's an empty TZ env, if so, replace it with the host's TZ
if containerConfig.Env != nil {
for i, env := range containerConfig.Env {
if strings.HasPrefix(env, "TZ=") {
if strings.TrimPrefix(env, "TZ=") == "" {
if os.Getenv("TZ") != "" {
containerConfig.Env[i] = "TZ=" + os.Getenv("TZ")
} else {
containerConfig.Env = append(containerConfig.Env[:i], containerConfig.Env[i+1:]...)
}
}
}
}
}
if container.Command != "" { if container.Command != "" {
containerConfig.Cmd = strings.Fields(container.Command) containerConfig.Cmd = strings.Fields(container.Command)