ui: Better layout for root team

This commit is contained in:
Andras Bacsai 2022-04-07 15:23:32 +02:00
parent 5bf14f4639
commit 2f8d0ee60c
12 changed files with 396 additions and 132 deletions

View File

@ -100,6 +100,7 @@ export const getUserDetails = async (event, isAdminRequired = true) => {
message: 'OK' message: 'OK'
} }
}; };
if (isAdminRequired && permission !== 'admin' && permission !== 'owner') { if (isAdminRequired && permission !== 'admin' && permission !== 'owner') {
payload.status = 401; payload.status = 401;
payload.body.message = payload.body.message =

View File

@ -12,7 +12,7 @@
if (!session.userId) { if (!session.userId) {
return {}; return {};
} }
const endpoint = `/teams.json`; const endpoint = `/dashboard.json`;
const res = await fetch(endpoint); const res = await fetch(endpoint);
if (res.ok) { if (res.ok) {

View File

@ -8,6 +8,16 @@
const { id } = await post('/applications/new', {}); const { id } = await post('/applications/new', {});
return await goto(`/applications/${id}`, { replaceState: true }); return await goto(`/applications/${id}`, { replaceState: true });
} }
const ownApplications = applications.filter((application) => {
if (application.teams[0].id === $session.teamId) {
return application;
}
});
const otherApplications = applications.filter((application) => {
if (application.teams[0].id !== $session.teamId) {
return application;
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -36,8 +46,23 @@
<div class="text-center text-xl font-bold">No applications found</div> <div class="text-center text-xl font-bold">No applications found</div>
</div> </div>
{:else} {:else}
{#each applications as application} <div class="flex flex-col">
<Application {application} /> {#if $session.teamId === '0'}
{/each} <div class="text-xl font-bold pb-5 -ml-10">Your Team's Applications</div>
{/if}
<div class="flex flex-col md:flex-row">
{#each ownApplications as application}
<Application {application} />
{/each}
</div>
{#if otherApplications.length > 0 && $session.teamId === '0'}
<div class="text-xl font-bold pb-5 pt-10 -ml-10">Other Team's Applications</div>
<div class="flex">
{#each otherApplications as application}
<Application {application} />
{/each}
</div>
{/if}
</div>
{/if} {/if}
</div> </div>

View File

@ -9,23 +9,28 @@ export const get: RequestHandler = async (event) => {
try { try {
const applicationsCount = await db.prisma.application.count({ const applicationsCount = await db.prisma.application.count({
where: { teams: { some: { id: teamId } } } where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
}); });
const sourcesCount = await db.prisma.gitSource.count({ const sourcesCount = await db.prisma.gitSource.count({
where: { teams: { some: { id: teamId } } } where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
}); });
const destinationsCount = await db.prisma.destinationDocker.count({ const destinationsCount = await db.prisma.destinationDocker.count({
where: { teams: { some: { id: teamId } } } where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
}); });
const teamsCount = await db.prisma.permission.count({ where: { userId } }); const teamsCount = await db.prisma.permission.count({ where: { userId } });
const databasesCount = await db.prisma.database.count({ const databasesCount = await db.prisma.database.count({
where: { teams: { some: { id: teamId } } } where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
}); });
const servicesCount = await db.prisma.service.count({ const servicesCount = await db.prisma.service.count({
where: { teams: { some: { id: teamId } } } where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
});
const teams = await db.prisma.permission.findMany({
where: { userId },
include: { team: { include: { _count: { select: { users: true } } } } }
}); });
return { return {
body: { body: {
teams,
applicationsCount, applicationsCount,
sourcesCount, sourcesCount,
destinationsCount, destinationsCount,

View File

@ -14,6 +14,16 @@
const { id } = await post('/databases/new', {}); const { id } = await post('/databases/new', {});
return await goto(`/databases/${id}`, { replaceState: true }); return await goto(`/databases/${id}`, { replaceState: true });
} }
const ownDatabases = databases.filter((database) => {
if (database.teams[0].id === $session.teamId) {
return database;
}
});
const otherDatabases = databases.filter((database) => {
if (database.teams[0].id !== $session.teamId) {
return database;
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -41,37 +51,81 @@
<div class="text-center text-xl font-bold">No databases found</div> <div class="text-center text-xl font-bold">No databases found</div>
</div> </div>
{:else} {:else}
{#each databases as database} <div class="flex flex-col">
<a href="/databases/{database.id}" class="no-underline p-2 w-96"> {#if $session.teamId === '0'}
<div class="box-selection relative hover:bg-purple-600 group"> <div class="text-xl font-bold pb-5 -ml-10">Your Team's Databases</div>
{#if database.type === 'clickhouse'} {/if}
<Clickhouse isAbsolute /> <div class="flex flex-col md:flex-row">
{:else if database.type === 'couchdb'} {#each ownDatabases as database}
<CouchDB isAbsolute /> <a href="/databases/{database.id}" class="no-underline p-2 w-96">
{:else if database.type === 'mongodb'} <div class="box-selection relative hover:bg-purple-600 group">
<MongoDB isAbsolute /> {#if database.type === 'clickhouse'}
{:else if database.type === 'mysql'} <Clickhouse isAbsolute />
<MySQL isAbsolute /> {:else if database.type === 'couchdb'}
{:else if database.type === 'postgresql'} <CouchDB isAbsolute />
<PostgreSQL isAbsolute /> {:else if database.type === 'mongodb'}
{:else if database.type === 'redis'} <MongoDB isAbsolute />
<Redis isAbsolute /> {:else if database.type === 'mysql'}
{/if} <MySQL isAbsolute />
<div class="font-bold text-xl text-center truncate"> {:else if database.type === 'postgresql'}
{database.name} <PostgreSQL isAbsolute />
</div> {:else if database.type === 'redis'}
{#if $session.teamId === '0'} <Redis isAbsolute />
<div class="text-center truncate">Team {database.teams[0].name}</div> {/if}
{/if} <div class="font-bold text-xl text-center truncate">
{#if !database.type} {database.name}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white"> </div>
Configuration missing {#if $session.teamId === '0'}
<div class="text-center truncate">Team {database.teams[0].name}</div>
{/if}
{#if !database.type}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
Configuration missing
</div>
{:else}
<div class="text-center truncate">{database.type}</div>
{/if}
</div> </div>
{:else} </a>
<div class="text-center truncate">{database.type}</div> {/each}
{/if} </div>
{#if otherDatabases.length > 0 && $session.teamId === '0'}
<div class="text-xl font-bold pb-5 pt-10 -ml-10">Other Team's Databases</div>
<div class="flex">
{#each otherDatabases as database}
<a href="/databases/{database.id}" class="no-underline p-2 w-96">
<div class="box-selection relative hover:bg-purple-600 group">
{#if database.type === 'clickhouse'}
<Clickhouse isAbsolute />
{:else if database.type === 'couchdb'}
<CouchDB isAbsolute />
{:else if database.type === 'mongodb'}
<MongoDB isAbsolute />
{:else if database.type === 'mysql'}
<MySQL isAbsolute />
{:else if database.type === 'postgresql'}
<PostgreSQL isAbsolute />
{:else if database.type === 'redis'}
<Redis isAbsolute />
{/if}
<div class="font-bold text-xl text-center truncate">
{database.name}
</div>
{#if $session.teamId === '0'}
<div class="text-center truncate">Team {database.teams[0].name}</div>
{/if}
{#if !database.type}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
Configuration missing
</div>
{:else}
<div class="text-center truncate">{database.type}</div>
{/if}
</div>
</a>
{/each}
</div> </div>
</a> {/if}
{/each} </div>
{/if} {/if}
</div> </div>

View File

@ -24,6 +24,16 @@
import { session } from '$app/stores'; import { session } from '$app/stores';
export let destinations: Prisma.DestinationDocker[]; export let destinations: Prisma.DestinationDocker[];
const ownDestinations = destinations.filter((destination) => {
if (destination.teams[0].id === $session.teamId) {
return destination;
}
});
const otherDestinations = destinations.filter((destination) => {
if (destination.teams[0].id !== $session.teamId) {
return destination;
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -52,18 +62,40 @@
<div class="text-center text-xl font-bold">No destination found</div> <div class="text-center text-xl font-bold">No destination found</div>
</div> </div>
{:else} {:else}
<div class="flex flex-wrap justify-center"> <div class="flex flex-col">
{#each destinations as destination} {#if $session.teamId === '0'}
<a href="/destinations/{destination.id}" class="no-underline p-2 w-96"> <div class="text-xl font-bold pb-5 -ml-10">Your Team's Destinations</div>
<div class="box-selection hover:bg-sky-600"> {/if}
<div class="font-bold text-xl text-center truncate">{destination.name}</div> <div class="flex flex-col md:flex-row">
{#if $session.teamId === '0'} {#each ownDestinations as destination}
<div class="text-center truncate">Team {destination.teams[0].name}</div> <a href="/destinations/{destination.id}" class="no-underline p-2 w-96">
{/if} <div class="box-selection hover:bg-sky-600">
<div class="text-center truncate">{destination.network}</div> <div class="font-bold text-xl text-center truncate">{destination.name}</div>
</div> {#if $session.teamId === '0'}
</a> <div class="text-center truncate">Team {destination.teams[0].name}</div>
{/each} {/if}
<div class="text-center truncate">{destination.network}</div>
</div>
</a>
{/each}
</div>
{#if otherDestinations.length > 0 && $session.teamId === '0'}
<div class="text-xl font-bold pb-5 pt-10 -ml-10">Other Team's Destinations</div>
<div class="flex">
{#each otherDestinations as destination}
<a href="/destinations/{destination.id}" class="no-underline p-2 w-96">
<div class="box-selection hover:bg-sky-600">
<div class="font-bold text-xl text-center truncate">{destination.name}</div>
{#if $session.teamId === '0'}
<div class="text-center truncate">Team {destination.teams[0].name}</div>
{/if}
<div class="text-center truncate">{destination.network}</div>
</div>
</a>
{/each}
</div>
{/if}
</div> </div>
{/if} {/if}
</div> </div>

View File

@ -19,6 +19,16 @@
const { id } = await post('/services/new', {}); const { id } = await post('/services/new', {});
return await goto(`/services/${id}`, { replaceState: true }); return await goto(`/services/${id}`, { replaceState: true });
} }
const ownServices = services.filter((service) => {
if (service.teams[0].id === $session.teamId) {
return service;
}
});
const otherServices = services.filter((service) => {
if (service.teams[0].id !== $session.teamId) {
return service;
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -46,47 +56,101 @@
<div class="text-center text-xl font-bold">No services found</div> <div class="text-center text-xl font-bold">No services found</div>
</div> </div>
{:else} {:else}
{#each services as service} <div class="flex flex-col">
<a href="/services/{service.id}" class="no-underline p-2 w-96"> {#if $session.teamId === '0'}
<div class="box-selection relative hover:bg-pink-600 group"> <div class="text-xl font-bold pb-5 -ml-10">Your Team's Applications</div>
{#if service.type === 'plausibleanalytics'} {/if}
<PlausibleAnalytics isAbsolute /> <div class="flex flex-col md:flex-row">
{:else if service.type === 'nocodb'} {#each ownServices as service}
<NocoDb isAbsolute /> <a href="/services/{service.id}" class="no-underline p-2 w-96">
{:else if service.type === 'minio'} <div class="box-selection relative hover:bg-pink-600 group">
<MinIo isAbsolute /> {#if service.type === 'plausibleanalytics'}
{:else if service.type === 'vscodeserver'} <PlausibleAnalytics isAbsolute />
<VsCodeServer isAbsolute /> {:else if service.type === 'nocodb'}
{:else if service.type === 'wordpress'} <NocoDb isAbsolute />
<Wordpress isAbsolute /> {:else if service.type === 'minio'}
{:else if service.type === 'vaultwarden'} <MinIo isAbsolute />
<VaultWarden isAbsolute /> {:else if service.type === 'vscodeserver'}
{:else if service.type === 'languagetool'} <VsCodeServer isAbsolute />
<LanguageTool isAbsolute /> {:else if service.type === 'wordpress'}
{:else if service.type === 'n8n'} <Wordpress isAbsolute />
<N8n isAbsolute /> {:else if service.type === 'vaultwarden'}
{:else if service.type === 'uptimekuma'} <VaultWarden isAbsolute />
<UptimeKuma isAbsolute /> {:else if service.type === 'languagetool'}
{:else if service.type === 'ghost'} <LanguageTool isAbsolute />
<Ghost isAbsolute /> {:else if service.type === 'n8n'}
{:else if service.type === 'meilisearch'} <N8n isAbsolute />
<MeiliSearch isAbsolute /> {:else if service.type === 'uptimekuma'}
{/if} <UptimeKuma isAbsolute />
<div class="font-bold text-xl text-center truncate"> {:else if service.type === 'ghost'}
{service.name} <Ghost isAbsolute />
</div> {:else if service.type === 'meilisearch'}
{#if $session.teamId === '0'} <MeiliSearch isAbsolute />
<div class="text-center truncate">Team {service.teams[0].name}</div> {/if}
{/if} <div class="font-bold text-xl text-center truncate">
{#if !service.type || !service.fqdn} {service.name}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white"> </div>
Configuration missing {#if $session.teamId === '0'}
<div class="text-center truncate">Team {service.teams[0].name}</div>
{/if}
{#if !service.type || !service.fqdn}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
Configuration missing
</div>
{:else}
<div class="text-center truncate">{service.type}</div>
{/if}
</div> </div>
{:else} </a>
<div class="text-center truncate">{service.type}</div> {/each}
{/if} </div>
{#if otherServices.length > 0 && $session.teamId === '0'}
<div class="text-xl font-bold pb-5 pt-10 -ml-10">Other Team's Applications</div>
<div class="flex">
{#each otherServices as service}
<a href="/services/{service.id}" class="no-underline p-2 w-96">
<div class="box-selection relative hover:bg-pink-600 group">
{#if service.type === 'plausibleanalytics'}
<PlausibleAnalytics isAbsolute />
{:else if service.type === 'nocodb'}
<NocoDb isAbsolute />
{:else if service.type === 'minio'}
<MinIo isAbsolute />
{:else if service.type === 'vscodeserver'}
<VsCodeServer isAbsolute />
{:else if service.type === 'wordpress'}
<Wordpress isAbsolute />
{:else if service.type === 'vaultwarden'}
<VaultWarden isAbsolute />
{:else if service.type === 'languagetool'}
<LanguageTool isAbsolute />
{:else if service.type === 'n8n'}
<N8n isAbsolute />
{:else if service.type === 'uptimekuma'}
<UptimeKuma isAbsolute />
{:else if service.type === 'ghost'}
<Ghost isAbsolute />
{:else if service.type === 'meilisearch'}
<MeiliSearch isAbsolute />
{/if}
<div class="font-bold text-xl text-center truncate">
{service.name}
</div>
{#if $session.teamId === '0'}
<div class="text-center truncate">Team {service.teams[0].name}</div>
{/if}
{#if !service.type || !service.fqdn}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
Configuration missing
</div>
{:else}
<div class="text-center truncate">{service.type}</div>
{/if}
</div>
</a>
{/each}
</div> </div>
</a> {/if}
{/each} </div>
{/if} {/if}
</div> </div>

View File

@ -5,9 +5,9 @@ import type { RequestHandler } from '@sveltejs/kit';
import { promises as dns } from 'dns'; import { promises as dns } from 'dns';
export const get: RequestHandler = async (event) => { export const get: RequestHandler = async (event) => {
const { status, body } = await getUserDetails(event); const { teamId, status, body } = await getUserDetails(event);
if (status === 401) return { status, body }; if (status === 401) return { status, body };
if (teamId !== '0') return { status: 401, body: { message: 'You are not an admin.' } };
try { try {
const settings = await listSettings(); const settings = await listSettings();
return { return {

View File

@ -11,7 +11,12 @@
} }
}; };
} }
if (res.status === 401) {
return {
status: 302,
redirect: '/databases'
};
}
return { return {
status: res.status, status: res.status,
error: new Error(`Could not load ${url}`) error: new Error(`Could not load ${url}`)

View File

@ -22,6 +22,16 @@
<script lang="ts"> <script lang="ts">
export let sources; export let sources;
import { session } from '$app/stores'; import { session } from '$app/stores';
const ownSources = sources.filter((source) => {
if (source.teams[0].id === $session.teamId) {
return source;
}
});
const otherSources = sources.filter((source) => {
if (source.teams[0].id !== $session.teamId) {
return source;
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -50,29 +60,62 @@
<div class="text-center text-xl font-bold">No git sources found</div> <div class="text-center text-xl font-bold">No git sources found</div>
</div> </div>
{:else} {:else}
<div class="flex flex-wrap justify-center"> <div class="flex flex-col">
{#each sources as source} {#if $session.teamId === '0'}
<a href="/sources/{source.id}" class="no-underline p-2 w-96"> <div class="text-xl font-bold pb-5 -ml-10">Your Team's Applications</div>
<div {/if}
class="box-selection hover:bg-orange-600 group" <div class="flex flex-col md:flex-row">
class:border-red-500={source.gitlabApp && !source.gitlabAppId} {#each ownSources as source}
class:border-0={source.gitlabApp && !source.gitlabAppId} <a href="/sources/{source.id}" class="no-underline p-2 w-96">
class:border-l-4={source.gitlabApp && !source.gitlabAppId} <div
> class="box-selection hover:bg-orange-600 group"
<div class="font-bold text-xl text-center truncate">{source.name}</div> class:border-red-500={source.gitlabApp && !source.gitlabAppId}
{#if $session.teamId === '0'} class:border-0={source.gitlabApp && !source.gitlabAppId}
<div class="text-center truncate">Team {source.teams[0].name}</div> class:border-l-4={source.gitlabApp && !source.gitlabAppId}
{/if} >
{#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)} <div class="font-bold text-xl text-center truncate">{source.name}</div>
<div class="font-bold text-center truncate text-red-500 group-hover:text-white"> {#if $session.teamId === '0'}
Configuration missing <div class="text-center truncate">Team {source.teams[0].name}</div>
{/if}
{#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
Configuration missing
</div>
{:else}
<div class="truncate text-center">{source.htmlUrl}</div>
{/if}
</div>
</a>
{/each}
</div>
{#if otherSources.length > 0 && $session.teamId === '0'}
<div class="text-xl font-bold pb-5 pt-10 -ml-10">Other Team's Applications</div>
<div class="flex">
{#each otherSources as source}
<a href="/sources/{source.id}" class="no-underline p-2 w-96">
<div
class="box-selection hover:bg-orange-600 group"
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
class:border-0={source.gitlabApp && !source.gitlabAppId}
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
>
<div class="font-bold text-xl text-center truncate">{source.name}</div>
{#if $session.teamId === '0'}
<div class="text-center truncate">Team {source.teams[0].name}</div>
{/if}
{#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)}
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
Configuration missing
</div>
{:else}
<div class="truncate text-center">{source.htmlUrl}</div>
{/if}
</div> </div>
{:else} </a>
<div class="truncate text-center">{source.htmlUrl}</div> {/each}
{/if} </div>
</div> {/if}
</a>
{/each}
</div> </div>
{/if} {/if}
</div> </div>

View File

@ -9,7 +9,7 @@ export const get: RequestHandler = async (event) => {
try { try {
const teams = await db.prisma.permission.findMany({ const teams = await db.prisma.permission.findMany({
where: { userId: teamId === '0' ? undefined : teamId }, where: { userId: teamId === '0' ? undefined : userId },
include: { team: { include: { _count: { select: { users: true } } } } } include: { team: { include: { _count: { select: { users: true } } } } }
}); });

View File

@ -43,6 +43,16 @@
return errorNotification(error); return errorNotification(error);
} }
} }
const ownTeams = teams.filter((team) => {
if (team.team.id === $session.teamId) {
return team;
}
});
const otherTeams = teams.filter((team) => {
if (team.team.id !== $session.teamId) {
return team;
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -92,20 +102,45 @@
</div> </div>
{/if} {/if}
<div class="flex flex-wrap justify-center"> <div class="flex flex-wrap justify-center">
{#each teams as team} <div class="flex flex-col">
<a href="/teams/{team.teamId}" class="w-96 p-2 no-underline"> <div class="-ml-10 pb-5 text-xl font-bold">Current Team</div>
<div <div class="flex flex-col md:flex-row">
class="box-selection relative" {#each ownTeams as team}
class:hover:bg-cyan-600={team.team?.id !== '0'} <a href="/teams/{team.teamId}" class="w-96 p-2 no-underline">
class:hover:bg-red-500={team.team?.id === '0'} <div
> class="box-selection relative"
<div class="truncate text-center text-xl font-bold"> class:hover:bg-cyan-600={team.team?.id !== '0'}
{team.team.name} class:hover:bg-red-500={team.team?.id === '0'}
{team.team?.id === '0' ? '(root)' : ''} >
</div> <div class="truncate text-center text-xl font-bold">
{team.team.name}
{team.team?.id === '0' ? '(admin team)' : ''}
</div>
<div class="mt-1 text-center">{team.team._count.users} member(s)</div> <div class="mt-1 text-center">{team.team._count.users} member(s)</div>
</div> </div>
</a> </a>
{/each} {/each}
</div>
<div class="-ml-10 pb-5 pt-10 text-xl font-bold">Other Teams</div>
<div class="flex">
{#each otherTeams as team}
<a href="/teams/{team.teamId}" class="w-96 p-2 no-underline">
<div
class="box-selection relative"
class:hover:bg-cyan-600={team.team?.id !== '0'}
class:hover:bg-red-500={team.team?.id === '0'}
>
<div class="truncate text-center text-xl font-bold">
{team.team.name}
{team.team?.id === '0' ? '(admin team)' : ''}
</div>
<div class="mt-1 text-center">{team.team._count.users} member(s)</div>
</div>
</a>
{/each}
</div>
</div>
</div> </div>