[release] v0.9.5
This commit is contained in:
parent
6976f4d99d
commit
43a9ddef08
|
@ -1,8 +1,11 @@
|
||||||
## Version 0.9.1 > 0.9.4
|
## Version 0.9.1 > 0.9.5
|
||||||
- Fix subdomain logic for composed TLDs
|
- Fix subdomain logic for composed TLDs
|
||||||
|
- Add option for custom wildcard domains
|
||||||
- Fix domain depupe logic
|
- Fix domain depupe logic
|
||||||
|
- Add import button in market
|
||||||
- Update LEGO
|
- Update LEGO
|
||||||
- Fix issue with hot-reloading between HTTP and HTTPS
|
- Fix issue with hot-reloading between HTTP and HTTPS
|
||||||
|
- Fix loading bar in container overview page
|
||||||
|
|
||||||
## Version 0.9.0
|
## Version 0.9.0
|
||||||
- Rewrote the entire HTTPS / DNS challenge system to be more robust and easier to use
|
- Rewrote the entire HTTPS / DNS challenge system to be more robust and easier to use
|
||||||
|
|
|
@ -73,7 +73,7 @@ const AuthRegister = ({nickname, isRegister, isInviteLink, regkey}) => {
|
||||||
.max(255)
|
.max(255)
|
||||||
.required('Password is required')
|
.required('Password is required')
|
||||||
.matches(
|
.matches(
|
||||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[~!@#$%\^&\*\(\)_\+=\-\{\[\}\]:;"'<,>\.\?\/])(?=.{9,})/,
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[~!@#$%\^&\*\(\)_\+=\-\{\[\}\]:;"'<,>\.\/])(?=.{9,})/,
|
||||||
'Must Contain 9 Characters, One Uppercase, One Lowercase, One Number and one special case Character (~!@#$%^&*()_+=-{[}]:;"\'<>.?/)'
|
'Must Contain 9 Characters, One Uppercase, One Lowercase, One Number and one special case Character (~!@#$%^&*()_+=-{[}]:;"\'<>.?/)'
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -90,6 +90,7 @@ const ConfigManagement = () => {
|
||||||
DNSChallengeProvider: config.HTTPConfig.DNSChallengeProvider,
|
DNSChallengeProvider: config.HTTPConfig.DNSChallengeProvider,
|
||||||
DNSChallengeConfig: config.HTTPConfig.DNSChallengeConfig,
|
DNSChallengeConfig: config.HTTPConfig.DNSChallengeConfig,
|
||||||
ForceHTTPSCertificateRenewal: config.HTTPConfig.ForceHTTPSCertificateRenewal,
|
ForceHTTPSCertificateRenewal: config.HTTPConfig.ForceHTTPSCertificateRenewal,
|
||||||
|
OverrideWildcardDomains: config.HTTPConfig.OverrideWildcardDomains,
|
||||||
|
|
||||||
Email_Enabled: config.EmailConfig.Enabled,
|
Email_Enabled: config.EmailConfig.Enabled,
|
||||||
Email_Host: config.EmailConfig.Host,
|
Email_Host: config.EmailConfig.Host,
|
||||||
|
@ -136,6 +137,7 @@ const ConfigManagement = () => {
|
||||||
DNSChallengeProvider: values.DNSChallengeProvider,
|
DNSChallengeProvider: values.DNSChallengeProvider,
|
||||||
DNSChallengeConfig: values.DNSChallengeConfig,
|
DNSChallengeConfig: values.DNSChallengeConfig,
|
||||||
ForceHTTPSCertificateRenewal: values.ForceHTTPSCertificateRenewal,
|
ForceHTTPSCertificateRenewal: values.ForceHTTPSCertificateRenewal,
|
||||||
|
OverrideWildcardDomains: values.OverrideWildcardDomains.replace(/\s/g, ''),
|
||||||
},
|
},
|
||||||
EmailConfig: {
|
EmailConfig: {
|
||||||
...config.EmailConfig,
|
...config.EmailConfig,
|
||||||
|
@ -552,6 +554,19 @@ const ConfigManagement = () => {
|
||||||
formik={formik}
|
formik={formik}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{formik.values.UseWildcardCertificate && (
|
||||||
|
<CosmosInputText
|
||||||
|
name="OverrideWildcardDomains"
|
||||||
|
onChange={(e) => {
|
||||||
|
formik.setFieldValue("ForceHTTPSCertificateRenewal", true);
|
||||||
|
}}
|
||||||
|
label="(optional) Override Wildcard Domains (comma separated, need to add both wildcard AND root domain like in the placeholder)"
|
||||||
|
formik={formik}
|
||||||
|
placeholder={"example.com,*.example.com"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
{formik.values.HTTPSCertificateMode === "LETSENCRYPT" && (
|
{formik.values.HTTPSCertificateMode === "LETSENCRYPT" && (
|
||||||
<CosmosInputText
|
<CosmosInputText
|
||||||
name="SSLEmail"
|
name="SSLEmail"
|
||||||
|
|
|
@ -6,20 +6,21 @@ import { useTheme } from "@emotion/react";
|
||||||
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
|
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
import Carousel from 'react-material-ui-carousel'
|
import Carousel from 'react-material-ui-carousel'
|
||||||
import { Paper, Button , Chip} from '@mui/material'
|
import { Paper, Button, Chip } from '@mui/material'
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import {Link as LinkMUI} from '@mui/material'
|
import { Link as LinkMUI } from '@mui/material'
|
||||||
import DockerComposeImport from '../servapps/containers/docker-compose';
|
import DockerComposeImport from '../servapps/containers/docker-compose';
|
||||||
import { SearchOutlined } from "@ant-design/icons";
|
import { AppstoreAddOutlined, SearchOutlined } from "@ant-design/icons";
|
||||||
|
import ResponsiveButton from "../../components/responseiveButton";
|
||||||
|
|
||||||
function Screenshots({ screenshots }) {
|
function Screenshots({ screenshots }) {
|
||||||
return screenshots.length > 1 ? (
|
return screenshots.length > 1 ? (
|
||||||
<Carousel animation="slide" navButtonsAlwaysVisible={false} fullHeightHover="true" swipe={false}>
|
<Carousel animation="slide" navButtonsAlwaysVisible={false} fullHeightHover="true" swipe={false}>
|
||||||
{
|
{
|
||||||
screenshots.map((item, i) => <img style={{maxHeight:'300px', height: '100%', maxWidth: '100%'}} key={i} src={item} />)
|
screenshots.map((item, i) => <img style={{ maxHeight: '300px', height: '100%', maxWidth: '100%' }} key={i} src={item} />)
|
||||||
}
|
}
|
||||||
</Carousel>)
|
</Carousel>)
|
||||||
: <img src={screenshots[0]} style={{maxHeight:'300px', height: '100%', maxWidth: '100%'}} />
|
: <img src={screenshots[0]} style={{ maxHeight: '300px', height: '100%', maxWidth: '100%' }} />
|
||||||
}
|
}
|
||||||
|
|
||||||
function Showcases({ showcase, isDark }) {
|
function Showcases({ showcase, isDark }) {
|
||||||
|
@ -34,14 +35,14 @@ function Showcases({ showcase, isDark }) {
|
||||||
|
|
||||||
function ShowcasesItem({ isDark, item }) {
|
function ShowcasesItem({ isDark, item }) {
|
||||||
return (
|
return (
|
||||||
<Paper style={{
|
<Paper style={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
background: 'url(' + item.screenshots[0] + ')',
|
background: 'url(' + item.screenshots[0] + ')',
|
||||||
height: '31vh',
|
height: '31vh',
|
||||||
backgroundSize: 'auto 100%',
|
backgroundSize: 'auto 100%',
|
||||||
maxWidth: '120vh',
|
maxWidth: '120vh',
|
||||||
margin: 'auto',
|
margin: 'auto',
|
||||||
}}>
|
}}>
|
||||||
<Stack direction="row" spacing={2} style={{ height: '100%', overflow: 'hidden' }} justifyContent="flex-end">
|
<Stack direction="row" spacing={2} style={{ height: '100%', overflow: 'hidden' }} justifyContent="flex-end">
|
||||||
<Stack direction="column" spacing={2} style={{ height: '100%' }} sx={{
|
<Stack direction="column" spacing={2} style={{ height: '100%' }} sx={{
|
||||||
backgroundColor: isDark ? '#1A2027' : '#fff',
|
backgroundColor: isDark ? '#1A2027' : '#fff',
|
||||||
|
@ -49,7 +50,7 @@ function ShowcasesItem({ isDark, item }) {
|
||||||
width: '50%',
|
width: '50%',
|
||||||
filter: 'drop-shadow(-20px 0px 20px rgba(0, 0, 0, 1))',
|
filter: 'drop-shadow(-20px 0px 20px rgba(0, 0, 0, 1))',
|
||||||
|
|
||||||
'@media (max-width: 1100px)': {
|
'@media (max-width: 1100px)': {
|
||||||
width: '70%',
|
width: '70%',
|
||||||
padding: '20px 40px',
|
padding: '20px 40px',
|
||||||
},
|
},
|
||||||
|
@ -60,15 +61,15 @@ function ShowcasesItem({ isDark, item }) {
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<Stack direction="row" spacing={2}>
|
<Stack direction="row" spacing={2}>
|
||||||
<img src={item.icon} style={{ width: '36px', height: '36px' }} />
|
<img src={item.icon} style={{ width: '36px', height: '36px' }} />
|
||||||
<h2>{item.name}</h2>
|
<h2>{item.name}</h2>
|
||||||
</Stack>
|
</Stack>
|
||||||
<p dangerouslySetInnerHTML={{ __html: item.longDescription }} style={{
|
<p dangerouslySetInnerHTML={{ __html: item.longDescription }} style={{
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}></p>
|
}}></p>
|
||||||
<Stack direction="row" spacing={2} justifyContent="flex-start">
|
<Stack direction="row" spacing={2} justifyContent="flex-start">
|
||||||
<div>
|
<div>
|
||||||
<DockerComposeImport installerInit defaultName={item.name} dockerComposeInit={item.compose} />
|
<DockerComposeImport installerInit defaultName={item.name} dockerComposeInit={item.compose} />
|
||||||
</div>
|
</div>
|
||||||
<Link to={"/cosmos-ui/market-listing/cosmos-cloud/" + item.name} style={{
|
<Link to={"/cosmos-ui/market-listing/cosmos-cloud/" + item.name} style={{
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
|
@ -143,23 +144,23 @@ const MarketPage = () => {
|
||||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||||
}}>
|
}}>
|
||||||
<Link to="/cosmos-ui/market-listing" as={Box}
|
<Link to="/cosmos-ui/market-listing" as={Box}
|
||||||
style={{
|
style={{
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
}}></Link>
|
}}></Link>
|
||||||
|
|
||||||
<Stack direction="row" spacing={2} style={{ height: '100%'}} justifyContent="flex-end">
|
<Stack direction="row" spacing={2} style={{ height: '100%' }} justifyContent="flex-end">
|
||||||
<Stack direction="column" spacing={3} style={{ height: '100%', overflow: "auto"}} sx={{
|
<Stack direction="column" spacing={3} style={{ height: '100%', overflow: "auto" }} sx={{
|
||||||
backgroundColor: isDark ? '#1A2027' : '#fff',
|
backgroundColor: isDark ? '#1A2027' : '#fff',
|
||||||
padding: '80px 80px',
|
padding: '80px 80px',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: '800px',
|
maxWidth: '800px',
|
||||||
filter: 'drop-shadow(-20px 0px 20px rgba(0, 0, 0, 1))',
|
filter: 'drop-shadow(-20px 0px 20px rgba(0, 0, 0, 1))',
|
||||||
|
|
||||||
'@media (max-width: 700px)': {
|
'@media (max-width: 700px)': {
|
||||||
padding: '60px 40px',
|
padding: '60px 40px',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -176,7 +177,7 @@ const MarketPage = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div style={{textAlign: 'center'}}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<Screenshots screenshots={openedApp.screenshots} />
|
<Screenshots screenshots={openedApp.screenshots} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -202,7 +203,7 @@ const MarketPage = () => {
|
||||||
<div dangerouslySetInnerHTML={{ __html: openedApp.longDescription }}></div>
|
<div dangerouslySetInnerHTML={{ __html: openedApp.longDescription }}></div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<DockerComposeImport installerInit defaultName={openedApp.name} dockerComposeInit={openedApp.compose} />
|
<DockerComposeImport installerInit defaultName={openedApp.name} dockerComposeInit={openedApp.compose} />
|
||||||
</div>
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -222,7 +223,7 @@ const MarketPage = () => {
|
||||||
size={100}
|
size={100}
|
||||||
/>
|
/>
|
||||||
</Box>}
|
</Box>}
|
||||||
{showcase && showcase.length > 0 && <Showcases showcase={showcase} isDark={isDark}/>}
|
{showcase && showcase.length > 0 && <Showcases showcase={showcase} isDark={isDark} />}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack spacing={1} style={{
|
<Stack spacing={1} style={{
|
||||||
|
@ -234,18 +235,28 @@ const MarketPage = () => {
|
||||||
padding: '24px',
|
padding: '24px',
|
||||||
}}>
|
}}>
|
||||||
<h2>Applications</h2>
|
<h2>Applications</h2>
|
||||||
<Input placeholder="Search"
|
<Stack direction="row" spacing={2}>
|
||||||
value={search}
|
<Input placeholder="Search"
|
||||||
style={{maxWidth: '400px'}}
|
value={search}
|
||||||
startAdornment={
|
style={{ maxWidth: '400px' }}
|
||||||
<InputAdornment position="start">
|
startAdornment={
|
||||||
<SearchOutlined />
|
<InputAdornment position="start">
|
||||||
</InputAdornment>
|
<SearchOutlined />
|
||||||
}
|
</InputAdornment>
|
||||||
onChange={(e) => {
|
}
|
||||||
setSearch(e.target.value);
|
onChange={(e) => {
|
||||||
}}
|
setSearch(e.target.value);
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Link to="/cosmos-ui/servapps/new-service">
|
||||||
|
<ResponsiveButton
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AppstoreAddOutlined />}
|
||||||
|
>Start ServApp</ResponsiveButton>
|
||||||
|
</Link>
|
||||||
|
<DockerComposeImport refresh={() => { }} />
|
||||||
|
</Stack>
|
||||||
{(!apps || !Object.keys(apps).length) && <Box style={{
|
{(!apps || !Object.keys(apps).length) && <Box style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
@ -262,46 +273,48 @@ const MarketPage = () => {
|
||||||
|
|
||||||
{apps && Object.keys(apps).length > 0 && <Grid2 container spacing={{ xs: 1, sm: 1, md: 2 }}>
|
{apps && Object.keys(apps).length > 0 && <Grid2 container spacing={{ xs: 1, sm: 1, md: 2 }}>
|
||||||
{Object.keys(apps).map(appstore => apps[appstore]
|
{Object.keys(apps).map(appstore => apps[appstore]
|
||||||
.filter((app) => {
|
.filter((app) => {
|
||||||
if (!search || search.length <= 2) {
|
if (!search || search.length <= 2) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return app.name.toLowerCase().includes(search.toLowerCase()) ||
|
return app.name.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
app.tags.join(' ').toLowerCase().includes(search.toLowerCase());
|
app.tags.join(' ').toLowerCase().includes(search.toLowerCase());
|
||||||
})
|
})
|
||||||
.map((app) => {
|
.map((app) => {
|
||||||
return <Grid2 style={{
|
return <Grid2 style={{
|
||||||
...gridAnim,
|
...gridAnim,
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
}} xs={12} sm={12} md={6} lg={4} xl={3} key={app.name} item><Link to={"/cosmos-ui/market-listing/" + appstore + "/" + app.name} style={{
|
}} xs={12} sm={12} md={6} lg={4} xl={3} key={app.name} item><Link to={"/cosmos-ui/market-listing/" + appstore + "/" + app.name} style={{
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
}}>
|
}}>
|
||||||
<div key={app.name} style={appCardStyle(theme)}>
|
<div key={app.name} style={appCardStyle(theme)}>
|
||||||
<Stack spacing={3} direction={'row'} alignItems={'center'} style={{ padding: '0px 15px' }}>
|
<Stack spacing={3} direction={'row'} alignItems={'center'} style={{ padding: '0px 15px' }}>
|
||||||
<img src={app.icon} style={{ width: 64, height: 64 }} />
|
<img src={app.icon} style={{ width: 64, height: 64 }} />
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<div style={{ fontWeight: "bold" }}>{app.name}</div>
|
<div style={{ fontWeight: "bold" }}>{app.name}</div>
|
||||||
<div style={{
|
<div style={{
|
||||||
height: '40px',
|
height: '40px',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'pre-wrap',
|
whiteSpace: 'pre-wrap',
|
||||||
}}
|
}}
|
||||||
>{app.description}</div>
|
>{app.description}</div>
|
||||||
<Stack direction={'row'} spacing={1}>
|
<Stack direction={'row'} spacing={1}>
|
||||||
<div style={{ fontStyle: "italic", opacity: 0.7,
|
<div style={{
|
||||||
overflow: 'hidden',
|
fontStyle: "italic", opacity: 0.7,
|
||||||
height: '21px',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
height: '21px',
|
||||||
whiteSpace: 'pre-wrap', }}>{app.tags.slice(0,3).join(", ")}</div>
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
}}>{app.tags.slice(0, 3).join(", ")}</div>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</div>
|
||||||
</Stack>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Link>
|
</Link>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
}))}
|
}))}
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
|
@ -485,7 +485,7 @@ const NewInstall = () => {
|
||||||
// nickname cant be admin or root
|
// nickname cant be admin or root
|
||||||
nickname: Yup.string().required('Nickname is required').min(3).max(32)
|
nickname: Yup.string().required('Nickname is required').min(3).max(32)
|
||||||
.matches(/^(?!admin|root).*$/, 'Nickname cannot be admin or root'),
|
.matches(/^(?!admin|root).*$/, 'Nickname cannot be admin or root'),
|
||||||
password: Yup.string().required('Password is required').min(8).max(128).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[~!@#$%\^&\*\(\)_\+=\-\{\[\}\]:;"'<,>\.\?\/])(?=.{9,})/, 'Password must contain 9 characters: at least 1 lowercase, 1 uppercase, 1 number, and 1 special character'),
|
password: Yup.string().required('Password is required').min(8).max(128).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[~!@#$%\^&\*\(\)_\+=\-\{\[\}\]:;"'<,>\.\/])(?=.{9,})/, 'Password must contain 9 characters: at least 1 lowercase, 1 uppercase, 1 number, and 1 special character'),
|
||||||
email: Yup.string().email('Must be a valid email').max(255),
|
email: Yup.string().email('Must be a valid email').max(255),
|
||||||
confirmPassword: Yup.string().oneOf([Yup.ref('password'), null], 'Passwords must match'),
|
confirmPassword: Yup.string().oneOf([Yup.ref('password'), null], 'Passwords must match'),
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -496,9 +496,7 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
|
||||||
<DialogContent style={{ width: '800px', maxWidth: '100%' }}>
|
<DialogContent style={{ width: '800px', maxWidth: '100%' }}>
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
{step === 0 && !installer && <><Stack spacing={2}>
|
{step === 0 && !installer && <><Stack spacing={2}>
|
||||||
<Alert severity="warning" icon={<WarningOutlined />}>
|
|
||||||
This is an experimental feature. It is recommended to use with caution. Please report any issue you find!
|
|
||||||
</Alert>
|
|
||||||
|
|
||||||
<UploadButtons
|
<UploadButtons
|
||||||
accept='.yml,.yaml,.json'
|
accept='.yml,.yaml,.json'
|
||||||
|
|
|
@ -30,9 +30,9 @@ const ContainerOverview = ({ containerInfo, config, refresh, updatesAvailable, s
|
||||||
const healthIconColor = healthStatus === 'Healthy' ? 'green' : 'red';
|
const healthIconColor = healthStatus === 'Healthy' ? 'green' : 'red';
|
||||||
const routes = getContainersRoutes(config, Name.replace('/', ''));
|
const routes = getContainersRoutes(config, Name.replace('/', ''));
|
||||||
|
|
||||||
let refreshAll = refresh && (() => refresh().then(() => {
|
let refreshAll = refresh ? (() => refresh().then(() => {
|
||||||
setIsUpdating(false);
|
setIsUpdating(false);
|
||||||
}));
|
})) : (() => {setIsUpdating(false);});
|
||||||
|
|
||||||
const updateRoutes = (newRoute) => {
|
const updateRoutes = (newRoute) => {
|
||||||
API.config.addRoute(newRoute).then(() => {
|
API.config.addRoute(newRoute).then(() => {
|
||||||
|
@ -95,6 +95,7 @@ const ContainerOverview = ({ containerInfo, config, refresh, updatesAvailable, s
|
||||||
image={Image}
|
image={Image}
|
||||||
state={State.Status}
|
state={State.Status}
|
||||||
refreshServApps={() => {
|
refreshServApps={() => {
|
||||||
|
setIsUpdating(false);
|
||||||
refreshAll()
|
refreshAll()
|
||||||
}}
|
}}
|
||||||
setIsUpdatingId={() => {
|
setIsUpdatingId={() => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.9.4",
|
"version": "0.9.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -119,6 +119,7 @@ type HTTPConfig struct {
|
||||||
Hostname string `validate:"required,excludesall=0x2C/ "`
|
Hostname string `validate:"required,excludesall=0x2C/ "`
|
||||||
SSLEmail string `validate:"omitempty,email"`
|
SSLEmail string `validate:"omitempty,email"`
|
||||||
UseWildcardCertificate bool
|
UseWildcardCertificate bool
|
||||||
|
OverrideWildcardDomains string `validate:"omitempty,excludesall=/ "`
|
||||||
AcceptAllInsecureHostname bool
|
AcceptAllInsecureHostname bool
|
||||||
DNSChallengeConfig map[string]string `json:"DNSChallengeConfig,omitempty"`
|
DNSChallengeConfig map[string]string `json:"DNSChallengeConfig,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,6 +330,7 @@ func LetsEncryptValidOnly(hostnames []string, acceptWildcard bool) []string {
|
||||||
|
|
||||||
func GetAllHostnames(applyWildCard bool, removePorts bool) []string {
|
func GetAllHostnames(applyWildCard bool, removePorts bool) []string {
|
||||||
mainHostname := GetMainConfig().HTTPConfig.Hostname
|
mainHostname := GetMainConfig().HTTPConfig.Hostname
|
||||||
|
OverrideWildcardDomains := GetMainConfig().HTTPConfig.OverrideWildcardDomains
|
||||||
|
|
||||||
if removePorts {
|
if removePorts {
|
||||||
mainHostname = strings.Split(mainHostname, ":")[0]
|
mainHostname = strings.Split(mainHostname, ":")[0]
|
||||||
|
@ -370,6 +371,10 @@ func GetAllHostnames(applyWildCard bool, removePorts bool) []string {
|
||||||
"*." + bareMainHostname,
|
"*." + bareMainHostname,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(OverrideWildcardDomains != "") {
|
||||||
|
filteredHostnames = strings.Split(OverrideWildcardDomains, ",")
|
||||||
|
}
|
||||||
|
|
||||||
for _, hostname := range uniqueHostnames {
|
for _, hostname := range uniqueHostnames {
|
||||||
if hostname != bareMainHostname && !strings.HasSuffix(hostname, "." + bareMainHostname) {
|
if hostname != bareMainHostname && !strings.HasSuffix(hostname, "." + bareMainHostname) {
|
||||||
filteredHostnames = append(filteredHostnames, hostname)
|
filteredHostnames = append(filteredHostnames, hostname)
|
||||||
|
|
Loading…
Reference in a new issue