From 4ccca5e55a8bfa4bb1c09da5995ff53555140885 Mon Sep 17 00:00:00 2001 From: Josh Stark Date: Sat, 4 Jan 2020 18:29:03 +0000 Subject: [PATCH] Graphing/Edit Image - Updated graph on view image page - Initial form format for edit image page. --- .../fleet/core/FleetAppController.java | 6 + .../java/io/linuxserver/fleet/v2/Utils.java | 30 ++ .../fleet/v2/db/DefaultImageDAO.java | 2 + .../io/linuxserver/fleet/v2/db/ImageDAO.java | 1 + .../fleet/v2/key/AbstractHasKey.java | 4 +- .../fleet/v2/service/RepositoryService.java | 22 ++ .../schedule/CheckAppVersionSchedule.java | 2 +- .../schedule/TidyHistoricDataSchedule.java | 33 +++ .../io/linuxserver/fleet/v2/types/Image.java | 4 + .../linuxserver/fleet/v2/types/TagBranch.java | 2 + .../types/api/ApiImagePullHistoryWrapper.java | 14 +- .../v2/types/docker/DockerCapability.java | 59 ++++ .../meta/history/ImagePullStatistic.java | 15 +- .../linuxserver/fleet/v2/web/Locations.java | 2 + .../fleet/v2/web/WebRouteController.java | 5 + .../web/routes/AdminImageEditController.java | 56 ++++ .../v2/web/routes/InternalApiController.java | 16 +- .../db/migration/V2.1__MigrateToNewTables.sql | 1 + src/main/resources/static/assets/js/admin.js | 25 ++ src/main/resources/static/assets/js/app.js | 38 ++- src/main/resources/version.properties | 4 +- .../views/pages/admin/image-edit.ftl | 270 ++++++++++++++++++ .../resources/views/pages/admin/images.ftl | 2 +- src/main/resources/views/pages/image.ftl | 20 +- src/main/resources/views/prebuilt/base.ftl | 2 +- 25 files changed, 614 insertions(+), 21 deletions(-) create mode 100644 src/main/java/io/linuxserver/fleet/v2/Utils.java create mode 100644 src/main/java/io/linuxserver/fleet/v2/thread/schedule/TidyHistoricDataSchedule.java create mode 100644 src/main/java/io/linuxserver/fleet/v2/types/docker/DockerCapability.java create mode 100644 src/main/java/io/linuxserver/fleet/v2/web/routes/AdminImageEditController.java create mode 100644 src/main/resources/views/pages/admin/image-edit.ftl diff --git a/src/main/java/io/linuxserver/fleet/core/FleetAppController.java b/src/main/java/io/linuxserver/fleet/core/FleetAppController.java index 6f523f9..bba930a 100644 --- a/src/main/java/io/linuxserver/fleet/core/FleetAppController.java +++ b/src/main/java/io/linuxserver/fleet/core/FleetAppController.java @@ -161,4 +161,10 @@ public class FleetAppController extends AbstractAppController implements Service public final AuthenticationResult authenticateUser(final String username, final String password) { return authenticationDelegate.authenticate(username, password); } + + public final void trackBranch(final ImageKey imageKey, final String branchName) { + + getRepositoryService().trackBranchOnImage(imageKey, branchName); + synchroniseImage(imageKey); + } } diff --git a/src/main/java/io/linuxserver/fleet/v2/Utils.java b/src/main/java/io/linuxserver/fleet/v2/Utils.java new file mode 100644 index 0000000..1bf1958 --- /dev/null +++ b/src/main/java/io/linuxserver/fleet/v2/Utils.java @@ -0,0 +1,30 @@ +/* + * 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 . + */ + +package io.linuxserver.fleet.v2; + +public final class Utils { + + public static T ensureNotNull(final T obj) { + + if (null == obj) { + throw new IllegalArgumentException("Parameter null"); + } + + return obj; + } +} diff --git a/src/main/java/io/linuxserver/fleet/v2/db/DefaultImageDAO.java b/src/main/java/io/linuxserver/fleet/v2/db/DefaultImageDAO.java index 38cd898..fc31391 100644 --- a/src/main/java/io/linuxserver/fleet/v2/db/DefaultImageDAO.java +++ b/src/main/java/io/linuxserver/fleet/v2/db/DefaultImageDAO.java @@ -33,6 +33,7 @@ import io.linuxserver.fleet.v2.types.meta.history.ImagePullHistory; import io.linuxserver.fleet.v2.types.meta.history.ImagePullStatistic; import java.sql.*; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashSet; @@ -58,6 +59,7 @@ public class DefaultImageDAO extends AbstractDAO implements ImageDAO { private static final String GetImage = "{CALL Image_Get(?)}"; private static final String DeleteImage = "{CALL Image_Delete(?)}"; private static final String GetImageStats = "{CALL Image_GetStats(?)}"; + private static final String DeleteStats = "{CALL Image_ClearStatsBefore(?)}"; public DefaultImageDAO(final DatabaseProvider databaseConnection) { super(databaseConnection); diff --git a/src/main/java/io/linuxserver/fleet/v2/db/ImageDAO.java b/src/main/java/io/linuxserver/fleet/v2/db/ImageDAO.java index f75fe5d..5d00a43 100644 --- a/src/main/java/io/linuxserver/fleet/v2/db/ImageDAO.java +++ b/src/main/java/io/linuxserver/fleet/v2/db/ImageDAO.java @@ -27,6 +27,7 @@ import io.linuxserver.fleet.v2.types.internal.ImageOutlineRequest; import io.linuxserver.fleet.v2.types.internal.RepositoryOutlineRequest; import io.linuxserver.fleet.v2.types.internal.TagBranchOutlineRequest; +import java.time.LocalDate; import java.util.List; public interface ImageDAO { diff --git a/src/main/java/io/linuxserver/fleet/v2/key/AbstractHasKey.java b/src/main/java/io/linuxserver/fleet/v2/key/AbstractHasKey.java index 3294df2..5dbea86 100644 --- a/src/main/java/io/linuxserver/fleet/v2/key/AbstractHasKey.java +++ b/src/main/java/io/linuxserver/fleet/v2/key/AbstractHasKey.java @@ -17,12 +17,14 @@ package io.linuxserver.fleet.v2.key; +import io.linuxserver.fleet.v2.Utils; + public abstract class AbstractHasKey implements HasKey { private final KEY key; public AbstractHasKey(final KEY key) { - this.key = key; + this.key = Utils.ensureNotNull(key); } @Override diff --git a/src/main/java/io/linuxserver/fleet/v2/service/RepositoryService.java b/src/main/java/io/linuxserver/fleet/v2/service/RepositoryService.java index bb58226..67e8e66 100644 --- a/src/main/java/io/linuxserver/fleet/v2/service/RepositoryService.java +++ b/src/main/java/io/linuxserver/fleet/v2/service/RepositoryService.java @@ -29,6 +29,7 @@ import io.linuxserver.fleet.v2.types.docker.DockerImage; import io.linuxserver.fleet.v2.types.docker.DockerTag; import io.linuxserver.fleet.v2.types.internal.ImageOutlineRequest; import io.linuxserver.fleet.v2.types.internal.RepositoryOutlineRequest; +import io.linuxserver.fleet.v2.types.internal.TagBranchOutlineRequest; import io.linuxserver.fleet.v2.types.meta.ItemSyncSpec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -232,6 +233,27 @@ public class RepositoryService { } } + public void trackBranchOnImage(final ImageKey imageKey, final String branchName) { + + final Image image = repositoryCache.findImage(imageKey); + if (null == image) { + throw new IllegalArgumentException("Could not find image with key " + imageKey); + } + + if (image.findTagBranchByName(branchName) != null) { + throw new IllegalArgumentException("Image is already tracking branch " + branchName); + } + + final InsertUpdateResult outlineResult = imageDAO.createTagBranchOutline(new TagBranchOutlineRequest(imageKey, branchName)); + if (outlineResult.isError()) { + throw new RuntimeException(outlineResult.getStatusMessage()); + } + + final Image updatableClone = image.cloneForUpdate(); + updatableClone.addTagBranch(outlineResult.getResult()); + storeImage(updatableClone); + } + private void updateCache(final Image storedImage) { final Repository imageParentRepository = repositoryCache.findItem(storedImage.getRepositoryKey()); diff --git a/src/main/java/io/linuxserver/fleet/v2/thread/schedule/CheckAppVersionSchedule.java b/src/main/java/io/linuxserver/fleet/v2/thread/schedule/CheckAppVersionSchedule.java index f787b83..8ca6634 100644 --- a/src/main/java/io/linuxserver/fleet/v2/thread/schedule/CheckAppVersionSchedule.java +++ b/src/main/java/io/linuxserver/fleet/v2/thread/schedule/CheckAppVersionSchedule.java @@ -28,6 +28,6 @@ public class CheckAppVersionSchedule extends AbstractAppSchedule { @Override public void executeSchedule() { - + getLogger().info("Currently not implemented. This is a placeholder schedule"); } } diff --git a/src/main/java/io/linuxserver/fleet/v2/thread/schedule/TidyHistoricDataSchedule.java b/src/main/java/io/linuxserver/fleet/v2/thread/schedule/TidyHistoricDataSchedule.java new file mode 100644 index 0000000..d9f5890 --- /dev/null +++ b/src/main/java/io/linuxserver/fleet/v2/thread/schedule/TidyHistoricDataSchedule.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 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 . + */ + +package io.linuxserver.fleet.v2.thread.schedule; + +import io.linuxserver.fleet.core.FleetAppController; + +public class TidyHistoricDataSchedule extends AbstractAppSchedule { + + public TidyHistoricDataSchedule(final ScheduleSpec spec, + final FleetAppController controller) { + super(spec, controller); + } + + @Override + public void executeSchedule() { + getLogger().info("Currently not implemented. This is a placeholder schedule"); + } +} diff --git a/src/main/java/io/linuxserver/fleet/v2/types/Image.java b/src/main/java/io/linuxserver/fleet/v2/types/Image.java index fd1963e..e5320f6 100644 --- a/src/main/java/io/linuxserver/fleet/v2/types/Image.java +++ b/src/main/java/io/linuxserver/fleet/v2/types/Image.java @@ -67,6 +67,10 @@ public class Image extends AbstractSyncItem { return cloned; } + public final Image cloneForUpdate() { + return cloneWithSyncSpec(getSpec()); + } + @Override public final Image cloneWithSyncSpec(final ItemSyncSpec syncSpec) { diff --git a/src/main/java/io/linuxserver/fleet/v2/types/TagBranch.java b/src/main/java/io/linuxserver/fleet/v2/types/TagBranch.java index 63fedab..e3a282b 100644 --- a/src/main/java/io/linuxserver/fleet/v2/types/TagBranch.java +++ b/src/main/java/io/linuxserver/fleet/v2/types/TagBranch.java @@ -18,6 +18,8 @@ package io.linuxserver.fleet.v2.types; import io.linuxserver.fleet.v2.key.AbstractHasKey; +import io.linuxserver.fleet.v2.key.HasKey; +import io.linuxserver.fleet.v2.key.ImageKey; import io.linuxserver.fleet.v2.key.TagBranchKey; import java.util.concurrent.atomic.AtomicReference; diff --git a/src/main/java/io/linuxserver/fleet/v2/types/api/ApiImagePullHistoryWrapper.java b/src/main/java/io/linuxserver/fleet/v2/types/api/ApiImagePullHistoryWrapper.java index e480261..144bc43 100644 --- a/src/main/java/io/linuxserver/fleet/v2/types/api/ApiImagePullHistoryWrapper.java +++ b/src/main/java/io/linuxserver/fleet/v2/types/api/ApiImagePullHistoryWrapper.java @@ -24,8 +24,16 @@ import java.util.stream.Collectors; public class ApiImagePullHistoryWrapper extends AbstractApiWrapper> { - public ApiImagePullHistoryWrapper(final List originalObject) { + private final ImagePullStatistic.StatGroupMode groupMode; + + public ApiImagePullHistoryWrapper(final List originalObject, + final ImagePullStatistic.StatGroupMode groupMode) { super(originalObject); + this.groupMode = groupMode; + } + + public final String getGroupModeDataPoint() { + return groupMode.getDataPoint(); } public final List getLabels() { @@ -36,6 +44,10 @@ public class ApiImagePullHistoryWrapper extends AbstractApiWrapper. + */ + +package io.linuxserver.fleet.v2.types.docker; + +public enum DockerCapability { + + AUDIT_CONTROL, + AUDIT_WRITE, + BLOCK_SUSPEND, + CHOWN, + DAC_OVERRIDE, + DAC_READ_SEARCH, + FOWNER, + FSETID, + IPC_LOCK, + IPC_OWNER, + KILL, + LEASE, + LINUX_IMMUTABLE, + MAC_ADMIN, + MAC_OVERRIDE, + MKNOD, + NET_ADMIN, + NET_BIND_SERVICE, + NET_BROADCAST, + NET_RAW, + SETFCAP, + SETGID, + SETPCAP, + SETUID, + SYSLOG, + SYS_ADMIN, + SYS_BOOT, + SYS_CHROOT, + SYS_MODULE, + SYS_NICE, + SYS_PACCT, + SYS_PTRACE, + SYS_RAWIO, + SYS_RESOURCE, + SYS_TIME, + SYS_TTY_CONFIG, + WAKE_ALARM; +} diff --git a/src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullStatistic.java b/src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullStatistic.java index 4681151..729e47b 100644 --- a/src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullStatistic.java +++ b/src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullStatistic.java @@ -76,6 +76,19 @@ public class ImagePullStatistic implements Comparable { } public enum StatGroupMode { - Day, Week, Month; + + Day("hour"), + Week("day"), + Month("day"); + + private final String dataPoints; + + StatGroupMode(final String dataPoints) { + this.dataPoints = dataPoints; + } + + public final String getDataPoint() { + return dataPoints; + } } } diff --git a/src/main/java/io/linuxserver/fleet/v2/web/Locations.java b/src/main/java/io/linuxserver/fleet/v2/web/Locations.java index 8fc653d..3ba5dde 100644 --- a/src/main/java/io/linuxserver/fleet/v2/web/Locations.java +++ b/src/main/java/io/linuxserver/fleet/v2/web/Locations.java @@ -45,12 +45,14 @@ public interface Locations { String Schedule = "schedule"; String Sync = "sync"; String Stats = "stats"; + String Track = "track"; } interface Admin { String Repositories = "/admin/repositories"; String Images = "/admin/images"; + String ImageEdit = "/admin/image"; String Schedules = "/admin/schedules"; String Users = "/admin/users"; } diff --git a/src/main/java/io/linuxserver/fleet/v2/web/WebRouteController.java b/src/main/java/io/linuxserver/fleet/v2/web/WebRouteController.java index 20665e8..f31967b 100644 --- a/src/main/java/io/linuxserver/fleet/v2/web/WebRouteController.java +++ b/src/main/java/io/linuxserver/fleet/v2/web/WebRouteController.java @@ -64,6 +64,7 @@ public class WebRouteController { get(Locations.Admin.Repositories, new AdminRepositoryController(app), roles(AppRole.Anyone)); get(Locations.Admin.Images, new AdminImageController( app), roles(AppRole.Anyone)); + get(Locations.Admin.ImageEdit, new AdminImageEditController( app), roles(AppRole.Anyone)); get(Locations.Admin.Schedules, new AdminScheduleController( app), roles(AppRole.Anyone)); path(Locations.Internal.Api, () -> { @@ -90,6 +91,10 @@ public class WebRouteController { path(Locations.Internal.Stats, () -> { get(apiController::getImagePullHistory, roles(AppRole.Anyone)); }); + + path(Locations.Internal.Track, () -> { + put(apiController::trackNewBranch, roles(AppRole.Anyone)); + }); }); path(Locations.Internal.Schedule, () -> { diff --git a/src/main/java/io/linuxserver/fleet/v2/web/routes/AdminImageEditController.java b/src/main/java/io/linuxserver/fleet/v2/web/routes/AdminImageEditController.java new file mode 100644 index 0000000..1efa409 --- /dev/null +++ b/src/main/java/io/linuxserver/fleet/v2/web/routes/AdminImageEditController.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 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 . + */ + +package io.linuxserver.fleet.v2.web.routes; + +import io.javalin.http.Context; +import io.linuxserver.fleet.core.FleetAppController; +import io.linuxserver.fleet.v2.key.ImageKey; +import io.linuxserver.fleet.v2.service.RepositoryService; +import io.linuxserver.fleet.v2.types.docker.DockerCapability; +import io.linuxserver.fleet.v2.web.PageModelSpec; + +public class AdminImageEditController extends AbstractPageHandler { + + private RepositoryService repositoryService; + + public AdminImageEditController(final FleetAppController controller) { + super(controller); + repositoryService = controller.getRepositoryService(); + } + + @Override + protected PageModelSpec handlePageLoad(final Context ctx) { + + final String imageKeyParam = ctx.queryParam("imageKey"); + if (null != imageKeyParam) { + + final PageModelSpec modelSpec = new PageModelSpec("views/pages/admin/image-edit.ftl"); + modelSpec.addModelAttribute("image", repositoryService.getImage(ImageKey.parse(imageKeyParam))); + modelSpec.addModelAttribute("containerCapabilities", DockerCapability.values()); + return modelSpec; + + } else { + return new PageModelSpec("views/pages/not-found.ftl"); + } + } + + @Override + protected PageModelSpec handleFormSubmission(final Context ctx) { + return null; + } +} diff --git a/src/main/java/io/linuxserver/fleet/v2/web/routes/InternalApiController.java b/src/main/java/io/linuxserver/fleet/v2/web/routes/InternalApiController.java index 1a32968..2535b97 100644 --- a/src/main/java/io/linuxserver/fleet/v2/web/routes/InternalApiController.java +++ b/src/main/java/io/linuxserver/fleet/v2/web/routes/InternalApiController.java @@ -172,7 +172,21 @@ public class InternalApiController extends AbstractAppService { final ImagePullStatistic.StatGroupMode groupMode = ctx.queryParam("groupMode", ImagePullStatistic.StatGroupMode.class).get(); final Image cachedImage = getController().getRepositoryService().getImage(ImageKey.parse(imageKeyParam)); - ctx.json(new ApiImagePullHistoryWrapper(cachedImage.getMetaData().getHistoryFor(groupMode))); + ctx.json(new ApiImagePullHistoryWrapper(cachedImage.getMetaData().getHistoryFor(groupMode), groupMode)); + + } catch (IllegalArgumentException e) { + throw new ApiException(e.getMessage(), e); + } + } + + public void trackNewBranch(final Context ctx) { + + try { + + final String imageKeyParam = ctx.formParam("imageKey", String.class).get(); + final String branchName = ctx.formParam("branchName", String.class).get(); + + getController().trackBranch(ImageKey.parse(imageKeyParam), branchName); } catch (IllegalArgumentException e) { throw new ApiException(e.getMessage(), e); diff --git a/src/main/resources/db/migration/V2.1__MigrateToNewTables.sql b/src/main/resources/db/migration/V2.1__MigrateToNewTables.sql index 445f057..73fcc2b 100644 --- a/src/main/resources/db/migration/V2.1__MigrateToNewTables.sql +++ b/src/main/resources/db/migration/V2.1__MigrateToNewTables.sql @@ -24,4 +24,5 @@ VALUES ('SyncAllCachedImages', '1:hours', '0:minutes', 'io.linuxserver.fleet.v2.thread.schedule.sync.AllImagesSyncSchedule'), ('GetMissingImages', '30:minutes', '0:minutes', 'io.linuxserver.fleet.v2.thread.schedule.sync.GetMissingImagesSchedule'), ('RefreshCache', '1:days', '15:minutes', 'io.linuxserver.fleet.v2.thread.schedule.cache.RefreshCacheSchedule'), + ('TidyHistoricData', '1:days', '0:minutes', 'io.linuxserver.fleet.v2.thread.schedule.TidyHistoricDataSchedule'), ('CheckAppVersion', '1:days', '0:minutes', 'io.linuxserver.fleet.v2.thread.schedule.CheckAppVersionSchedule'); diff --git a/src/main/resources/static/assets/js/admin.js b/src/main/resources/static/assets/js/admin.js index 508665a..ef283ca 100644 --- a/src/main/resources/static/assets/js/admin.js +++ b/src/main/resources/static/assets/js/admin.js @@ -187,6 +187,23 @@ var adminManager = (function($) { ajaxManager.call(request, function() {}); }; + var trackNewBranch = function(branchName, imageKey) { + + var request = { + + url: '/internalapi/image/track', + method: 'put', + data: { + 'imageKey': imageKey, + 'branchName': branchName + } + }; + + ajaxManager.call(request, function() { + window.location.reload(); + }); + }; + var cleanEmpty = function(val) { return (typeof val === 'undefined' || $.trim(val).length === 0) ? null : val; }; @@ -233,6 +250,14 @@ var adminManager = (function($) { $('.sync-image').on('click', function() { syncImage($(this)); }); + + $('#TrackNewBranch').on('click', function() { + + var branchName = $.trim($('#NewTrackedBranch').val()); + if (branchName.length > 0) { + trackNewBranch(branchName, $('#ImageKey').val()); + } + }); }; return { diff --git a/src/main/resources/static/assets/js/app.js b/src/main/resources/static/assets/js/app.js index 621cac1..1a19116 100644 --- a/src/main/resources/static/assets/js/app.js +++ b/src/main/resources/static/assets/js/app.js @@ -268,6 +268,19 @@ var imageSearchManager = (function($) { var chartManager = (function($) { + var formatNumber = function(num) { + + var array = num.toString().split(''); + var index = -3; + + while (array.length + index > 0) { + array.splice(index, 0, ','); + index -= 4; + } + + return array.join(''); + }; + var populateChart = function(imageKey, groupMode) { var request = { @@ -278,16 +291,29 @@ var chartManager = (function($) { ajaxManager.call(request, function(history) { - var ctx = document.getElementById('ImagePullHistory').getContext('2d'); + $('#PullActivityDataPoint').text(history.groupModeDataPoint); + $('#PullActivityRate').text(formatNumber(history.mean)); + + var ctx = document.getElementById('ImagePullHistory').getContext('2d'); + var gradient = ctx.createLinearGradient(0, 0, 0, 400); + gradient.addColorStop(0, 'rgba(0, 209, 178, 0.5)'); + gradient.addColorStop(0.3, 'rgba(0, 209, 178, 0)'); + new Chart(ctx, { type: 'line', data: { labels: history.pullDifferential.labels, - datasets: [{ - data: history.pullDifferential.pulls, - borderColor: 'rgba(0, 209, 178, 1)', - backgroundColor: 'rgba(0, 209, 178, 0.3)' - }] + datasets: [ + { + lineTension: 0, + data: history.pullDifferential.pulls, + pointRadius: 0, + pointHitRadius: 2, + borderWidth: 2, + borderColor: 'rgba(0, 209, 178, 1)', + backgroundColor : gradient + } + ] }, options: { responsive: true, diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties index 9a8156c..845ce7f 100644 --- a/src/main/resources/version.properties +++ b/src/main/resources/version.properties @@ -1,5 +1,5 @@ -#Fri Jan 03 17:22:49 GMT 2020 -app.build.date=2020-01-03T17\:22\:49 +#Sat Jan 04 18:27:43 GMT 2020 +app.build.date=2020-01-04T18\:27\:43 app.build.os=Linux app.build.user=josh app.version=2.0.0 diff --git a/src/main/resources/views/pages/admin/image-edit.ftl b/src/main/resources/views/pages/admin/image-edit.ftl new file mode 100644 index 0000000..7bf959a --- /dev/null +++ b/src/main/resources/views/pages/admin/image-edit.ftl @@ -0,0 +1,270 @@ +<#-- + Copyright (c) 2019 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 . +--> +<#import "../../prebuilt/base.ftl" as base /> +<#import "../../prebuilt/fleet-title.ftl" as title /> + +<#import "../../ui/components/dropdown.ftl" as dropdown /> +<#import "../../ui/layout/section.ftl" as section /> +<#import "../../ui/layout/container.ftl" as container /> +<#import "../../ui/form/input.ftl" as input /> +<#import "../../ui/elements/button.ftl" as button /> +<#import "../../ui/elements/table.ftl" as table /> + +<@base.base title='Edit ${image.name} | Admin' context="admin_image_edit"> + + <#if image?has_content> + + + + <@section.section id="ManageImage"> + <@container.container> + +
+ +
+ <@title.title icon="cube" thinValue=image.repositoryName boldValue=image.name separator="/" subtitle="Update metadata and tracked branches" /> +
+ + <#-- + Tag branches + --> +
+ +

Tracked Tag Branches

+ <@table.table id="ImageTrackedBranches" isScrollable=true isFullWidth=true> + + + Branch Name + + + + + <#list image.tagBranches as tagBranch> + + ${tagBranch.branchName} + + <#if !tagBranch.branchProtected> + <@button.buttons isRightAligned=true> + <@button.button extraClasses="remove-tag-branch" colour="danger" size="small"> + Remove + + + <#else> + <@button.buttons isRightAligned=true> + <@button.button colour="light" size="small" isDisabled=true> + Protected + + + + + + + + + <@input.text id="NewTrackedBranch" icon="sitemap" size="small" /> + + + <@button.buttons isRightAligned=true> + <@button.button id="TrackNewBranch" size="small" colour="success"> + Track + + + + + + + +
+ + <#-- + General base information which is to be added manually (data which can't necessarily be inferred from upstream) + --> +
+

General

+
+
+ <@input.text id="ImageBase" label="Base Image" /> +
+
+ <@input.text id="ImageCategory" label="Category" /> +
+
+ <@input.text id="ImageSupportUrl" label="Support Url" /> +
+
+ <@input.text id="ImageAppUrl" label="Application Url" /> +
+ + <#-- + A display logo for the grid listing and main image display page + --> +
+ +

App Logo

+ +
+ +
+
+ + <#-- + Port/Volume mappings for containers created from this image + --> +
+ +

Container Template

+

Recommended Runtime

+
+
+ <@input.text id="ImageTemplateUpstreamUrl" label="Registry Url" /> +
+
+ <@input.dropdown label="Restart Policy" id="ImageTemplateRestartPolicy"> + + + + + +
+
+ <@input.toggle id="ImageTemplateNetworkHost" label="Host Network" size="large" /> +
+
+ <@input.toggle id="ImageTemplatePrivileged" label="Privileged" size="large" /> +
+
+ <@input.dropdown id="ImageTemplateCapabilities" label="Capabilities" isMultiple=true> + <#list containerCapabilities as capability> + + + +
+
+ +

Ports

+ <@table.table id="ImageTemplatePorts" isScrollable=true isFullWidth=true> + + + Port + Protocol + Description + + + + + + + <@button.buttons isRightAligned=true> + <@button.button id="AddNewPort" colour="normal-colour" size="small"> + Add + + + +
+
+ +

Volumes

+ <@table.table id="ImageTemplateVolumes" isScrollable=true isFullWidth=true> + + + Volume + Read Only? + Description + + + + + + + <@button.buttons isRightAligned=true> + <@button.button id="AddNewVolume" colour="normal-colour" size="small"> + Add + + + +
+
+ +

Environment

+ <@table.table id="ImageTemplateEnv" isScrollable=true isFullWidth=true> + + + Environment Variable + Description + + + + + + + <@button.buttons isRightAligned=true> + <@button.button id="AddNewEnv" colour="normal-colour" size="small"> + Add + + + +
+
+ +

Devices

+ <@table.table id="ImageTemplateDevices" isScrollable=true isFullWidth=true> + + + Device + Description + + + + + + + <@button.buttons isRightAligned=true> + <@button.button id="AddNewDevice" colour="normal-colour" size="small"> + Add + + + +
+
+ + + + + <#else> + + <@section.section id="ManageImages"> + <@container.container> + Unable to find repository. + + + + + + diff --git a/src/main/resources/views/pages/admin/images.ftl b/src/main/resources/views/pages/admin/images.ftl index 2cb6b3f..a6412c6 100644 --- a/src/main/resources/views/pages/admin/images.ftl +++ b/src/main/resources/views/pages/admin/images.ftl @@ -75,7 +75,7 @@ <@button.button id="ForceResync_${image.key.id}" size="small" title="Force resync" colour="normal-colour" extraAttributes='data-image-key="${image.key}"' extraClasses="sync-image"> - <@button.link size="small" title="Edit image metadata" colour="normal-colour" link="/admin/image?key=${image.fullName}"> + <@button.link size="small" title="Edit image metadata" colour="normal-colour" link="/admin/image?imageKey=${image.key}"> diff --git a/src/main/resources/views/pages/image.ftl b/src/main/resources/views/pages/image.ftl index 6d2d294..35393be 100644 --- a/src/main/resources/views/pages/image.ftl +++ b/src/main/resources/views/pages/image.ftl @@ -83,26 +83,34 @@
- <@box.box extraClasses="is-paddingless is-clipped is-relative"> + <@box.box> -

Pull Activity

+

Pull Activity

-
- +
+
+

Pulls per

+ <@tag.tag value='' colour="light" /> +
+
+
+ +
+
diff --git a/src/main/resources/views/prebuilt/base.ftl b/src/main/resources/views/prebuilt/base.ftl index 3c78e8f..597974c 100644 --- a/src/main/resources/views/prebuilt/base.ftl +++ b/src/main/resources/views/prebuilt/base.ftl @@ -112,7 +112,7 @@ <#if context=='image'> - chartManager.populateChart('${image.key}', 'Week'); + chartManager.populateChart('${image.key}', 'Month'); appManager.init();