diff --git a/src/fireedge/src/client/apps/provision/_app.js b/src/fireedge/src/client/apps/provision/_app.js index 2b900a1c45..2726285558 100644 --- a/src/fireedge/src/client/apps/provision/_app.js +++ b/src/fireedge/src/client/apps/provision/_app.js @@ -28,7 +28,7 @@ import { _APPS } from 'client/constants' const APP_NAME = _APPS.provision.name const ProvisionApp = () => { - const { jwt, firstRender } = useAuth() + const { isLogged, jwt, firstRender } = useAuth() const { getAuthUser, logout } = useAuthApi() const provisionTemplate = useProvisionTemplate() @@ -39,6 +39,7 @@ const ProvisionApp = () => { (async () => { try { if (jwt) { + changeTitle(APP_NAME) getAuthUser() !provisionTemplate?.length && await getProvisionsTemplates() } @@ -48,15 +49,11 @@ const ProvisionApp = () => { })() }, [jwt]) - React.useEffect(() => { - changeTitle(APP_NAME) - }, []) - if (jwt && firstRender) { return } - return + return } ProvisionApp.displayName = '_ProvisionApp' diff --git a/src/fireedge/src/client/apps/provision/routes.js b/src/fireedge/src/client/apps/provision/routes.js index 715c2b536b..06d368971a 100644 --- a/src/fireedge/src/client/apps/provision/routes.js +++ b/src/fireedge/src/client/apps/provision/routes.js @@ -29,8 +29,7 @@ export const PATH = { CREATE: '/provisions/create', EDIT: '/provisions/edit/:id' }, - SETTINGS: '/settings', - TEST_API: '/test-api' + SETTINGS: '/settings' } export const ENDPOINTS = [ diff --git a/src/fireedge/src/client/apps/flow/_app.js b/src/fireedge/src/client/apps/sunstone/_app.js similarity index 73% rename from src/fireedge/src/client/apps/flow/_app.js rename to src/fireedge/src/client/apps/sunstone/_app.js index ca07154b8e..7b8948d326 100644 --- a/src/fireedge/src/client/apps/flow/_app.js +++ b/src/fireedge/src/client/apps/sunstone/_app.js @@ -16,45 +16,37 @@ import * as React from 'react' import Router from 'client/router' -import routes from 'client/apps/flow/routes' +import routes from 'client/apps/sunstone/routes' import { useGeneralApi } from 'client/features/General' import { useAuth, useAuthApi } from 'client/features/Auth' import LoadingScreen from 'client/components/LoadingScreen' -import { fakeDelay } from 'client/utils' -import { _APPS, TIME_HIDE_LOGO } from 'client/constants' +import { _APPS } from 'client/constants' const APP_NAME = _APPS.sunstone.name const SunstoneApp = () => { - const [firstRender, setFirstRender] = React.useState(() => true) - - const { jwt } = useAuth() - const { getAuthUser } = useAuthApi() + const { isLogged, jwt, firstRender } = useAuth() + const { getAuthUser, logout } = useAuthApi() const { changeTitle } = useGeneralApi() React.useEffect(() => { - if (firstRender) { - jwt && (async () => { - await getAuthUser() - })() + (async () => { + try { + jwt && changeTitle(APP_NAME) + jwt && getAuthUser() + } catch { + logout() + } + })() + }, [jwt]) - fakeDelay(TIME_HIDE_LOGO).then(() => setFirstRender(false)) - } - }, [firstRender, jwt]) - - React.useEffect(() => { - changeTitle(APP_NAME) - }, []) - - if (firstRender) { + if (jwt && firstRender) { return } - return ( - - ) + return } SunstoneApp.displayName = '_SunstoneApp' diff --git a/src/fireedge/src/client/apps/flow/index.js b/src/fireedge/src/client/apps/sunstone/index.js similarity index 87% rename from src/fireedge/src/client/apps/flow/index.js rename to src/fireedge/src/client/apps/sunstone/index.js index a44af82b6a..9eb7c4f08f 100644 --- a/src/fireedge/src/client/apps/flow/index.js +++ b/src/fireedge/src/client/apps/sunstone/index.js @@ -23,24 +23,24 @@ import MuiProvider from 'client/providers/muiProvider' import NotistackProvider from 'client/providers/notistackProvider' import { TranslateProvider } from 'client/components/HOC' -import App from 'client/apps/flow/_app' -import theme from 'client/apps/flow/theme' +import App from 'client/apps/sunstone/_app' +import theme from 'client/apps/sunstone/theme' import { _APPS, APP_URL } from 'client/constants' const APP_NAME = _APPS.sunstone.name -const Sunstone = ({ store, location, context }) => ( +const Provision = ({ store, location, context }) => ( {location && context ? ( - // server build + // server build ) : ( - // browser build + // browser build @@ -51,18 +51,18 @@ const Sunstone = ({ store, location, context }) => ( ) -Sunstone.propTypes = { +Provision.propTypes = { location: PropTypes.string, context: PropTypes.shape({}), store: PropTypes.shape({}) } -Sunstone.defaultProps = { +Provision.defaultProps = { location: '', context: {}, store: {} } -Sunstone.displayName = 'SunstoneApp' +Provision.displayName = 'SunstoneApp' -export default Sunstone +export default Provision diff --git a/src/fireedge/src/client/apps/flow/routes.js b/src/fireedge/src/client/apps/sunstone/routes-flow.js similarity index 70% rename from src/fireedge/src/client/apps/flow/routes.js rename to src/fireedge/src/client/apps/sunstone/routes-flow.js index 6e95845f61..7a519a52e8 100644 --- a/src/fireedge/src/client/apps/flow/routes.js +++ b/src/fireedge/src/client/apps/sunstone/routes-flow.js @@ -1,21 +1,10 @@ import { - ReportColumns as DashboardIcon, List as TemplatesIcons, Cell4x4 as InstancesIcons } from 'iconoir-react' import loadable from '@loadable/component' -const Dashboard = loadable( - () => import('client/containers/Dashboard'), - { ssr: false } -) - -const Settings = loadable( - () => import('client/containers/Settings'), - { ssr: false } -) - const ApplicationsTemplates = loadable( () => import('client/containers/ApplicationsTemplates'), { ssr: false } @@ -32,7 +21,6 @@ const ApplicationsTemplatesFormCreate = loadable( ) export const PATH = { - DASHBOARD: '/dashboard', APPLICATIONS_TEMPLATES: { LIST: '/applications-templates', CREATE: '/applications-templates/create', @@ -40,26 +28,12 @@ export const PATH = { }, APPLICATIONS: { LIST: '/applications' - }, - SETTINGS: '/settings' + } } export const ENDPOINTS = [ { - label: 'Dashboard', - path: PATH.DASHBOARD, - sidebar: true, - icon: DashboardIcon, - Component: Dashboard - }, - { - label: 'Settings', - path: PATH.SETTINGS, - header: true, - Component: Settings - }, - { - label: 'Templates', + label: 'Service Templates', path: PATH.APPLICATIONS_TEMPLATES.LIST, sidebar: true, icon: TemplatesIcons, @@ -76,7 +50,7 @@ export const ENDPOINTS = [ Component: ApplicationsTemplatesFormCreate }, { - label: 'Instances', + label: 'Service Instances', path: PATH.APPLICATIONS.LIST, sidebar: true, icon: InstancesIcons, diff --git a/src/fireedge/src/client/apps/sunstone/routes.js b/src/fireedge/src/client/apps/sunstone/routes.js new file mode 100644 index 0000000000..1716e5db81 --- /dev/null +++ b/src/fireedge/src/client/apps/sunstone/routes.js @@ -0,0 +1,225 @@ +import { + ReportColumns as DashboardIcon, + Settings as SettingsIcon, + Cell4x4 as InstancesIcons, + User as UserIcon, + SimpleCart as MarketplaceIcon, + CloudDownload as MarketplaceAppIcon, + EmptyPage as TemplateIcon, + Server as ClusterIcon, + HardDrive as HostIcon, + Folder as DatastoreIcon, + Group as GroupIcon, + Archive as ImageIcon, + NetworkAlt as NetworkIcon +} from 'iconoir-react' + +import loadable from '@loadable/component' + +const Dashboard = loadable(() => import('client/containers/Dashboard/Sunstone'), { ssr: false }) +const Settings = loadable(() => import('client/containers/Settings'), { ssr: false }) + +const VirtualMachines = loadable(() => import('client/containers/VirtualMachines'), { ssr: false }) +// const VirtualRouters = loadable(() => import('client/containers/VirtualRouters'), { ssr: false }) + +const VmTemplates = loadable(() => import('client/containers/VmTemplates'), { ssr: false }) +// const VrTemplates = loadable(() => import('client/containers/VrTemplates'), { ssr: false }) +// const VmGroups = loadable(() => import('client/containers/VmGroups'), { ssr: false }) + +const Datastores = loadable(() => import('client/containers/Datastores'), { ssr: false }) +const Images = loadable(() => import('client/containers/Images'), { ssr: false }) +// const Files = loadable(() => import('client/containers/Files'), { ssr: false }) +const Marketplaces = loadable(() => import('client/containers/Marketplaces'), { ssr: false }) +const MarketplaceApps = loadable(() => import('client/containers/MarketplaceApps'), { ssr: false }) + +// const VirtualNetworks = loadable(() => import('client/containers/VirtualNetworks'), { ssr: false }) +// const NetworkTemplates = loadable(() => import('client/containers/NetworkTemplates'), { ssr: false }) +// const NetworkTopologies = loadable(() => import('client/containers/NetworkTopologies'), { ssr: false }) +// const SecurityGroups = loadable(() => import('client/containers/SecurityGroups'), { ssr: false }) + +const Clusters = loadable(() => import('client/containers/Clusters'), { ssr: false }) +const Hosts = loadable(() => import('client/containers/Hosts'), { ssr: false }) +// const Zones = loadable(() => import('client/containers/Zones'), { ssr: false }) + +const Users = loadable(() => import('client/containers/Users'), { ssr: false }) +const Groups = loadable(() => import('client/containers/Groups'), { ssr: false }) +// const VDCs = loadable(() => import('client/containers/VDCs'), { ssr: false }) +// const ACLs = loadable(() => import('client/containers/ACLs'), { ssr: false }) + +export const PATH = { + DASHBOARD: '/dashboard', + INSTANCE: { + VMS: { + LIST: '/vms' + } + }, + TEMPLATE: { + VMS: { + LIST: '/vm-templates' + } + }, + STORAGE: { + DATASTORES: { + LIST: '/datastores' + }, + IMAGES: { + LIST: '/images' + }, + FILES: { + LIST: '/files' + }, + MARKETPLACES: { + LIST: '/marketplaces' + }, + MARKETPLACE_APPS: { + LIST: '/marketplaces-apps' + } + }, + NETWORK: { + VNETS: { + LIST: '/virtual-networks' + }, + VN_TEMPLATES: { + LIST: '/network-templates' + }, + SEC_GROUPS: { + LIST: '/security-groups' + } + }, + INFRASTRUCTURE: { + CLUSTERS: { + LIST: '/clusters' + }, + HOSTS: { + LIST: '/hosts' + } + }, + SYSTEM: { + USERS: { + LIST: '/users' + }, + GROUPS: { + LIST: '/groups' + } + }, + SETTINGS: '/settings' +} + +export const ENDPOINTS = [ + { + label: 'Dashboard', + path: PATH.DASHBOARD, + sidebar: true, + icon: DashboardIcon, + Component: Dashboard + }, + { + label: 'Instances', + sidebar: true, + routes: [ + { + label: 'VMs', + path: PATH.INSTANCE.VMS.LIST, + sidebar: true, + icon: InstancesIcons, + Component: VirtualMachines + } + ] + }, + { + label: 'Templates', + sidebar: true, + routes: [ + { + label: 'VMs', + path: PATH.TEMPLATE.VMS.LIST, + sidebar: true, + icon: TemplateIcon, + Component: VmTemplates + } + ] + }, + { + label: 'Storage', + sidebar: true, + routes: [ + { + label: 'Datastores', + path: PATH.STORAGE.DATASTORES.LIST, + sidebar: true, + icon: DatastoreIcon, + Component: Datastores + }, + { + label: 'Images', + path: PATH.STORAGE.IMAGES.LIST, + sidebar: true, + icon: ImageIcon, + Component: Images + }, + { + label: 'Marketplaces', + path: PATH.STORAGE.MARKETPLACES.LIST, + sidebar: true, + icon: MarketplaceIcon, + Component: Marketplaces + }, + { + label: 'Apps', + path: PATH.STORAGE.MARKETPLACE_APPS.LIST, + sidebar: true, + icon: MarketplaceAppIcon, + Component: MarketplaceApps + } + ] + }, + { + label: 'Infrastructure', + sidebar: true, + routes: [ + { + label: 'Clusters', + path: PATH.INFRASTRUCTURE.CLUSTERS.LIST, + sidebar: true, + icon: ClusterIcon, + Component: Clusters + }, + { + label: 'Hosts', + path: PATH.INFRASTRUCTURE.HOSTS.LIST, + sidebar: true, + icon: HostIcon, + Component: Hosts + } + ] + }, + { + label: 'System', + sidebar: true, + routes: [ + { + label: 'Users', + path: PATH.SYSTEM.USERS.LIST, + sidebar: true, + icon: UserIcon, + Component: Users + }, + { + label: 'Groups', + path: PATH.SYSTEM.GROUPS.LIST, + sidebar: true, + icon: GroupIcon, + Component: Groups + } + ] + }, + { + label: 'Settings', + path: PATH.SETTINGS, + sidebar: true, + icon: SettingsIcon, + Component: Settings + } +] + +export default { PATH, ENDPOINTS } diff --git a/src/fireedge/src/client/apps/flow/theme.js b/src/fireedge/src/client/apps/sunstone/theme.js similarity index 100% rename from src/fireedge/src/client/apps/flow/theme.js rename to src/fireedge/src/client/apps/sunstone/theme.js diff --git a/src/fireedge/src/client/components/Sidebar/SidebarCollapseItem.js b/src/fireedge/src/client/components/Sidebar/SidebarCollapseItem.js index 3ebd7fc87d..c85130b454 100644 --- a/src/fireedge/src/client/components/Sidebar/SidebarCollapseItem.js +++ b/src/fireedge/src/client/components/Sidebar/SidebarCollapseItem.js @@ -4,6 +4,7 @@ import clsx from 'clsx' import { List, + Icon as MIcon, Collapse, ListItem, ListItemText, @@ -32,26 +33,24 @@ const SidebarCollapseItem = ({ label, routes, icon: Icon }) => { )} - - {expanded ? ( - - ) : ( - - )} + + + {expanded ? : } + {routes?.map((subItem, index) => ( - + diff --git a/src/fireedge/src/client/components/Sidebar/styles.js b/src/fireedge/src/client/components/Sidebar/styles.js index be45e92c6c..5165268b9e 100644 --- a/src/fireedge/src/client/components/Sidebar/styles.js +++ b/src/fireedge/src/client/components/Sidebar/styles.js @@ -36,11 +36,11 @@ export default makeStyles(theme => ({ '& #logo__text': { visibility: 'hidden' }, - '& $menu': { - overflowY: 'hidden' - }, '& $expandIcon, & $subItemWrapper': { display: 'none' + }, + '& $itemText::before': { + content: 'attr(data-min-label)' } } } @@ -62,6 +62,9 @@ export default makeStyles(theme => ({ }, '& $expandIcon, & $subItemWrapper': { display: 'block !important' + }, + '& $itemText::before': { + content: 'attr(data-max-label) !important' } } }, @@ -114,6 +117,14 @@ export default makeStyles(theme => ({ list: { color: theme.palette.text.primary }, + itemText: { + '&::before': { + ...theme.typography.body1, + display: 'block', + minWidth: 100, + content: 'attr(data-max-label)' + } + }, expandIcon: {}, subItemWrapper: {}, subItem: { diff --git a/src/fireedge/src/client/components/Tables/Groups/columns.js b/src/fireedge/src/client/components/Tables/Groups/columns.js new file mode 100644 index 0000000000..b28f64aeb8 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Groups/columns.js @@ -0,0 +1,12 @@ +const getTotalOfResources = resources => [resources?.ID ?? []].flat().length || 0 + +export default [ + { Header: 'ID', accessor: 'ID', sortType: 'number' }, + { Header: 'Name', accessor: 'NAME' }, + { + Header: 'Total Users', + id: 'TOTAL_USERS', + accessor: row => getTotalOfResources(row?.USERS), + sortType: 'number' + } +] diff --git a/src/fireedge/src/client/components/Tables/Groups/index.js b/src/fireedge/src/client/components/Tables/Groups/index.js new file mode 100644 index 0000000000..1cb62ed97a --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Groups/index.js @@ -0,0 +1,31 @@ +import React, { useEffect } from 'react' + +import { useFetch } from 'client/hooks' +import { useGroup, useGroupApi } from 'client/features/One' + +import { EnhancedTable } from 'client/components/Tables' +import GroupColumns from 'client/components/Tables/Groups/columns' +import GroupRow from 'client/components/Tables/Groups/row' + +const GroupsTable = () => { + const columns = React.useMemo(() => GroupColumns, []) + + const groups = useGroup() + const { getGroups } = useGroupApi() + + const { fetchRequest, loading, reloading } = useFetch(getGroups) + + useEffect(() => { fetchRequest() }, []) + + return ( + String(row.ID)} + RowComponent={GroupRow} + /> + ) +} + +export default GroupsTable diff --git a/src/fireedge/src/client/components/Tables/Groups/row.js b/src/fireedge/src/client/components/Tables/Groups/row.js new file mode 100644 index 0000000000..cb8cabf42b --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Groups/row.js @@ -0,0 +1,42 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { Group } from 'iconoir-react' +import { Typography } from '@material-ui/core' + +import { rowStyles } from 'client/components/Tables/styles' + +const Row = ({ original, value, ...props }) => { + const classes = rowStyles() + const { ID, NAME, TOTAL_USERS } = value + + return ( +
+
+
+ + {NAME} + +
+
+ + {`#${ID}`} + + + + {` ${TOTAL_USERS}`} + +
+
+
+ ) +} + +Row.propTypes = { + original: PropTypes.object, + value: PropTypes.object, + isSelected: PropTypes.bool, + handleClick: PropTypes.func +} + +export default Row diff --git a/src/fireedge/src/client/components/Tables/Users/columns.js b/src/fireedge/src/client/components/Tables/Users/columns.js new file mode 100644 index 0000000000..873eaa14f5 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Users/columns.js @@ -0,0 +1,7 @@ +export default [ + { Header: 'ID', accessor: 'ID', sortType: 'number' }, + { Header: 'Name', accessor: 'NAME' }, + { Header: 'Group', accessor: 'GNAME' }, + { Header: 'Enabled', accessor: 'ENABLED' }, + { Header: 'Auth driver', accessor: 'AUTH_DRIVER' } +] diff --git a/src/fireedge/src/client/components/Tables/Users/index.js b/src/fireedge/src/client/components/Tables/Users/index.js new file mode 100644 index 0000000000..a2d57e9205 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Users/index.js @@ -0,0 +1,31 @@ +import React, { useEffect } from 'react' + +import { useFetch } from 'client/hooks' +import { useUser, useUserApi } from 'client/features/One' + +import { EnhancedTable } from 'client/components/Tables' +import UserColumns from 'client/components/Tables/Users/columns' +import UserRow from 'client/components/Tables/Users/row' + +const UsersTable = () => { + const columns = React.useMemo(() => UserColumns, []) + + const users = useUser() + const { getUsers } = useUserApi() + + const { fetchRequest, loading, reloading } = useFetch(getUsers) + + useEffect(() => { fetchRequest() }, []) + + return ( + String(row.ID)} + RowComponent={UserRow} + /> + ) +} + +export default UsersTable diff --git a/src/fireedge/src/client/components/Tables/Users/row.js b/src/fireedge/src/client/components/Tables/Users/row.js new file mode 100644 index 0000000000..52972b1580 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Users/row.js @@ -0,0 +1,49 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { Group, Lock, LockKey } from 'iconoir-react' +import { Typography } from '@material-ui/core' + +import { rowStyles } from 'client/components/Tables/styles' + +const Row = ({ original, value, ...props }) => { + const classes = rowStyles() + const { ID, NAME, GNAME, ENABLED, AUTH_DRIVER } = value + + return ( +
+
+
+ + {NAME} + + + {!+ENABLED && } + +
+
+ + {`#${ID}`} + + + + {` ${GNAME}`} + + + + {` ${AUTH_DRIVER}`} + +
+
+
+ ) +} + +Row.propTypes = { + original: PropTypes.object, + value: PropTypes.object, + isSelected: PropTypes.bool, + handleClick: PropTypes.func +} + +export default Row diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/columns.js b/src/fireedge/src/client/components/Tables/VmTemplates/columns.js new file mode 100644 index 0000000000..62bc55ff96 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/VmTemplates/columns.js @@ -0,0 +1,8 @@ +export default [ + { Header: 'ID', accessor: 'ID', sortType: 'number' }, + { Header: 'Name', accessor: 'NAME' }, + { Header: 'Owner', accessor: 'UNAME' }, + { Header: 'Group', accessor: 'GNAME' }, + { Header: 'Start Time', accessor: 'REGTIME' }, + { Header: 'Locked', accessor: 'LOCK' } +] diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/detail.js b/src/fireedge/src/client/components/Tables/VmTemplates/detail.js new file mode 100644 index 0000000000..a76679e55a --- /dev/null +++ b/src/fireedge/src/client/components/Tables/VmTemplates/detail.js @@ -0,0 +1,70 @@ +import React, { useEffect } from 'react' +import PropTypes from 'prop-types' +import { LinearProgress } from '@material-ui/core' + +import Tabs from 'client/components/Tabs' + +import { useFetch } from 'client/hooks' +import { useVmTemplateApi } from 'client/features/One' + +import * as Helper from 'client/models/Helper' + +const VmTemplateDetail = ({ id }) => { + const { getVmTemplate } = useVmTemplateApi() + const { data, fetchRequest, loading, error } = useFetch(getVmTemplate) + + useEffect(() => { + fetchRequest(id) + }, [id]) + + if ((!data && !error) || loading) { + return + } + + if (error) { + return
{error}
+ } + + const { ID, NAME, UNAME, GNAME, REGTIME, LOCK, TEMPLATE } = data + + const tabs = [ + { + name: 'info', + renderContent: ( +
+ + {`#${ID} - ${NAME}`} + +
+

Owner: {UNAME}

+

Group: {GNAME}

+

Locked: {Helper.levelLockToString(LOCK?.LOCKED)}

+

Register time: {Helper.timeToString(REGTIME)}

+
+
+ ) + }, + { + name: 'template', + renderContent: ( +
+
+            
+              {JSON.stringify(TEMPLATE, null, 2)}
+            
+          
+
+ ) + } + ] + + return ( + + ) +} + +VmTemplateDetail.propTypes = { + id: PropTypes.string.isRequired +} + +export default VmTemplateDetail diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/index.js b/src/fireedge/src/client/components/Tables/VmTemplates/index.js new file mode 100644 index 0000000000..80ee0823ea --- /dev/null +++ b/src/fireedge/src/client/components/Tables/VmTemplates/index.js @@ -0,0 +1,33 @@ +import React, { useEffect } from 'react' + +import { useFetch } from 'client/hooks' +import { useVmTemplate, useVmTemplateApi } from 'client/features/One' + +import { EnhancedTable } from 'client/components/Tables' +import VmTemplateColumns from 'client/components/Tables/VmTemplates/columns' +import VmTemplateRow from 'client/components/Tables/VmTemplates/row' +import VmTemplateDetail from 'client/components/Tables/VmTemplates/detail' + +const VmTemplatesTable = () => { + const columns = React.useMemo(() => VmTemplateColumns, []) + + const vmTemplates = useVmTemplate() + const { getVmTemplates } = useVmTemplateApi() + + const { fetchRequest, loading, reloading } = useFetch(getVmTemplates) + + useEffect(() => { fetchRequest() }, []) + + return ( + String(row.ID)} + RowComponent={VmTemplateRow} + renderDetail={row => } + /> + ) +} + +export default VmTemplatesTable diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/row.js b/src/fireedge/src/client/components/Tables/VmTemplates/row.js new file mode 100644 index 0000000000..4188079589 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/VmTemplates/row.js @@ -0,0 +1,54 @@ +import * as React from 'react' +import PropTypes from 'prop-types' + +import { User, Group, Lock } from 'iconoir-react' +import { Typography } from '@material-ui/core' + +import { rowStyles } from 'client/components/Tables/styles' + +import * as Helper from 'client/models/Helper' + +const Row = ({ original, value, ...props }) => { + const classes = rowStyles() + const { ID, NAME, UNAME, GNAME, REGTIME, LOCK } = value + + const time = Helper.timeFromMilliseconds(+REGTIME) + const timeAgo = `registered ${time.toRelative()}` + + return ( +
+
+
+ + {NAME} + + + {LOCK && } + +
+
+ + {`#${ID} ${timeAgo}`} + + + + {` ${UNAME}`} + + + + {` ${GNAME}`} + +
+
+
+ ) +} + +Row.propTypes = { + original: PropTypes.object, + value: PropTypes.object, + isSelected: PropTypes.bool, + handleClick: PropTypes.func +} + +export default Row diff --git a/src/fireedge/src/client/components/Tables/Vms/multiple.js b/src/fireedge/src/client/components/Tables/Vms/multiple.js index c5b45efe2a..d45217a1b0 100644 --- a/src/fireedge/src/client/components/Tables/Vms/multiple.js +++ b/src/fireedge/src/client/components/Tables/Vms/multiple.js @@ -17,7 +17,11 @@ const Multiple = ({ tags, limitTags = 1 }) => { )) return ( -
+
{Tags} {more > 0 && ( { + const classes = useStyles() + const users = useUser() + const groups = useGroup() + const images = useImage() + const vnetworks = useVNetwork() + + return React.useMemo(() => ( +
+ } + bgColor='#fa7892' + icon={UserIcon} + /> + } + bgColor='#b25aff' + icon={GroupIcon} + /> + } + bgColor='#1fbbc6' + icon={ImageIcon} + /> + } + bgColor='#f09d42' + icon={NetworkIcon} + /> +
+ ), [users.length, groups.length, images.length, vnetworks.length]) +} + +TotalProvisionInfrastructures.displayName = 'TotalProvisionInfrastructures' + +export default TotalProvisionInfrastructures diff --git a/src/fireedge/src/client/components/Widgets/index.js b/src/fireedge/src/client/components/Widgets/index.js index b9a000583a..5ad0a2023f 100644 --- a/src/fireedge/src/client/components/Widgets/index.js +++ b/src/fireedge/src/client/components/Widgets/index.js @@ -1,9 +1,11 @@ import TotalProviders from 'client/components/Widgets/TotalProviders' import TotalProvisionsByState from 'client/components/Widgets/TotalProvisionsByState' import TotalProvisionInfrastructures from 'client/components/Widgets/TotalProvisionInfrastructures' +import TotalSunstoneResources from 'client/components/Widgets/TotalSunstoneResources' export { TotalProviders, TotalProvisionInfrastructures, - TotalProvisionsByState + TotalProvisionsByState, + TotalSunstoneResources } diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js index de51ab311b..2ffd0eebcf 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js @@ -8,7 +8,7 @@ import { yupResolver } from '@hookform/resolvers' import FormStepper from 'client/components/FormStepper' import Steps from 'client/containers/ApplicationsTemplates/Form/Create/Steps' -import { PATH } from 'client/apps/flow/routes' +import { PATH } from 'client/apps/sunstone/routes-flow' import { useFetch } from 'client/hooks' import { useApplicationTemplateApi } from 'client/features/One' import { parseApplicationToForm, parseFormToApplication } from 'client/utils' diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/index.js index 31e3047b18..14d6bd4c51 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/index.js @@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react' import { useHistory } from 'react-router-dom' import { Container, Box } from '@material-ui/core' -import { PATH } from 'client/apps/flow/routes' +import { PATH } from 'client/apps/sunstone/routes-flow' import { useFetch } from 'client/hooks' import { useApplicationTemplate, useApplicationTemplateApi } from 'client/features/One' diff --git a/src/fireedge/src/client/containers/Clusters/index.js b/src/fireedge/src/client/containers/Clusters/index.js new file mode 100644 index 0000000000..e69a759c49 --- /dev/null +++ b/src/fireedge/src/client/containers/Clusters/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function Clusters () { + return ( + + + + + + ) +} + +export default Clusters diff --git a/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js b/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js new file mode 100644 index 0000000000..e8b7c8e11f --- /dev/null +++ b/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js @@ -0,0 +1,45 @@ +import * as React from 'react' + +import clsx from 'clsx' +import { Container, Box, Grid } from '@material-ui/core' + +import { useAuth } from 'client/features/Auth' +import { useUserApi, useGroupApi, useImageApi, useVNetworkApi } from 'client/features/One' +import * as Widgets from 'client/components/Widgets' +import dashboardStyles from 'client/containers/Dashboard/Provision/styles' + +function Dashboard () { + const { getUsers } = useUserApi() + const { getGroups } = useGroupApi() + const { getImages } = useImageApi() + const { getVNetworks } = useVNetworkApi() + + const { settings: { disableanimations } = {} } = useAuth() + const classes = dashboardStyles({ disableanimations }) + + React.useEffect(() => { + getUsers() + getGroups() + getImages() + getVNetworks() + }, []) + + const withoutAnimations = String(disableanimations).toUpperCase() === 'YES' + + return ( + + + + + + + + + + ) +} + +export default Dashboard diff --git a/src/fireedge/src/client/containers/Dashboard/Sunstone/styles.js b/src/fireedge/src/client/containers/Dashboard/Sunstone/styles.js new file mode 100644 index 0000000000..36c9d24e4d --- /dev/null +++ b/src/fireedge/src/client/containers/Dashboard/Sunstone/styles.js @@ -0,0 +1,9 @@ +import { makeStyles } from '@material-ui/core' + +export default makeStyles({ + withoutAnimations: { + '& *, & *::before, & *::after': { + animation: 'none !important' + } + } +}) diff --git a/src/fireedge/src/client/containers/Dashboard/index.js b/src/fireedge/src/client/containers/Dashboard/index.js deleted file mode 100644 index cf4c3e58b8..0000000000 --- a/src/fireedge/src/client/containers/Dashboard/index.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems */ -/* */ -/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ -/* not use this file except in compliance with the License. You may obtain */ -/* a copy of the License at */ -/* */ -/* http://www.apache.org/licenses/LICENSE-2.0 */ -/* */ -/* Unless required by applicable law or agreed to in writing, software */ -/* distributed under the License is distributed on an "AS IS" BASIS, */ -/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ -/* See the License for the specific language governing permissions and */ -/* limitations under the License. */ -/* -------------------------------------------------------------------------- */ - -import * as React from 'react' - -import { Box, Typography } from '@material-ui/core' - -import dashboardStyles from 'client/containers/Dashboard/styles' -import { Tr } from 'client/components/HOC/Translate' -import { T } from 'client/constants' - -function Dashboard () { - const classes = dashboardStyles() - - return ( - - - {Tr(T.Dashboard)} - - - ) -} - -export default Dashboard diff --git a/src/fireedge/src/client/containers/Dashboard/styles.js b/src/fireedge/src/client/containers/Dashboard/styles.js deleted file mode 100644 index 633b537522..0000000000 --- a/src/fireedge/src/client/containers/Dashboard/styles.js +++ /dev/null @@ -1,8 +0,0 @@ -import { makeStyles } from '@material-ui/core' - -export default makeStyles(theme => ({ - root: {}, - title: { - color: theme.palette.common.black - } -})) diff --git a/src/fireedge/src/client/containers/Datastores/index.js b/src/fireedge/src/client/containers/Datastores/index.js new file mode 100644 index 0000000000..2fea353c61 --- /dev/null +++ b/src/fireedge/src/client/containers/Datastores/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function Datastores () { + return ( + + + + + + ) +} + +export default Datastores diff --git a/src/fireedge/src/client/containers/Groups/index.js b/src/fireedge/src/client/containers/Groups/index.js new file mode 100644 index 0000000000..42ae22f3fe --- /dev/null +++ b/src/fireedge/src/client/containers/Groups/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function Groups () { + return ( + + + + + + ) +} + +export default Groups diff --git a/src/fireedge/src/client/containers/Hosts/index.js b/src/fireedge/src/client/containers/Hosts/index.js new file mode 100644 index 0000000000..98fc61415c --- /dev/null +++ b/src/fireedge/src/client/containers/Hosts/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function Hosts () { + return ( + + + + + + ) +} + +export default Hosts diff --git a/src/fireedge/src/client/containers/Images/index.js b/src/fireedge/src/client/containers/Images/index.js new file mode 100644 index 0000000000..d14a0e5e89 --- /dev/null +++ b/src/fireedge/src/client/containers/Images/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function Images () { + return ( + + + + + + ) +} + +export default Images diff --git a/src/fireedge/src/client/containers/MarketplaceApps/index.js b/src/fireedge/src/client/containers/MarketplaceApps/index.js new file mode 100644 index 0000000000..9253529695 --- /dev/null +++ b/src/fireedge/src/client/containers/MarketplaceApps/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function MarketplaceApps () { + return ( + + + + + + ) +} + +export default MarketplaceApps diff --git a/src/fireedge/src/client/containers/Marketplaces/index.js b/src/fireedge/src/client/containers/Marketplaces/index.js new file mode 100644 index 0000000000..8f007c162e --- /dev/null +++ b/src/fireedge/src/client/containers/Marketplaces/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function Marketplaces () { + return ( + + + + + + ) +} + +export default Marketplaces diff --git a/src/fireedge/src/client/containers/Newstone/index.js b/src/fireedge/src/client/containers/Sunstone/index.js similarity index 93% rename from src/fireedge/src/client/containers/Newstone/index.js rename to src/fireedge/src/client/containers/Sunstone/index.js index f94934885e..290d946f15 100644 --- a/src/fireedge/src/client/containers/Newstone/index.js +++ b/src/fireedge/src/client/containers/Sunstone/index.js @@ -58,9 +58,9 @@ const Newstone = () => { - + - } /> + } /> diff --git a/src/fireedge/src/client/containers/Users/index.js b/src/fireedge/src/client/containers/Users/index.js new file mode 100644 index 0000000000..5c5d476460 --- /dev/null +++ b/src/fireedge/src/client/containers/Users/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function Users () { + return ( + + + + + + ) +} + +export default Users diff --git a/src/fireedge/src/client/containers/VirtualMachines/index.js b/src/fireedge/src/client/containers/VirtualMachines/index.js new file mode 100644 index 0000000000..cfd7f51598 --- /dev/null +++ b/src/fireedge/src/client/containers/VirtualMachines/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function VirtualMachines () { + return ( + + + + + + ) +} + +export default VirtualMachines diff --git a/src/fireedge/src/client/containers/VmTemplates/index.js b/src/fireedge/src/client/containers/VmTemplates/index.js new file mode 100644 index 0000000000..0ba8cac5c3 --- /dev/null +++ b/src/fireedge/src/client/containers/VmTemplates/index.js @@ -0,0 +1,23 @@ +import * as React from 'react' + +import { styled, Container as MContainer, Box } from '@material-ui/core' + +import * as Tables from 'client/components/Tables' + +const Container = styled(MContainer)` + display: flex; + flexDirection: column; + height: 100% +` + +function VmTemplates () { + return ( + + + + + + ) +} + +export default VmTemplates diff --git a/src/fireedge/src/client/dev/_app.js b/src/fireedge/src/client/dev/_app.js index 67aacaceea..fdfe41efe8 100644 --- a/src/fireedge/src/client/dev/_app.js +++ b/src/fireedge/src/client/dev/_app.js @@ -15,7 +15,7 @@ import * as React from 'react' -import FlowApp from 'client/apps/flow' +import SunstoneApp from 'client/apps/sunstone' import ProvisionApp from 'client/apps/provision' import { isDevelopment, isBackend } from 'client/utils' @@ -39,7 +39,7 @@ const DevelopmentApp = props => { return ( <> {appName === _APPS.provision.name && } - {appName === _APPS.sunstone.name && } + {appName === _APPS.sunstone.name && } ) } diff --git a/src/fireedge/src/client/features/One/vmTemplate/services.js b/src/fireedge/src/client/features/One/vmTemplate/services.js index 1035a4c327..49b0df4740 100644 --- a/src/fireedge/src/client/features/One/vmTemplate/services.js +++ b/src/fireedge/src/client/features/One/vmTemplate/services.js @@ -1,9 +1,10 @@ import { Actions, Commands } from 'server/utils/constants/commands/template' import { httpCodes } from 'server/utils/constants' import { requestParams, RestClient } from 'client/utils' +import { poolRequest } from 'client/features/One/utils' export const vmTemplateService = ({ - getVNetwork: ({ filter, id }) => { + getVmTemplate: ({ filter, id }) => { const name = Actions.TEMPLATE_INFO const { url, options } = requestParams( { filter, id }, @@ -15,5 +16,10 @@ export const vmTemplateService = ({ return res?.data?.VMTEMPLATE ?? {} }) + }, + getVmTemplates: data => { + const name = Actions.TEMPLATE_POOL_INFO + const command = { name, ...Commands[name] } + return poolRequest(data, command, 'VMTEMPLATE') } }) diff --git a/src/fireedge/src/client/hooks/useFetch.js b/src/fireedge/src/client/hooks/useFetch.js index ad4a0de8e8..a50bfdd133 100644 --- a/src/fireedge/src/client/hooks/useFetch.js +++ b/src/fireedge/src/client/hooks/useFetch.js @@ -69,7 +69,7 @@ const useFetch = (request, socket) => { }, []) const doFetch = useCallback(async (payload, reload = false) => { - dispatch({ type: ACTIONS.REQUEST, reload }) + !cancelRequest.current && dispatch({ type: ACTIONS.REQUEST, reload }) try { const response = await request(payload) diff --git a/src/fireedge/src/client/router/dev.js b/src/fireedge/src/client/router/dev.js index f0315c6a9d..bd3b2a5108 100644 --- a/src/fireedge/src/client/router/dev.js +++ b/src/fireedge/src/client/router/dev.js @@ -1,25 +1,13 @@ import loadable from '@loadable/component' -import { - Code as DevIcon, - ViewGrid as NewstoneIcon -} from 'iconoir-react' +import { Code as DevIcon } from 'iconoir-react' -const Newstone = loadable(() => import('client/containers/Newstone'), { ssr: false }) const TestApi = loadable(() => import('client/containers/TestApi'), { ssr: false }) export const PATH = { - NEWSTONE: '/newstone/:resource', TEST_API: '/test-api' } export const ENDPOINTS = [ - { - label: 'Newstone', - path: PATH.NEWSTONE, - sidebar: true, - icon: NewstoneIcon, - Component: Newstone - }, { label: 'Test API', path: PATH.TEST_API, diff --git a/src/fireedge/src/client/router/index.js b/src/fireedge/src/client/router/index.js index c7f7879f3c..08b09cad98 100644 --- a/src/fireedge/src/client/router/index.js +++ b/src/fireedge/src/client/router/index.js @@ -18,6 +18,7 @@ import PropTypes from 'prop-types' import { Redirect, Route, Switch } from 'react-router-dom' import { TransitionGroup } from 'react-transition-group' +import { LinearProgress } from '@material-ui/core' import devRoutes from 'client/router/dev' import commonRoutes from 'client/router/common' @@ -28,51 +29,67 @@ import Sidebar from 'client/components/Sidebar' import Notifier from 'client/components/Notifier' import { isDevelopment } from 'client/utils' -const Router = ({ routes }) => { +const Router = ({ isLogged, routes }) => { const ENDPOINTS = React.useMemo(() => [ ...routes.ENDPOINTS, ...(isDevelopment() ? devRoutes.ENDPOINTS : []) ], []) + const renderRoute = React.useCallback( + ({ Component, ...rest }, index) => ( + + + } /> + + + ), []) + return ( - - - {ENDPOINTS?.map(({ Component, ...rest }, index, endpoints) => - - - - + <> + {isLogged && ( + <> + + + + )} + + + {ENDPOINTS?.map(({ routes: subRoutes, ...rest }, index) => + Array.isArray(subRoutes) + ? subRoutes?.map(renderRoute) + : renderRoute(rest, index) + )} + {commonRoutes.ENDPOINTS?.map(({ Component, ...rest }, index) => + - - - )} - {commonRoutes.ENDPOINTS?.map(({ Component, ...rest }, index) => - - - - )} - } /> - - + + )} + } /> + + + ) } Router.propTypes = { + isLogged: PropTypes.bool, routes: PropTypes.shape({ PATH: PropTypes.object, ENDPOINTS: PropTypes.arrayOf( PropTypes.shape({ - Component: PropTypes.object.isRequired, + Component: PropTypes.object, icon: PropTypes.object, label: PropTypes.string.isRequired, - path: PropTypes.string.isRequired, - sidebar: PropTypes.bool + path: PropTypes.string, + sidebar: PropTypes.bool, + routes: PropTypes.array }) ) }) } Router.defaultProps = { + isLogged: false, routes: { PATH: {}, ENDPOINTS: [] diff --git a/src/fireedge/src/client/sunstone.js b/src/fireedge/src/client/sunstone.js index edd78b1616..42b8377f96 100644 --- a/src/fireedge/src/client/sunstone.js +++ b/src/fireedge/src/client/sunstone.js @@ -17,7 +17,7 @@ import * as React from 'react' import { hydrate, render } from 'react-dom' import { createStore } from 'client/store' -import App from 'client/apps/flow' +import App from 'client/apps/sunstone' const { store } = createStore({ initState: window.REDUX_DATA })