add-frames #1
14 changed files with 71 additions and 33 deletions
|
@ -1,4 +1,5 @@
|
||||||
STACK_NAME=dashboard
|
STACK_NAME=dashboard
|
||||||
DOCKER_CONTEXT=
|
DOCKER_CONTEXT=dev.local-it.cloud
|
||||||
DOMAIN=
|
DOMAIN=dashboard.dev.local-it.cloud
|
||||||
LETS_ENCRYPT_ENV=production
|
LETS_ENCRYPT_ENV=production
|
||||||
|
REACT_APP_API_URL=http://127.0.0.1:5000/api/v1
|
|
@ -90,7 +90,6 @@
|
||||||
"postcss": "^7",
|
"postcss": "^7",
|
||||||
"pre-commit": "^1.2.2",
|
"pre-commit": "^1.2.2",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
"react-inject-env": "^2.1.0",
|
|
||||||
"sass": "^1.36.0"
|
"sass": "^1.36.0"
|
||||||
},
|
},
|
||||||
"pre-commit": "lint-staged",
|
"pre-commit": "lint-staged",
|
||||||
|
|
44
public/assets/vikunja.svg
Normal file
44
public/assets/vikunja.svg
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="1024.000000pt" height="1025.000000pt" viewBox="0 0 1024.000000 1025.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,1025.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M4925 10243 c-810 -31 -1602 -254 -2310 -648 -152 -85 -487 -308
|
||||||
|
-629 -419 -1058 -827 -1743 -2004 -1930 -3318 -38 -267 -49 -429 -49 -733 0
|
||||||
|
-580 81 -1083 262 -1625 248 -739 639 -1376 1195 -1948 468 -480 1048 -878
|
||||||
|
1656 -1134 231 -97 340 -134 350 -119 4 7 11 47 14 90 4 42 29 234 56 426 63
|
||||||
|
455 80 636 80 874 0 239 12 454 47 846 34 385 38 804 10 985 -37 233 -77 353
|
||||||
|
-224 663 -110 234 -167 370 -216 517 -83 249 -103 371 -112 695 -7 248 0 345
|
||||||
|
76 1098 11 104 10 129 -6 212 -33 177 -6 428 60 555 9 18 11 31 5 35 -16 10
|
||||||
|
-50 133 -66 237 -36 240 -35 783 1 1048 69 500 251 861 530 1051 183 125 426
|
||||||
|
189 502 133 52 -38 64 -80 64 -215 -1 -66 -3 -124 -5 -128 -11 -17 -49 -1262
|
||||||
|
-41 -1327 l6 -51 97 24 c251 60 586 89 957 80 404 -10 689 -53 959 -147 33
|
||||||
|
-11 63 -17 67 -13 11 12 47 242 63 413 20 196 42 531 61 910 15 296 21 343 56
|
||||||
|
412 60 118 192 90 367 -76 163 -156 284 -335 347 -516 88 -253 125 -461 125
|
||||||
|
-707 0 -325 -66 -590 -245 -987 l-26 -59 40 -86 c67 -146 85 -232 86 -406 0
|
||||||
|
-106 -5 -166 -16 -205 -12 -42 -14 -74 -8 -135 30 -310 61 -769 66 -980 11
|
||||||
|
-484 -51 -783 -235 -1145 -47 -91 -124 -242 -171 -335 -179 -351 -241 -625
|
||||||
|
-241 -1064 0 -236 9 -358 60 -811 21 -190 41 -376 45 -415 10 -110 41 -301 85
|
||||||
|
-535 22 -118 70 -370 106 -560 35 -189 66 -345 67 -346 1 -1 65 25 142 57 468
|
||||||
|
198 901 463 1305 799 161 134 496 469 630 630 612 736 998 1590 1139 2520 57
|
||||||
|
377 72 876 37 1222 -121 1208 -629 2301 -1465 3151 -628 639 -1372 1081 -2226
|
||||||
|
1322 -500 142 -1074 209 -1600 188z"/>
|
||||||
|
<path d="M4240 6012 c-61 -33 -140 -170 -197 -345 -36 -111 36 -77 146 68 42
|
||||||
|
55 89 106 104 115 46 26 90 -7 167 -123 71 -108 90 -126 110 -102 33 39 -62
|
||||||
|
266 -148 354 -45 48 -51 51 -98 51 -29 0 -64 -8 -84 -18z"/>
|
||||||
|
<path d="M6075 6011 c-64 -38 -109 -111 -171 -273 -37 -97 -43 -138 -19 -138
|
||||||
|
23 0 84 59 144 140 69 93 97 120 127 120 35 0 99 -63 146 -142 41 -69 83 -112
|
||||||
|
99 -102 5 3 9 20 9 37 0 101 -118 325 -191 362 -39 21 -108 19 -144 -4z"/>
|
||||||
|
<path d="M5540 4821 c-64 -21 -106 -41 -175 -87 l-50 -33 -69 34 c-75 36 -179
|
||||||
|
59 -223 49 -76 -16 -78 -21 -30 -49 49 -29 129 -108 192 -190 l56 -74 -11
|
||||||
|
-118 c-8 -75 -10 -177 -5 -282 l7 -164 -89 7 c-48 3 -171 17 -273 30 -102 13
|
||||||
|
-186 23 -188 21 -2 -2 34 -27 80 -57 207 -136 423 -187 668 -159 198 24 387
|
||||||
|
84 483 155 35 25 77 94 77 125 l0 22 -26 -20 c-57 -45 -228 -83 -474 -106 -36
|
||||||
|
-3 -75 -8 -86 -10 -19 -4 -22 1 -28 53 -16 136 -18 301 -6 397 11 91 15 103
|
||||||
|
45 135 43 46 245 319 245 331 0 14 -60 10 -120 -10z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
3
public/env.js
vendored
Normal file
3
public/env.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
window.env = {
|
||||||
|
REACT_APP_API_URL: 'http://localhost:5000/api/v1',
|
||||||
|
};
|
|
@ -22,7 +22,7 @@
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<script src='/env.js'></script>
|
<script src='%PUBLIC_URL%/env.js'></script>
|
||||||
<title>Dashboard</title>
|
<title>Dashboard</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
13
src/App.tsx
13
src/App.tsx
|
@ -16,10 +16,8 @@ function App() {
|
||||||
const { apps, loadApps } = useApps();
|
const { apps, loadApps } = useApps();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (apps.length === 0) {
|
|
||||||
loadApps();
|
loadApps();
|
||||||
}
|
}, []);
|
||||||
}, [loadApps, apps.length]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -38,12 +36,9 @@ function App() {
|
||||||
<Layout>
|
<Layout>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/dashboard" element={<Dashboard />} />
|
<Route path="/dashboard" element={<Dashboard />} />
|
||||||
{
|
{apps.map((app) => (
|
||||||
// @ts-ignore
|
<Route key={app.name} path={app.slug} element={<AppIframe app={app} />} />
|
||||||
apps.map((app) => (
|
))}
|
||||||
<Route key={app.name} path={app.internalUrl} element={<AppIframe app={app} />} />
|
|
||||||
))
|
|
||||||
}
|
|
||||||
<Route path="*" element={<Navigate to="/dashboard" />} />
|
<Route path="*" element={<Navigate to="/dashboard" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -40,12 +40,12 @@ const Header: React.FC<HeaderProps> = () => {
|
||||||
{apps.map((app) => (
|
{apps.map((app) => (
|
||||||
<Link
|
<Link
|
||||||
key={app.name}
|
key={app.name}
|
||||||
to={app.internalUrl}
|
to={app.slug}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'border-primary-50 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium litbutton',
|
'border-primary-50 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium litbutton',
|
||||||
{
|
{
|
||||||
'border-primary-500 litbutton-active hover:border-gray-300 inline-flex items-center px-1 pt-1 text-sm font-medium':
|
'border-primary-500 litbutton-active hover:border-gray-300 inline-flex items-center px-1 pt-1 text-sm font-medium':
|
||||||
pathname.includes(app.internalUrl),
|
pathname.includes(app.slug),
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -64,13 +64,11 @@ const Header: React.FC<HeaderProps> = () => {
|
||||||
apps.map((app) => (
|
apps.map((app) => (
|
||||||
<Link
|
<Link
|
||||||
key={app.name}
|
key={app.name}
|
||||||
to={app.internalUrl}
|
to={app.slug}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'border-transparent litbutton block pl-3 pr-4 py-2 border-l-4 litbutton text-base font-medium',
|
'border-transparent litbutton block pl-3 pr-4 py-2 border-l-4 litbutton text-base font-medium',
|
||||||
{
|
{
|
||||||
'litbutton-active border-primary-400 block pl-3 pr-4 py-2': pathname.includes(
|
'litbutton-active border-primary-400 block pl-3 pr-4 py-2': pathname.includes(app.slug),
|
||||||
app.internalUrl,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
1
src/env.js
vendored
1
src/env.js
vendored
|
@ -1 +0,0 @@
|
||||||
export const env = { ...process.env, ...window.env };
|
|
|
@ -13,7 +13,7 @@ export const AppIframe: React.FC<any> = ({ app }: { app: any }) => {
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
title={app.name}
|
title={app.name}
|
||||||
url={app.externalUrl}
|
url={app.url}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
export const DashboardCard: React.FC<any> = ({ app }: { app: any }) => {
|
export const DashboardCard: React.FC<any> = ({ app }: { app: any }) => {
|
||||||
const url = `/${app.internalUrl}`;
|
const url = `/${app.slug}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -18,7 +18,7 @@ export const DashboardCard: React.FC<any> = ({ app }: { app: any }) => {
|
||||||
<div className="mr-4 flex items-center">
|
<div className="mr-4 flex items-center">
|
||||||
<img
|
<img
|
||||||
className="h-16 w-16 rounded-md overflow-hidden mr-4 flex-shrink-0"
|
className="h-16 w-16 rounded-md overflow-hidden mr-4 flex-shrink-0"
|
||||||
src={`/assets/${app.assetSrc}`}
|
src={`/assets/${app.slug}.svg`}
|
||||||
alt={app.name}
|
alt={app.name}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export const api = {
|
export const api = {
|
||||||
hostname: process.env.REACT_APP_API_URL,
|
// @ts-ignore
|
||||||
|
hostname: window.env.REACT_APP_API_URL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { env } from '../../env';
|
|
||||||
import { performApiCall } from '../api';
|
import { performApiCall } from '../api';
|
||||||
import { transformApp } from './transformations';
|
import { transformApp } from './transformations';
|
||||||
import { App } from './types';
|
import { App } from './types';
|
||||||
|
|
||||||
export const fetchApps = async (): Promise<App> => {
|
export const fetchApps = async (): Promise<App> => {
|
||||||
const apiUrl = env.REACT_APP_API_URL;
|
// @ts-ignore
|
||||||
|
const apiUrl = window.env.REACT_APP_API_URL;
|
||||||
|
|
||||||
const res = await performApiCall({ hostname: apiUrl, path: '/apps', method: 'GET' });
|
const res = await performApiCall({ hostname: apiUrl, path: '/apps', method: 'GET' });
|
||||||
return transformApp(res);
|
return transformApp(res);
|
||||||
|
|
|
@ -4,8 +4,7 @@ export const transformApp = (response: any): App => {
|
||||||
return {
|
return {
|
||||||
id: response.id ?? '',
|
id: response.id ?? '',
|
||||||
name: response.name ?? '',
|
name: response.name ?? '',
|
||||||
assetSrc: response.assetSrc ?? '',
|
slug: response.slug ?? '',
|
||||||
internalUrl: response.internalUrl ?? '',
|
url: response.url ?? '',
|
||||||
externalUrl: response.externalUrl ?? '',
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
export interface App {
|
export interface App {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
assetSrc: string;
|
slug: string;
|
||||||
internalUrl: string;
|
url: string;
|
||||||
externalUrl: string;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue