[release] version 0.5.0-unstable20
This commit is contained in:
parent
4beede621b
commit
0f46cff353
|
@ -2,7 +2,7 @@ import { useParams } from "react-router";
|
||||||
import Back from "../../components/back";
|
import Back from "../../components/back";
|
||||||
import { Alert, Box, CircularProgress, Grid, Stack, useTheme } from "@mui/material";
|
import { Alert, Box, CircularProgress, Grid, Stack, useTheme } from "@mui/material";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import * as API from "../../api";
|
import * as API from "../../api";
|
||||||
import wallpaper from '../../assets/images/wallpaper.jpg';
|
import wallpaper from '../../assets/images/wallpaper.jpg';
|
||||||
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
|
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
|
||||||
import { getFaviconURL } from "../../utils/routes";
|
import { getFaviconURL } from "../../utils/routes";
|
||||||
|
@ -14,14 +14,14 @@ import IsLoggedIn from "../../isLoggedIn";
|
||||||
const HomeBackground = () => {
|
const HomeBackground = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<Box sx={{ position: 'fixed', float: 'left', overflow: 'hidden', zIndex: 0, top: 0, left: 0, right: 0, bottom: 0 }}>
|
<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%" />
|
<img src={wallpaper} style={{ display: 'inline' }} alt="Cosmos" width="100%" height="100%" />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const blockStyle = {
|
const blockStyle = {
|
||||||
margin: 0,
|
margin: 0,
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
|
@ -30,35 +30,40 @@ const blockStyle = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const HomePage = () => {
|
const HomePage = () => {
|
||||||
const { routeName } = useParams();
|
const { routeName } = useParams();
|
||||||
const [config, setConfig] = useState(null);
|
const [serveApps, setServeApps] = useState([]);
|
||||||
const [coStatus, setCoStatus] = useState(null);
|
const [config, setConfig] = useState(null);
|
||||||
|
const [coStatus, setCoStatus] = useState(null);
|
||||||
|
const [containers, setContainers] = useState(null);
|
||||||
|
|
||||||
const refreshStatus = () => {
|
const refreshStatus = () => {
|
||||||
API.getStatus().then((res) => {
|
API.getStatus().then((res) => {
|
||||||
setCoStatus(res.data);
|
setCoStatus(res.data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshConfig = () => {
|
const refreshConfig = () => {
|
||||||
API.config.get().then((res) => {
|
API.docker.list().then((res) => {
|
||||||
setConfig(res.data);
|
setServeApps(res.data);
|
||||||
});
|
});
|
||||||
};
|
API.config.get().then((res) => {
|
||||||
|
setConfig(res.data);
|
||||||
let routes = config && (config.HTTPConfig.ProxyConfig.Routes || []);
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
let routes = config && (config.HTTPConfig.ProxyConfig.Routes || []);
|
||||||
refreshConfig();
|
|
||||||
refreshStatus();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
|
|
||||||
return <Stack spacing={2} >
|
useEffect(() => {
|
||||||
<IsLoggedIn />
|
refreshConfig();
|
||||||
<HomeBackground />
|
refreshStatus();
|
||||||
<style>
|
}, []);
|
||||||
{`header {
|
|
||||||
|
|
||||||
|
return <Stack spacing={2} >
|
||||||
|
<IsLoggedIn />
|
||||||
|
<HomeBackground />
|
||||||
|
<style>
|
||||||
|
{`header {
|
||||||
background: rgba(0.2,0.2,0.2,0.2) !important;
|
background: rgba(0.2,0.2,0.2,0.2) !important;
|
||||||
border-bottom-color: rgba(0.4,0.4,0.4,0.4) !important;
|
border-bottom-color: rgba(0.4,0.4,0.4,0.4) !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
|
@ -84,81 +89,91 @@ const HomePage = () => {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
<Stack style={{zIndex: 2}} spacing={1}>
|
<Stack style={{ zIndex: 2 }} spacing={1}>
|
||||||
{coStatus && !coStatus.database && (
|
{coStatus && !coStatus.database && (
|
||||||
<Alert severity="error">
|
<Alert severity="error">
|
||||||
No Database is setup for Cosmos! User Management and Authentication will not work.<br />
|
No Database is setup for Cosmos! User Management and Authentication will not work.<br />
|
||||||
You can either setup the database, or disable user management in the configuration panel.<br />
|
You can either setup the database, or disable user management in the configuration panel.<br />
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{coStatus && coStatus.letsencrypt && (
|
{coStatus && coStatus.letsencrypt && (
|
||||||
<Alert severity="error">
|
<Alert severity="error">
|
||||||
You have enabled Let's Encrypt for automatic HTTPS Certificate. You need to provide the configuration with an email address to use for Let's Encrypt in the configs.
|
You have enabled Let's Encrypt for automatic HTTPS Certificate. You need to provide the configuration with an email address to use for Let's Encrypt in the configs.
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{coStatus && coStatus.newVersionAvailable && (
|
{coStatus && coStatus.newVersionAvailable && (
|
||||||
<Alert severity="warning">
|
<Alert severity="warning">
|
||||||
A new version of Cosmos is available! Please update to the latest version to get the latest features and bug fixes.
|
A new version of Cosmos is available! Please update to the latest version to get the latest features and bug fixes.
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{coStatus && coStatus.needsRestart && (
|
{coStatus && coStatus.needsRestart && (
|
||||||
<Alert severity="warning">
|
<Alert severity="warning">
|
||||||
You have made changes to the configuration that require a restart to take effect. Please restart Cosmos to apply the changes.
|
You have made changes to the configuration that require a restart to take effect. Please restart Cosmos to apply the changes.
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{coStatus && coStatus.domain && (
|
{coStatus && coStatus.domain && (
|
||||||
<Alert severity="error">
|
<Alert severity="error">
|
||||||
You are using localhost or 0.0.0.0 as a hostname in the configuration. It is recommended that you use a domain name instead.
|
You are using localhost or 0.0.0.0 as a hostname in the configuration. It is recommended that you use a domain name instead.
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{coStatus && !coStatus.docker && (
|
{coStatus && !coStatus.docker && (
|
||||||
<Alert severity="error">
|
<Alert severity="error">
|
||||||
Docker is not connected! Please check your docker connection.<br/>
|
Docker is not connected! Please check your docker connection.<br />
|
||||||
Did you forget to add <pre>-v /var/run/docker.sock:/var/run/docker.sock</pre> to your docker run command?<br />
|
Did you forget to add <pre>-v /var/run/docker.sock:/var/run/docker.sock</pre> to your docker run command?<br />
|
||||||
if your docker daemon is running somewhere else, please add <pre>-e DOCKER_HOST=...</pre> to your docker run command.
|
if your docker daemon is running somewhere else, please add <pre>-e DOCKER_HOST=...</pre> to your docker run command.
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Grid2 container spacing={2} style={{zIndex: 2}}>
|
<Grid2 container spacing={2} style={{ zIndex: 2 }}>
|
||||||
{config && config.HTTPConfig.ProxyConfig.Routes.map((route) => {
|
{config && serveApps && config.HTTPConfig.ProxyConfig.Routes.map((route) => {
|
||||||
return <Grid2 item xs={12} sm={6} md={4} lg={3} xl={3} xxl={2} key={route.Name}>
|
let skip = false;
|
||||||
<Box className='app' style={{padding: 10, color: 'white', background: 'rgba(0,0,0,0.35)', borderRadius: 5}}>
|
if(route.Mode == "SERVAPP") {
|
||||||
<Link to={getFullOrigin(route)} target="_blank" style={{textDecoration: 'none', color: 'white'}}>
|
const containerName = route.Target.split(':')[1].slice(2);
|
||||||
|
console.log('try ' + containerName)
|
||||||
|
const container = serveApps.find((c) => c.Names.includes('/' + containerName));
|
||||||
|
console.log('found ' + container)
|
||||||
|
if(container && container.State != "running") {
|
||||||
|
skip = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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' }}>
|
||||||
|
<Stack direction="row" spacing={2} alignItems="center">
|
||||||
|
<img src={getFaviconURL(route)} width="64px" />
|
||||||
|
|
||||||
|
<div style={{ width: '100%' }}>
|
||||||
|
<h3 style={blockStyle}>{route.Name}</h3>
|
||||||
|
<p style={blockStyle}>{route.Description}</p>
|
||||||
|
<p style={blockStyle}>{route.Target}</p>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</Link>
|
||||||
|
</Box>
|
||||||
|
</Grid2>
|
||||||
|
})}
|
||||||
|
|
||||||
|
{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 }}>
|
||||||
<Stack direction="row" spacing={2} alignItems="center">
|
<Stack direction="row" spacing={2} alignItems="center">
|
||||||
<img src={getFaviconURL(route)} width="64px" />
|
<div style={{ width: '100%' }}>
|
||||||
|
<h3 style={blockStyle}>No Apps</h3>
|
||||||
<div style={{width: '100%'}}>
|
<p style={blockStyle}>You have no apps configured. Please add some apps in the configuration panel.</p>
|
||||||
<h3 style={blockStyle}>{route.Name}</h3>
|
|
||||||
<p style={blockStyle}>{route.Description}</p>
|
|
||||||
<p style={blockStyle}>{route.Target}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Link>
|
</Box>
|
||||||
</Box>
|
</Grid2>
|
||||||
</Grid2>
|
)}
|
||||||
})}
|
</Grid2>
|
||||||
|
</Stack>
|
||||||
{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}}>
|
|
||||||
<Stack direction="row" spacing={2} alignItems="center">
|
|
||||||
<div style={{width: '100%'}}>
|
|
||||||
<h3 style={blockStyle}>No Apps</h3>
|
|
||||||
<p style={blockStyle}>You have no apps configured. Please add some apps in the configuration panel.</p>
|
|
||||||
</div>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Grid2>
|
|
||||||
)}
|
|
||||||
</Grid2>
|
|
||||||
</Stack>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HomePage;
|
export default HomePage;
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.5.0-unstable19",
|
"version": "0.5.0-unstable20",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
79
src/icons.go
79
src/icons.go
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"path"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
|
@ -21,22 +22,67 @@ type CachedImage struct {
|
||||||
|
|
||||||
var cache = make(map[string]CachedImage)
|
var cache = make(map[string]CachedImage)
|
||||||
|
|
||||||
func ExtractFaviconMetaTag(html string) string {
|
func ExtractFaviconMetaTag(filename string) string {
|
||||||
|
// Read the contents of the file
|
||||||
|
htmlBytes, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return "/favicon.ico"
|
||||||
|
}
|
||||||
|
html := string(htmlBytes)
|
||||||
|
|
||||||
// Regular expression pattern to match the favicon metatag
|
// Regular expression pattern to match the favicon metatag
|
||||||
pattern := `<link[^>]*rel="icon"[^>]*href="([^"]+)"[^>]*>`
|
pattern := `<link[^>]*rel="icon"[^>]*(?:sizes="([^"]+)")?[^>]*href="([^"]+)"[^>]*>|<meta[^>]*name="msapplication-TileImage"[^>]*content="([^"]+)"[^>]*>`
|
||||||
|
|
||||||
// Compile the regular expression pattern
|
// Compile the regular expression pattern
|
||||||
regex := regexp.MustCompile(pattern)
|
regex := regexp.MustCompile(pattern)
|
||||||
|
|
||||||
// Find the first match in the HTML string
|
// Find all matches in the HTML string
|
||||||
match := regex.FindStringSubmatch(html)
|
matches := regex.FindAllStringSubmatch(html, -1)
|
||||||
|
|
||||||
if len(match) > 1 {
|
var faviconURL string
|
||||||
// Extract the URL from the matched metatag
|
|
||||||
faviconURL := match[1]
|
// Iterate over the matches to find the appropriate favicon
|
||||||
|
for _, match := range matches {
|
||||||
|
sizes := match[1]
|
||||||
|
href := match[2]
|
||||||
|
msAppTileImage := match[3]
|
||||||
|
|
||||||
|
// Check if the meta tag specifies msapplication-TileImage
|
||||||
|
if msAppTileImage != "" {
|
||||||
|
faviconURL = msAppTileImage
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the sizes attribute contains 96x96
|
||||||
|
if strings.Contains(sizes, "96x96") {
|
||||||
|
faviconURL = href
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the sizes attribute contains 64x64
|
||||||
|
if strings.Contains(sizes, "64x64") {
|
||||||
|
faviconURL = href
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the sizes attribute contains 32x32
|
||||||
|
if strings.Contains(sizes, "32x32") {
|
||||||
|
faviconURL = href
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no sizes specified, set faviconURL to the first match without sizes
|
||||||
|
if faviconURL == "" && sizes == "" {
|
||||||
|
faviconURL = href
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a favicon URL is found, return it
|
||||||
|
if faviconURL != "" {
|
||||||
return faviconURL
|
return faviconURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return an error if no favicon URL is found
|
||||||
return "/favicon.ico"
|
return "/favicon.ico"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,10 +165,23 @@ func GetFavicon(w http.ResponseWriter, req *http.Request) {
|
||||||
sendFallback(w)
|
sendFallback(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(faviconURL, "/") {
|
|
||||||
faviconURL = "/" + faviconURL
|
if strings.HasPrefix(faviconURL, ".") {
|
||||||
|
// Relative URL starting with "."
|
||||||
|
// Resolve the relative URL based on the base URL
|
||||||
|
baseURL := u.Scheme + "://" + u.Host
|
||||||
|
faviconURL = baseURL + faviconURL[1:]
|
||||||
|
} else if strings.HasPrefix(faviconURL, "/") {
|
||||||
|
// Relative URL starting with "/"
|
||||||
|
// Append the relative URL to the base URL
|
||||||
|
faviconURL = u.Scheme + "://" + u.Host + faviconURL
|
||||||
|
} else {
|
||||||
|
// Relative URL without starting dot or slash
|
||||||
|
// Construct the absolute URL based on the current page's URL path
|
||||||
|
baseURL := u.Scheme + "://" + u.Host
|
||||||
|
baseURLPath := path.Dir(u.Path)
|
||||||
|
faviconURL = baseURL + baseURLPath + "/" + faviconURL
|
||||||
}
|
}
|
||||||
faviconURL = u.Scheme + "://" + u.Host + faviconURL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.Log("Favicon: " + faviconURL)
|
utils.Log("Favicon: " + faviconURL)
|
||||||
|
|
Loading…
Reference in a new issue