Adds dynamically generated installation instructions
This commit is contained in:
226
src/lib/InstallationInstructions.svelte
Normal file
226
src/lib/InstallationInstructions.svelte
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
import { templatesUrl, gitHubRepo } from '$src/constants';
|
||||||
|
import type { Template, Volume, Service } from '$src/Types';
|
||||||
|
|
||||||
|
export let portainerTemplate: Template | null = null;
|
||||||
|
export let portainerServices: Service[] | null = null;
|
||||||
|
|
||||||
|
const copyToClipboard = (content: string) => {
|
||||||
|
navigator.clipboard.writeText(content);
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateDockerRunCommand = (template: Template) => {
|
||||||
|
let command = `docker run -d \\ \n`;
|
||||||
|
if (template.ports) {
|
||||||
|
template.ports.forEach((port) => {
|
||||||
|
command += ` -p ${port} \\\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (template.env) {
|
||||||
|
template.env.forEach((env) => {
|
||||||
|
command += ` -e ${env.name}=\${${env.name}} \\\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (template.volumes) {
|
||||||
|
template.volumes.forEach((volume: Volume) => {
|
||||||
|
const readOnly = volume.readonly ? ":ro" : "";
|
||||||
|
command += ` -v ${volume.bind}:${volume.container}${readOnly} \\\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (template.restart_policy) {
|
||||||
|
command += ` --restart=${template.restart_policy} \\\n`;
|
||||||
|
}
|
||||||
|
command += ` ${template.image}`;
|
||||||
|
return command;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateDockerRunCommands = (stack: Service[]) => {
|
||||||
|
const commands = stack.map((service) => {
|
||||||
|
let cmd = `docker run --name ${service.name} -d \\\n`;
|
||||||
|
if (service.command) {
|
||||||
|
cmd += ` ${service.command} \\\n`;
|
||||||
|
}
|
||||||
|
if (service.env) {
|
||||||
|
service.env.forEach((envVar) => {
|
||||||
|
cmd += ` -e "${envVar.value}" \\\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (service.ports) {
|
||||||
|
service.ports.forEach((port) => {
|
||||||
|
cmd += ` -p ${port} \\\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (service.volumes) {
|
||||||
|
service.volumes.forEach((volume) => {
|
||||||
|
cmd += ` -v ${volume.bind}:${volume.container} \\\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (service.restart_policy) {
|
||||||
|
cmd += ` --restart=${service.restart_policy} \\\n`;
|
||||||
|
}
|
||||||
|
cmd += ` ${service.image}`;
|
||||||
|
return cmd;
|
||||||
|
});
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dockerRunCommand = portainerTemplate?.image ? generateDockerRunCommand(portainerTemplate) : null;
|
||||||
|
const dockerRunCommands = portainerServices && !dockerRunCommand ? generateDockerRunCommands(portainerServices) : null;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Installation</h2>
|
||||||
|
|
||||||
|
<h3>Via Portainer</h3>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
Ensure both
|
||||||
|
<a href="https://docs.docker.com/engine/install/">Docker</a> and
|
||||||
|
<a href="https://www.portainer.io/installation/">Portainer</a> are installed, and up-to-date
|
||||||
|
</li>
|
||||||
|
<li>Log into your Portainer web UI
|
||||||
|
<li>Under Settings → App Templates, paste the below URL</li>
|
||||||
|
<li>Head to Home → App Templates, and the list of apps will show up</li>
|
||||||
|
<li>Select the app you wish to deploy, fill in any config options, and hit Deploy</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h4>Template Import URL</h4>
|
||||||
|
<pre>{templatesUrl}</pre>
|
||||||
|
<button on:click={() => copyToClipboard(templatesUrl)}>Copy</button>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Show Me</summary>
|
||||||
|
<img class="demo" src="https://i.ibb.co/XxGRjrs/portainer-templates-installation.gif" alt="demo" />
|
||||||
|
</details>
|
||||||
|
|
||||||
|
{#if dockerRunCommand}
|
||||||
|
<hr />
|
||||||
|
<h3>Via Docker Run</h3>
|
||||||
|
<div class="docker-run-command">
|
||||||
|
<button class="docker-command-copy" on:click={() => copyToClipboard(dockerRunCommand)}>Copy</button>
|
||||||
|
<pre>{dockerRunCommand}</pre>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if dockerRunCommands}
|
||||||
|
<hr />
|
||||||
|
<h3>Via Docker Run</h3>
|
||||||
|
|
||||||
|
{#each dockerRunCommands as command, index}
|
||||||
|
<h4>Service #{index + 1} - {portainerServices[index].name}</h4>
|
||||||
|
<div class="docker-run-command">
|
||||||
|
<button class="docker-command-copy" on:click={() => copyToClipboard(command)}>Copy</button>
|
||||||
|
<pre>{command}</pre>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<h3>Alternative Methods</h3>
|
||||||
|
<p>For more installation options, see the <a href={gitHubRepo}>Documentation</a> in the GitHub repo</p>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
section {
|
||||||
|
background: var(--card);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin: 1rem auto;
|
||||||
|
max-width: 1000px;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
margin: 0.5rem;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
li {
|
||||||
|
counter-increment: item;
|
||||||
|
}
|
||||||
|
li:before {
|
||||||
|
content: counter(item);
|
||||||
|
color: var(--accent);
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
width: 1ch;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
opacity: 0.5;
|
||||||
|
margin: 1.5rem auto;
|
||||||
|
height: 2px;
|
||||||
|
border: none;
|
||||||
|
background: var(--accent);
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
background: var(--card-2);
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
display: inline;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background: var(--background);
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: none;
|
||||||
|
color: var(--foreground);
|
||||||
|
font-family: Kanit;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
&:hover {
|
||||||
|
background: var(--gradient);
|
||||||
|
transform: scale(1.1) rotate(-1deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
details {
|
||||||
|
summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.demo {
|
||||||
|
display: block;
|
||||||
|
margin: 0.5rem auto;
|
||||||
|
border-radius: 6px;
|
||||||
|
max-width: 50rem;
|
||||||
|
}
|
||||||
|
.docker-run-command {
|
||||||
|
background: var(--card-2);
|
||||||
|
position: relative;
|
||||||
|
padding: 0.5rem;
|
||||||
|
.docker-command-copy {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5rem;
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
9
src/routes/usage/+page.svelte
Normal file
9
src/routes/usage/+page.svelte
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import InstallationInstructions from '$lib/InstallationInstructions.svelte';
|
||||||
|
import Header from '$lib/Header.svelte';
|
||||||
|
import Footer from '$lib/Footer.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Header />
|
||||||
|
<InstallationInstructions />
|
||||||
|
<Footer bottom />
|
||||||
Reference in New Issue
Block a user