diff --git a/resources/scripts/components/elements/Spinner.tsx b/resources/scripts/components/elements/Spinner.tsx
index 090980e3f..d1704916f 100644
--- a/resources/scripts/components/elements/Spinner.tsx
+++ b/resources/scripts/components/elements/Spinner.tsx
@@ -1,6 +1,11 @@
import React from 'react';
import classNames from 'classnames';
-export default ({ large }: { large?: boolean }) => (
-
+export default ({ large, centered }: { large?: boolean; centered?: boolean }) => (
+ centered ?
+
+ :
+
);
diff --git a/resources/scripts/components/server/ServerDatabases.tsx b/resources/scripts/components/server/ServerDatabases.tsx
deleted file mode 100644
index a0cf75aac..000000000
--- a/resources/scripts/components/server/ServerDatabases.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import React, { useEffect } from 'react';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faDatabase } from '@fortawesome/free-solid-svg-icons/faDatabase';
-import getServerDatabases from '@/api/server/getServerDatabases';
-import { useStoreState } from 'easy-peasy';
-
-export default () => {
- useEffect(() => {
- getServerDatabases('s');
- }, []);
-
- return (
-
- );
-};
diff --git a/resources/scripts/components/server/databases/DatabaseRow.tsx b/resources/scripts/components/server/databases/DatabaseRow.tsx
new file mode 100644
index 000000000..5638839b9
--- /dev/null
+++ b/resources/scripts/components/server/databases/DatabaseRow.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { ServerDatabase } from '@/api/server/getServerDatabases';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faDatabase } from '@fortawesome/free-solid-svg-icons/faDatabase';
+import { faTrashAlt } from '@fortawesome/free-solid-svg-icons/faTrashAlt';
+import { faEye } from '@fortawesome/free-solid-svg-icons/faEye';
+
+export default ({ database }: { database: ServerDatabase }) => {
+ return (
+
+
+
+
+
+
+
Endpoint:
+
{database.connectionString}
+
+
+
Connections From:
+
{database.allowConnectionsFrom}
+
+
+
Username:
+
{database.username}
+
+
+
+
+
+
+ );
+};
diff --git a/resources/scripts/components/server/databases/DatabasesContainer.tsx b/resources/scripts/components/server/databases/DatabasesContainer.tsx
new file mode 100644
index 000000000..a4843cc80
--- /dev/null
+++ b/resources/scripts/components/server/databases/DatabasesContainer.tsx
@@ -0,0 +1,51 @@
+import React, { useEffect, useState } from 'react';
+import getServerDatabases, { ServerDatabase } from '@/api/server/getServerDatabases';
+import { ServerContext } from '@/state/server';
+import { Actions, useStoreActions } from 'easy-peasy';
+import { ApplicationStore } from '@/state';
+import { httpErrorToHuman } from '@/api/http';
+import FlashMessageRender from '@/components/FlashMessageRender';
+import DatabaseRow from '@/components/server/databases/DatabaseRow';
+import Spinner from '@/components/elements/Spinner';
+import { CSSTransition } from 'react-transition-group';
+
+export default () => {
+ const [ loading, setLoading ] = useState(true);
+ const [ databases, setDatabases ] = useState
([]);
+ const server = ServerContext.useStoreState(state => state.server.data!);
+ const { addFlash, clearFlashes } = useStoreActions((actions: Actions) => actions.flashes);
+
+ useEffect(() => {
+ clearFlashes('databases');
+ getServerDatabases(server.uuid)
+ .then(databases => {
+ setDatabases(databases);
+ setLoading(false);
+ })
+ .catch(error => addFlash({
+ key: 'databases',
+ title: 'Error',
+ message: httpErrorToHuman(error),
+ type: 'error',
+ }));
+ }, []);
+
+ return (
+
+
+ {loading ?
+
+ :
+
+
+ {databases.length > 0 ?
+ databases.map(database => )
+ :
+ No databases. :(
+ }
+
+
+ }
+
+ );
+};
diff --git a/resources/scripts/routers/ServerRouter.tsx b/resources/scripts/routers/ServerRouter.tsx
index 4e2708b86..4b01f0b63 100644
--- a/resources/scripts/routers/ServerRouter.tsx
+++ b/resources/scripts/routers/ServerRouter.tsx
@@ -5,9 +5,9 @@ import ServerConsole from '@/components/server/ServerConsole';
import TransitionRouter from '@/TransitionRouter';
import Spinner from '@/components/elements/Spinner';
import WebsocketHandler from '@/components/server/WebsocketHandler';
-import ServerDatabases from '@/components/server/ServerDatabases';
import { ServerContext } from '@/state/server';
import { Provider } from 'react-redux';
+import DatabasesContainer from '@/components/server/databases/DatabasesContainer';
const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => {
const server = ServerContext.useStoreState(state => state.server.data);
@@ -45,7 +45,7 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
-
+
}
diff --git a/resources/styles/components/miscellaneous.css b/resources/styles/components/miscellaneous.css
index 158970f9b..f023a834b 100644
--- a/resources/styles/components/miscellaneous.css
+++ b/resources/styles/components/miscellaneous.css
@@ -7,114 +7,15 @@ code.clean {
display: inline-block;
}
-/**
- * Indicators for server online status.
- */
-.indicator {
- @apply .bg-neutral-800 .border .border-primary-500;
- border-radius: 50%;
- width: 16px;
- height: 16px;
+.grey-row-box {
+ @apply .flex .rounded .no-underline .text-neutral-200 .items-center .bg-neutral-700 .p-4 .border .border-transparent;
+ transition: border-color 150ms linear;
- &.online {
- @apply .bg-green-600 .border-green-500;
- animation: onlineblink 2s infinite alternate;
+ &:not(.no-hover):hover {
+ @apply .border-neutral-500;
}
- &.offline {
- @apply .bg-green-600 .border-red-500;
- animation: offlineblink 2s infinite alternate;
- }
-}
-
-/**
- * Usage indicator labels for the server listing.
- */
-.usage {
- @apply .flex-1 .text-center .relative;
-
- & > .indicator-title {
- @apply .text-xs .uppercase .font-hairline .bg-white .absolute .text-primary-500;
- margin-top:-9px;
- padding: 0 8px;
- left: 50%;
- transform: translate(-50%, 0);
- }
-}
-
-/**
- * Styling for elements that contain the core page content.
- */
-.content-box {
- @apply .bg-white .p-6 .rounded .shadow .border .border-neutral-100;
-}
-
-/**
- * Flex boxes for server listing on user dashboard.
- */
-.server-card-container {
- @apply .mb-4 .w-full;
-
- @screen md {
- @apply .w-1/2 .pr-4;
-
- &:nth-of-type(2n) {
- @apply .pr-0;
- }
- }
-
- @screen lg {
- @apply .w-1/3 .pr-4;
-
- &:nth-of-type(2n) {
- @apply .pr-4;
- }
-
- &:nth-of-type(3n) {
- @apply .pr-0;
- }
- }
-
- & > div {
- @apply .flex .flex-col;
- transition: box-shadow 150ms ease-in;
-
- &:hover {
- @apply .shadow-md;
- }
- }
-
- & > div > .server-card {
- @apply .flex .flex-col .p-4 .border .border-t-4 .border-neutral-100 .bg-white;
- transition: all 100ms ease-in;
-
- & .identifier-icon {
- @apply .select-none .inline-block .rounded-full .text-white .text-center .leading-none .justify-center .w-8 .h-8 .mr-2 .flex .flex-row .items-center;
- }
-
- & a, & a:visited {
- @apply .no-underline .text-neutral-800;
- }
- }
-
- & > div > .footer {
- @apply .border .border-neutral-100 .border-t-0 .bg-neutral-50 .shadow-inner;
- }
-}
-
-.pillbox {
- @apply .rounded-full .px-2 .py-1 .text-white .font-medium .leading-none .text-xs;
-}
-
-.server-search {
- @apply .w-full .my-4;
-
- & > input[type="text"] {
- @apply .w-full .p-4 .rounded .border .border-neutral-200 .text-neutral-500;
- transition: border 150ms ease-in;
-
- &:focus {
- @apply .border-primary-500;
- }
+ & > div.icon {
+ @apply .rounded-full .bg-neutral-500 .p-3;
}
}