Templating

- Generate snippets for running containers from images
This commit is contained in:
Josh Stark 2020-01-18 13:24:33 +00:00
parent af7849cbb5
commit cd0f025d55
13 changed files with 420 additions and 70 deletions

View File

@ -5,6 +5,12 @@
}
}
.title {
font-family: 'Nunito', sans-serif !important;
font-weight: 600;
letter-spacing: .01rem;
}
.has-text-small {
font-size: 0.85rem;
}
@ -17,6 +23,10 @@
font-weight: 500 !important;
}
.has-text-weight-600 {
font-weight: 600 !important;
}
span.icon i.fas, span.icon i.far, span.icon i.fab {
margin: 0;
}
@ -29,12 +39,6 @@ i.fas, i.far, i.fab {
font-size: 1.8rem;
}
.navbar-title, .repository-title {
font-family: 'Nunito', sans-serif !important;
font-weight: 600;
letter-spacing: .01rem;
}
.has-icon-large i.fas, .has-icon-large i.far, .has-icon-large i.fab {
font-size: 3rem;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,191 @@
/* PrismJS 1.19.0
https://prismjs.com/download.html#themes=prism-okaidia&languages=bash+yaml&plugins=toolbar+copy-to-clipboard */
/**
* okaidia theme for JavaScript, CSS and HTML
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
* @author ocodia
*/
code[class*="language-"],
pre[class*="language-"] {
color: #f8f8f2;
background: none;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #272822;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #f8f8f2;
}
.token.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #f92672;
}
.token.boolean,
.token.number {
color: #ae81ff;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #a6e22e;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #e6db74;
}
.token.keyword {
color: #66d9ef;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
div.code-toolbar {
position: relative;
}
div.code-toolbar > .toolbar {
position: absolute;
top: .3em;
right: .2em;
transition: opacity 0.3s ease-in-out;
opacity: 0;
}
div.code-toolbar:hover > .toolbar {
opacity: 1;
}
/* Separate line b/c rules are thrown out if selector is invalid.
IE11 and old Edge versions don't support :focus-within. */
div.code-toolbar:focus-within > .toolbar {
opacity: 1;
}
div.code-toolbar > .toolbar .toolbar-item {
display: inline-block;
}
div.code-toolbar > .toolbar a {
cursor: pointer;
}
div.code-toolbar > .toolbar button {
background: none;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
-webkit-user-select: none; /* for button */
-moz-user-select: none;
-ms-user-select: none;
}
div.code-toolbar > .toolbar a,
div.code-toolbar > .toolbar button,
div.code-toolbar > .toolbar span {
color: #bbb;
font-size: .8em;
padding: 0 .5em;
background: #f5f2f0;
background: rgba(224, 224, 224, 0.2);
box-shadow: 0 2px 0 0 rgba(0,0,0,0.2);
border-radius: .5em;
}
div.code-toolbar > .toolbar a:hover,
div.code-toolbar > .toolbar a:focus,
div.code-toolbar > .toolbar button:hover,
div.code-toolbar > .toolbar button:focus,
div.code-toolbar > .toolbar span:hover,
div.code-toolbar > .toolbar span:focus {
color: inherit;
text-decoration: none;
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
#Wed Jan 15 21:16:19 GMT 2020
app.build.date=2020-01-15T21\:16\:19
#Sat Jan 18 12:56:52 GMT 2020
app.build.date=2020-01-18T12\:56\:52
app.build.os=Linux
app.build.user=josh
app.version=2.0.0

View File

@ -21,7 +21,7 @@
<div class="columns is-multiline">
<div class="column is-full">
<@input.text id="ImageTemplateUpstreamUrl" label="Registry Url" value=templateHolder.registryUrl!""?html />
<@input.text id="ImageTemplateUpstreamUrl" label="Registry Url" value=templateHolder.registryUrl!"" />
</div>
<div class="column is-3-desktop is-full-tablet is-full-mobile">
<@input.dropdown label="Restart Policy" id="ImageTemplateRestartPolicy">

View File

@ -15,13 +15,15 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<#import "../prebuilt/base.ftl" as base />
<#import "../prebuilt/fleet-title.ftl" as title />
<#import "../ui/layout/section.ftl" as section />
<#import "../ui/layout/container.ftl" as container />
<#import "../ui/elements/box.ftl" as box />
<#import "../ui/elements/table.ftl" as table />
<#import "../ui/elements/tag.ftl" as tag />
<#import "../prebuilt/base.ftl" as base />
<#import "../prebuilt/fleet-title.ftl" as title />
<#import "../prebuilt/docker-example.ftl" as dockerExample />
<#import "../ui/layout/section.ftl" as section />
<#import "../ui/layout/container.ftl" as container />
<#import "../ui/elements/box.ftl" as box />
<#import "../ui/elements/table.ftl" as table />
<#import "../ui/elements/tag.ftl" as tag />
<@base.base title="${(image.fullName)!'Unknown Image'}" context="image" hasHero=false>
@ -35,11 +37,7 @@
<div class="column is-full">
<@title.title icon="cube" thinValue=image.repositoryName boldValue=image.name separator="/" subtitle=image.description>
<#if image.deprecated>
<@tag.tag colour="warning" value="Deprecated" />
</#if>
</@title.title>
<@title.title icon="cube" thinValue=image.repositoryName boldValue=image.name separator="/" subtitle=image.description />
<div class="tags">
@ -53,9 +51,17 @@
</#list>
</#if>
<#if image.deprecated>
<@tag.tag colour="warning" value="Deprecated" />
</#if>
<#if !image.stable>
<@tag.tag colour="danger" value="Unstable" />
</#if>
</div>
</div>
</div>
</@container.container>
@ -65,50 +71,78 @@
<@section.section>
<@container.container>
<div class="columns is-multiline">
<div class="column is-full has-margin-bottom">
<h2 class="title is-5">Build Information</h2>
<h3 class="subtitle is-6">General build information for this image</h3>
<@table.table isFullWidth=true isNarrow=false isStriped=true isScrollable=true>
<thead>
<tr>
<th scope="row" colspan="2"></th>
</tr>
</thead>
<tbody>
<@table.halfDisplayRow title="Repository" value=image.repositoryName link="/?key=${image.repositoryKey}" />
<@table.halfDisplayRow title="Build Time" value=image.lastUpdatedAsString />
<@table.halfDisplayRow title="Synchronised" value=image.syncEnabled?string("Yes", "No") />
<@table.halfDisplayRow title="Stable" value=image.stable?string("Yes", "No") />
<@table.halfDisplayRow title="Deprecated" value=image.deprecated?string("Yes", "No") />
</tbody>
</@table.table>
</div>
<div class="column is-full has-margin-bottom">
<h2 class="title is-5">Tracked Tags</h2>
<h3 class="subtitle is-6">Known tags which link to a specific branched app version.</h3>
<@table.table isFullWidth=true isNarrow=false isStriped=true isScrollable=true>
<thead>
<tr>
<th scope="row" colspan="2"></th>
</tr>
</thead>
<tbody>
<#list image.tagBranches as tagBranch>
<@table.halfDisplayRow title=tagBranch.branchName?html value='<i class="fas fa-tag"></i> ${image.getMaskedVersion(tagBranch.latestTag)}' />
</#list>
</tbody>
</@table.table>
</div>
<div class="columns">
<div class="column is-full">
<div class="columns has-margin-top">
<div class="tabs" data-tabs-for="#ImageViewTabContent">
<ul>
<li data-tab-for="#GeneralInfo" class="is-active">
<a><i class="fas fa-info"></i> General</a>
</li>
<li data-tab-for="#PullStatsInfo">
<a><i class="fas fa-chart-line"></i> Statistics</a>
</li>
<li data-tab-for="#TemplateInfo">
<a><i class="fas fa-layer-group"></i> Container Info</a>
</li>
</ul>
</div>
</div>
</div>
<div id="ImageViewTabContent" class="columns has-tabs-content is-multiline has-margin-top">
<div id="GeneralInfo" class="column tab-content is-full is-active">
<div class="columns is-multiline">
<div class="column is-full">
<h2 class="title is-5">Build Information</h2>
<h3 class="subtitle is-6">General build information for this image</h3>
<@table.table isFullWidth=true isNarrow=false isStriped=true isScrollable=true>
<thead>
<tr>
<th scope="row" colspan="2"></th>
</tr>
</thead>
<tbody>
<@table.halfDisplayRow title="Repository" value=image.repositoryName link="/?key=${image.repositoryKey}" />
<@table.halfDisplayRow title="Build Time" value=image.lastUpdatedAsString />
<@table.halfDisplayRow title="Synchronised" value=image.syncEnabled?string("Yes", "No") />
<@table.halfDisplayRow title="Stable" value=image.stable?string("Yes", "No") />
<@table.halfDisplayRow title="Deprecated" value=image.deprecated?string("Yes", "No") />
</tbody>
</@table.table>
</div>
<div class="column is-full has-margin-bottom">
<h2 class="title is-5">Tracked Tags</h2>
<h3 class="subtitle is-6">Known tags which link to a specific branched app version.</h3>
<@table.table isFullWidth=true isNarrow=false isStriped=true isScrollable=true>
<thead>
<tr>
<th scope="row" colspan="2"></th>
</tr>
</thead>
<tbody>
<#list image.tagBranches as tagBranch>
<@table.halfDisplayRow title=tagBranch.branchName?html value='<i class="fas fa-tag"></i> ${image.getMaskedVersion(tagBranch.latestTag)}' />
</#list>
</tbody>
</@table.table>
</div>
</div>
</div>
<div id="PullStatsInfo" class="column tab-content is-full">
<div class="columns">
<div class="column is-full is-full-mobile">
<h2 class="title is-5">Daily Pull Statistics</h2>
<div class="chart-container" style="position: relative; width: 100%; height: 250px">
@ -118,6 +152,29 @@
</div>
</div>
<div id="TemplateInfo" class="column tab-content is-full">
<div id="TemplateInfo" class="columns is-multiline">
<div class="column is-full">
<h2 class="title is-5">Running this as a container</h2>
<h3 class="subtitle is-6">
Basic examples for getting this image running as a container
</h3>
</div>
<div class="column is-full has-margin-bottom">
<h2 class="title is-6">Docker Compose</h2>
<@dockerExample.compose fullName=image.fullName containerName=image.name templates=image.metaData.templates latest=image.latestTag.version />
</div>
<div class="column is-full has-margin-bottom">
<h2 class="title is-6">CLI</h2>
<@dockerExample.cli fullName=image.fullName containerName=image.name templates=image.metaData.templates latest=image.latestTag.version />
</div>
</div>
</div>
</div>
</@container.container>

View File

@ -36,6 +36,7 @@
<link rel="stylesheet" type="text/css" href="/assets/css/bulma-0.8.0.min.css" />
<link rel="stylesheet" type="text/css" href="/assets/css/app.css" />
<link rel="stylesheet" type="text/css" href="/assets/css/fontawesome-all.min.css" />
<link rel="stylesheet" type="text/css" href="/assets/css/prism.css" />
</head>
@ -98,6 +99,7 @@
<script type="text/javascript" src="/assets/js/Chart.bundle.min.js"></script>
<script type="text/javascript" src="/assets/js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="/assets/js/app.js"></script>
<script type="text/javascript" src="/assets/js/prism.js"></script>
<#if context?starts_with("admin")>
<script type="text/javascript" src="/assets/js/admin.js"></script>
</#if>

View File

@ -0,0 +1,89 @@
<#--
Copyright (c) 2020 LinuxServer.io
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<#macro compose fullName containerName templates latest="">
<div class="content">
<pre><code class="language-yaml">---
version: "2"
services:
${containerName}:
image: ${fullName}<#if latest?has_content>:${latest}</#if>
container_name: ${containerName}<#if templates.restartPolicy?has_content>
restart: ${templates.restartPolicy}</#if>
<#if templates.capabilities?has_content> cap_add:
<#list templates.capabilities as cap>
- ${cap}
</#list>
</#if>
<#if templates.env?has_content> environment:
<#list templates.env as env>
- ${env.name}=<#if env.description?has_content> # ${env.description}</#if>
</#list>
</#if>
<#if templates.volumes?has_content> volumes:
<#list templates.volumes as volume>
- /host/path/to${volume.name}:${volume.name}<#if volume.readonly>:ro</#if> <#if volume.description?has_content># ${volume.description}</#if>
</#list>
</#if>
<#if templates.ports?has_content> ports:
<#list templates.ports as port>
- ${port.name?string["##0"]}:${port.name?string["##0"]}/${port.protocol} <#if port.description?has_content># ${port.description}</#if>
</#list>
</#if>
<#if templates.devices?has_content> devices:
<#list templates.devices as device>
- ${device.name}:${device.name} <#if device.description?has_content># ${device.description}</#if>
</#list>
</#if></code></pre>
</div>
</#macro>
<#macro cli fullName containerName templates latest="">
<div class="content">
<pre><code class="language-bash">docker create \
--name=${containerName} \<#if templates.env?has_content>
<#list templates.env as env>
-e ${env.name}=<#if env.description?has_content> `# ${env.description}`</#if> \
</#list>
</#if>
<#if templates.volumes?has_content>
<#list templates.volumes as volume>
-v /host/path/to${volume.name}:${volume.name}<#if volume.readonly>:ro</#if><#if volume.description?has_content> `# ${volume.description}`</#if> \
</#list>
</#if>
<#if templates.ports?has_content>
<#list templates.ports as port>
-p ${port.name?string["##0"]}:${port.name?string["##0"]}/${port.protocol}<#if port.description?has_content> `# ${port.description}`</#if> \
</#list>
</#if>
<#if templates.devices?has_content>
<#list templates.devices as device>
--device ${device.name}:${device.name}<#if device.description?has_content> `# ${device.description}`</#if> \
</#list>
</#if>
<#if templates.capabilities?has_content>
<#list templates.capabilities as cap>
--cap-add=${cap} \
</#list>
</#if>
<#if templates.restartPolicy?has_content> --restart ${templates.restartPolicy} \</#if>
${fullName}<#if latest?has_content>:${latest}</#if></code></pre>
</div>
</#macro>

View File

@ -16,7 +16,7 @@
-->
<#macro title thinValue="" boldValue="" separator="" icon="" subtitle="">
<h2 class="title is-size-3-desktop is-size-4-mobile repository-title">
<h2 class="title is-size-3-desktop is-size-4-mobile">
<#if icon?has_content><i class="fas fa-${icon}"></i> </#if><#if thinValue?has_content><span class="has-text-weight-light">${thinValue}</span>${separator}</#if>${boldValue}<span class="has-text-primary">.</span>
<#nested />
</h2>
@ -26,4 +26,4 @@
</h3>
</#if>
</#macro>
</#macro>

View File

@ -25,7 +25,7 @@
<td class="is-vcentered">
<h4 class="title is-6">
<a class="has-text-grey-dark" href="/image?name=${image.fullName}">
<i class="fas fa-cube"></i> <span class="has-text-weight-light">${image.repositoryKey.name} / </span><span class="has-text-weight-500">${image.name}</span>
<i class="fas fa-cube"></i> <span class="has-text-weight-light">${image.repositoryKey.name} / </span><span class="has-text-weight-bold">${image.name}</span>
</a>
</h4>
</td>

View File

@ -14,7 +14,7 @@ Constructs a navigation bar for display (usually) at the top of the page.
<div class="navbar-brand">
<a class="navbar-item" href="/">
<span class="navbar-title">fleet<span class="has-text-primary">.</span></span>
<span class="title">fleet<span class="has-text-primary">.</span></span>
</a>
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">

View File

@ -31,7 +31,7 @@ Reference: https://bulma.io/documentation/form/input/
<label class="label is-${size}" for="${id}">${label}</label>
</#if>
<div class="control is-${size}<#if icon?has_content> has-icons has-icons-left</#if>">
<input type="${type}"<#if title?has_content> title="${title}"</#if> class="input<#if isReadonly> is-static</#if> is-${size}<#if extraClasses?has_content> ${extraClasses}</#if>" id="${id}" name="${id}"<#if isRequired> required</#if><#if isReadonly> readonly</#if><#if isDisabled> disabled</#if><#if value?has_content> value="${value}"</#if><#if placeholder?has_content> placeholder="${placeholder}"</#if><#if extraAttributes?has_content> ${extraAttributes}</#if>/>
<input type="${type}"<#if title?has_content> title="${title}"</#if> class="input<#if isReadonly> is-static</#if> is-${size}<#if extraClasses?has_content> ${extraClasses}</#if>" id="${id}" name="${id}"<#if isRequired> required</#if><#if isReadonly> readonly</#if><#if isDisabled> disabled</#if><#if value?has_content> value="${value?html}"</#if><#if placeholder?has_content> placeholder="${placeholder}"</#if><#if extraAttributes?has_content> ${extraAttributes}</#if>/>
<#if icon?has_content>
<span class="icon is-${size} is-left"><i class="fas fa-${icon}"></i></span>
</#if>