WIP: Install app feature
This commit is contained in:
parent
52efcc9e0f
commit
8eda18b15b
52 changed files with 1419 additions and 14523 deletions
10
apps/anonaddy/config.json
Normal file
10
apps/anonaddy/config.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "Anonaddy",
|
||||
"id": "anonaddy",
|
||||
"description": "",
|
||||
"short_desc": "Anonymous email forwarding",
|
||||
"author": "",
|
||||
"source": "https://github.com/anonaddy/anonaddy",
|
||||
"image": "https://avatars.githubusercontent.com/u/51450862?s=200&v=4",
|
||||
"form_fields": {}
|
||||
}
|
10
apps/freshrss/config.json
Normal file
10
apps/freshrss/config.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "FreshRSS",
|
||||
"id": "freshrss",
|
||||
"description": "FreshRSS is a self-hosted RSS feed aggregator like Leed or Kriss Feed.\nIt is lightweight, easy to work with, powerful, and customizable.\n\nIt is a multi-user application with an anonymous reading mode. It supports custom tags. There is an API for (mobile) clients, and a Command-Line Interface.\n\nThanks to the WebSub standard (formerly PubSubHubbub), FreshRSS is able to receive instant push notifications from compatible sources, such as Mastodon, Friendica, WordPress, Blogger, FeedBurner, etc.\n\nFreshRSS natively supports basic Web scraping, based on XPath, for Web sites not providing any RSS / Atom feed.\n\nFinally, it supports extensions for further tuning.",
|
||||
"short_desc": "A free, self-hostable aggregator… ",
|
||||
"author": "https://freshrss.org/",
|
||||
"source": "https://github.com/FreshRSS/FreshRSS",
|
||||
"image": "https://avatars.githubusercontent.com/u/9414285?s=200&v=4",
|
||||
"form_fields": {}
|
||||
}
|
|
@ -15,10 +15,10 @@ services:
|
|||
TZ: $TZ
|
||||
networks:
|
||||
- tipi_main_network
|
||||
labels:
|
||||
traefik.enable: true
|
||||
traefik.http.routers.freshrss.rule: Host(`freshrss.tipi.home`)
|
||||
traefik.http.routers.freshrss.service: freshrss
|
||||
traefik.http.routers.freshrss.tls: true
|
||||
traefik.http.routers.freshrss.entrypoints: websecure
|
||||
traefik.http.services.freshrss.loadbalancer.server.port: 80
|
||||
# labels:
|
||||
# traefik.enable: true
|
||||
# traefik.http.routers.freshrss.rule: Host(`freshrss.tipi.home`)
|
||||
# traefik.http.routers.freshrss.service: freshrss
|
||||
# traefik.http.routers.freshrss.tls: true
|
||||
# traefik.http.routers.freshrss.entrypoints: websecure
|
||||
# traefik.http.services.freshrss.loadbalancer.server.port: 80
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "Nextcloud",
|
||||
"id": "nextcloud",
|
||||
"description": "Nextcloud is a self-hosted, open source, and fully-featured cloud storage solution for your personal files, office documents, and photos.",
|
||||
"short_desc": "Productivity platform that keeps you in control",
|
||||
"author": "Nextcloud GmbH",
|
||||
"source": "https://github.com/nextcloud/server",
|
||||
"image": "https://avatars.githubusercontent.com/u/19211038?s=200&v=4",
|
||||
"form_fields": {
|
||||
"username": {
|
||||
"type": "text",
|
||||
|
|
10
apps/simple-torrent/config.json
Normal file
10
apps/simple-torrent/config.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "Simple Torrent",
|
||||
"id": "simple-torrent",
|
||||
"description": "SimpleTorrent is a a self-hosted remote torrent client, written in Go (golang). Started torrents remotely, download sets of files on the local disk of the server, which are then retrievable or streamable via HTTP.",
|
||||
"short_desc": "A self-hosted remote torrent client",
|
||||
"author": "",
|
||||
"source": "https://github.com/boypt/simple-torrent",
|
||||
"image": "https://getumbrel.github.io/umbrel-apps-gallery/simple-torrent/icon.svg",
|
||||
"form_fields": {}
|
||||
}
|
|
@ -1,3 +1,25 @@
|
|||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
"extends": [
|
||||
"next/core-web-vitals",
|
||||
"airbnb-typescript",
|
||||
"eslint:recommended",
|
||||
"plugin:import/typescript"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": ["@typescript-eslint", "import"],
|
||||
"rules": {
|
||||
"arrow-body-style": 0,
|
||||
"no-restricted-exports": 0,
|
||||
"max-len": [1, { "code": 200 }],
|
||||
"import/extensions": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
{ "js": "never", "jsx": "never", "ts": "never", "tsx": "never" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
6
dashboard/.prettierrc.js
Normal file
6
dashboard/.prettierrc.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
singleQuote: true,
|
||||
semi: true,
|
||||
trailingComma: "all",
|
||||
printWidth: 200,
|
||||
};
|
|
@ -12,20 +12,33 @@
|
|||
"@chakra-ui/react": "^1.8.7",
|
||||
"@emotion/react": "^11",
|
||||
"@emotion/styled": "^11",
|
||||
"axios": "^0.26.1",
|
||||
"clsx": "^1.1.1",
|
||||
"final-form": "^4.20.6",
|
||||
"framer-motion": "^6",
|
||||
"immer": "^9.0.12",
|
||||
"next": "12.1.4",
|
||||
"react": "18.0.0",
|
||||
"react-dom": "18.0.0",
|
||||
"react-final-form": "^6.5.9",
|
||||
"react-icons": "^4.3.1",
|
||||
"swr": "^1.3.0",
|
||||
"systeminformation": "^5.11.9",
|
||||
"validator": "^13.7.0"
|
||||
"validator": "^13.7.0",
|
||||
"zustand": "^3.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "17.0.43",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"@types/validator": "^13.7.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"eslint": "8.12.0",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-next": "12.1.4",
|
||||
"postcss": "^8.4.12",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"typescript": "4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
6
dashboard/postcss.config.js
Normal file
6
dashboard/postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
BIN
dashboard/public/logo.png
Normal file
BIN
dashboard/public/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -1,4 +0,0 @@
|
|||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
22
dashboard/src/components/AppTile/AppStatus.tsx
Normal file
22
dashboard/src/components/AppTile/AppStatus.tsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
import { FiPauseCircle, FiPlayCircle } from 'react-icons/fi';
|
||||
|
||||
const AppStatus: React.FC<{ status: 'running' | 'stopped' }> = ({ status }) => {
|
||||
if (status === 'running') {
|
||||
return (
|
||||
<>
|
||||
<FiPlayCircle className="text-green-500 mr-1" size={20} />
|
||||
<span className="text-gray-400 text-sm">Running</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FiPauseCircle className="text-red-500 mr-1" size={20} />
|
||||
<span className="text-gray-400 text-sm">Stopped</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppStatus;
|
30
dashboard/src/components/AppTile/index.tsx
Normal file
30
dashboard/src/components/AppTile/index.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { Box, SlideFade, Image } from '@chakra-ui/react';
|
||||
import Link from 'next/link';
|
||||
import React from 'react';
|
||||
import { FiChevronRight } from 'react-icons/fi';
|
||||
import { AppConfig } from '../../core/types';
|
||||
import AppStatus from './AppStatus';
|
||||
|
||||
const AppTile: React.FC<{ app: AppConfig }> = ({ app }) => {
|
||||
return (
|
||||
<Link href={`/apps/${app.id}`} passHref>
|
||||
<SlideFade in className="flex flex-1" offsetY="20px">
|
||||
<Box minWidth={400} className="flex flex-1 bg-white drop-shadow-lg rounded-lg p-3 items-center cursor-pointer group hover:drop-shadow-md hover:bg-gray-100 transition-all">
|
||||
<Image alt={`${app.name} logo`} className="rounded-md drop-shadow mr-3 group-hover:scale-105 transition-all" src={app.image} width={100} height={100} />
|
||||
<div className="mr-3 flex-1">
|
||||
<h3 className="font-bold text-xl">{app.name}</h3>
|
||||
<span>{app.short_desc}</span>
|
||||
{app.installed && (
|
||||
<div className="flex mt-1">
|
||||
<AppStatus status={app.status} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<FiChevronRight className="text-slate-300" size={30} />
|
||||
</Box>
|
||||
</SlideFade>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppTile;
|
23
dashboard/src/components/Form/FormInput.tsx
Normal file
23
dashboard/src/components/Form/FormInput.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import React from 'react';
|
||||
import { Input } from '@chakra-ui/react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
interface IProps {
|
||||
placeholder?: string;
|
||||
error?: string;
|
||||
type?: Parameters<typeof Input>[0]['type'];
|
||||
label: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const FormInput: React.FC<IProps> = ({ placeholder, error, type, label, className, ...rest }) => {
|
||||
return (
|
||||
<div className={clsx('transition-all', className)}>
|
||||
<label>{label}</label>
|
||||
<Input type={type} placeholder={placeholder} isInvalid={Boolean(error)} {...rest} />
|
||||
{error && <span className="text-red-500 text-sm">{error}</span>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormInput;
|
17
dashboard/src/components/Form/validators.ts
Normal file
17
dashboard/src/components/Form/validators.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { AppConfig } from '../../core/types';
|
||||
|
||||
export const validateAppConfig = (values: Record<string, string>, fields: (AppConfig['form_fields'][0] & { id: string })[]) => {
|
||||
const errors: any = {};
|
||||
|
||||
fields.forEach((field) => {
|
||||
if (field.required && !values[field.id]) {
|
||||
errors[field.id] = 'Field required';
|
||||
} else if (field.min && values[field.id].length < field.min) {
|
||||
errors[field.id] = `Field must be at least ${field.min} characters long`;
|
||||
} else if (field.max && values[field.id].length > field.max) {
|
||||
errors[field.id] = `Field must be at most ${field.max} characters long`;
|
||||
}
|
||||
});
|
||||
|
||||
return errors;
|
||||
};
|
0
dashboard/src/components/InstallForm/index.ts
Normal file
0
dashboard/src/components/InstallForm/index.ts
Normal file
|
@ -1,27 +1,22 @@
|
|||
import React from "react";
|
||||
import Img from "next/image";
|
||||
import Link from "next/link";
|
||||
import { Button, Flex, useBreakpointValue } from "@chakra-ui/react";
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { FiMenu } from 'react-icons/fi';
|
||||
|
||||
interface IProps {
|
||||
onClickMenu: () => void;
|
||||
}
|
||||
|
||||
const Header: React.FC<IProps> = ({ onClickMenu }) => {
|
||||
const buttonVisibility = useBreakpointValue<"visible" | "hidden">({
|
||||
base: "visible",
|
||||
md: "hidden",
|
||||
});
|
||||
|
||||
return (
|
||||
<header>
|
||||
<Flex alignItems="center" bg="tomato" paddingLeft={5} paddingRight={5}>
|
||||
<Flex position="absolute" visibility={buttonVisibility || "visible"}>
|
||||
<Button onClick={onClickMenu}>O</Button>
|
||||
</Flex>
|
||||
<header style={{ width: '100%' }} className="flex">
|
||||
<Flex className="items-center bg-gray-700 drop-shadow-md px-5 flex-1">
|
||||
<div onClick={onClickMenu} className="visible md:invisible absolute cursor-pointer py-2">
|
||||
<FiMenu color="white" />
|
||||
</div>
|
||||
<Flex justifyContent="center" flex="1">
|
||||
<Link href="/" passHref>
|
||||
<Img src="/logo.svg" alt="Tipi" width={100} height={60} />
|
||||
<img src="/logo.png" alt="Tipi" width={230} height={60} />
|
||||
</Link>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
|
|
@ -1,30 +1,60 @@
|
|||
import {
|
||||
Button,
|
||||
Flex,
|
||||
useBreakpointValue,
|
||||
useDisclosure,
|
||||
} from "@chakra-ui/react";
|
||||
import React from "react";
|
||||
import Header from "./Header";
|
||||
import Menu from "./Menu";
|
||||
import MenuDrawer from "./MenuDrawer";
|
||||
import { Flex, useDisclosure, Spinner, Breadcrumb, BreadcrumbItem } from '@chakra-ui/react';
|
||||
import Link from 'next/link';
|
||||
import React from 'react';
|
||||
import { FiChevronRight } from 'react-icons/fi';
|
||||
import Header from './Header';
|
||||
import Menu from './Menu';
|
||||
import MenuDrawer from './MenuDrawer';
|
||||
|
||||
const Layout: React.FC = ({ children }) => {
|
||||
const menuWidth = useBreakpointValue({ base: 0, md: 200 });
|
||||
interface IProps {
|
||||
loading?: boolean;
|
||||
breadcrumbs?: { name: string; href: string; current?: boolean }[];
|
||||
}
|
||||
|
||||
const Layout: React.FC<IProps> = ({ children, loading, breadcrumbs }) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const renderContent = () => {
|
||||
if (loading) {
|
||||
return (
|
||||
<Flex className="justify-center flex-1">
|
||||
<Spinner />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
const renderBreadcrumbs = () => {
|
||||
return (
|
||||
<Breadcrumb spacing="8px" separator={<FiChevronRight color="gray.500" />}>
|
||||
{breadcrumbs?.map((breadcrumb, index) => {
|
||||
return (
|
||||
<BreadcrumbItem className="hover:underline" isCurrentPage={breadcrumb.current} key={index}>
|
||||
<Link href={breadcrumb.href}>{breadcrumb.name}</Link>
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
})}
|
||||
</Breadcrumb>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex height="100vh" bg="green.500" direction="column">
|
||||
<Flex height="100vh" className="drop-shadow-md border-r-8" direction="column">
|
||||
<MenuDrawer isOpen={isOpen} onClose={onClose}>
|
||||
<Menu />
|
||||
</MenuDrawer>
|
||||
<Header onClickMenu={onOpen} />
|
||||
<Flex flex="1">
|
||||
<Flex width={menuWidth} bg="blue.500">
|
||||
<Flex className="invisible md:visible w-0 md:w-56">
|
||||
<Menu />
|
||||
</Flex>
|
||||
<Flex flex="1" padding={5} bg="yellow.300">
|
||||
{children}
|
||||
<Flex className="bg-slate-200 flex flex-1 p-5">
|
||||
<div className="flex-1 flex flex-col">
|
||||
{renderBreadcrumbs()}
|
||||
<div className="flex-1 ">{renderContent()}</div>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
|
|
@ -1,11 +1,40 @@
|
|||
import React from "react";
|
||||
import { AiOutlineDashboard, AiOutlineSetting, AiOutlineAppstore } from 'react-icons/ai';
|
||||
import { Divider, List, ListItem } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import clsx from 'clsx';
|
||||
import { useRouter } from 'next/router';
|
||||
import { IconType } from 'react-icons';
|
||||
|
||||
const SideMenu: React.FC = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const path = router.pathname.split('/')[1];
|
||||
|
||||
const renderMenuItem = (title: string, name: string, Icon: IconType) => {
|
||||
const selected = path === name;
|
||||
|
||||
return (
|
||||
<Link href={`/${name}`} passHref>
|
||||
<div className={clsx('mx-3 rounded-lg p-3 transition-colors', { 'bg-slate-200 drop-shadow-sm': selected })}>
|
||||
<ListItem className={'flex items-center cursor-pointer hover:font-bold'}>
|
||||
<Icon size={20} className="mr-3" />
|
||||
<p className={clsx({ 'font-bold': selected })}>{title}</p>
|
||||
</ListItem>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const Menu: React.FC = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Menu</h1>
|
||||
</div>
|
||||
<List spacing={3} className="pt-5 flex-1 bg-white md:border-r-2">
|
||||
{renderMenuItem('Dashboard', '', AiOutlineDashboard)}
|
||||
<Divider />
|
||||
{renderMenuItem('Apps', 'apps', AiOutlineAppstore)}
|
||||
<Divider />
|
||||
{renderMenuItem('Settings', 'settings', AiOutlineSetting)}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
export default Menu;
|
||||
export default SideMenu;
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
import {
|
||||
Drawer,
|
||||
DrawerBody,
|
||||
DrawerCloseButton,
|
||||
DrawerContent,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerOverlay,
|
||||
} from "@chakra-ui/react";
|
||||
import React from "react";
|
||||
import { Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerFooter, DrawerHeader, DrawerOverlay } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
interface IProps {
|
||||
isOpen: boolean;
|
||||
|
@ -16,11 +8,11 @@ interface IProps {
|
|||
|
||||
const MenuDrawer: React.FC<IProps> = ({ children, isOpen, onClose }) => {
|
||||
return (
|
||||
<Drawer isOpen={isOpen} placement="left" onClose={onClose}>
|
||||
<Drawer size="xs" isOpen={isOpen} placement="left" onClose={onClose}>
|
||||
<DrawerOverlay />
|
||||
<DrawerContent>
|
||||
<DrawerCloseButton />
|
||||
<DrawerHeader>Create your account</DrawerHeader>
|
||||
<DrawerHeader>My Tipi</DrawerHeader>
|
||||
<DrawerBody>{children}</DrawerBody>
|
||||
<DrawerFooter>
|
||||
<div>Github</div>
|
||||
|
|
|
@ -1 +1 @@
|
|||
export { default } from "./Layout";
|
||||
export { default } from './Layout';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import validator from "validator";
|
||||
import validator from 'validator';
|
||||
|
||||
interface IFormField {
|
||||
name: string;
|
||||
|
@ -20,81 +20,79 @@ interface IAppConfig {
|
|||
}
|
||||
|
||||
const APP_ANONADDY: IAppConfig = {
|
||||
id: "anonaddy",
|
||||
name: "Anonaddy",
|
||||
description: "Create Unlimited Email Aliases For Free",
|
||||
url: "https://anonaddy.com/",
|
||||
color: "#00a8ff",
|
||||
logo: "https://anonaddy.com/favicon.ico",
|
||||
id: 'anonaddy',
|
||||
name: 'Anonaddy',
|
||||
description: 'Create Unlimited Email Aliases For Free',
|
||||
url: 'https://anonaddy.com/',
|
||||
color: '#00a8ff',
|
||||
logo: 'https://anonaddy.com/favicon.ico',
|
||||
install_form: {
|
||||
fields: [
|
||||
{
|
||||
name: "API Key",
|
||||
type: "text",
|
||||
placeholder: "API Key",
|
||||
name: 'API Key',
|
||||
type: 'text',
|
||||
placeholder: 'API Key',
|
||||
required: true,
|
||||
validate: (value: string) => validator.isBase64(value),
|
||||
},
|
||||
{
|
||||
name: "Return Path",
|
||||
type: "text",
|
||||
description: "The email address that bounces will be sent to",
|
||||
placeholder: "Return Path",
|
||||
name: 'Return Path',
|
||||
type: 'text',
|
||||
description: 'The email address that bounces will be sent to',
|
||||
placeholder: 'Return Path',
|
||||
required: false,
|
||||
validate: (value: string) => validator.isEmail(value),
|
||||
},
|
||||
{
|
||||
name: "Admin Username",
|
||||
type: "text",
|
||||
description: "The username of the admin user",
|
||||
placeholder: "Admin Username",
|
||||
name: 'Admin Username',
|
||||
type: 'text',
|
||||
description: 'The username of the admin user',
|
||||
placeholder: 'Admin Username',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "Enable Registration",
|
||||
type: "boolean",
|
||||
description: "Allow users to register",
|
||||
placeholder: "Enable Registration",
|
||||
name: 'Enable Registration',
|
||||
type: 'boolean',
|
||||
description: 'Allow users to register',
|
||||
placeholder: 'Enable Registration',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "Domain",
|
||||
type: "text",
|
||||
description: "The domain that will be used for the email address",
|
||||
placeholder: "Domain",
|
||||
name: 'Domain',
|
||||
type: 'text',
|
||||
description: 'The domain that will be used for the email address',
|
||||
placeholder: 'Domain',
|
||||
required: true,
|
||||
validate: (value: string) => validator.isFQDN(value),
|
||||
},
|
||||
{
|
||||
name: "Hostname",
|
||||
type: "text",
|
||||
description: "The hostname that will be used for the email address",
|
||||
placeholder: "Hostname",
|
||||
name: 'Hostname',
|
||||
type: 'text',
|
||||
description: 'The hostname that will be used for the email address',
|
||||
placeholder: 'Hostname',
|
||||
required: true,
|
||||
validate: (value: string) => validator.isFQDN(value),
|
||||
},
|
||||
{
|
||||
name: "Secret",
|
||||
type: "text",
|
||||
description: "The secret that will be used for the email address",
|
||||
placeholder: "Secret",
|
||||
name: 'Secret',
|
||||
type: 'text',
|
||||
description: 'The secret that will be used for the email address',
|
||||
placeholder: 'Secret',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "From Name",
|
||||
type: "text",
|
||||
description: "The name that will be used for the email address",
|
||||
placeholder: "From Name",
|
||||
name: 'From Name',
|
||||
type: 'text',
|
||||
description: 'The name that will be used for the email address',
|
||||
placeholder: 'From Name',
|
||||
required: true,
|
||||
validate: (value: string) =>
|
||||
validator.isLength(value, { min: 1, max: 64 }),
|
||||
validate: (value: string) => validator.isLength(value, { min: 1, max: 64 }),
|
||||
},
|
||||
{
|
||||
name: "From Address",
|
||||
type: "text",
|
||||
description:
|
||||
"The email address that will be used for the email address",
|
||||
placeholder: "From Address",
|
||||
name: 'From Address',
|
||||
type: 'text',
|
||||
description: 'The email address that will be used for the email address',
|
||||
placeholder: 'From Address',
|
||||
required: true,
|
||||
validate: (value: string) => validator.isEmail(value),
|
||||
},
|
||||
|
|
31
dashboard/src/core/api.ts
Normal file
31
dashboard/src/core/api.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import axios, { Method } from 'axios';
|
||||
|
||||
const BASE_URL = 'http://localhost:3001';
|
||||
|
||||
interface IFetchParams {
|
||||
endpoint: string;
|
||||
method?: Method;
|
||||
params?: JSON;
|
||||
}
|
||||
|
||||
const api = async <T = unknown>(fetchParams: IFetchParams): Promise<T> => {
|
||||
const { endpoint, method = 'GET', params } = fetchParams;
|
||||
|
||||
try {
|
||||
const response = await axios.request<T>({
|
||||
method,
|
||||
params,
|
||||
url: `${BASE_URL}${endpoint}`,
|
||||
});
|
||||
|
||||
if (response.data) return response.data;
|
||||
|
||||
throw new Error(`Network request error. status : ${response.status}`);
|
||||
} catch (error) {
|
||||
console.error('Error during fetch', `params: ${JSON.stringify(fetchParams)}`, error);
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
export default { fetch: api };
|
8
dashboard/src/core/fetcher.ts
Normal file
8
dashboard/src/core/fetcher.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { BareFetcher } from 'swr';
|
||||
import axios from 'axios';
|
||||
|
||||
const fetcher: BareFetcher<any> = (url: string) => {
|
||||
return axios.get(url, { baseURL: 'http://localhost:3001' }).then((res) => res.data);
|
||||
};
|
||||
|
||||
export default fetcher;
|
34
dashboard/src/core/types.ts
Normal file
34
dashboard/src/core/types.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
interface FormField {
|
||||
type: string;
|
||||
label: string;
|
||||
max?: number;
|
||||
min?: number;
|
||||
required?: boolean;
|
||||
env_variable: string;
|
||||
}
|
||||
|
||||
export interface AppConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
version: string;
|
||||
image: string;
|
||||
form_fields: Record<string, FormField>;
|
||||
short_desc: string;
|
||||
author: string;
|
||||
source: string;
|
||||
installed: boolean;
|
||||
status: 'running' | 'stopped';
|
||||
}
|
||||
|
||||
export enum RequestStatus {
|
||||
SUCCESS = 'SUCCESS',
|
||||
ERROR = 'ERROR',
|
||||
LOADING = 'LOADING',
|
||||
}
|
||||
|
||||
export enum AppStatus {
|
||||
RUNNING = 'running',
|
||||
STOPPED = 'stopped',
|
||||
INSTALLING = 'installing',
|
||||
}
|
44
dashboard/src/modules/Apps/components/AppActions.tsx
Normal file
44
dashboard/src/modules/Apps/components/AppActions.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { Button } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { FiPause, FiPlay, FiTrash2 } from 'react-icons/fi';
|
||||
import { AppConfig } from '../../../core/types';
|
||||
|
||||
interface IProps {
|
||||
app: AppConfig;
|
||||
onInstall: () => void;
|
||||
onUninstall: () => void;
|
||||
onStart: () => void;
|
||||
onStop: () => void;
|
||||
}
|
||||
|
||||
const AppActions: React.FC<IProps> = ({ app, onInstall, onUninstall, onStart, onStop }) => {
|
||||
if (app?.installed && app.status === 'stopped') {
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={onStart} width={160} colorScheme="green" className="mt-3">
|
||||
Start
|
||||
<FiPlay className="ml-1" />
|
||||
</Button>
|
||||
<Button onClick={onUninstall} width={160} colorScheme="gray" className="mt-3 ml-2">
|
||||
Remove
|
||||
<FiTrash2 className="ml-1" />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
} else if (app?.installed && app.status === 'running') {
|
||||
return (
|
||||
<Button onClick={onStop} width={160} colorScheme="red" className="mt-3">
|
||||
Stop
|
||||
<FiPause className="ml-2" />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button onClick={onInstall} width={160} colorScheme="green" className="mt-3">
|
||||
Install
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppActions;
|
38
dashboard/src/modules/Apps/components/InstallForm.tsx
Normal file
38
dashboard/src/modules/Apps/components/InstallForm.tsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { Button } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { Form, Field } from 'react-final-form';
|
||||
import FormInput from '../../../components/Form/FormInput';
|
||||
import { validateAppConfig } from '../../../components/Form/validators';
|
||||
import { AppConfig } from '../../../core/types';
|
||||
import { objectKeys } from '../../../utils/typescript';
|
||||
|
||||
interface IProps {
|
||||
formFields: AppConfig['form_fields'];
|
||||
onSubmit: (values: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
const InstallForm: React.FC<IProps> = ({ formFields, onSubmit }) => {
|
||||
const fields = objectKeys(formFields).map((key) => ({ ...formFields[key], id: key }));
|
||||
|
||||
const renderField = (field: typeof fields[0]) => {
|
||||
return <Field key={field.id} name={field.id} render={({ input, meta }) => <FormInput className="mb-3" error={meta.error} label={field.label} {...input} />} />;
|
||||
};
|
||||
|
||||
return (
|
||||
<Form<Record<string, string>>
|
||||
onSubmit={onSubmit}
|
||||
validateOnBlur={true}
|
||||
validate={(values) => validateAppConfig(values, fields)}
|
||||
render={({ handleSubmit, validating, submitting }) => (
|
||||
<form className="flex flex-col" onSubmit={handleSubmit}>
|
||||
{fields.map(renderField)}
|
||||
<Button isLoading={validating || submitting} className="self-end mb-2" colorScheme="green" type="submit">
|
||||
Install
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default InstallForm;
|
28
dashboard/src/modules/Apps/components/InstallModal.tsx
Normal file
28
dashboard/src/modules/Apps/components/InstallModal.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { AppConfig } from '../../../core/types';
|
||||
import InstallForm from './InstallForm';
|
||||
|
||||
interface IProps {
|
||||
app: AppConfig;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: (values: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
const InstallModal: React.FC<IProps> = ({ app, isOpen, onClose, onSubmit }) => {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Install {app.name}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<InstallForm onSubmit={onSubmit} formFields={app.form_fields} />
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default InstallModal;
|
48
dashboard/src/modules/Apps/containers/AppDetails.tsx
Normal file
48
dashboard/src/modules/Apps/containers/AppDetails.tsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { SlideFade, Image, VStack, Flex, Divider, useDisclosure } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { FiExternalLink } from 'react-icons/fi';
|
||||
import { AppConfig } from '../../../core/types';
|
||||
import AppActions from '../components/AppActions';
|
||||
import InstallModal from '../components/InstallModal';
|
||||
|
||||
interface IProps {
|
||||
app: AppConfig;
|
||||
}
|
||||
|
||||
const AppDetails: React.FC<IProps> = ({ app }) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const handleInstallSubmit = (values: Record<string, unknown>) => {
|
||||
console.error(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<SlideFade in className="flex flex-1" offsetY="20px">
|
||||
<div className="flex flex-1 bg-white p-4 mt-3 rounded-lg drop-shadow-xl flex-col">
|
||||
<Flex className="flex-col md:flex-row">
|
||||
<Image src={app?.image} height={180} width={180} className="rounded-xl self-center sm:self-auto" alt={app.name} />
|
||||
<VStack align="flex-start" justify="space-between" className="ml-0 md:ml-4">
|
||||
<div className="mt-3 items-center self-center flex flex-col sm:items-start sm:self-start md:mt-0">
|
||||
<h1 className="font-bold text-2xl">{app?.name}</h1>
|
||||
<h2 className="text-center md:text-left">{app?.short_desc}</h2>
|
||||
<a target="_blank" rel="noreferrer" className="text-blue-500 text-xs" href={app?.source}>
|
||||
<Flex className="mt-2 items-center">
|
||||
{app?.source} <FiExternalLink className="ml-1" />
|
||||
</Flex>
|
||||
</a>
|
||||
<p className="text-xs text-gray-600">By {app?.author}</p>
|
||||
</div>
|
||||
<div className="flex justify-center sm:absolute md:static top-0 right-5 self-center sm:self-auto">
|
||||
<AppActions onStart={() => null} onStop={() => null} onUninstall={() => null} onInstall={onOpen} app={app} />
|
||||
</div>
|
||||
</VStack>
|
||||
</Flex>
|
||||
<Divider className="mt-5" />
|
||||
<p className="mt-3">{app?.description}</p>
|
||||
<InstallModal onSubmit={handleInstallSubmit} isOpen={isOpen} onClose={onClose} app={app} />
|
||||
</div>
|
||||
</SlideFade>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppDetails;
|
|
@ -1,6 +1,6 @@
|
|||
import { ChakraProvider } from "@chakra-ui/react";
|
||||
import "../styles/globals.css";
|
||||
import type { AppProps } from "next/app";
|
||||
import { ChakraProvider } from '@chakra-ui/react';
|
||||
import '../styles/globals.css';
|
||||
import type { AppProps } from 'next/app';
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import si from "systeminformation";
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import si from 'systeminformation';
|
||||
|
||||
type Data = Awaited<ReturnType<typeof si.currentLoad>>;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import si from "systeminformation";
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import si from 'systeminformation';
|
||||
|
||||
type Data = Awaited<ReturnType<typeof si.fsSize>>;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import si from "systeminformation";
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import si from 'systeminformation';
|
||||
|
||||
type Data = Awaited<ReturnType<typeof si.mem>>;
|
||||
|
||||
|
|
38
dashboard/src/pages/apps/[id].tsx
Normal file
38
dashboard/src/pages/apps/[id].tsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
import type { NextPage } from 'next';
|
||||
import { useEffect } from 'react';
|
||||
import Layout from '../../components/Layout';
|
||||
import { useAppsStore } from '../../state/appsStore';
|
||||
import AppDetails from '../../modules/Apps/containers/AppDetails';
|
||||
|
||||
interface Props {
|
||||
appId: string;
|
||||
}
|
||||
|
||||
const AppDetailsPage: NextPage<Props> = ({ appId }) => {
|
||||
const { getApp, fetchApp } = useAppsStore((state) => state);
|
||||
|
||||
const app = getApp(appId);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApp(appId);
|
||||
}, [appId, fetchApp]);
|
||||
|
||||
const breadcrumb = [
|
||||
{ name: 'Apps', href: '/apps' },
|
||||
{ name: app?.name || '', href: `/apps/${appId}`, current: true },
|
||||
];
|
||||
|
||||
return (
|
||||
<Layout breadcrumbs={breadcrumb} loading={!app}>
|
||||
{app && <AppDetails app={app} />}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
AppDetailsPage.getInitialProps = async ({ query, pathname }) => {
|
||||
const appId = (query.id as string) || pathname.split('/')[1];
|
||||
|
||||
return { appId };
|
||||
};
|
||||
|
||||
export default AppDetailsPage;
|
39
dashboard/src/pages/apps/index.tsx
Normal file
39
dashboard/src/pages/apps/index.tsx
Normal file
|
@ -0,0 +1,39 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { Flex, SimpleGrid } from '@chakra-ui/react';
|
||||
import type { NextPage } from 'next';
|
||||
import Layout from '../../components/Layout';
|
||||
import { RequestStatus } from '../../core/types';
|
||||
import { useAppsStore } from '../../state/appsStore';
|
||||
import AppTile from '../../components/AppTile';
|
||||
|
||||
const Apps: NextPage = () => {
|
||||
const { available, installed, fetch, status } = useAppsStore((state) => state);
|
||||
|
||||
useEffect(() => {
|
||||
fetch();
|
||||
}, [fetch]);
|
||||
|
||||
const installedCount: number = installed().length || 0;
|
||||
const loading = status === RequestStatus.LOADING && !installed && !available;
|
||||
|
||||
return (
|
||||
<Layout loading={loading}>
|
||||
<Flex className="flex-col">
|
||||
{installedCount > 0 && <h1 className="font-bold text-2xl mb-3">Your Apps ({installedCount})</h1>}
|
||||
<SimpleGrid minChildWidth="400px" spacing="20px">
|
||||
{installed().map((app) => (
|
||||
<AppTile key={app.name} app={app} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
{available().length && <h1 className="font-bold text-2xl mb-3 mt-3">Available Apps</h1>}
|
||||
<SimpleGrid minChildWidth="400px" spacing="20px">
|
||||
{available().map((app) => (
|
||||
<AppTile key={app.name} app={app} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Flex>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Apps;
|
|
@ -1,5 +1,5 @@
|
|||
import type { NextPage } from "next";
|
||||
import Layout from "../components/Layout";
|
||||
import type { NextPage } from 'next';
|
||||
import Layout from '../components/Layout';
|
||||
|
||||
const Home: NextPage = () => {
|
||||
return (
|
||||
|
|
12
dashboard/src/pages/settings.tsx
Normal file
12
dashboard/src/pages/settings.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
import type { NextPage } from 'next';
|
||||
import Layout from '../components/Layout';
|
||||
|
||||
const Settings: NextPage = () => {
|
||||
return (
|
||||
<Layout>
|
||||
<div>Settings</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
70
dashboard/src/state/appsStore.ts
Normal file
70
dashboard/src/state/appsStore.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
import create from 'zustand';
|
||||
import api from '../core/api';
|
||||
import { AppConfig, AppStatus, RequestStatus } from '../core/types';
|
||||
|
||||
type AppsStore = {
|
||||
apps: AppConfig[];
|
||||
status: RequestStatus;
|
||||
installed: () => AppConfig[];
|
||||
available: () => AppConfig[];
|
||||
fetch: () => void;
|
||||
getApp: (id: string) => AppConfig | undefined;
|
||||
fetchApp: (id: string) => void;
|
||||
statues: {};
|
||||
};
|
||||
|
||||
export const useAppsStore = create<AppsStore>((set, get) => ({
|
||||
apps: [],
|
||||
status: RequestStatus.LOADING,
|
||||
installed: () => {
|
||||
const i = get().apps.filter((app) => app.installed);
|
||||
return i;
|
||||
},
|
||||
available: () => {
|
||||
return get().apps.filter((app) => !app.installed);
|
||||
},
|
||||
fetch: async () => {
|
||||
set({ status: RequestStatus.LOADING });
|
||||
|
||||
const response = await api.fetch<AppConfig[]>({
|
||||
endpoint: '/apps/list',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
set({ apps: response, status: RequestStatus.SUCCESS });
|
||||
},
|
||||
install: async (appId: string) => {
|
||||
set((state) => ({ ...state, statues: { [appId]: AppStatus.INSTALLING } }));
|
||||
|
||||
await api.fetch({
|
||||
endpoint: `/apps/install/${appId}`,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
set((state) => ({ ...state, statues: { [appId]: AppStatus.RUNNING } }));
|
||||
|
||||
await get().fetch();
|
||||
},
|
||||
fetchApp: async (appId: string) => {
|
||||
const response = await api.fetch<AppConfig>({
|
||||
endpoint: `/apps/info/${appId}`,
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
set((state) => {
|
||||
const apps = state.apps.map((app) => {
|
||||
if (app.id === response.id) {
|
||||
return response;
|
||||
}
|
||||
|
||||
return app;
|
||||
});
|
||||
|
||||
return { ...state, apps };
|
||||
});
|
||||
},
|
||||
getApp: (appId: string) => {
|
||||
return get().apps.find((app) => app.id === appId);
|
||||
},
|
||||
statues: {},
|
||||
}));
|
12
dashboard/src/state/uiStore.ts
Normal file
12
dashboard/src/state/uiStore.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import create from 'zustand';
|
||||
|
||||
type UIStore = {
|
||||
menuItem: string;
|
||||
};
|
||||
|
||||
export const useUIStore = create<UIStore>((set) => ({
|
||||
menuItem: 'dashboard',
|
||||
setMenuItem: (menuItem: string) => {
|
||||
set({ menuItem: menuItem });
|
||||
},
|
||||
}));
|
|
@ -1,3 +1,7 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
|
|
3
dashboard/src/utils/typescript.ts
Normal file
3
dashboard/src/utils/typescript.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
const objectKeys = <T>(obj: T): (keyof T)[] => Object.keys(obj) as (keyof T)[];
|
||||
|
||||
export { objectKeys };
|
7
dashboard/tailwind.config.js
Normal file
7
dashboard/tailwind.config.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
content: ['./src/pages/**/*.{ts,tsx}', './src/components/**/*.{ts,tsx}', './src/modules/**/*.{ts,tsx}'],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
|
@ -57,6 +57,13 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.10.0", "@babel/runtime@^7.15.4":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
|
||||
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/types@^7.16.7":
|
||||
version "7.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
|
||||
|
@ -892,6 +899,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.0.8.tgz#be3e914e84eacf16dbebd311c0d0b44aa1174c64"
|
||||
integrity sha512-ZK5v4bJwgXldAUA8r3q9YKfCwOqoHTK/ZqRjSeRXQrBXWouoPnS4MQtgC4AXGiiBuUu5wxrRgTlv0ktmM4P1Aw==
|
||||
|
||||
"@types/json-schema@^7.0.9":
|
||||
version "7.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
|
||||
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
|
||||
|
||||
"@types/json5@^0.0.29":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
|
@ -955,6 +967,21 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52"
|
||||
integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.18.0":
|
||||
version "5.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.18.0.tgz#950df411cec65f90d75d6320a03b2c98f6c3af7d"
|
||||
integrity sha512-tzrmdGMJI/uii9/V6lurMo4/o+dMTKDH82LkNjhJ3adCW22YQydoRs5MwTiqxGF9CSYxPxQ7EYb4jLNlIs+E+A==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "5.18.0"
|
||||
"@typescript-eslint/type-utils" "5.18.0"
|
||||
"@typescript-eslint/utils" "5.18.0"
|
||||
debug "^4.3.2"
|
||||
functional-red-black-tree "^1.0.1"
|
||||
ignore "^5.1.8"
|
||||
regexpp "^3.2.0"
|
||||
semver "^7.3.5"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/parser@5.10.1":
|
||||
version "5.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.10.1.tgz#4ce9633cc33fc70bc13786cb793c1a76fe5ad6bd"
|
||||
|
@ -973,11 +1000,33 @@
|
|||
"@typescript-eslint/types" "5.10.1"
|
||||
"@typescript-eslint/visitor-keys" "5.10.1"
|
||||
|
||||
"@typescript-eslint/scope-manager@5.18.0":
|
||||
version "5.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.18.0.tgz#a7d7b49b973ba8cebf2a3710eefd457ef2fb5505"
|
||||
integrity sha512-C0CZML6NyRDj+ZbMqh9FnPscg2PrzSaVQg3IpTmpe0NURMVBXlghGZgMYqBw07YW73i0MCqSDqv2SbywnCS8jQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.18.0"
|
||||
"@typescript-eslint/visitor-keys" "5.18.0"
|
||||
|
||||
"@typescript-eslint/type-utils@5.18.0":
|
||||
version "5.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.18.0.tgz#62dbfc8478abf36ba94a90ddf10be3cc8e471c74"
|
||||
integrity sha512-vcn9/6J5D6jtHxpEJrgK8FhaM8r6J1/ZiNu70ZUJN554Y3D9t3iovi6u7JF8l/e7FcBIxeuTEidZDR70UuCIfA==
|
||||
dependencies:
|
||||
"@typescript-eslint/utils" "5.18.0"
|
||||
debug "^4.3.2"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/types@5.10.1":
|
||||
version "5.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.1.tgz#dca9bd4cb8c067fc85304a31f38ec4766ba2d1ea"
|
||||
integrity sha512-ZvxQ2QMy49bIIBpTqFiOenucqUyjTQ0WNLhBM6X1fh1NNlYAC6Kxsx8bRTY3jdYsYg44a0Z/uEgQkohbR0H87Q==
|
||||
|
||||
"@typescript-eslint/types@5.18.0":
|
||||
version "5.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.18.0.tgz#4f0425d85fdb863071680983853c59a62ce9566e"
|
||||
integrity sha512-bhV1+XjM+9bHMTmXi46p1Led5NP6iqQcsOxgx7fvk6gGiV48c6IynY0apQb7693twJDsXiVzNXTflhplmaiJaw==
|
||||
|
||||
"@typescript-eslint/typescript-estree@5.10.1":
|
||||
version "5.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.1.tgz#b268e67be0553f8790ba3fe87113282977adda15"
|
||||
|
@ -991,6 +1040,31 @@
|
|||
semver "^7.3.5"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@5.18.0":
|
||||
version "5.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.18.0.tgz#6498e5ee69a32e82b6e18689e2f72e4060986474"
|
||||
integrity sha512-wa+2VAhOPpZs1bVij9e5gyVu60ReMi/KuOx4LKjGx2Y3XTNUDJgQ+5f77D49pHtqef/klglf+mibuHs9TrPxdQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.18.0"
|
||||
"@typescript-eslint/visitor-keys" "5.18.0"
|
||||
debug "^4.3.2"
|
||||
globby "^11.0.4"
|
||||
is-glob "^4.0.3"
|
||||
semver "^7.3.5"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/utils@5.18.0":
|
||||
version "5.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.18.0.tgz#27fc84cf95c1a96def0aae31684cb43a37e76855"
|
||||
integrity sha512-+hFGWUMMri7OFY26TsOlGa+zgjEy1ssEipxpLjtl4wSll8zy85x0GrUSju/FHdKfVorZPYJLkF3I4XPtnCTewA==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.9"
|
||||
"@typescript-eslint/scope-manager" "5.18.0"
|
||||
"@typescript-eslint/types" "5.18.0"
|
||||
"@typescript-eslint/typescript-estree" "5.18.0"
|
||||
eslint-scope "^5.1.1"
|
||||
eslint-utils "^3.0.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@5.10.1":
|
||||
version "5.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.1.tgz#29102de692f59d7d34ecc457ed59ab5fc558010b"
|
||||
|
@ -999,11 +1073,38 @@
|
|||
"@typescript-eslint/types" "5.10.1"
|
||||
eslint-visitor-keys "^3.0.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@5.18.0":
|
||||
version "5.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.18.0.tgz#c7c07709823804171d569017f3b031ced7253e60"
|
||||
integrity sha512-Hf+t+dJsjAKpKSkg3EHvbtEpFFb/1CiOHnvI8bjHgOD4/wAw3gKrA0i94LrbekypiZVanJu3McWJg7rWDMzRTg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.18.0"
|
||||
eslint-visitor-keys "^3.0.0"
|
||||
|
||||
acorn-jsx@^5.3.1:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
acorn-node@^1.6.1:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
|
||||
integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
|
||||
dependencies:
|
||||
acorn "^7.0.0"
|
||||
acorn-walk "^7.0.0"
|
||||
xtend "^4.0.2"
|
||||
|
||||
acorn-walk@^7.0.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
|
||||
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
|
||||
|
||||
acorn@^7.0.0:
|
||||
version "7.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
acorn@^8.7.0:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
|
||||
|
@ -1038,6 +1139,19 @@ ansi-styles@^4.1.0:
|
|||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
anymatch@~3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
|
||||
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
|
||||
dependencies:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
arg@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.1.tgz#eb0c9a8f77786cad2af8ff2b862899842d7b6adb"
|
||||
integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
|
@ -1097,11 +1211,30 @@ ast-types-flow@^0.0.7:
|
|||
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
|
||||
integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
|
||||
|
||||
autoprefixer@^10.4.4:
|
||||
version "10.4.4"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e"
|
||||
integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==
|
||||
dependencies:
|
||||
browserslist "^4.20.2"
|
||||
caniuse-lite "^1.0.30001317"
|
||||
fraction.js "^4.2.0"
|
||||
normalize-range "^0.1.2"
|
||||
picocolors "^1.0.0"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
axe-core@^4.3.5:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413"
|
||||
integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==
|
||||
|
||||
axios@^0.26.1:
|
||||
version "0.26.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
|
||||
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
|
||||
dependencies:
|
||||
follow-redirects "^1.14.8"
|
||||
|
||||
axobject-query@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
|
||||
|
@ -1121,6 +1254,11 @@ balanced-match@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
||||
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
|
@ -1129,13 +1267,24 @@ brace-expansion@^1.1.7:
|
|||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
braces@^3.0.2:
|
||||
braces@^3.0.2, braces@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
browserslist@^4.20.2:
|
||||
version "4.20.2"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88"
|
||||
integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30001317"
|
||||
electron-to-chromium "^1.4.84"
|
||||
escalade "^3.1.1"
|
||||
node-releases "^2.0.2"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
call-bind@^1.0.0, call-bind@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
|
||||
|
@ -1149,11 +1298,21 @@ callsites@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
camelcase-css@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
|
||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||
|
||||
caniuse-lite@^1.0.30001283:
|
||||
version "1.0.30001323"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz#a451ff80dec7033016843f532efda18f02eec011"
|
||||
integrity sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==
|
||||
|
||||
caniuse-lite@^1.0.30001317:
|
||||
version "1.0.30001327"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001327.tgz#c1546d7d7bb66506f0ccdad6a7d07fc6d668c858"
|
||||
integrity sha512-1/Cg4jlD9qjZzhbzkzEaAC2JHsP0WrOc8Rd/3a3LuajGzGWR/hD7TVyvq99VqmTy99eVh8Zkmdq213OgvgXx7w==
|
||||
|
||||
chalk@^2.0.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
|
@ -1163,7 +1322,7 @@ chalk@^2.0.0:
|
|||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^4.0.0:
|
||||
chalk@^4.0.0, chalk@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
|
@ -1171,6 +1330,26 @@ chalk@^4.0.0:
|
|||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chokidar@^3.5.3:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||
dependencies:
|
||||
anymatch "~3.1.2"
|
||||
braces "~3.0.2"
|
||||
glob-parent "~5.1.2"
|
||||
is-binary-path "~2.1.0"
|
||||
is-glob "~4.0.1"
|
||||
normalize-path "~3.0.0"
|
||||
readdirp "~3.6.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
clsx@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
|
||||
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
|
@ -1190,7 +1369,7 @@ color-name@1.1.3:
|
|||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
|
||||
color-name@~1.1.4:
|
||||
color-name@^1.1.4, color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
@ -1205,6 +1384,11 @@ concat-map@0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
confusing-browser-globals@^1.0.10:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81"
|
||||
integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==
|
||||
|
||||
convert-source-map@^1.5.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
|
||||
|
@ -1235,6 +1419,17 @@ cosmiconfig@^6.0.0:
|
|||
path-type "^4.0.0"
|
||||
yaml "^1.7.2"
|
||||
|
||||
cosmiconfig@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
|
||||
integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
|
||||
dependencies:
|
||||
"@types/parse-json" "^4.0.0"
|
||||
import-fresh "^3.2.1"
|
||||
parse-json "^5.0.0"
|
||||
path-type "^4.0.0"
|
||||
yaml "^1.10.0"
|
||||
|
||||
cross-spawn@^7.0.2:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
|
@ -1251,6 +1446,11 @@ css-box-model@1.2.1:
|
|||
dependencies:
|
||||
tiny-invariant "^1.0.6"
|
||||
|
||||
cssesc@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||
|
||||
csstype@3.0.9:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b"
|
||||
|
@ -1299,11 +1499,30 @@ define-properties@^1.1.3:
|
|||
dependencies:
|
||||
object-keys "^1.0.12"
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
|
||||
|
||||
detect-node-es@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
|
||||
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
|
||||
|
||||
detective@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b"
|
||||
integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==
|
||||
dependencies:
|
||||
acorn-node "^1.6.1"
|
||||
defined "^1.0.0"
|
||||
minimist "^1.1.1"
|
||||
|
||||
didyoumean@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
|
||||
|
||||
dir-glob@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
|
||||
|
@ -1311,6 +1530,11 @@ dir-glob@^3.0.1:
|
|||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
dlv@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
|
||||
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
|
||||
|
||||
doctrine@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
|
||||
|
@ -1325,6 +1549,11 @@ doctrine@^3.0.0:
|
|||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
electron-to-chromium@^1.4.84:
|
||||
version "1.4.106"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.106.tgz#e7a3bfa9d745dd9b9e597616cb17283cc349781a"
|
||||
integrity sha512-ZYfpVLULm67K7CaaGP7DmjyeMY4naxsbTy+syVVxT6QHI1Ww8XbJjmr9fDckrhq44WzCrcC5kH3zGpdusxwwqg==
|
||||
|
||||
emoji-regex@^9.2.2:
|
||||
version "9.2.2"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
|
||||
|
@ -1372,6 +1601,11 @@ es-to-primitive@^1.2.1:
|
|||
is-date-object "^1.0.1"
|
||||
is-symbol "^1.0.2"
|
||||
|
||||
escalade@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
|
@ -1382,6 +1616,23 @@ escape-string-regexp@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
eslint-config-airbnb-base@^15.0.0:
|
||||
version "15.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz#6b09add90ac79c2f8d723a2580e07f3925afd236"
|
||||
integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==
|
||||
dependencies:
|
||||
confusing-browser-globals "^1.0.10"
|
||||
object.assign "^4.1.2"
|
||||
object.entries "^1.1.5"
|
||||
semver "^6.3.0"
|
||||
|
||||
eslint-config-airbnb-typescript@^17.0.0:
|
||||
version "17.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz#360dbcf810b26bbcf2ff716198465775f1c49a07"
|
||||
integrity sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==
|
||||
dependencies:
|
||||
eslint-config-airbnb-base "^15.0.0"
|
||||
|
||||
eslint-config-next@12.1.4:
|
||||
version "12.1.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.1.4.tgz#939ea2ff33034763300bf1e62482cea91212d274"
|
||||
|
@ -1494,6 +1745,14 @@ eslint-plugin-react@7.29.1:
|
|||
semver "^6.3.0"
|
||||
string.prototype.matchall "^4.0.6"
|
||||
|
||||
eslint-scope@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
|
||||
|
@ -1583,6 +1842,11 @@ esrecurse@^4.3.0:
|
|||
dependencies:
|
||||
estraverse "^5.2.0"
|
||||
|
||||
estraverse@^4.1.1:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
|
||||
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
||||
|
||||
estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
|
||||
|
@ -1598,7 +1862,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
|||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-glob@^3.2.9:
|
||||
fast-glob@^3.2.11, fast-glob@^3.2.9:
|
||||
version "3.2.11"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
|
||||
integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
|
||||
|
@ -1640,6 +1904,13 @@ fill-range@^7.0.1:
|
|||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
final-form@^4.20.6:
|
||||
version "4.20.6"
|
||||
resolved "https://registry.yarnpkg.com/final-form/-/final-form-4.20.6.tgz#da42f3741db068c0c875e18950a2c4a9a148c63e"
|
||||
integrity sha512-fCdwIj49KOaFfDRlXB57Eo+GghIMZQWrA9TakQI3C9uQxHwaFHXqZSNRlUdfnQmNNeySwGOaGPZCvjy58hyv4w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.0"
|
||||
|
||||
find-root@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
||||
|
@ -1672,6 +1943,16 @@ focus-lock@^0.9.1:
|
|||
dependencies:
|
||||
tslib "^2.0.3"
|
||||
|
||||
follow-redirects@^1.14.8:
|
||||
version "1.14.9"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
|
||||
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
|
||||
|
||||
fraction.js@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
|
||||
integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
|
||||
|
||||
framer-motion@^6:
|
||||
version "6.2.8"
|
||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.2.8.tgz#02abb529191af7e2df444185fe27e932215b715d"
|
||||
|
@ -1704,6 +1985,11 @@ fs.realpath@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
|
@ -1736,14 +2022,14 @@ get-symbol-description@^1.0.0:
|
|||
call-bind "^1.0.2"
|
||||
get-intrinsic "^1.1.1"
|
||||
|
||||
glob-parent@^5.1.2:
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob-parent@^6.0.1:
|
||||
glob-parent@^6.0.1, glob-parent@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
|
||||
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
|
||||
|
@ -1839,11 +2125,16 @@ hoist-non-react-statics@^3.3.1:
|
|||
dependencies:
|
||||
react-is "^16.7.0"
|
||||
|
||||
ignore@^5.2.0:
|
||||
ignore@^5.1.8, ignore@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
|
||||
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
|
||||
|
||||
immer@^9.0.12:
|
||||
version "9.0.12"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20"
|
||||
integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==
|
||||
|
||||
import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
|
@ -1898,6 +2189,13 @@ is-bigint@^1.0.1:
|
|||
dependencies:
|
||||
has-bigints "^1.0.1"
|
||||
|
||||
is-binary-path@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
|
||||
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
|
||||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-boolean-object@^1.1.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
|
||||
|
@ -1930,7 +2228,7 @@ is-extglob@^2.1.1:
|
|||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
|
||||
|
||||
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
|
||||
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
|
||||
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||
|
@ -2055,6 +2353,11 @@ levn@^0.4.1:
|
|||
prelude-ls "^1.2.1"
|
||||
type-check "~0.4.0"
|
||||
|
||||
lilconfig@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25"
|
||||
integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==
|
||||
|
||||
lines-and-columns@^1.1.6:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
|
@ -2112,7 +2415,7 @@ minimatch@^3.0.4, minimatch@^3.1.2:
|
|||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@^1.2.0, minimist@^1.2.6:
|
||||
minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||
|
@ -2132,7 +2435,7 @@ ms@^2.1.1:
|
|||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
nanoid@^3.1.30:
|
||||
nanoid@^3.1.30, nanoid@^3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557"
|
||||
integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==
|
||||
|
@ -2165,11 +2468,31 @@ next@12.1.4:
|
|||
"@next/swc-win32-ia32-msvc" "12.1.4"
|
||||
"@next/swc-win32-x64-msvc" "12.1.4"
|
||||
|
||||
node-releases@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01"
|
||||
integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
normalize-range@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
|
||||
|
||||
object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-hash@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
|
||||
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
|
||||
|
||||
object-inspect@^1.12.0, object-inspect@^1.9.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
|
||||
|
@ -2310,7 +2633,7 @@ picocolors@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||
|
||||
picomatch@^2.3.1:
|
||||
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
@ -2325,6 +2648,41 @@ popmotion@11.0.3:
|
|||
style-value-types "5.0.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
postcss-js@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
|
||||
integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
|
||||
dependencies:
|
||||
camelcase-css "^2.0.1"
|
||||
|
||||
postcss-load-config@^3.1.0:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
|
||||
integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
|
||||
dependencies:
|
||||
lilconfig "^2.0.5"
|
||||
yaml "^1.10.2"
|
||||
|
||||
postcss-nested@5.0.6:
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc"
|
||||
integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.0.6"
|
||||
|
||||
postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9:
|
||||
version "6.0.10"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
|
||||
integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
|
||||
dependencies:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-value-parser@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss@8.4.5:
|
||||
version "8.4.5"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95"
|
||||
|
@ -2334,6 +2692,15 @@ postcss@8.4.5:
|
|||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.1"
|
||||
|
||||
postcss@^8.4.12, postcss@^8.4.6:
|
||||
version "8.4.12"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905"
|
||||
integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
|
||||
dependencies:
|
||||
nanoid "^3.3.1"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
|
@ -2358,6 +2725,11 @@ queue-microtask@^1.2.2:
|
|||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
quick-lru@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
||||
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
||||
|
||||
react-clientside-effect@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz#e2c4dc3c9ee109f642fac4f5b6e9bf5bcd2219a3"
|
||||
|
@ -2378,6 +2750,13 @@ react-fast-compare@3.2.0:
|
|||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
|
||||
|
||||
react-final-form@^6.5.9:
|
||||
version "6.5.9"
|
||||
resolved "https://registry.yarnpkg.com/react-final-form/-/react-final-form-6.5.9.tgz#644797d4c122801b37b58a76c87761547411190b"
|
||||
integrity sha512-x3XYvozolECp3nIjly+4QqxdjSSWfcnpGEL5K8OBT6xmGrq5kBqbA6+/tOqoom9NwqIPPbxPNsOViFlbKgowbA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
|
||||
react-focus-lock@2.5.2:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.5.2.tgz#f1e4db5e25cd8789351f2bd5ebe91e9dcb9c2922"
|
||||
|
@ -2390,6 +2769,11 @@ react-focus-lock@2.5.2:
|
|||
use-callback-ref "^1.2.5"
|
||||
use-sidecar "^1.0.5"
|
||||
|
||||
react-icons@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.3.1.tgz#2fa92aebbbc71f43d2db2ed1aed07361124e91ca"
|
||||
integrity sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==
|
||||
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
|
@ -2430,6 +2814,13 @@ react@18.0.0:
|
|||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
regenerator-runtime@^0.13.4:
|
||||
version "0.13.9"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||
|
@ -2453,7 +2844,7 @@ resolve-from@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.20.0:
|
||||
resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.22.0:
|
||||
version "1.22.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
|
||||
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
|
||||
|
@ -2539,7 +2930,7 @@ slash@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||
|
||||
source-map-js@^1.0.1:
|
||||
source-map-js@^1.0.1, source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
@ -2633,11 +3024,43 @@ supports-preserve-symlinks-flag@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||
|
||||
swr@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8"
|
||||
integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==
|
||||
|
||||
systeminformation@^5.11.9:
|
||||
version "5.11.9"
|
||||
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.11.9.tgz#95f2334e739dd224178948a2afaced7d9abfdf9d"
|
||||
integrity sha512-eeMtL9UJFR/LYG+2rpeAgZ0Va4ojlNQTkYiQH/xbbPwDjDMsaetj3Pkc+C1aH5G8mav6HvDY8kI4Vl4noksSkA==
|
||||
|
||||
tailwindcss@^3.0.23:
|
||||
version "3.0.23"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.23.tgz#c620521d53a289650872a66adfcb4129d2200d10"
|
||||
integrity sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==
|
||||
dependencies:
|
||||
arg "^5.0.1"
|
||||
chalk "^4.1.2"
|
||||
chokidar "^3.5.3"
|
||||
color-name "^1.1.4"
|
||||
cosmiconfig "^7.0.1"
|
||||
detective "^5.2.0"
|
||||
didyoumean "^1.2.2"
|
||||
dlv "^1.1.3"
|
||||
fast-glob "^3.2.11"
|
||||
glob-parent "^6.0.2"
|
||||
is-glob "^4.0.3"
|
||||
normalize-path "^3.0.0"
|
||||
object-hash "^2.2.0"
|
||||
postcss "^8.4.6"
|
||||
postcss-js "^4.0.0"
|
||||
postcss-load-config "^3.1.0"
|
||||
postcss-nested "5.0.6"
|
||||
postcss-selector-parser "^6.0.9"
|
||||
postcss-value-parser "^4.2.0"
|
||||
quick-lru "^5.1.1"
|
||||
resolve "^1.22.0"
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||
|
@ -2739,6 +3162,11 @@ use-sidecar@^1.0.1, use-sidecar@^1.0.5:
|
|||
detect-node-es "^1.1.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
util-deprecate@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
|
||||
|
@ -2784,12 +3212,22 @@ wrappy@1:
|
|||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
xtend@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
||||
yaml@^1.7.2:
|
||||
yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||
|
||||
zustand@^3.7.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d"
|
||||
integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"installed": "",
|
||||
"installed": "nextcloud",
|
||||
"environment": {
|
||||
"anonaddy": {}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
module.exports = {
|
||||
env: { node: true },
|
||||
extends: ['airbnb-base', 'eslint:recommended', 'plugin:import/typescript'],
|
||||
extends: ['airbnb-typescript', 'eslint:recommended', 'plugin:import/typescript'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'import'],
|
||||
plugins: ['@typescript-eslint', 'import', 'react'],
|
||||
rules: {
|
||||
'arrow-body-style': 0,
|
||||
'no-restricted-exports': 0,
|
||||
'max-len': [{ code: 200 }],
|
||||
'max-len': [1, { code: 200 }],
|
||||
'import/extensions': ['error', 'ignorePackages', { js: 'never', jsx: 'never', ts: 'never', tsx: 'never' }],
|
||||
},
|
||||
};
|
||||
|
|
14501
system-api/package-lock.json
generated
14501
system-api/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,7 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.0.0",
|
||||
"express": "^4.17.3",
|
||||
"helmet": "^5.0.2",
|
||||
|
@ -26,6 +27,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/compression": "^1.7.2",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/validator": "^13.7.2",
|
||||
"concurrently": "^7.1.0",
|
||||
|
@ -34,8 +36,10 @@
|
|||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-hardcore": "^24.5.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-react": "^1.1.7",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-unicorn": "^42.0.0",
|
||||
"nodemon": "^2.0.15",
|
||||
"prettier": "2.6.2"
|
||||
|
|
1
system-api/src/config/apps.ts
Normal file
1
system-api/src/config/apps.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const appNames = ['nextcloud', 'simple-torrent', 'freshrss', 'anonaddy'];
|
|
@ -11,5 +11,7 @@ export interface AppConfig {
|
|||
name: string;
|
||||
description: string;
|
||||
version: string;
|
||||
image: string;
|
||||
form_fields: Record<string, FormField>;
|
||||
installed: boolean;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { Request, Response } from 'express';
|
||||
import si from 'systeminformation';
|
||||
import { appNames } from '../../config/apps';
|
||||
import { AppConfig } from '../../config/types';
|
||||
import { createFolder, fileExists, readJsonFile, writeFile, copyFile, runScript, deleteFolder } from '../fs/fs.helpers';
|
||||
|
||||
|
@ -34,31 +36,38 @@ const generateEnvFile = (appName: string, form: Record<string, string>) => {
|
|||
|
||||
const installApp = (req: Request, res: Response) => {
|
||||
try {
|
||||
const { appName, form } = req.body;
|
||||
const { id } = req.params;
|
||||
const { form } = req.body;
|
||||
|
||||
if (!appName) {
|
||||
if (!id) {
|
||||
throw new Error('App name is required');
|
||||
}
|
||||
|
||||
const appExists = fileExists(`/app-data/${appName}`);
|
||||
const appExists = fileExists(`/app-data/${id}`);
|
||||
|
||||
if (appExists) {
|
||||
throw new Error(`App ${appName} already installed`);
|
||||
throw new Error(`App ${id} already installed`);
|
||||
}
|
||||
|
||||
const appIsAvailable = appNames.includes(id);
|
||||
|
||||
if (!appIsAvailable) {
|
||||
throw new Error(`App ${id} not available`);
|
||||
}
|
||||
|
||||
// Create app folder
|
||||
createFolder(`/app-data/${appName}`);
|
||||
createFolder(`/app-data/${id}`);
|
||||
// Copy default app files from app-data folder
|
||||
copyFile(`/apps/${appName}/data`, `/app-data/${appName}/data`);
|
||||
copyFile(`/apps/${id}/data`, `/app-data/${id}/data`);
|
||||
|
||||
// Create env file
|
||||
generateEnvFile(appName, form);
|
||||
generateEnvFile(id, form);
|
||||
const state = getStateFile();
|
||||
state.installed += ` ${appName}`;
|
||||
state.installed += ` ${id}`;
|
||||
writeFile('/state/apps.json', JSON.stringify(state));
|
||||
|
||||
// Run script
|
||||
runScript('/scripts/app.sh', ['install', appName]);
|
||||
runScript('/scripts/app.sh', ['install', id]);
|
||||
|
||||
res.status(200).json({ message: 'App installed successfully' });
|
||||
} catch (e) {
|
||||
|
@ -99,20 +108,20 @@ const uninstallApp = (req: Request, res: Response) => {
|
|||
|
||||
const stopApp = (req: Request, res: Response) => {
|
||||
try {
|
||||
const { appName } = req.body;
|
||||
const { name } = req.params;
|
||||
|
||||
if (!appName) {
|
||||
if (!name) {
|
||||
throw new Error('App name is required');
|
||||
}
|
||||
|
||||
const appExists = fileExists(`/app-data/${appName}`);
|
||||
const appExists = fileExists(`/app-data/${name}`);
|
||||
|
||||
if (!appExists) {
|
||||
throw new Error(`App ${appName} not installed`);
|
||||
throw new Error(`App ${name} not installed`);
|
||||
}
|
||||
|
||||
// Run script
|
||||
runScript('/scripts/app.sh', ['stop', appName]);
|
||||
runScript('/scripts/app.sh', ['stop', name]);
|
||||
|
||||
res.status(200).json({ message: 'App stopped successfully' });
|
||||
} catch (e) {
|
||||
|
@ -146,32 +155,45 @@ const updateAppConfig = (req: Request, res: Response) => {
|
|||
}
|
||||
};
|
||||
|
||||
const installedApps = (req: Request, res: Response) => {
|
||||
const getAppInfo = (req: Request, res: Response<AppConfig>) => {
|
||||
try {
|
||||
const apps = readJsonFile('/state/apps.json');
|
||||
const appNames = apps.installed.split(' ');
|
||||
const { id } = req.params;
|
||||
|
||||
if (appNames.length === 0) {
|
||||
res.status(204).json([]);
|
||||
} else {
|
||||
res.status(200).json(appNames);
|
||||
if (!id) {
|
||||
throw new Error('App name is required');
|
||||
}
|
||||
|
||||
const configFile: AppConfig = readJsonFile(`/apps/${id}/config.json`);
|
||||
|
||||
const state = getStateFile();
|
||||
const installed: string[] = state.installed.split(' ').filter(Boolean);
|
||||
configFile.installed = installed.includes(id);
|
||||
|
||||
res.status(200).json(configFile);
|
||||
} catch (e) {
|
||||
res.status(500).end(e);
|
||||
}
|
||||
};
|
||||
|
||||
const getAppInfo = (req: Request, res: Response<AppConfig>) => {
|
||||
const listApps = async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { appName } = req.body;
|
||||
const apps = appNames.map((app) => {
|
||||
return readJsonFile(`/apps/${app}/config.json`);
|
||||
});
|
||||
|
||||
if (!appName) {
|
||||
throw new Error('App name is required');
|
||||
}
|
||||
const dockerContainers = await si.dockerContainers();
|
||||
|
||||
const configFile: AppConfig = readJsonFile(`/apps/${appName}/config.json`);
|
||||
const state = getStateFile();
|
||||
const installed: string[] = state.installed.split(' ').filter(Boolean);
|
||||
|
||||
res.status(200).json(configFile);
|
||||
apps.forEach((app) => {
|
||||
app.installed = installed.includes(app.id);
|
||||
app.status = dockerContainers.find((container) => container.name === `${app.id}`)?.state || 'stopped';
|
||||
});
|
||||
|
||||
console.log(apps);
|
||||
|
||||
res.status(200).json(apps);
|
||||
} catch (e) {
|
||||
res.status(500).end(e);
|
||||
}
|
||||
|
@ -182,8 +204,8 @@ const AppController = {
|
|||
installApp,
|
||||
stopApp,
|
||||
updateAppConfig,
|
||||
installedApps,
|
||||
getAppInfo,
|
||||
listApps,
|
||||
};
|
||||
|
||||
export default AppController;
|
||||
|
|
|
@ -3,8 +3,9 @@ import AppController from './apps.controller';
|
|||
|
||||
const router = Router();
|
||||
|
||||
router.route('/install').post(AppController.installApp);
|
||||
router.route('/install/:id').post(AppController.installApp);
|
||||
router.route('/uninstall').post(AppController.uninstallApp);
|
||||
router.route('/list').get(AppController.installedApps);
|
||||
router.route('/list').get(AppController.listApps);
|
||||
router.route('/info/:id').get(AppController.getAppInfo);
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import express from 'express';
|
||||
import compression from 'compression';
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
import { isProd } from './constants/constants';
|
||||
import appsRoutes from './modules/apps/apps.routes';
|
||||
import systemRoutes from './modules/system/system.routes';
|
||||
|
@ -13,8 +14,10 @@ if (isProd) {
|
|||
app.use(helmet());
|
||||
}
|
||||
|
||||
app.use(cors());
|
||||
|
||||
app.use('/system', systemRoutes);
|
||||
app.use('/app', appsRoutes);
|
||||
app.use('/apps', appsRoutes);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`System API listening on port ${port}`);
|
||||
|
|
Loading…
Reference in a new issue