This commit is contained in:
Alicia Sykes
2023-04-21 11:10:00 +01:00
parent 11e43843a8
commit 56b52ade1e
4 changed files with 265 additions and 93 deletions

View File

@@ -12,11 +12,15 @@ export interface Template {
command?: string;
interactive?: boolean;
logo: string;
image: string;
image?: string;
restart_policy?: 'always' | 'unless-stopped' | 'on-failure' | 'no';
ports?: string[];
volumes?: Volume[];
environment?: Environment[];
env?: Environment[];
repository?: {
stackfile: string;
url: string;
};
}
export interface Volume {
@@ -27,4 +31,20 @@ export interface Volume {
export interface Environment {
name: string;
label?: string;
set?: string;
}
export interface Service {
name: string;
image?: string;
entrypoint?: string;
restart_policy?: 'always' | 'unless-stopped' | 'on-failure' | 'no';
volumes?: Volume[];
command?: string;
ports?: string[];
build?: string;
interactive?: boolean;
environment?: Environment[];
}
export interface TemplateOrService extends Template, Service {}

129
src/lib/ServiceStats.svelte Normal file
View File

@@ -0,0 +1,129 @@
<script lang="ts">
import type { TemplateOrService } from '$src/Types';
export let template: TemplateOrService;
</script>
<div class="stats">
{#if template.type}
<div class="row">
<span class="lbl">Type</span>
{#if template.type === 1}
<span>Container</span>
{:else if template.type === 2}
<span>Swarm</span>
{:else if template.type === 3}
<span>Kubernetes</span>
{:else}
<span>Unknown</span>
{/if}
</div>
{/if}
{#if template.platform}
<div class="row">
<span class="lbl">Platform</span>
<code>{template.platform}</code>
</div>
{/if}
{#if template.image}
<div class="row">
<span class="lbl">Image</span>
<code>{template.image}</code>
</div>
{/if}
{#if template.command}
<div class="row">
<span class="lbl">Command</span>
<code>{template.command}</code>
</div>
{/if}
{#if typeof template.interactive === 'boolean'}
<div class="row">
<span class="lbl">Interactive</span>
<code>{template.interactive ? 'Yes' : 'No'}</code>
</div>
{/if}
{#if template.ports}
<div class="row">
<span class="lbl">Ports</span>
<p>
{#each template.ports as port}<code>{port}</code>{/each}
</p>
</div>
{/if}
{#if template.volumes}
<div class="row">
<span class="lbl">Volumes</span>
<p>
{#each template.volumes as volume}<code>{volume.container || volume}</code>{/each}
</p>
</div>
{/if}
{#if template.restart_policy}
<div class="row">
<span class="lbl">Restart Policy</span>
<code>{template.restart_policy}</code>
</div>
{/if}
{#if template.repository}
<div class="row">
<span class="lbl">Sourced</span>
<a href={template.repository.url}>Repo</a>
</div>
{/if}
{#if template.entrypoint}
<div class="row">
<span class="lbl">Entrypoint</span>
<code>{template.entrypoint}</code>
</div>
{/if}
{#if template.build}
<div class="row">
<span class="lbl">Build</span>
<code>{template.build}</code>
</div>
{/if}
{#if template.env}
<div class="row">
<span class="lbl">Env Vars</span>
<p>
{#each template.env as env}<code>{env.name}={env.set || env.value || env.default}</code>{/each}
</p>
</div>
{/if}
</div>
<style lang="scss">
.stats {
min-width: 15rem;
border: 2px solid var(--background);
border-radius: 6px;
.row {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
padding: 0.5rem;
gap: 0.5rem;
&:not(:last-child) {
border-bottom: 2px dotted var(--background);
}
span {
font-style: italic;
}
p {
margin: 0;
display: flex;
flex-direction: column;
}
.lbl {
font-weight: 400;
font-style: normal;
min-width: 5rem;
}
a {
color: var(--accent);
}
}
}
</style>

View File

@@ -11,7 +11,6 @@ export const load = async () => {
} else {
const data = await fetch(templatesUrl).then((res) => res.json());
templates.set(data.templates);
return {
templates: data.templates,
}

View File

@@ -1,8 +1,11 @@
<script lang="ts">
import yaml from 'js-yaml';
import { page } from '$app/stores';
import TemplateNotFound from '$lib/TemplateNotFound.svelte';
import type { Template } from '$src/Types';
import type { Template, Service } from '$src/Types';
import ServiceStats from '$lib/ServiceStats.svelte';
const templates = $page.data.templates as Template[];
const templateSlug = $page.params.slug as string;
@@ -11,6 +14,70 @@
);
console.log(template);
type Service = {
name: string;
image: string;
entrypoint: string;
command: string;
ports: string[];
build: string;
interactive: boolean;
volumes: { bind: string; container: string }[];
restart_policy: string;
environment: { name: string; value: string }[];
};
const getServices = async (): Promise<Service[]> => {
try {
if (template?.repository) {
const { url: repoUrl, stackfile } = template.repository;
const path = `${repoUrl.replace(
'github.com',
'raw.githubusercontent.com'
)}/HEAD/${stackfile}`;
const response = await fetch(path);
const data = await response.text();
const parsedData = yaml.load(data);
const someServices: Service[] = [];
if (!parsedData.services) return [];
console.log(parsedData);
Object.keys(parsedData.services).forEach((service) => {
const serviceData = parsedData.services[service];
someServices.push({
name: service,
image: serviceData.image,
entrypoint: serviceData.entrypoint,
command: serviceData.command,
ports: serviceData.ports,
build: serviceData.build,
interactive: serviceData.interactive,
volumes: serviceData.volumes?.map((vol) => ({
bind: vol.split(':')[0],
container: vol.split(':')[1],
})),
restart_policy: serviceData.restart,
env: Object.keys(serviceData.environment || {}).map((envName) => ({
name: envName,
value: serviceData.environment[envName],
})),
});
});
console.log(someServices);
return someServices;
} else {
return [];
}
} catch (error) {
console.error('Error fetching or parsing YAML:', error);
return [];
}
};
const services: Service[] = getServices();
</script>
<header>
@@ -26,74 +93,38 @@
{#if template}
<section class="summary-section">
<h1><img src={template.logo} alt={template.title} />{template.title}</h1>
{#if template.categories}
<h1>
{#if template.logo} <img src={template.logo} /> {/if}
{template.title}
</h1>
{#if template.categories || template.category }
<p class="tags">
{#each (template.categories) as tag}
{#each (template.categories || template.category || []) as tag}
<span>{tag}</span>
{/each}
</p>
{/if}
<div class="content">
<p class="description">{template.description}</p>
<div class="stats">
{#if template.type}
<div class="row">
<span class="lbl">Type</span>
{#if template.type === 1}
<span>Container</span>
{:else if template.type === 2}
<span>Swarm</span>
{:else if template.type === 3}
<span>Kubernetes</span>
{:else}
<span>Unknown</span>
{/if}
</div>
{/if}
{#if template.platform}
<div class="row">
<span class="lbl">Platform</span>
<code>{template.platform}</code>
</div>
{/if}
{#if template.image}
<div class="row">
<span class="lbl">Image</span>
<code>{template.image}</code>
</div>
{/if}
{#if template.command}
<div class="row">
<span class="lbl">Command</span>
<code>{template.command}</code>
</div>
{/if}
{#if typeof template.interactive === 'boolean'}
<div class="row">
<span class="lbl">Interactive</span>
<code>{template.interactive ? 'Yes' : 'No'}</code>
</div>
{/if}
{#if template.ports}
<div class="row">
<span class="lbl">Ports</span>
<p>
{#each template.ports as port}<code>{port}</code>{/each}
</p>
</div>
{/if}
{#if template.volumes}
<div class="row">
<span class="lbl">Volumes</span>
<p>
{#each template.volumes as volume}<code>{volume.container}</code>{/each}
</p>
</div>
{/if}
</div>
<ServiceStats template={template} />
</div>
</section>
{#await services then returnedServices}
{#if returnedServices && returnedServices.length > 0}
<section class="service-section">
<h2>Services</h2>
<div class="service-list">
{#each returnedServices as service}
<div>
<h3>{service.name}</h3>
<ServiceStats template={service} />
</div>
{/each}
</div>
</section>
{/if}
{/await}
{:else}
<TemplateNotFound />
{/if}
@@ -156,6 +187,7 @@
gap: 1rem;
}
img {
border-radius: 6px;
width: 64px;
max-height: 64px;
}
@@ -183,33 +215,25 @@
p.description {
max-width: 60%;
}
.stats {
min-width: 15rem;
border: 2px solid var(--background);
}
.service-section {
background: var(--card);
border-radius: 6px;
.row {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
padding: 0.5rem;
gap: 0.5rem;
&:not(:last-child) {
border-bottom: 2px dotted var(--background);
}
span {
font-style: italic;
}
p {
margin: 1rem;
padding: 1rem;
h2 {
margin: 0;
font-size: 2rem;
}
.service-list {
display: flex;
flex-direction: column;
}
.lbl {
gap: 1rem;
// justify-content: space-between;
flex-wrap: wrap;
h3 {
margin: 0.5rem 0;
font-weight: 400;
font-style: normal;
min-width: 5rem;
}
}
}
}