mirror of https://github.com/portainer/portainer
resolve conflicts
commit
1991475437
|
@ -1,54 +0,0 @@
|
|||
# Config for Stalebot, limited to only `issues`
|
||||
only: issues
|
||||
|
||||
# Issues config
|
||||
issues:
|
||||
daysUntilStale: 60
|
||||
daysUntilClose: 7
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- kind/enhancement
|
||||
- kind/question
|
||||
- kind/style
|
||||
- kind/workaround
|
||||
- kind/refactor
|
||||
- bug/need-confirmation
|
||||
- bug/confirmed
|
||||
- status/discuss
|
||||
|
||||
# Only issues with all of these labels are checked if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: true
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: true
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: true
|
||||
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: status/stale
|
||||
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been marked as stale as it has not had recent activity,
|
||||
it will be closed if no further activity occurs in the next 7 days.
|
||||
If you believe that it has been incorrectly labelled as stale,
|
||||
leave a comment and the label will be removed.
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
Since no further activity has appeared on this issue it will be closed.
|
||||
If you believe that it has been incorrectly closed, leave a comment
|
||||
mentioning `ametdoohan`, `balasu` or `keverv` and one of our staff will then review the issue.
|
||||
|
||||
Note - If it is an old bug report, make sure that it is reproduceable in the
|
||||
latest version of Portainer as it may have already been fixed.
|
|
@ -0,0 +1,27 @@
|
|||
name: Close Stale Issues
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 12 * * *'
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v4.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Issue Config
|
||||
days-before-issue-stale: 60
|
||||
days-before-issue-close: 7
|
||||
stale-issue-label: 'status/stale'
|
||||
exempt-all-issue-milestones: true # Do not stale issues in a milestone
|
||||
exempt-issue-labels: kind/enhancement, kind/style, kind/workaround, kind/refactor, bug/need-confirmation, bug/confirmed, status/discuss
|
||||
stale-issue-message: 'This issue has been marked as stale as it has not had recent activity, it will be closed if no further activity occurs in the next 7 days. If you believe that it has been incorrectly labelled as stale, leave a comment and the label will be removed.'
|
||||
close-issue-message: 'Since no further activity has appeared on this issue it will be closed. If you believe that it has been incorrectly closed, leave a comment mentioning `portainer/support` and one of our staff will then review the issue. Note - If it is an old bug report, make sure that it is reproduceable in the latest version of Portainer as it may have already been fixed.'
|
||||
|
||||
# Pull Request Config
|
||||
days-before-pr-stale: -1 # Do not stale pull request
|
||||
days-before-pr-close: -1 # Do not close pull request
|
|
@ -28,7 +28,6 @@ import (
|
|||
"github.com/portainer/portainer/api/kubernetes"
|
||||
kubecli "github.com/portainer/portainer/api/kubernetes/cli"
|
||||
"github.com/portainer/portainer/api/ldap"
|
||||
"github.com/portainer/portainer/api/libcompose"
|
||||
"github.com/portainer/portainer/api/oauth"
|
||||
"github.com/portainer/portainer/api/scheduler"
|
||||
"github.com/portainer/portainer/api/stacks"
|
||||
|
@ -86,18 +85,17 @@ func shutdownDatastore(shutdownCtx context.Context, datastore portainer.DataStor
|
|||
datastore.Close()
|
||||
}
|
||||
|
||||
func initComposeStackManager(assetsPath string, dataStorePath string, reverseTunnelService portainer.ReverseTunnelService, proxyManager *proxy.Manager) portainer.ComposeStackManager {
|
||||
composeWrapper, err := exec.NewComposeStackManager(assetsPath, dataStorePath, proxyManager)
|
||||
func initComposeStackManager(assetsPath string, configPath string, reverseTunnelService portainer.ReverseTunnelService, proxyManager *proxy.Manager) portainer.ComposeStackManager {
|
||||
composeWrapper, err := exec.NewComposeStackManager(assetsPath, configPath, proxyManager)
|
||||
if err != nil {
|
||||
log.Printf("[INFO] [main,compose] [message: falling-back to libcompose] [error: %s]", err)
|
||||
return libcompose.NewComposeStackManager(dataStorePath, reverseTunnelService)
|
||||
log.Fatalf("failed creating compose manager: %s", err)
|
||||
}
|
||||
|
||||
return composeWrapper
|
||||
}
|
||||
|
||||
func initSwarmStackManager(assetsPath string, dataStorePath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService, reverseTunnelService portainer.ReverseTunnelService) (portainer.SwarmStackManager, error) {
|
||||
return exec.NewSwarmStackManager(assetsPath, dataStorePath, signatureService, fileService, reverseTunnelService)
|
||||
func initSwarmStackManager(assetsPath string, configPath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService, reverseTunnelService portainer.ReverseTunnelService) (portainer.SwarmStackManager, error) {
|
||||
return exec.NewSwarmStackManager(assetsPath, configPath, signatureService, fileService, reverseTunnelService)
|
||||
}
|
||||
|
||||
func initKubernetesDeployer(kubernetesTokenCacheManager *kubeproxy.TokenCacheManager, kubernetesClientFactory *kubecli.ClientFactory, dataStore portainer.DataStore, reverseTunnelService portainer.ReverseTunnelService, signatureService portainer.DigitalSignatureService, proxyManager *proxy.Manager, assetsPath string) portainer.KubernetesDeployer {
|
||||
|
@ -446,14 +444,17 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
|
|||
authorizationService := authorization.NewService(dataStore)
|
||||
authorizationService.K8sClientFactory = kubernetesClientFactory
|
||||
|
||||
swarmStackManager, err := initSwarmStackManager(*flags.Assets, *flags.Data, digitalSignatureService, fileService, reverseTunnelService)
|
||||
if err != nil {
|
||||
log.Fatalf("failed initializing swarm stack manager: %v", err)
|
||||
}
|
||||
kubernetesTokenCacheManager := kubeproxy.NewTokenCacheManager()
|
||||
proxyManager := proxy.NewManager(dataStore, digitalSignatureService, reverseTunnelService, dockerClientFactory, kubernetesClientFactory, kubernetesTokenCacheManager)
|
||||
|
||||
composeStackManager := initComposeStackManager(*flags.Assets, *flags.Data, reverseTunnelService, proxyManager)
|
||||
dockerConfigPath := fileService.GetDockerConfigPath()
|
||||
|
||||
composeStackManager := initComposeStackManager(*flags.Assets, dockerConfigPath, reverseTunnelService, proxyManager)
|
||||
|
||||
swarmStackManager, err := initSwarmStackManager(*flags.Assets, dockerConfigPath, digitalSignatureService, fileService, reverseTunnelService)
|
||||
if err != nil {
|
||||
log.Fatalf("failed initializing swarm stack manager: %s", err)
|
||||
}
|
||||
|
||||
kubernetesDeployer := initKubernetesDeployer(kubernetesTokenCacheManager, kubernetesClientFactory, dataStore, reverseTunnelService, digitalSignatureService, proxyManager, *flags.Assets)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -8,7 +9,10 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
wrapper "github.com/portainer/docker-compose-wrapper"
|
||||
|
||||
libstack "github.com/portainer/docker-compose-wrapper"
|
||||
"github.com/portainer/docker-compose-wrapper/compose"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/http/proxy"
|
||||
"github.com/portainer/portainer/api/http/proxy/factory"
|
||||
|
@ -16,33 +20,31 @@ import (
|
|||
|
||||
// ComposeStackManager is a wrapper for docker-compose binary
|
||||
type ComposeStackManager struct {
|
||||
wrapper *wrapper.ComposeWrapper
|
||||
configPath string
|
||||
deployer libstack.Deployer
|
||||
proxyManager *proxy.Manager
|
||||
}
|
||||
|
||||
// NewComposeStackManager returns a docker-compose wrapper if corresponding binary present, otherwise nil
|
||||
func NewComposeStackManager(binaryPath string, configPath string, proxyManager *proxy.Manager) (*ComposeStackManager, error) {
|
||||
wrap, err := wrapper.NewComposeWrapper(binaryPath)
|
||||
deployer, err := compose.NewComposeDeployer(binaryPath, configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ComposeStackManager{
|
||||
wrapper: wrap,
|
||||
deployer: deployer,
|
||||
proxyManager: proxyManager,
|
||||
configPath: configPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ComposeSyntaxMaxVersion returns the maximum supported version of the docker compose syntax
|
||||
func (w *ComposeStackManager) ComposeSyntaxMaxVersion() string {
|
||||
func (manager *ComposeStackManager) ComposeSyntaxMaxVersion() string {
|
||||
return portainer.ComposeSyntaxMaxVersion
|
||||
}
|
||||
|
||||
// Up builds, (re)creates and starts containers in the background. Wraps `docker-compose up -d` command
|
||||
func (w *ComposeStackManager) Up(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
url, proxy, err := w.fetchEndpointProxy(endpoint)
|
||||
func (manager *ComposeStackManager) Up(ctx context.Context, stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
url, proxy, err := manager.fetchEndpointProxy(endpoint)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to fetch endpoint proxy")
|
||||
}
|
||||
|
@ -57,13 +59,12 @@ func (w *ComposeStackManager) Up(stack *portainer.Stack, endpoint *portainer.End
|
|||
}
|
||||
|
||||
filePaths := append([]string{stack.EntryPoint}, stack.AdditionalFiles...)
|
||||
_, err = w.wrapper.Up(filePaths, stack.ProjectPath, url, stack.Name, envFilePath, w.configPath)
|
||||
return errors.Wrap(err, "failed to deploy a stack")
|
||||
return manager.deployer.Deploy(ctx, stack.ProjectPath, url, stack.Name, filePaths, envFilePath)
|
||||
}
|
||||
|
||||
// Down stops and removes containers, networks, images, and volumes. Wraps `docker-compose down --remove-orphans` command
|
||||
func (w *ComposeStackManager) Down(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
url, proxy, err := w.fetchEndpointProxy(endpoint)
|
||||
func (manager *ComposeStackManager) Down(ctx context.Context, stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
url, proxy, err := manager.fetchEndpointProxy(endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -73,27 +74,26 @@ func (w *ComposeStackManager) Down(stack *portainer.Stack, endpoint *portainer.E
|
|||
|
||||
filePaths := append([]string{stack.EntryPoint}, stack.AdditionalFiles...)
|
||||
|
||||
_, err = w.wrapper.Down(filePaths, stack.ProjectPath, url, stack.Name)
|
||||
return err
|
||||
return manager.deployer.Remove(ctx, stack.ProjectPath, url, stack.Name, filePaths)
|
||||
}
|
||||
|
||||
// NormalizeStackName returns a new stack name with unsupported characters replaced
|
||||
func (w *ComposeStackManager) NormalizeStackName(name string) string {
|
||||
func (manager *ComposeStackManager) NormalizeStackName(name string) string {
|
||||
r := regexp.MustCompile("[^a-z0-9]+")
|
||||
return r.ReplaceAllString(strings.ToLower(name), "")
|
||||
}
|
||||
|
||||
func (w *ComposeStackManager) fetchEndpointProxy(endpoint *portainer.Endpoint) (string, *factory.ProxyServer, error) {
|
||||
func (manager *ComposeStackManager) fetchEndpointProxy(endpoint *portainer.Endpoint) (string, *factory.ProxyServer, error) {
|
||||
if strings.HasPrefix(endpoint.URL, "unix://") || strings.HasPrefix(endpoint.URL, "npipe://") {
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
proxy, err := w.proxyManager.CreateAgentProxyServer(endpoint)
|
||||
proxy, err := manager.proxyManager.CreateAgentProxyServer(endpoint)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("http://127.0.0.1:%d", proxy.Port), proxy, nil
|
||||
return fmt.Sprintf("tcp://127.0.0.1:%d", proxy.Port), proxy, nil
|
||||
}
|
||||
|
||||
func createEnvFile(stack *portainer.Stack) (string, error) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
@ -47,7 +48,9 @@ func Test_UpAndDown(t *testing.T) {
|
|||
t.Fatalf("Failed creating manager: %s", err)
|
||||
}
|
||||
|
||||
err = w.Up(stack, endpoint)
|
||||
ctx := context.TODO()
|
||||
|
||||
err = w.Up(ctx, stack, endpoint)
|
||||
if err != nil {
|
||||
t.Fatalf("Error calling docker-compose up: %s", err)
|
||||
}
|
||||
|
@ -56,7 +59,7 @@ func Test_UpAndDown(t *testing.T) {
|
|||
t.Fatal("container should exist")
|
||||
}
|
||||
|
||||
err = w.Down(stack, endpoint)
|
||||
err = w.Down(ctx, stack, endpoint)
|
||||
if err != nil {
|
||||
t.Fatalf("Error calling docker-compose down: %s", err)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
// SwarmStackManager represents a service for managing stacks.
|
||||
type SwarmStackManager struct {
|
||||
binaryPath string
|
||||
dataPath string
|
||||
configPath string
|
||||
signatureService portainer.DigitalSignatureService
|
||||
fileService portainer.FileService
|
||||
reverseTunnelService portainer.ReverseTunnelService
|
||||
|
@ -27,16 +27,16 @@ type SwarmStackManager struct {
|
|||
|
||||
// NewSwarmStackManager initializes a new SwarmStackManager service.
|
||||
// It also updates the configuration of the Docker CLI binary.
|
||||
func NewSwarmStackManager(binaryPath, dataPath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService, reverseTunnelService portainer.ReverseTunnelService) (*SwarmStackManager, error) {
|
||||
func NewSwarmStackManager(binaryPath, configPath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService, reverseTunnelService portainer.ReverseTunnelService) (*SwarmStackManager, error) {
|
||||
manager := &SwarmStackManager{
|
||||
binaryPath: binaryPath,
|
||||
dataPath: dataPath,
|
||||
configPath: configPath,
|
||||
signatureService: signatureService,
|
||||
fileService: fileService,
|
||||
reverseTunnelService: reverseTunnelService,
|
||||
}
|
||||
|
||||
err := manager.updateDockerCLIConfiguration(dataPath)
|
||||
err := manager.updateDockerCLIConfiguration(manager.configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func NewSwarmStackManager(binaryPath, dataPath string, signatureService portaine
|
|||
|
||||
// Login executes the docker login command against a list of registries (including DockerHub).
|
||||
func (manager *SwarmStackManager) Login(registries []portainer.Registry, endpoint *portainer.Endpoint) {
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.configPath, endpoint)
|
||||
for _, registry := range registries {
|
||||
if registry.Authentication {
|
||||
registryArgs := append(args, "login", "--username", registry.Username, "--password", registry.Password, registry.URL)
|
||||
|
@ -57,7 +57,7 @@ func (manager *SwarmStackManager) Login(registries []portainer.Registry, endpoin
|
|||
|
||||
// Logout executes the docker logout command.
|
||||
func (manager *SwarmStackManager) Logout(endpoint *portainer.Endpoint) error {
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.configPath, endpoint)
|
||||
args = append(args, "logout")
|
||||
return runCommandAndCaptureStdErr(command, args, nil, "")
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ func (manager *SwarmStackManager) Logout(endpoint *portainer.Endpoint) error {
|
|||
// Deploy executes the docker stack deploy command.
|
||||
func (manager *SwarmStackManager) Deploy(stack *portainer.Stack, prune bool, endpoint *portainer.Endpoint) error {
|
||||
filePaths := stackutils.GetStackFilePaths(stack)
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.configPath, endpoint)
|
||||
|
||||
if prune {
|
||||
args = append(args, "stack", "deploy", "--prune", "--with-registry-auth")
|
||||
|
@ -85,7 +85,7 @@ func (manager *SwarmStackManager) Deploy(stack *portainer.Stack, prune bool, end
|
|||
|
||||
// Remove executes the docker stack rm command.
|
||||
func (manager *SwarmStackManager) Remove(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.dataPath, endpoint)
|
||||
command, args := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.configPath, endpoint)
|
||||
args = append(args, "stack", "rm", stack.Name)
|
||||
return runCommandAndCaptureStdErr(command, args, nil, "")
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ func runCommandAndCaptureStdErr(command string, args []string, env []string, wor
|
|||
return nil
|
||||
}
|
||||
|
||||
func (manager *SwarmStackManager) prepareDockerCommandAndArgs(binaryPath, dataPath string, endpoint *portainer.Endpoint) (string, []string) {
|
||||
func (manager *SwarmStackManager) prepareDockerCommandAndArgs(binaryPath, configPath string, endpoint *portainer.Endpoint) (string, []string) {
|
||||
// Assume Linux as a default
|
||||
command := path.Join(binaryPath, "docker")
|
||||
|
||||
|
@ -118,7 +118,7 @@ func (manager *SwarmStackManager) prepareDockerCommandAndArgs(binaryPath, dataPa
|
|||
}
|
||||
|
||||
args := make([]string, 0)
|
||||
args = append(args, "--config", dataPath)
|
||||
args = append(args, "--config", configPath)
|
||||
|
||||
endpointURL := endpoint.URL
|
||||
if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment {
|
||||
|
@ -145,8 +145,8 @@ func (manager *SwarmStackManager) prepareDockerCommandAndArgs(binaryPath, dataPa
|
|||
return command, args
|
||||
}
|
||||
|
||||
func (manager *SwarmStackManager) updateDockerCLIConfiguration(dataPath string) error {
|
||||
configFilePath := path.Join(dataPath, "config.json")
|
||||
func (manager *SwarmStackManager) updateDockerCLIConfiguration(configPath string) error {
|
||||
configFilePath := path.Join(configPath, "config.json")
|
||||
config, err := manager.retrieveConfigurationFromDisk(configFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -43,6 +43,8 @@ const (
|
|||
BinaryStorePath = "bin"
|
||||
// EdgeJobStorePath represents the subfolder where schedule files are stored.
|
||||
EdgeJobStorePath = "edge_jobs"
|
||||
// DockerConfigPath represents the subfolder where docker configuration is stored.
|
||||
DockerConfigPath = "docker_config"
|
||||
// ExtensionRegistryManagementStorePath represents the subfolder where files related to the
|
||||
// registry management extension are stored.
|
||||
ExtensionRegistryManagementStorePath = "extensions"
|
||||
|
@ -100,6 +102,11 @@ func NewService(dataStorePath, fileStorePath string) (*Service, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = service.createDirectoryInStore(DockerConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return service, nil
|
||||
}
|
||||
|
||||
|
@ -108,6 +115,11 @@ func (service *Service) GetBinaryFolder() string {
|
|||
return path.Join(service.fileStorePath, BinaryStorePath)
|
||||
}
|
||||
|
||||
// GetDockerConfigPath returns the full path to the docker config store on the filesystem
|
||||
func (service *Service) GetDockerConfigPath() string {
|
||||
return path.Join(service.fileStorePath, DockerConfigPath)
|
||||
}
|
||||
|
||||
// RemoveDirectory removes a directory on the filesystem.
|
||||
func (service *Service) RemoveDirectory(directoryPath string) error {
|
||||
return os.RemoveAll(directoryPath)
|
||||
|
|
20
api/go.mod
20
api/go.mod
|
@ -3,15 +3,21 @@ module github.com/portainer/portainer/api
|
|||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.16
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535
|
||||
github.com/boltdb/bolt v1.3.1
|
||||
github.com/containerd/containerd v1.3.1 // indirect
|
||||
github.com/coreos/go-semver v0.3.0
|
||||
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/docker/cli v0.0.0-20191126203649-54d085b857e9
|
||||
github.com/docker/docker v0.0.0-00010101000000-000000000000
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/g07cha/defender v0.0.0-20180505193036-5665c627c814
|
||||
github.com/go-git/go-git/v5 v5.3.0
|
||||
github.com/go-ldap/ldap/v3 v3.1.8
|
||||
|
@ -21,23 +27,27 @@ require (
|
|||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/jpillora/chisel v0.0.0-20190724232113-f3a8df20e389
|
||||
github.com/json-iterator/go v1.1.8
|
||||
github.com/json-iterator/go v1.1.10
|
||||
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
|
||||
github.com/mattn/go-shellwords v1.0.6 // indirect
|
||||
github.com/mitchellh/mapstructure v1.1.2 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210810234209-d01bc85eb481
|
||||
github.com/portainer/libcompose v0.5.3
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210906052132-ef24824f7548
|
||||
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a
|
||||
github.com/portainer/libhttp v0.0.0-20190806161843-ba068f58be33
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gotest.tools v2.2.0+incompatible // indirect
|
||||
k8s.io/api v0.17.2
|
||||
k8s.io/apimachinery v0.17.2
|
||||
k8s.io/client-go v0.17.2
|
||||
|
|
109
api/go.sum
109
api/go.sum
|
@ -1,8 +1,8 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
|
@ -11,40 +11,31 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB
|
|||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Microsoft/go-winio v0.3.8/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=
|
||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4=
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2 h1:axBiC50cNZOs7ygH5BgQp4N+aYrZ2DNpWZ1KG3VOSOM=
|
||||
github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2/go.mod h1:jnzFpU88PccN/tPPhCpnNU8mZphvKxYM9lLNkd8e+os=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/containerd/containerd v1.3.1 h1:LdbWxLhkAIxGO7h3mATHkyav06WuDs/yTWxIljJOTks=
|
||||
github.com/containerd/containerd v1.3.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
|
@ -56,23 +47,16 @@ github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9 h1:74lLNRzvsdIlkTgfD
|
|||
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/docker/cli v0.0.0-20190711175710-5b38d82aa076/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v0.0.0-20191126203649-54d085b857e9 h1:Q6D6b2iRKhvtL3Wj9p0SyPOvUDJ1ht62mbiBoNJ3Aus=
|
||||
github.com/docker/cli v0.0.0-20191126203649-54d085b857e9/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
|
||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/engine v1.4.2-0.20200204220554-5f6d6f3f2203 h1:QeBh8wW8pIZKlXxlMOQ8hSCMdJA+2Z/bD/iDyCAS8XU=
|
||||
github.com/docker/engine v1.4.2-0.20200204220554-5f6d6f3f2203/go.mod h1:3CPr2caMgTHxxIAZgEMd3uLYPDlRvPqCpyeRf6ncPcY=
|
||||
github.com/docker/go-connections v0.3.0 h1:3lOnM9cSzgGwx8VfK/NGOW5fLQ0GjIlCkaktF+n1M6o=
|
||||
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA=
|
||||
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M=
|
||||
|
@ -82,7 +66,6 @@ github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg
|
|||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
|
@ -102,20 +85,15 @@ github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbK
|
|||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc=
|
||||
github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-ldap/ldap/v3 v3.1.8 h1:5vU/2jOh9HqprwXp8aF915s9p6Z8wmbSEVF7/gdTFhM=
|
||||
github.com/go-ldap/ldap/v3 v3.1.8/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
|
@ -124,7 +102,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -142,8 +119,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
|||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v0.0.0-20160317213430-0eeaf8392f5b/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
|
@ -174,12 +149,10 @@ github.com/jpillora/requestlog v0.0.0-20181015073026-df8817be5f82/go.mod h1:w8bu
|
|||
github.com/jpillora/sizestr v0.0.0-20160130011556-e2ea2fa42fb9 h1:0c9jcgBtHRtDU//jTrcCgWG6UHjMZytiq/3WhraNgUM=
|
||||
github.com/jpillora/sizestr v0.0.0-20160130011556-e2ea2fa42fb9/go.mod h1:1ffp+CRe0eAwwRb0/BownUAjMBsmTLwgAvRbfj9dRwE=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
|
@ -187,11 +160,9 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c h1:N7A4JCA2G+j5fuFxCsJqjFU/sZe0mj8H0sSoSwbaikw=
|
||||
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c/go.mod h1:Nn5wlyECw3iJrzi0AhIWg+AJUb4PlRQVW4/3XHH1LZA=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v0.0.0-20150511174710-5cf931ef8f76/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
|
@ -199,8 +170,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
|
||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
|
@ -212,10 +181,9 @@ github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lN
|
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
@ -225,49 +193,29 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
|||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420 h1:Yu3681ykYHDfLoI6XVjL4JWmkE+3TX9yfIWwRCh1kFM=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v0.0.0-20170515205857-f03dbe35d449 h1:Aq8iG72akPb/kszE7ksZ5ldV+JYPYii/KZOxlpJF07s=
|
||||
github.com/opencontainers/image-spec v0.0.0-20170515205857-f03dbe35d449/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.0.0-20161109192122-51371867a01c h1:iOMba/KmaXgSX5PFKu1u6s+DZXiq+EzPayawa76w6aA=
|
||||
github.com/opencontainers/runc v0.0.0-20161109192122-51371867a01c/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 h1:lNCW6THrCKBiJBpz8kbVGjC7MgdCGKwuvBgc7LoD6sw=
|
||||
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210810234209-d01bc85eb481 h1:5c8N9Gh21Ja/9EIpfyHFmQvTCKgOjnRhosmo0ZshkFk=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210810234209-d01bc85eb481/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c=
|
||||
github.com/portainer/libcompose v0.5.3 h1:tE4WcPuGvo+NKeDkDWpwNavNLZ5GHIJ4RvuZXsI9uI8=
|
||||
github.com/portainer/libcompose v0.5.3/go.mod h1:7SKd/ho69rRKHDFSDUwkbMcol2TMKU5OslDsajr8Ro8=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210906052132-ef24824f7548 h1:5I9j0e6f9KG/RV6YBKWyks8LSHheE+ltJgpMyyWYUoo=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210906052132-ef24824f7548/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c=
|
||||
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a h1:qY8TbocN75n5PDl16o0uVr5MevtM5IhdwSelXEd4nFM=
|
||||
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a/go.mod h1:n54EEIq+MM0NNtqLeCby8ljL+l275VpolXO0ibHegLE=
|
||||
github.com/portainer/libhttp v0.0.0-20190806161843-ba068f58be33 h1:H8HR2dHdBf8HANSkUyVw4o8+4tegGcd+zyKZ3e599II=
|
||||
github.com/portainer/libhttp v0.0.0-20190806161843-ba068f58be33/go.mod h1:Y2TfgviWI4rT2qaOTHr+hq6MdKIE5YjgQAu7qwptTV0=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
|
@ -285,17 +233,15 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
|
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
|
||||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
|
||||
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -307,18 +253,15 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
|
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs=
|
||||
|
@ -331,8 +274,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
|
@ -351,9 +292,7 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -363,9 +302,8 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
|
|||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -394,7 +332,6 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
|||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.17.2 h1:NF1UFXcKN7/OOv1uxdRz3qfra8AHsPav5M93hlV9+Dc=
|
||||
k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
|
||||
k8s.io/apimachinery v0.17.2 h1:hwDQQFbdRlpnnsR64Asdi55GyCaIP/3WQpMmbNBeWr4=
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package stacks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
@ -177,7 +178,7 @@ func (handler *Handler) deleteStack(stack *portainer.Stack, endpoint *portainer.
|
|||
return handler.SwarmStackManager.Remove(stack, endpoint)
|
||||
}
|
||||
if stack.Type == portainer.DockerComposeStack {
|
||||
return handler.ComposeStackManager.Down(stack, endpoint)
|
||||
return handler.ComposeStackManager.Down(context.TODO(), stack, endpoint)
|
||||
}
|
||||
if stack.Type == portainer.KubernetesStack {
|
||||
return nil
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package stacks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
@ -120,7 +121,7 @@ func (handler *Handler) stackStart(w http.ResponseWriter, r *http.Request) *http
|
|||
func (handler *Handler) startStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
switch stack.Type {
|
||||
case portainer.DockerComposeStack:
|
||||
return handler.ComposeStackManager.Up(stack, endpoint)
|
||||
return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint)
|
||||
case portainer.DockerSwarmStack:
|
||||
return handler.SwarmStackManager.Deploy(stack, true, endpoint)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package stacks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
|
@ -104,7 +105,7 @@ func (handler *Handler) stackStop(w http.ResponseWriter, r *http.Request) *httpe
|
|||
func (handler *Handler) stopStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
switch stack.Type {
|
||||
case portainer.DockerComposeStack:
|
||||
return handler.ComposeStackManager.Down(stack, endpoint)
|
||||
return handler.ComposeStackManager.Down(context.TODO(), stack, endpoint)
|
||||
case portainer.DockerSwarmStack:
|
||||
return handler.SwarmStackManager.Remove(stack, endpoint)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
type userUpdatePayload struct {
|
||||
Username string `validate:"required" example:"bob"`
|
||||
Password string `validate:"required" example:"cg9Wgky3"`
|
||||
UserTheme string `example:"dark"`
|
||||
// User role (1 for administrator account and 2 for regular account)
|
||||
Role int `validate:"required" enums:"1,2" example:"2"`
|
||||
}
|
||||
|
@ -104,6 +105,10 @@ func (handler *Handler) userUpdate(w http.ResponseWriter, r *http.Request) *http
|
|||
user.Role = portainer.UserRole(payload.Role)
|
||||
}
|
||||
|
||||
if payload.UserTheme != "" {
|
||||
user.UserTheme = payload.UserTheme
|
||||
}
|
||||
|
||||
err = handler.DataStore.User().UpdateUser(user.ID, user)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist user changes inside the database", err}
|
||||
|
|
|
@ -68,7 +68,7 @@ func (factory *ProxyFactory) NewAgentProxy(endpoint *portainer.Endpoint) (*Proxy
|
|||
return nil, errors.Wrap(err, "failed starting proxy server")
|
||||
}
|
||||
|
||||
return proxyServer, err
|
||||
return proxyServer, nil
|
||||
}
|
||||
|
||||
func (proxy *ProxyServer) start() error {
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
package libcompose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/portainer/libcompose/config"
|
||||
"github.com/portainer/libcompose/docker"
|
||||
"github.com/portainer/libcompose/docker/client"
|
||||
"github.com/portainer/libcompose/docker/ctx"
|
||||
"github.com/portainer/libcompose/lookup"
|
||||
"github.com/portainer/libcompose/project"
|
||||
"github.com/portainer/libcompose/project/options"
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/internal/stackutils"
|
||||
)
|
||||
|
||||
const (
|
||||
dockerClientVersion = "1.24"
|
||||
composeSyntaxMaxVersion = "2"
|
||||
)
|
||||
|
||||
// ComposeStackManager represents a service for managing compose stacks.
|
||||
type ComposeStackManager struct {
|
||||
dataPath string
|
||||
reverseTunnelService portainer.ReverseTunnelService
|
||||
}
|
||||
|
||||
// NewComposeStackManager initializes a new ComposeStackManager service.
|
||||
func NewComposeStackManager(dataPath string, reverseTunnelService portainer.ReverseTunnelService) *ComposeStackManager {
|
||||
return &ComposeStackManager{
|
||||
dataPath: dataPath,
|
||||
reverseTunnelService: reverseTunnelService,
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *ComposeStackManager) createClient(endpoint *portainer.Endpoint) (client.Factory, error) {
|
||||
|
||||
endpointURL := endpoint.URL
|
||||
if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment {
|
||||
tunnel := manager.reverseTunnelService.GetTunnelDetails(endpoint.ID)
|
||||
endpointURL = fmt.Sprintf("tcp://127.0.0.1:%d", tunnel.Port)
|
||||
}
|
||||
|
||||
clientOpts := client.Options{
|
||||
Host: endpointURL,
|
||||
APIVersion: dockerClientVersion,
|
||||
}
|
||||
|
||||
if endpoint.TLSConfig.TLS {
|
||||
clientOpts.TLS = endpoint.TLSConfig.TLS
|
||||
clientOpts.TLSVerify = !endpoint.TLSConfig.TLSSkipVerify
|
||||
clientOpts.TLSCAFile = endpoint.TLSConfig.TLSCACertPath
|
||||
clientOpts.TLSCertFile = endpoint.TLSConfig.TLSCertPath
|
||||
clientOpts.TLSKeyFile = endpoint.TLSConfig.TLSKeyPath
|
||||
}
|
||||
|
||||
return client.NewDefaultFactory(clientOpts)
|
||||
}
|
||||
|
||||
// ComposeSyntaxMaxVersion returns the maximum supported version of the docker compose syntax
|
||||
func (manager *ComposeStackManager) ComposeSyntaxMaxVersion() string {
|
||||
return composeSyntaxMaxVersion
|
||||
}
|
||||
|
||||
// NormalizeStackName returns a new stack name with unsupported characters replaced
|
||||
func (manager *ComposeStackManager) NormalizeStackName(name string) string {
|
||||
// this is coming from libcompose
|
||||
// https://github.com/portainer/libcompose/blob/master/project/context.go#L117-L120
|
||||
r := regexp.MustCompile("[^a-z0-9]+")
|
||||
return r.ReplaceAllString(strings.ToLower(name), "")
|
||||
}
|
||||
|
||||
// Up will deploy a compose stack (equivalent of docker-compose up)
|
||||
func (manager *ComposeStackManager) Up(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
|
||||
clientFactory, err := manager.createClient(endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
env := make(map[string]string)
|
||||
for _, envvar := range stack.Env {
|
||||
env[envvar.Name] = envvar.Value
|
||||
}
|
||||
filePaths := stackutils.GetStackFilePaths(stack)
|
||||
|
||||
proj, err := docker.NewProject(&ctx.Context{
|
||||
ConfigDir: manager.dataPath,
|
||||
Context: project.Context{
|
||||
ComposeFiles: filePaths,
|
||||
EnvironmentLookup: &lookup.ComposableEnvLookup{
|
||||
Lookups: []config.EnvironmentLookup{
|
||||
&lookup.EnvfileLookup{
|
||||
Path: filepath.Join(stack.ProjectPath, ".env"),
|
||||
},
|
||||
&lookup.MapLookup{
|
||||
Vars: env,
|
||||
},
|
||||
},
|
||||
},
|
||||
ProjectName: stack.Name,
|
||||
},
|
||||
ClientFactory: clientFactory,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return proj.Up(context.Background(), options.Up{})
|
||||
}
|
||||
|
||||
// Down will shutdown a compose stack (equivalent of docker-compose down)
|
||||
func (manager *ComposeStackManager) Down(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
clientFactory, err := manager.createClient(endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var composeFiles []string
|
||||
for _, file := range append([]string{stack.EntryPoint}, stack.AdditionalFiles...) {
|
||||
composeFiles = append(composeFiles, path.Join(stack.ProjectPath, file))
|
||||
}
|
||||
proj, err := docker.NewProject(&ctx.Context{
|
||||
Context: project.Context{
|
||||
ComposeFiles: composeFiles,
|
||||
ProjectName: stack.Name,
|
||||
},
|
||||
ClientFactory: clientFactory,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return proj.Down(context.Background(), options.Down{RemoveVolume: false, RemoveOrphans: true})
|
||||
}
|
||||
|
||||
func stackFilePaths(stack *portainer.Stack) []string {
|
||||
var filePaths []string
|
||||
for _, file := range append([]string{stack.EntryPoint}, stack.AdditionalFiles...) {
|
||||
filePaths = append(filePaths, path.Join(stack.ProjectPath, file))
|
||||
}
|
||||
return filePaths
|
||||
}
|
|
@ -1003,6 +1003,8 @@ type (
|
|||
ID UserID `json:"Id" example:"1"`
|
||||
Username string `json:"Username" example:"bob"`
|
||||
Password string `json:"Password,omitempty" example:"passwd"`
|
||||
// User Theme
|
||||
UserTheme string `example:"dark"`
|
||||
// User role (1 for administrator account and 2 for regular account)
|
||||
Role UserRole `json:"Role" example:"1"`
|
||||
|
||||
|
@ -1054,8 +1056,8 @@ type (
|
|||
ComposeStackManager interface {
|
||||
ComposeSyntaxMaxVersion() string
|
||||
NormalizeStackName(name string) string
|
||||
Up(stack *Stack, endpoint *Endpoint) error
|
||||
Down(stack *Stack, endpoint *Endpoint) error
|
||||
Up(ctx context.Context, stack *Stack, endpoint *Endpoint) error
|
||||
Down(ctx context.Context, stack *Stack, endpoint *Endpoint) error
|
||||
}
|
||||
|
||||
// CryptoService represents a service for encrypting/hashing data
|
||||
|
@ -1179,6 +1181,7 @@ type (
|
|||
|
||||
// FileService represents a service for managing files
|
||||
FileService interface {
|
||||
GetDockerConfigPath() string
|
||||
GetFileContent(filePath string) ([]byte, error)
|
||||
Rename(oldPath, newPath string) error
|
||||
RemoveDirectory(directoryPath string) error
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package stacks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
|
@ -50,7 +51,7 @@ func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *por
|
|||
d.swarmStackManager.Login(registries, endpoint)
|
||||
defer d.swarmStackManager.Logout(endpoint)
|
||||
|
||||
return d.composeStackManager.Up(stack, endpoint)
|
||||
return d.composeStackManager.Up(context.TODO(), stack, endpoint)
|
||||
}
|
||||
|
||||
func (d *stackDeployer) DeployKubernetesStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
|
|
|
@ -59,10 +59,10 @@ body,
|
|||
}
|
||||
|
||||
.form-section-title {
|
||||
border-bottom: 1px solid #777;
|
||||
border-bottom: 1px solid var(--border-form-section-title-color);
|
||||
margin-top: 5px;
|
||||
margin-bottom: 15px;
|
||||
color: #777;
|
||||
color: var(--text-form-section-title-color);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
@ -108,12 +108,33 @@ a[ng-click] {
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
.datatable-highlighted {
|
||||
background-color: var(--bg-item-highlighted-color);
|
||||
}
|
||||
|
||||
.datatable-unhighlighted {
|
||||
background-color: var(--bg-item-highlighted-null-color);
|
||||
}
|
||||
|
||||
.service-datatable {
|
||||
background-color: var(--bg-item-highlighted-color);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.service-datatable thead {
|
||||
background-color: var(--bg-service-datatable-thead) !important;
|
||||
}
|
||||
|
||||
.service-datatable tbody {
|
||||
background-color: var(--bg-service-datatable-tbody);
|
||||
}
|
||||
|
||||
.tooltip.portainer-tooltip .tooltip-inner {
|
||||
font-family: Montserrat;
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-tooltip-color);
|
||||
padding: 0.833em 1em;
|
||||
color: #333333;
|
||||
border: 1px solid #d4d4d5;
|
||||
color: var(--text-tooltip-color);
|
||||
border: 1px solid var(--border-tooltip-color);
|
||||
border-radius: 0.14285714rem;
|
||||
box-shadow: 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
@ -145,7 +166,7 @@ a[ng-click] {
|
|||
|
||||
.fa.blue-icon,
|
||||
.fab.blue-icon {
|
||||
color: #337ab7;
|
||||
color: var(--blue-2);
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
|
@ -207,25 +228,25 @@ a[ng-click] {
|
|||
padding: 0.7rem;
|
||||
margin-bottom: 0.7rem;
|
||||
cursor: pointer;
|
||||
border: 1px solid #cccccc;
|
||||
border: 1px solid var(--border-blocklist-color);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 3px 10px -2px rgba(161, 170, 166, 0.5);
|
||||
box-shadow: var(--shadow-box-color);
|
||||
}
|
||||
|
||||
.blocklist-item--disabled {
|
||||
cursor: auto;
|
||||
background-color: #ececec;
|
||||
background-color: var(--grey-12);
|
||||
}
|
||||
|
||||
.blocklist-item--selected {
|
||||
border: 2px solid #bbbbbb;
|
||||
background-color: #ececec;
|
||||
color: #2d3e63;
|
||||
background-color: var(--bg-blocklist-item-selected-color);
|
||||
border: 2px solid var(--border-blocklist-item-selected-color);
|
||||
color: var(--text-blocklist-item-selected-color);
|
||||
}
|
||||
|
||||
.blocklist-item:hover {
|
||||
background-color: #ececec;
|
||||
color: #2d3e63;
|
||||
background-color: var(--bg-blocklist-hover-color);
|
||||
color: var(--text-blocklist-hover-color);
|
||||
}
|
||||
|
||||
.blocklist-item-box {
|
||||
|
@ -360,7 +381,7 @@ a[ng-click] {
|
|||
|
||||
.panel-body {
|
||||
padding-top: 30px;
|
||||
background-color: #ffffff;
|
||||
background-color: var(--white-color) fff;
|
||||
}
|
||||
|
||||
.pagination-controls {
|
||||
|
@ -443,8 +464,8 @@ a[ng-click] {
|
|||
display: inline-block;
|
||||
padding: 0px 6px;
|
||||
margin-left: 10px;
|
||||
color: #555555;
|
||||
background-color: #fff;
|
||||
color: var(--text-small-select-color);
|
||||
background-color: var(--bg-small-select-color);
|
||||
background-image: none;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
|
@ -462,11 +483,11 @@ a[ng-click] {
|
|||
}
|
||||
|
||||
.visualizer_container .node {
|
||||
border: 1px dashed #337ab7;
|
||||
border: 1px dashed var(--blue-2);
|
||||
background-color: rgb(51, 122, 183);
|
||||
background-color: rgba(51, 122, 183, 0.1);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 3px 10px -2px rgba(161, 170, 166, 0.5);
|
||||
box-shadow: 0 3px 10px -2px var(--grey-50);
|
||||
padding: 15px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
@ -476,7 +497,7 @@ a[ng-click] {
|
|||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #777;
|
||||
border-bottom: 1px solid var(--grey-26);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
|
@ -486,7 +507,7 @@ a[ng-click] {
|
|||
}
|
||||
|
||||
.visualizer_container .node .node_info .node_labels {
|
||||
border-top: 1px solid #777;
|
||||
border-top: 1px solid var(--grey-26);
|
||||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
@ -503,9 +524,9 @@ a[ng-click] {
|
|||
}
|
||||
|
||||
.visualizer_container .node .tasks .task {
|
||||
border: 1px solid #333333;
|
||||
border: 1px solid var(--grey-6);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 3px 10px -2px rgba(161, 170, 166, 0.5);
|
||||
box-shadow: 0 3px 10px -2px var(--grey-50);
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
font-size: 10px;
|
||||
|
@ -547,9 +568,9 @@ a[ng-click] {
|
|||
.log_viewer {
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
color: black;
|
||||
color: var(--text-log-viewer-color);
|
||||
font-size: 0.85em;
|
||||
background-color: white;
|
||||
background-color: var(--bg-log-viewer-color);
|
||||
}
|
||||
|
||||
.log_viewer.wrap_lines {
|
||||
|
@ -568,7 +589,7 @@ a[ng-click] {
|
|||
}
|
||||
|
||||
.log_viewer .line_selected {
|
||||
background-color: #c5cae9;
|
||||
background-color: var(--bg-log-line-selected-color);
|
||||
}
|
||||
|
||||
.row.header .meta .page {
|
||||
|
@ -578,7 +599,7 @@ a[ng-click] {
|
|||
.tag {
|
||||
padding: 2px 6px;
|
||||
color: white;
|
||||
background-color: #337ab7;
|
||||
background-color: var(--blue-2);
|
||||
border: 1px solid #2e6da4;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
@ -588,7 +609,7 @@ a[ng-click] {
|
|||
}
|
||||
|
||||
.line-separator {
|
||||
border-bottom: 1px solid #777;
|
||||
border-bottom: 1px solid var(--grey-26);
|
||||
width: 50%;
|
||||
margin: 20px auto 10px auto;
|
||||
}
|
||||
|
@ -613,7 +634,7 @@ a[ng-click] {
|
|||
}
|
||||
|
||||
.striked::after {
|
||||
border-bottom: 0.2em solid #777777;
|
||||
border-bottom: 0.2em solid var(--grey-26);
|
||||
content: '';
|
||||
left: 0;
|
||||
margin-top: calc(0.2em / 2 * -1);
|
||||
|
@ -625,7 +646,7 @@ a[ng-click] {
|
|||
|
||||
.striketext:before,
|
||||
.striketext:after {
|
||||
background-color: #777777;
|
||||
background-color: var(--grey-26);
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 1px;
|
||||
|
@ -657,20 +678,51 @@ a[ng-click] {
|
|||
/*angular-multi-select override*/
|
||||
.multiSelect > button {
|
||||
min-height: 30px !important;
|
||||
background-color: unset;
|
||||
background-image: unset;
|
||||
background-image: var(--bg-image-multiselect-button);
|
||||
border-color: var(--border-multiselect);
|
||||
color: var(--text-multiselect);
|
||||
background-color: var(--bg-multiselect-color);
|
||||
}
|
||||
|
||||
.multiSelect > button:hover {
|
||||
background-image: var(--bg-image-multiselect-hover);
|
||||
}
|
||||
|
||||
.multiSelect .checkboxLayer {
|
||||
border-color: var(--border-multiselect-checkboxlayer);
|
||||
}
|
||||
|
||||
.multiSelect .checkBoxContainer {
|
||||
background-color: var(--bg-multiselect-checkboxcontainer);
|
||||
}
|
||||
|
||||
.multiSelect .multiSelectItem {
|
||||
color: var(--text-multiselect-item);
|
||||
}
|
||||
|
||||
.multiSelect .helperContainer {
|
||||
background-color: var(--bg-multiselect-helpercontainer);
|
||||
}
|
||||
|
||||
.multiSelect .multiSelectFocus {
|
||||
background-image: var(--bg-image-multiselect);
|
||||
}
|
||||
|
||||
.multiSelect .multiSelectItem:not(.multiSelectGroup).selected {
|
||||
background-image: linear-gradient(#337ab7, #337ab7);
|
||||
color: #fff;
|
||||
background-image: var(--bg-image-multiselect);
|
||||
color: var(--white-color);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.multiSelect .multiSelectItem:hover,
|
||||
.multiSelect .multiSelectGroup:hover {
|
||||
background-image: linear-gradient(#337ab7, #337ab7) !important;
|
||||
color: #fff !important;
|
||||
border-color: var(--grey-3);
|
||||
}
|
||||
|
||||
.multiSelect .multiSelectItem:hover,
|
||||
.multiSelect .multiSelectGroup:hover {
|
||||
background-image: var(--bg-image-multiselect) !important;
|
||||
color: var(--white-color) !important;
|
||||
}
|
||||
|
||||
.multiSelect .tickMark,
|
||||
|
@ -696,7 +748,7 @@ a[ng-click] {
|
|||
#loading-bar .bar {
|
||||
position: relative;
|
||||
height: 3px;
|
||||
background: #738bc0;
|
||||
background: var(--blue-3);
|
||||
}
|
||||
/*!angular-loading-bar override*/
|
||||
|
||||
|
@ -708,11 +760,11 @@ a[ng-click] {
|
|||
/* json-tree override */
|
||||
json-tree {
|
||||
font-size: 13px;
|
||||
color: #30426a;
|
||||
color: var(--blue-5);
|
||||
}
|
||||
|
||||
json-tree .key {
|
||||
color: #738bc0;
|
||||
color: var(--blue-3);
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
|
@ -725,7 +777,7 @@ json-tree .branch-preview {
|
|||
|
||||
/* uib-progressbar override */
|
||||
.progress-bar {
|
||||
color: #4e4e4e;
|
||||
color: var(--text-progress-bar-color);
|
||||
}
|
||||
/* !uib-progressbar override */
|
||||
|
||||
|
@ -756,7 +808,7 @@ json-tree .branch-preview {
|
|||
}
|
||||
|
||||
.sk-fold-cube:before {
|
||||
background-color: #337ab7;
|
||||
background-color: var(--blue-2);
|
||||
}
|
||||
/* !spinkit override */
|
||||
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
import './rdash.css';
|
||||
import './app.css';
|
||||
import './theme.css';
|
||||
import './vendor-override.css';
|
||||
|
|
|
@ -52,7 +52,8 @@
|
|||
* Header
|
||||
*/
|
||||
.row.header {
|
||||
background: #fff;
|
||||
height: 60px;
|
||||
background: var(--bg-row-header-color);
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.row.header > div:last-child {
|
||||
|
@ -202,9 +203,9 @@ html {
|
|||
overflow-y: scroll;
|
||||
}
|
||||
body {
|
||||
background: #f3f3f3;
|
||||
background: var(--bg-body-color);
|
||||
font-family: 'Montserrat';
|
||||
color: #333333 !important;
|
||||
color: var(--text-body-color) !important;
|
||||
}
|
||||
.row {
|
||||
margin-left: 0 !important;
|
||||
|
@ -236,7 +237,7 @@ body {
|
|||
background: #23ae89 !important;
|
||||
}
|
||||
.blue {
|
||||
background: #2361ae !important;
|
||||
background: var(--blue-color) !important;
|
||||
}
|
||||
.orange {
|
||||
background: #d3a938 !important;
|
||||
|
@ -258,20 +259,20 @@ div.input-mask {
|
|||
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
background: #ffffff;
|
||||
background: var(--bg-widget-color);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
border-color: #e9e9e9;
|
||||
border-color: var(--border-widget-color);
|
||||
}
|
||||
.widget .widget-header .pagination,
|
||||
.widget .widget-footer .pagination {
|
||||
margin: 0;
|
||||
}
|
||||
.widget .widget-header {
|
||||
color: #767676;
|
||||
background-color: #f6f6f6;
|
||||
color: var(--text-widget-header-color);
|
||||
background-color: var(--bg-widget-header-color);
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
border-bottom: 1px solid var(--border-widget-color);
|
||||
line-height: 30px;
|
||||
}
|
||||
.widget .widget-header i {
|
||||
|
@ -281,7 +282,7 @@ div.input-mask {
|
|||
padding: 20px;
|
||||
}
|
||||
.widget .widget-body table thead {
|
||||
background: #fafafa;
|
||||
background: var(--bg-widget-table-color);
|
||||
}
|
||||
.widget .widget-body table thead * {
|
||||
font-size: 14px !important;
|
||||
|
|
|
@ -0,0 +1,576 @@
|
|||
/* Color Variable */
|
||||
html {
|
||||
--black-color: #000;
|
||||
--white-color: #fff;
|
||||
|
||||
--grey-1: #212121;
|
||||
--grey-2: #181818;
|
||||
--grey-3: #383838;
|
||||
--grey-4: #585858;
|
||||
--grey-5: #323c48;
|
||||
--grey-6: #333333;
|
||||
--grey-7: #767676;
|
||||
--grey-8: #aaa;
|
||||
--grey-9: #f3f3f3;
|
||||
--grey-10: #f6f6f6;
|
||||
--grey-11: #eeeeee;
|
||||
--grey-12: #ececec;
|
||||
--grey-13: #fafafa;
|
||||
--grey-14: #f5f5f5;
|
||||
--grey-15: #f9f2f4;
|
||||
--grey-16: #eee;
|
||||
--grey-17: #f7f7f7;
|
||||
--grey-18: #c5cae9;
|
||||
--grey-19: #ddd;
|
||||
--grey-20: #dae3f3;
|
||||
--grey-21: #d5e8f3;
|
||||
--grey-22: #c3c3e4;
|
||||
--grey-23: #e7f6ff;
|
||||
--grey-24: #f1f9fd;
|
||||
--grey-25: #555555;
|
||||
--grey-26: #777777;
|
||||
--grey-27: #4e4e4e;
|
||||
--grey-28: #262626;
|
||||
--grey-29: #555;
|
||||
--grey-30: #444;
|
||||
--grey-31: #868686;
|
||||
--grey-32: #65798e;
|
||||
--grey-34: #314252;
|
||||
--grey-35: #546477;
|
||||
--grey-36: #55637d;
|
||||
--grey-37: #2d3e63;
|
||||
--grey-38: #434343;
|
||||
--grey-39: #194973;
|
||||
--grey-40: #cfddfc;
|
||||
--grey-41: #b4b4b4;
|
||||
--grey-42: #d2d1d1;
|
||||
--grey-43: #e9e9e9;
|
||||
--grey-44: #ccc;
|
||||
--grey-45: #e5e5e5;
|
||||
--grey-46: #bbbbbb;
|
||||
--grey-47: #d4d4d5;
|
||||
--grey-48: #c6c6c6;
|
||||
--grey-49: rgba(0, 0, 0, 0.54);
|
||||
--grey-50: rgba(161, 170, 166, 0.5);
|
||||
--grey-51: rgba(0, 0, 0, 0.15);
|
||||
--grey-52: rgba(255, 255, 255, 0.3);
|
||||
--grey-53: rgba(255, 255, 255, 0.6);
|
||||
--grey-54: rgb(54, 54, 54);
|
||||
--grey-55: rgba(255, 255, 255, 0.8);
|
||||
--grey-56: #b2bfdc;
|
||||
--grey-57: #999;
|
||||
--grey-58: #ebf4f8;
|
||||
--grey-59: #e6e6e6;
|
||||
--grey-60: #cacaca;
|
||||
|
||||
--blue-1: #219;
|
||||
--blue-2: #337ab7;
|
||||
--blue-3: #738bc0;
|
||||
--blue-4: #23527c;
|
||||
--blue-5: #30426a;
|
||||
--blue-6: #577bc9;
|
||||
--blue-7: #6b9aff;
|
||||
--blue-8: #90ccff;
|
||||
--blue-9: #3ea6ff;
|
||||
--blue-10: #61b6ff;
|
||||
--blue-11: #3ea5ff;
|
||||
--blue-12: #41a6ff;
|
||||
--blue-13: #2361ae;
|
||||
--blue-14: #357ebd;
|
||||
|
||||
--red-1: #a94442;
|
||||
--red-2: #c7254e;
|
||||
--red-3: #a11;
|
||||
--red-4: #d9534f;
|
||||
--red-5: #ff2727;
|
||||
--red-6: #ff00e0;
|
||||
--red-7: #f00;
|
||||
|
||||
--green-1: #164;
|
||||
--green-2: #1ec863;
|
||||
}
|
||||
|
||||
:root {
|
||||
--bg-card-color: var(--grey-10);
|
||||
--bg-main-color: var(--white-color);
|
||||
--bg-body-color: var(--grey-9);
|
||||
--bg-checkbox-border-color: var(--grey-49);
|
||||
--bg-sidebar-color: var(--grey-37);
|
||||
--bg-sidebar-header-color: var(--grey-37);
|
||||
--bg-widget-color: var(--white-color);
|
||||
--bg-widget-header-color: var(--grey-10);
|
||||
--bg-widget-table-color: var(--grey-13);
|
||||
--bg-header-color: var(--white-color);
|
||||
--bg-hover-table-color: var(--grey-14);
|
||||
--bg-switch-box-color: var(--white-color);
|
||||
--bg-input-group-addon-color: var(--grey-11);
|
||||
--bg-btn-default-color: var(--white-color);
|
||||
--bg-blocklist-hover-color: var(--grey-12);
|
||||
--bg-boxselector-color: var(--white-color);
|
||||
--bg-table-color: var(--white-color);
|
||||
--bg-md-checkbox-color: var(--grey-12);
|
||||
--bg-form-control-disabled-color: var(--grey-11);
|
||||
--bg-modal-content-color: var(--white-color);
|
||||
--bg-code-color: var(--grey-15);
|
||||
--bg-navtabs-color: var(--white-color);
|
||||
--bg-navtabs-hover-color: var(--grey-16);
|
||||
--bg-table-selected-color: var(--grey-14);
|
||||
--bg-codemirror-gutters-color: var(--grey-17);
|
||||
--bg-dropdown-menu-color: var(--white-color);
|
||||
--bg-log-viewer-color: var(--white-color);
|
||||
--bg-log-line-selected-color: var(--grey-18);
|
||||
--bg-pre-color: var(--grey-14);
|
||||
--bg-blocklist-item-selected-color: var(--grey-12);
|
||||
--bg-progress-color: var(--grey-14);
|
||||
--bg-pagination-color: var(--white-color);
|
||||
--bg-pagination-span-color: var(--white-color);
|
||||
--bg-pagination-hover-color: var(--grey-11);
|
||||
--bg-ui-select-hover-color: var(--grey-14);
|
||||
--bg-motd-body-color: var(--grey-20);
|
||||
--bg-item-highlighted-color: var(--grey-21);
|
||||
--bg-item-highlighted-null-color: var(--grey-14);
|
||||
--bg-row-header-color: var(--white-color);
|
||||
--bg-image-multiselect-button: linear-gradient(var(--white-color), var(--grey-17));
|
||||
--bg-multiselect-checkbox-color: var(--white-color);
|
||||
--bg-sidebar-wrapper-color: var(--blue-5);
|
||||
--bg-panel-body-color: var(--white-color);
|
||||
--bg-codemirror-color: var(--white-color);
|
||||
--bg-codemirror-selected-color: var(--grey-22);
|
||||
--bg-multiselect-color: var(--white-color);
|
||||
--bg-daterangepicker-color: var(--white-color);
|
||||
--bg-calendar-color: var(--white-color);
|
||||
--bg-calendar-table-color: var(--white-color);
|
||||
--bg-daterangepicker-end-date: var(--white-color);
|
||||
--bg-daterangepicker-hover: var(--grey-16);
|
||||
--bg-daterangepicker-in-range: var(--grey-58);
|
||||
--bg-daterangepicker-active: var(--blue-14);
|
||||
--bg-tooltip-color: var(--white-color);
|
||||
--bg-input-autofill-color: var(--white-color);
|
||||
--bg-btn-default-hover-color: var(--grey-59);
|
||||
--bg-btn-focus: var(--grey-59);
|
||||
--bg-boxselector-disabled-color: var(--white-color);
|
||||
--bg-small-select-color: var(--white-color);
|
||||
|
||||
--text-main-color: var(--grey-7);
|
||||
--text-body-color: var(--grey-6);
|
||||
--text-sidebar-title-color: var(--blue-3);
|
||||
--text-widget-header-color: var(--grey-7);
|
||||
--text-form-control-color: var(--grey-25);
|
||||
--text-muted-color: var(--grey-26);
|
||||
--text-link-color: var(--blue-2);
|
||||
--text-link-hover-color: var(--blue-4);
|
||||
--text-input-group-addon-color: var(--grey-25);
|
||||
--text-btn-default-color: var(--grey-6);
|
||||
--text-blocklist-hover-color: var(--grey-37);
|
||||
--text-dashboard-item-color: var(--grey-32);
|
||||
--text-danger-color: var(--red-1);
|
||||
--text-code-color: var(--red-2);
|
||||
--text-navtabs-color: var(--grey-25);
|
||||
--text-form-section-title-color: var(--grey-26);
|
||||
--text-cm-default-color: var(--blue-1);
|
||||
--text-cm-meta-color: var(--black-color);
|
||||
--text-cm-string-color: var(--red-3);
|
||||
--text-cm-number-color: var(--green-1);
|
||||
--text-codemirror-color: var(--black-color);
|
||||
--text-dropdown-menu-color: var(--grey-6);
|
||||
--text-log-viewer-color: var(--black-color);
|
||||
--text-json-tree-color: var(--blue-3);
|
||||
--text-json-tree-leaf-color: var(--blue-5);
|
||||
--text-json-tree-branch-preview-color: var(--blue-5);
|
||||
--text-pre-color: var(--grey-6);
|
||||
--text-blocklist-item-selected-color: var(--grey-37);
|
||||
--text-progress-bar-color: var(--grey-27);
|
||||
--text-pagination-color: var(--grey-26);
|
||||
--text-pagination-span-color: var(--blue-2);
|
||||
--text-pagination-span-hover-color: var(--blue-4);
|
||||
--text-ui-select-color: var(--grey-6);
|
||||
--text-ui-select-hover-color: var(--grey-28);
|
||||
--text-summary-color: var(--black-color);
|
||||
--text-multiselect-button-color: var(--grey-29);
|
||||
--text-multiselect-item-color: var(--grey-30);
|
||||
--text-sidebar-list-color: var(--grey-56);
|
||||
--text-rzslider-color: var(--grey-36);
|
||||
--text-rzslider-limit-color: var(--grey-36);
|
||||
--text-daterangepicker-end-date: var(--grey-57);
|
||||
--text-daterangepicker-in-range: var(--black-color);
|
||||
--text-daterangepicker-active: var(--white-color);
|
||||
--text-tooltip-color: var(--grey-6);
|
||||
--text-input-autofill-color: var(--black-color);
|
||||
--text-button-hover-color: var(--grey-6);
|
||||
--text-small-select-color: var(--grey-25);
|
||||
|
||||
--border-color: var(--grey-42);
|
||||
--border-widget-color: var(--grey-43);
|
||||
--border-sidebar-color: var(--white-color);
|
||||
--border-form-control-color: var(--grey-44);
|
||||
--border-table-color: var(--grey-19);
|
||||
--border-table-top-color: var(--grey-19);
|
||||
--border-datatable-top-color: var(--grey-10);
|
||||
--border-blocklist-color: var(--grey-44) ccc;
|
||||
--border-input-group-addon-color: var(--grey-44);
|
||||
--border-btn-default-color: var(--grey-44);
|
||||
--border-boxselector-color: var(--grey-6);
|
||||
--border-md-checkbox-color: var(--grey-19);
|
||||
--border-modal-header-color: var(--grey-45);
|
||||
--border-navtabs-color: var(--grey-19);
|
||||
--border-form-section-title-color: var(--grey-26);
|
||||
--border-codemirror-cursor-color: var(--black-color);
|
||||
--border-codemirror-gutters-color: var(--grey-19);
|
||||
--border-pre-color: var(--grey-43);
|
||||
--border-blocklist-item-selected-color: var(--grey-46);
|
||||
--border-pagination-color: var(--grey-19);
|
||||
--border-pagination-span-color: var(--grey-19);
|
||||
--border-pagination-hover-color: var(--grey-19);
|
||||
--border-multiselect-button-color: var(--grey-48);
|
||||
--border-searchbar-color: var(--grey-10);
|
||||
--border-panel-color: var(--white-color);
|
||||
--border-daterangepicker-color: var(--grey-19);
|
||||
--border-calendar-table: var(--white-color);
|
||||
--border-daterangepicker: var(--grey-19);
|
||||
--border-pre-next-month: var(--black-color);
|
||||
--border-daterangepicker-after: var(--white-color);
|
||||
--border-tooltip-color: var(--grey-47);
|
||||
--border-modal: 0px;
|
||||
|
||||
--hover-sidebar-color: var(--grey-37);
|
||||
--shadow-box-color: 0 3px 10px -2px var(--grey-50);
|
||||
--shadow-boxselector-color: 0 3px 10px -2px var(--grey-50);
|
||||
--blue-color: var(--blue-13);
|
||||
--button-close-color: var(--black-color);
|
||||
--button-opacity: 0.2;
|
||||
--button-opacity-hover: 0.5;
|
||||
--bg-boxselector-wrapper-color: var(--grey-6);
|
||||
|
||||
--bg-image-multiselect: linear-gradient(var(--blue-2), var(--blue-2));
|
||||
--bg-image-multiselect-button: linear-gradient(var(--white-color), var(--grey-17));
|
||||
--bg-image-multiselect-hover: linear-gradient(var(--white-color), var(--grey-43));
|
||||
--border-multiselect: var(--grey-48);
|
||||
--border-multiselect-checkboxlayer: var(--grey-51);
|
||||
--text-multiselect: var(--grey-29);
|
||||
--text-multiselect-selectitem: var(--white-color);
|
||||
--bg-multiselect-checkboxcontainer: var(--white-color);
|
||||
--text-multiselect-item: var(--grey-30);
|
||||
--bg-multiselect-helpercontainer: var(--white-color);
|
||||
--text-input-textarea: var(--white-color);
|
||||
--bg-service-datatable-thead: var(--grey-23);
|
||||
--bg-service-datatable-tbody: var(--grey-24);
|
||||
}
|
||||
|
||||
:root[theme='dark'] {
|
||||
--bg-card-color: var(--grey-1);
|
||||
--bg-main-color: var(--grey-2);
|
||||
--bg-body-color: var(--grey-2);
|
||||
--bg-checkbox-border-color: var(--grey-8);
|
||||
--bg-sidebar-color: var(--grey-3);
|
||||
--bg-widget-color: var(--grey-1);
|
||||
--bg-widget-header-color: var(--grey-1);
|
||||
--bg-widget-table-color: var(--grey-1);
|
||||
--bg-header-color: var(--grey-2);
|
||||
--bg-hover-table-color: var(--grey-3);
|
||||
--bg-switch-box-color: var(--grey-53);
|
||||
--bg-input-group-addon-color: var(--grey-3);
|
||||
--bg-btn-default-color: var(--grey-3);
|
||||
--bg-blocklist-hover-color: var(--grey-3);
|
||||
--bg-boxselector-color: var(--grey-54);
|
||||
--bg-table-color: var(--grey-1);
|
||||
--bg-md-checkbox-color: var(--grey-31);
|
||||
--bg-form-control-disabled-color: var(--grey-3);
|
||||
--bg-modal-content-color: var(--grey-1);
|
||||
--bg-code-color: var(--red-4);
|
||||
--bg-navtabs-color: var(--grey-3);
|
||||
--bg-navtabs-hover-color: var(--grey-3);
|
||||
--bg-table-selected-color: var(--grey-3);
|
||||
--bg-codemirror-color: var(--grey-2);
|
||||
--bg-codemirror-gutters-color: var(--grey-2);
|
||||
--bg-dropdown-menu-color: var(--grey-1);
|
||||
--bg-log-viewer-color: var(--grey-2);
|
||||
--bg-log-line-selected-color: var(--grey-3);
|
||||
--bg-pre-color: var(--grey-2);
|
||||
--bg-blocklist-item-selected-color: var(--grey-3);
|
||||
--bg-progress-color: var(--grey-3);
|
||||
--bg-pagination-color: var(--grey-3);
|
||||
--bg-pagination-span-color: var(--grey-3);
|
||||
--bg-pagination-hover-color: var(--grey-4);
|
||||
--bg-ui-select-hover-color: var(--grey-3);
|
||||
--bg-motd-body-color: var(--grey-1);
|
||||
--bg-item-highlighted-color: var(--grey-2);
|
||||
--bg-item-highlighted-null-color: var(--grey-2);
|
||||
--bg-row-header-color: var(--grey-2);
|
||||
--bg-multiselect-button-color: var(--grey-3);
|
||||
--bg-image-multiselect-button: none !important;
|
||||
--bg-multiselect-checkbox-color: var(--grey-3);
|
||||
--bg-sidebar-wrapper-color: var(--grey-1);
|
||||
--bg-panel-body-color: var(--grey-1);
|
||||
--bg-boxselector-wrapper-disabled-color: var(--grey-39);
|
||||
--bg-codemirror-selected-color: var(--grey-3);
|
||||
--bg-sidebar-header-color: var(--grey-1);
|
||||
--bg-multiselect-color: var(--grey-1);
|
||||
--bg-daterangepicker-color: var(--grey-3);
|
||||
--bg-calendar-color: var(--grey-3);
|
||||
--bg-calendar-table-color: var(--grey-3);
|
||||
--bg-daterangepicker-end-date: var(--grey-4);
|
||||
--bg-daterangepicker-hover: var(--grey-4);
|
||||
--bg-daterangepicker-in-range: var(--grey-2);
|
||||
--bg-daterangepicker-active: var(--blue-14);
|
||||
--bg-tooltip-color: var(--grey-3);
|
||||
--bg-input-autofill-color: var(--grey-2);
|
||||
--bg-btn-default-hover-color: var(--grey-3);
|
||||
--bg-btn-focus: var(--grey-3);
|
||||
--bg-boxselector-disabled-color: var(--grey-54);
|
||||
--bg-small-select-color: var(--grey-2);
|
||||
|
||||
--text-main-color: var(--white-color);
|
||||
--text-body-color: var(--white-color);
|
||||
--text-sidebar-title-color: var(--grey-8);
|
||||
--text-widget-header-color: var(--white-color);
|
||||
--text-form-control-color: var(--grey-8);
|
||||
--text-muted-color: var(--grey-8);
|
||||
--text-link-color: var(--blue-9);
|
||||
--text-link-hover-color: var(--blue-2);
|
||||
--text-input-group-addon-color: var(--grey-8);
|
||||
--text-btn-default-color: var(--grey-8);
|
||||
--text-blocklist-hover-color: var(--white-color);
|
||||
--text-dashboard-item-color: var(--blue-2);
|
||||
--text-danger-color: var(--red-4);
|
||||
--text-code-color: var(--white-color);
|
||||
--text-navtabs-color: var(--white-color);
|
||||
--text-form-section-title-color: var(--grey-8);
|
||||
--text-cm-default-color: var(--blue-10);
|
||||
--text-cm-meta-color: var(--white-color);
|
||||
--text-cm-string-color: var(--red-5);
|
||||
--text-cm-number-color: var(--green-2);
|
||||
--text-codemirror-color: var(--white-color);
|
||||
--text-dropdown-menu-color: var(--white-color);
|
||||
--text-log-viewer-color: var(--white-color);
|
||||
--text-json-tree-color: var(--grey-40);
|
||||
--text-json-tree-leaf-color: var(--blue-6);
|
||||
--text-json-tree-branch-preview-color: var(--blue-7);
|
||||
--text-pre-color: var(--white-color);
|
||||
--text-blocklist-item-selected-color: var(--white-color);
|
||||
--text-progress-bar-color: var(--white-color);
|
||||
--text-pagination-color: var(--white-color);
|
||||
--text-pagination-span-color: var(--white-color);
|
||||
--text-pagination-span-hover-color: var(--white-color);
|
||||
--text-ui-select-color: var(--white-color);
|
||||
--text-ui-select-hover-color: var(--white-color);
|
||||
--text-summary-color: var(--white-color);
|
||||
--text-multiselect-button-color: var(--white-color);
|
||||
--text-multiselect-item-color: var(--white-color);
|
||||
--text-sidebar-list-color: var(--white-color);
|
||||
--text-boxselector-wrapper-color: var(--white-color);
|
||||
--text-daterangepicker-end-date: var(--grey-7);
|
||||
--text-daterangepicker-in-range: var(--white-color);
|
||||
--text-daterangepicker-active: var(--white-color);
|
||||
--text-tooltip-color: var(--white-color);
|
||||
--text-btn-default-color: var(--white-color);
|
||||
--text-input-autofill-color: var(--grey-8);
|
||||
--text-button-hover-color: var(--white-color);
|
||||
--text-small-select-color: var(--grey-7);
|
||||
|
||||
--border-color: var(--grey-3);
|
||||
--border-widget-color: var(--grey-1);
|
||||
--border-sidebar-color: var(--blue-9);
|
||||
--border-form-control-color: var(--grey-54);
|
||||
--border-table-color: var(--grey-3);
|
||||
--border-table-top-color: var(--grey-3);
|
||||
--border-datatable-top-color: var(--grey-3);
|
||||
--border-blocklist-color: var(--grey-3);
|
||||
--border-input-group-addon-color: var(--grey-38);
|
||||
--border-btn-default-color: var(--grey-38);
|
||||
--border-boxselector-color: var(--grey-1);
|
||||
--border-md-checkbox-color: var(--grey-41);
|
||||
--border-modal-header-color: var(--grey-1);
|
||||
--border-navtabs-color: var(--grey-38);
|
||||
--border-form-section-title-color: var(--grey-8);
|
||||
--border-codemirror-cursor-color: var(--white-color);
|
||||
--border-codemirror-gutters-color: var(--grey-26);
|
||||
--border-pre-color: var(--grey-3);
|
||||
--border-blocklist-item-selected-color: var(--grey-38);
|
||||
--border-pagination-color: var(--grey-3);
|
||||
--border-pagination-span-color: var(--grey-3);
|
||||
--border-pagination-hover-color: var(--grey-3);
|
||||
--border-pagination-hover-color: var(--grey-3);
|
||||
--border-multiselect-button-color: var(--grey-3);
|
||||
--border-searchbar-color: var(--grey-1);
|
||||
--border-panel-color: var(--grey-2);
|
||||
--border-daterangepicker-color: var(--grey-3);
|
||||
--border-calendar-table: var(--grey-3);
|
||||
--border-daterangepicker: var(--grey-4);
|
||||
--border-pre-next-month: var(--white-color);
|
||||
--border-daterangepicker-after: var(--grey-3);
|
||||
--border-tooltip-color: var(--grey-3);
|
||||
--border-modal: 0px;
|
||||
|
||||
--hover-sidebar-color: var(--grey-3);
|
||||
--blue-color: var(--blue-2);
|
||||
--button-close-color: var(--white-color);
|
||||
--button-opacity: 0.6;
|
||||
--button-opacity-hover: 0.3;
|
||||
--shadow-box-color: none;
|
||||
--shadow-boxselector-color: none;
|
||||
|
||||
--bg-image-multiselect: linear-gradient(var(--grey-38), var(--grey-38));
|
||||
--bg-image-multiselect-button: linear-gradient(var(--grey-1), var(--grey-1));
|
||||
--bg-image-multiselect-hover: linear-gradient(var(--grey-3), var(--grey-3));
|
||||
--border-multiselect: var(--grey-3);
|
||||
--border-multiselect-checkboxlayer: var(--grey-3);
|
||||
--text-multiselect: var(--white-color);
|
||||
--bg-multiselect-checkboxcontainer: var(--grey-3);
|
||||
--text-multiselect-item: var(--white-color);
|
||||
--bg-multiselect-helpercontainer: var(--grey-1);
|
||||
--text-input-textarea: var(--grey-1);
|
||||
--bg-service-datatable-thead: var(--grey-1);
|
||||
--bg-service-datatable-tbody: var(--grey-1);
|
||||
}
|
||||
|
||||
:root[theme='highcontrast'] {
|
||||
--bg-card-color: var(--black-color);
|
||||
--bg-main-color: var(--black-color);
|
||||
--bg-body-color: var(--black-color);
|
||||
--bg-checkbox-border-color: var(--grey-8);
|
||||
--bg-sidebar-color: var(--black-color);
|
||||
--bg-widget-color: var(--black-color);
|
||||
--bg-widget-header-color: var(--black-color);
|
||||
--bg-widget-table-color: var(--black-color);
|
||||
--bg-header-color: var(--black-color);
|
||||
--bg-hover-table-color: var(--grey-3);
|
||||
--bg-switch-box-color: var(--grey-53);
|
||||
--bg-panel-body-color: var(--black-color);
|
||||
--bg-boxselector-wrapper-disabled-color: var(--grey-39);
|
||||
--bg-dropdown-menu-color: var(--black-color);
|
||||
--bg-codemirror-selected-color: var(--grey-3);
|
||||
--bg-row-header-color: var(--black-color);
|
||||
--bg-sidebar-wrapper-color: var(--black-color);
|
||||
--bg-motd-body-color: var(--black-color);
|
||||
--bg-blocklist-hover-color: var(--black-color);
|
||||
--bg-blocklist-item-selected-color: var(--black-color);
|
||||
--bg-input-group-addon-color: var(--grey-1);
|
||||
--bg-table-color: var(--black-color);
|
||||
--bg-codemirror-gutters-color: var(--black-color);
|
||||
--bg-codemirror-color: var(--black-color);
|
||||
--bg-codemirror-selected-color: var(--grey-3);
|
||||
--bg-log-viewer-color: var(--black-color);
|
||||
--bg-log-line-selected-color: var(--grey-3);
|
||||
--bg-sidebar-header-color: var(--black-color);
|
||||
--bg-modal-content-color: var(--black-color);
|
||||
--bg-form-control-disabled-color: var(--grey-1);
|
||||
--bg-input-sm-color: var(--black-color);
|
||||
--bg-item-highlighted-color: var(--black-color);
|
||||
--bg-service-datatable-thead: var(--black-color);
|
||||
--bg-service-datatable-tbody: var(--black-color);
|
||||
--bg-pagination-color: var(--grey-3);
|
||||
--bg-pagination-span-color: var(--grey-3);
|
||||
--bg-multiselect-color: var(--grey-1);
|
||||
--bg-daterangepicker-color: var(--black-color);
|
||||
--bg-calendar-color: var(--black-color);
|
||||
--bg-calendar-table-color: var(--black-color);
|
||||
--bg-daterangepicker-end-date: var(--grey-3);
|
||||
--bg-daterangepicker-hover: var(--grey-3);
|
||||
--bg-daterangepicker-in-range: var(--grey-2);
|
||||
--bg-daterangepicker-active: var(--blue-14);
|
||||
--bg-tooltip-color: var(--black-color);
|
||||
--bg-table-selected-color: var(--grey-3);
|
||||
--bg-pre-color: var(--grey-2);
|
||||
--bg-navtabs-hover-color: var(--grey-3);
|
||||
--bg-btn-default-color: var(--black-color);
|
||||
--bg-code-color: var(--red-4);
|
||||
--bg-navtabs-color: var(--black-color);
|
||||
--bg-input-autofill-color: var(--black-color);
|
||||
--bg-code-color: var(--grey-2);
|
||||
--bg-navtabs-color: var(--grey-2);
|
||||
--bg-navtabs-hover-color: var(--grey-3);
|
||||
--bg-btn-default-hover-color: var(--grey-3);
|
||||
--bg-btn-default-color: var(--black-color);
|
||||
--bg-btn-focus: var(--black-color);
|
||||
--bg-boxselector-color: var(--black-color);
|
||||
--bg-boxselector-disabled-color: var(--black-color);
|
||||
--bg-small-select-color: var(--black-color);
|
||||
|
||||
--text-main-color: var(--white-color);
|
||||
--text-body-color: var(--white-color);
|
||||
--text-sidebar-title-color: var(--grey-8);
|
||||
--text-widget-header-color: var(--white-color);
|
||||
--text-link-color: var(--blue-9);
|
||||
--text-link-hover-color: var(--blue-9);
|
||||
--text-danger-color: var(--red-7);
|
||||
--text-code-color: var(--red-7);
|
||||
--text-form-control-color: var(--white-color);
|
||||
--text-blocklist-hover-color: var(--blue-11);
|
||||
--text-boxselector-wrapper-color: var(--white-color);
|
||||
--text-dashboard-item-color: var(--blue-12);
|
||||
--text-form-section-title-color: var(--white-color);
|
||||
--text-muted-color: var(--white-color);
|
||||
--text-tooltip-color: var(--white-color);
|
||||
--text-blocklist-item-selected-color: var(--blue-9);
|
||||
--text-input-group-addon-color: var(--white-color);
|
||||
--text-codemirror-color: var(--white-color);
|
||||
--text-log-viewer-color: var(--white-color);
|
||||
--text-summary-color: var(--white-color);
|
||||
--text-rzslider-color: var(--white-color);
|
||||
--text-rzslider-limit-color: var(--white-color);
|
||||
--text-pagination-color: var(--white-color);
|
||||
--text-daterangepicker-end-date: var(--grey-7);
|
||||
--text-daterangepicker-in-range: var(--white-color);
|
||||
--text-daterangepicker-active: var(--white-color);
|
||||
--text-sidebar-list-color: var(--white-color);
|
||||
--text-ui-select-color: var(--white-color);
|
||||
--text-btn-default-color: var(--white-color);
|
||||
--text-json-tree-color: var(--white-color);
|
||||
--text-json-tree-leaf-color: var(--white-color);
|
||||
--text-json-tree-branch-preview-color: var(--white-color);
|
||||
--text-pre-color: var(--white-color);
|
||||
--text-navtabs-color: var(--white-color);
|
||||
--text-input-autofill-color: var(--white-color);
|
||||
--text-navtabs-color: var(--white-color);
|
||||
--text-button-hover-color: var(--white-color);
|
||||
--text-btn-default-color: var(--white-color);
|
||||
--text-small-select-color: var(--white-color);
|
||||
|
||||
--border-color: var(--grey-55);
|
||||
--border-widget-color: var(--white-color);
|
||||
--border-sidebar-color: var(--blue-9);
|
||||
--border-form-control-color: var(--grey-54);
|
||||
--border-table-color: var(--grey-55);
|
||||
--border-table-top-color: var(--grey-55);
|
||||
--border-datatable-top-color: var(--grey-55);
|
||||
--border-sidebar-high-contrast: 1px solid var(--blue-9);
|
||||
--border-code-high-contrast: 1px solid var(--white-color);
|
||||
--border-boxselector-wrapper: 3px solid var(--blue-2);
|
||||
--border-boxselector-wrapper-hover: 3px solid var(--blue-8);
|
||||
--border-panel-color: var(--white-color);
|
||||
--border-input-group-addon-color: var(--grey-54);
|
||||
--border-modal-header-color: var(--grey-3);
|
||||
--border-input-sm-color: var(--white-color);
|
||||
--border-pagination-color: var(--grey-3);
|
||||
--border-pagination-span-color: var(--grey-3);
|
||||
--border-daterangepicker-color: var(--white-color);
|
||||
--border-calendar-table: var(--black-color);
|
||||
--border-daterangepicker: var(--black-color);
|
||||
--border-pre-next-month: var(--white-color);
|
||||
--border-daterangepicker-after: var(--black-color);
|
||||
--border-tooltip-color: var(--white-color);
|
||||
--border-pre-color: var(--grey-3);
|
||||
--border-codemirror-cursor-color: var(--white-color);
|
||||
--border-modal: 1px solid var(--white-color);
|
||||
|
||||
--hover-sidebar-color: var(--blue-9);
|
||||
--hover-sidebar-color: var(--black-color);
|
||||
--shadow-box-color: none;
|
||||
--shadow-boxselector-color: none;
|
||||
|
||||
--bg-image-multiselect: linear-gradient(var(--black-color), var(--black-color));
|
||||
--bg-image-multiselect-button: linear-gradient(var(--grey-1), var(--grey-1));
|
||||
--bg-image-multiselect-hover: linear-gradient(var(--grey-3), var(--grey-3));
|
||||
--border-multiselect: var(--black-color);
|
||||
--border-multiselect-checkboxlayer: var(--grey-3);
|
||||
--text-multiselect: var(--white-color);
|
||||
--bg-multiselect-checkboxcontainer: var(--grey-3);
|
||||
--text-multiselect-item: var(--white-color);
|
||||
--bg-multiselect-helpercontainer: var(--grey-1);
|
||||
--text-input-textarea: var(--black-color);
|
||||
--bg-item-highlighted-null-color: var(--grey-2);
|
||||
--text-cm-default-color: var(--blue-9);
|
||||
--text-cm-meta-color: var(--white-color);
|
||||
--text-cm-string-color: var(--red-7);
|
||||
--text-progress-bar-color: var(--black-color);
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
/* Overide Vendor CSS */
|
||||
.form-control {
|
||||
background-color: var(--bg-main-color) !important;
|
||||
border: 1px solid var(--border-form-control-color);
|
||||
color: var(--text-form-control-color);
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--text-muted-color);
|
||||
}
|
||||
|
||||
.table > thead > tr > th {
|
||||
border-bottom: 2px solid var(--border-table-color);
|
||||
}
|
||||
|
||||
.table-hover > tbody > tr:hover {
|
||||
background-color: var(--bg-hover-table-color);
|
||||
}
|
||||
|
||||
.switch i,
|
||||
.bootbox-form .checkbox i {
|
||||
background: var(--bg-switch-box-color);
|
||||
}
|
||||
|
||||
.table > thead > tr > th,
|
||||
.table > tbody > tr > th,
|
||||
.table > tfoot > tr > th,
|
||||
.table > thead > tr > td,
|
||||
.table > tbody > tr > td,
|
||||
.table > tfoot > tr > td {
|
||||
border-top: 1px solid var(--border-table-top-color);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--text-link-color);
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: var(--text-link-hover-color);
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
color: var(--text-input-group-addon-color);
|
||||
background-color: var(--bg-input-group-addon-color);
|
||||
border: 1px solid var(--border-input-group-addon-color);
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color: var(--text-btn-default-color);
|
||||
background-color: var(--bg-btn-default-color);
|
||||
border-color: var(--border-btn-default-color);
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: var(--text-danger-color);
|
||||
}
|
||||
|
||||
.table .table {
|
||||
background-color: var(--bg-table-color);
|
||||
}
|
||||
|
||||
.table-bordered {
|
||||
border-color: var(--border-table-top-color);
|
||||
}
|
||||
|
||||
.table-bordered > thead > tr > th,
|
||||
.table-bordered > tbody > tr > th,
|
||||
.table-bordered > tfoot > tr > th,
|
||||
.table-bordered > thead > tr > td,
|
||||
.table-bordered > tbody > tr > td,
|
||||
.table-bordered > tfoot > tr > td {
|
||||
border-color: var(--border-table-top-color);
|
||||
}
|
||||
|
||||
.md-checkbox input[type='checkbox']:disabled + label:before {
|
||||
background: var(--bg-md-checkbox-color) !important;
|
||||
border-color: var(--border-md-checkbox-color) !important;
|
||||
}
|
||||
|
||||
.form-control[disabled],
|
||||
.form-control[readonly],
|
||||
fieldset[disabled] .form-control {
|
||||
background-color: var(--bg-form-control-disabled-color) !important;
|
||||
}
|
||||
|
||||
.modal.in .modal-dialog {
|
||||
border: var(--border-modal);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: var(--bg-modal-content-color);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
border-bottom: 1px solid var(--border-modal-header-color);
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-top: 1px solid var(--border-modal-header-color);
|
||||
}
|
||||
|
||||
.close {
|
||||
color: var(--button-close-color);
|
||||
opacity: var(--button-opacity);
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: var(--button-close-color);
|
||||
opacity: var(--button-opacity-hover);
|
||||
}
|
||||
|
||||
code {
|
||||
color: var(--text-code-color);
|
||||
background-color: var(--bg-code-color);
|
||||
}
|
||||
|
||||
.nav-tabs > li.active > a,
|
||||
.nav-tabs > li.active > a:hover,
|
||||
.nav-tabs > li.active > a:focus {
|
||||
color: var(--text-navtabs-color);
|
||||
background-color: var(--bg-navtabs-color);
|
||||
border: 1px solid var(--border-navtabs-color);
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
border-bottom: 1px solid var(--border-navtabs-color);
|
||||
}
|
||||
|
||||
.nav-tabs > li > a:hover {
|
||||
border-color: var(--border-navtabs-color);
|
||||
}
|
||||
|
||||
.nav > li > a:hover,
|
||||
.nav > li > a:focus {
|
||||
background-color: var(--bg-navtabs-hover-color);
|
||||
}
|
||||
|
||||
.table > thead > tr > td.active,
|
||||
.table > tbody > tr > td.active,
|
||||
.table > tfoot > tr > td.active,
|
||||
.table > thead > tr > th.active,
|
||||
.table > tbody > tr > th.active,
|
||||
.table > tfoot > tr > th.active,
|
||||
.table > thead > tr.active > td,
|
||||
.table > tbody > tr.active > td,
|
||||
.table > tfoot > tr.active > td,
|
||||
.table > thead > tr.active > th,
|
||||
.table > tbody > tr.active > th,
|
||||
.table > tfoot > tr.active > th {
|
||||
background-color: var(--bg-table-selected-color);
|
||||
}
|
||||
.table-hover > tbody > tr > td.active:hover,
|
||||
.table-hover > tbody > tr > th.active:hover,
|
||||
.table-hover > tbody > tr.active:hover > td,
|
||||
.table-hover > tbody > tr:hover > .active,
|
||||
.table-hover > tbody > tr.active:hover > th {
|
||||
background-color: var(--bg-table-selected-color);
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
background: var(--bg-codemirror-gutters-color);
|
||||
border-right: 1px solid var(--border-codemirror-gutters-color);
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
background: var(--bg-codemirror-color);
|
||||
color: var(--text-codemirror-color);
|
||||
}
|
||||
|
||||
.CodeMirror-selected {
|
||||
background: var(--bg-codemirror-selected-color) !important;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid var(--border-codemirror-cursor-color);
|
||||
}
|
||||
|
||||
.cm-s-default .cm-atom {
|
||||
color: var(--text-cm-default-color);
|
||||
}
|
||||
|
||||
.cm-s-default .cm-meta {
|
||||
color: var(--text-cm-meta-color);
|
||||
}
|
||||
|
||||
.cm-s-default .cm-string {
|
||||
color: var(--text-cm-string-color);
|
||||
}
|
||||
|
||||
.cm-s-default .cm-number {
|
||||
color: var(--text-cm-number-color);
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
background: var(--bg-dropdown-menu-color);
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
color: var(--text-dropdown-menu-color);
|
||||
}
|
||||
|
||||
pre {
|
||||
border: 1px solid var(--border-pre-color);
|
||||
background-color: var(--bg-pre-color);
|
||||
color: var(--text-pre-color);
|
||||
}
|
||||
json-tree .key {
|
||||
color: var(--text-json-tree-color);
|
||||
}
|
||||
|
||||
json-tree .leaf-value {
|
||||
color: var(--text-json-tree-leaf-color);
|
||||
}
|
||||
|
||||
json-tree .branch-preview {
|
||||
color: var(--text-json-tree-branch-preview-color);
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-color: var(--bg-progress-color);
|
||||
}
|
||||
|
||||
.pagination > .disabled > span,
|
||||
.pagination > .disabled > span:hover,
|
||||
.pagination > .disabled > span:focus,
|
||||
.pagination > .disabled > a,
|
||||
.pagination > .disabled > a:hover,
|
||||
.pagination > .disabled > a:focus {
|
||||
color: var(--text-pagination-color);
|
||||
background-color: var(--bg-pagination-color);
|
||||
border-color: var(--border-pagination-color);
|
||||
}
|
||||
|
||||
.pagination > li > a,
|
||||
.pagination > li > span {
|
||||
background-color: var(--bg-pagination-span-color);
|
||||
border-color: var(--border-pagination-span-color);
|
||||
color: var(--text-pagination-span-color);
|
||||
}
|
||||
|
||||
.pagination > li > a:hover,
|
||||
.pagination > li > span:hover,
|
||||
.pagination > li > a:focus,
|
||||
.pagination > li > span:focus {
|
||||
background-color: var(--bg-pagination-hover-color);
|
||||
border-color: var(--border-pagination-hover-color);
|
||||
}
|
||||
|
||||
.pagination > li > a:hover,
|
||||
.pagination > li > span:hover,
|
||||
.pagination > li > a:focus,
|
||||
.pagination > li > span:focus {
|
||||
color: var(--text-pagination-span-hover-color);
|
||||
}
|
||||
|
||||
.ui-select-bootstrap .ui-select-choices-row > span {
|
||||
color: var(--text-ui-select-color);
|
||||
}
|
||||
|
||||
.ui-select-bootstrap .ui-select-choices-row > span:hover,
|
||||
.ui-select-bootstrap .ui-select-choices-row > span:focus {
|
||||
background-color: var(--bg-ui-select-hover-color);
|
||||
color: var(--text-ui-select-hover-color);
|
||||
}
|
||||
|
||||
.motd-body {
|
||||
background-color: var(--bg-motd-body-color) !important;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color: var(--bg-panel-body-color) !important;
|
||||
}
|
||||
|
||||
.panel {
|
||||
border: 1px solid var(--border-panel-color);
|
||||
}
|
||||
|
||||
.theme-information .col-sm-12 {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.theme-panel {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.summary {
|
||||
color: var(--text-summary-color);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.input-sm {
|
||||
background-color: var(--bg-input-sm-color);
|
||||
border: 1px solid var(--border-input-sm-color);
|
||||
}
|
||||
|
||||
.rzslider .rz-bubble {
|
||||
color: var(--text-rzslider-color);
|
||||
}
|
||||
|
||||
.rzslider .rz-bubble.rz-limit {
|
||||
color: var(--text-rzslider-limit-color);
|
||||
}
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
textarea {
|
||||
background: var(--text-input-textarea);
|
||||
}
|
||||
|
||||
.daterangepicker {
|
||||
background-color: var(--bg-daterangepicker-color);
|
||||
border: 1px solid var(--border-daterangepicker-color);
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
background: var(--bg-calendar-color);
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left .calendar-table {
|
||||
background: var(--bg-calendar-table-color);
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right {
|
||||
background: var(--bg-calendar-color);
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right .calendar-table {
|
||||
background: var(--bg-calendar-table-color);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table {
|
||||
border: 1px solid var(--border-calendar-table);
|
||||
}
|
||||
|
||||
.daterangepicker td.off,
|
||||
.daterangepicker td.off.in-range,
|
||||
.daterangepicker td.off.start-date,
|
||||
.daterangepicker td.off.end-date {
|
||||
background-color: var(--bg-daterangepicker-end-date);
|
||||
color: var(--text-daterangepicker-end-date);
|
||||
}
|
||||
|
||||
.daterangepicker td.available:hover,
|
||||
.daterangepicker th.available:hover {
|
||||
background-color: var(--bg-daterangepicker-hover);
|
||||
}
|
||||
|
||||
.daterangepicker td.in-range {
|
||||
background-color: var(--bg-daterangepicker-in-range);
|
||||
color: var(--text-daterangepicker-in-range);
|
||||
}
|
||||
|
||||
.daterangepicker td.active,
|
||||
.daterangepicker td.active:hover {
|
||||
background-color: var(--bg-daterangepicker-active);
|
||||
color: var(--text-daterangepicker-active);
|
||||
}
|
||||
|
||||
.daterangepicker .drp-buttons {
|
||||
border-top: 1px solid var(--border-daterangepicker);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .next span,
|
||||
.daterangepicker .calendar-table .prev span {
|
||||
border-color: var(--border-pre-next-month);
|
||||
}
|
||||
|
||||
.daterangepicker:after {
|
||||
border-bottom: 6px solid var(--border-daterangepicker-after);
|
||||
}
|
||||
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
input:-webkit-autofill:active {
|
||||
-webkit-box-shadow: 0 0 0 30px var(--bg-input-autofill-color) inset !important;
|
||||
box-shadow: 0 0 0 30px var(--bg-input-autofill-color) inset !important;
|
||||
}
|
||||
|
||||
input:-webkit-autofill {
|
||||
-webkit-text-fill-color: var(--text-input-autofill-color) !important;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
color: var(--text-button-hover-color);
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
background-color: var(--bg-btn-default-hover-color);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
color: var(--white-color) !important;
|
||||
}
|
||||
/* Overide Vendor CSS */
|
|
@ -73,7 +73,11 @@
|
|||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr dir-paginate-end ng-show="$ctrl.itemCanExpand(value) && value.Expanded" ng-style="{ background: value.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
dir-paginate-end
|
||||
ng-show="$ctrl.itemCanExpand(value) && value.Expanded"
|
||||
ng-class="{ 'datatable-highlighted': value.Highlighted, 'datatable-unhighlighted': !value.Highlighted }"
|
||||
>
|
||||
<td colspan="1"></td>
|
||||
<td colspan="1">
|
||||
{{ value.GlobalIPv6Address }}
|
||||
|
|
|
@ -171,7 +171,7 @@
|
|||
allow-checkbox="true"
|
||||
>
|
||||
</tr>
|
||||
<tr dir-paginate-end ng-show="item.Expanded" ng-repeat="it in item.Subs" style="background: #d5e8f3;" network-row-content item="it" parent-ctrl="$ctrl"> </tr>
|
||||
<tr dir-paginate-end ng-show="item.Expanded" ng-repeat="it in item.Subs" class="datatable-highlighted" network-row-content item="it" parent-ctrl="$ctrl"> </tr>
|
||||
<tr ng-if="!$ctrl.dataset">
|
||||
<td colspan="9" class="text-center text-muted">Loading...</td>
|
||||
</tr>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div style="background-color: #d5e8f3; padding: 2px;">
|
||||
<div class="service-datatable">
|
||||
<table class="table table-condensed table-hover nowrap-cells">
|
||||
<thead style="background-color: #e7f6ff;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.filters.state.open" style="width: 10%;">
|
||||
<a ng-click="$ctrl.changeOrderBy('Status.State')">
|
||||
|
@ -54,7 +54,7 @@
|
|||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style="background-color: #f1f9fd;">
|
||||
<tbody>
|
||||
<tr
|
||||
ng-repeat="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter: $ctrl.applyFilters | filter:$ctrl.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder))"
|
||||
>
|
||||
|
|
|
@ -105,8 +105,7 @@
|
|||
<!-- dir-paginate-start track by $index -->
|
||||
<tr
|
||||
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
|
||||
ng-class="{ active: item.Checked }"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '' }"
|
||||
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }"
|
||||
ng-click="$ctrl.expandItem(item, !item.Expanded)"
|
||||
pagination-id="$ctrl.tableKey"
|
||||
>
|
||||
|
@ -177,7 +176,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
<!-- sub rows -->
|
||||
<tr ng-show="item.Expanded" ng-repeat-start="port in item.Ports" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr ng-show="item.Expanded" ng-repeat-start="port in item.Ports" ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }">
|
||||
<td ng-if="!$ctrl.portHasIngressRules(port)"></td>
|
||||
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
|
||||
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
|
||||
|
@ -190,7 +189,12 @@
|
|||
<td ng-if="!$ctrl.portHasIngressRules(port)">{{ port.TargetPort }}/{{ port.Protocol }}</td>
|
||||
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
|
||||
</tr>
|
||||
<tr ng-show="item.Expanded" ng-repeat-end ng-repeat="rule in port.IngressRules" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
ng-show="item.Expanded"
|
||||
ng-repeat-end
|
||||
ng-repeat="rule in port.IngressRules"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
|
|
|
@ -109,8 +109,7 @@
|
|||
<tbody>
|
||||
<tr
|
||||
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
|
||||
ng-class="{ active: item.Checked }"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '' }"
|
||||
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }"
|
||||
ng-click="$ctrl.expandItem(item, !item.Expanded)"
|
||||
pagination-id="$ctrl.tableKey"
|
||||
>
|
||||
|
@ -141,7 +140,12 @@
|
|||
<a ui-sref="kubernetes.stacks.stack.logs({ namespace: item.ResourcePool, name: item.Name })"> <i class="fa fa-file-alt" aria-hidden="true"></i> Logs </a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr dir-paginate-end ng-show="item.Expanded" ng-repeat="app in item.Applications" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
dir-paginate-end
|
||||
ng-show="item.Expanded"
|
||||
ng-repeat="app in item.Applications"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td></td>
|
||||
<td colspan="4">
|
||||
<a ui-sref="kubernetes.applications.application({ name: app.Name, namespace: app.ResourcePool })">{{ app.Name }}</a>
|
||||
|
|
|
@ -2,9 +2,10 @@ import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
|
|||
|
||||
export default class KubernetesRegistryAccessController {
|
||||
/* @ngInject */
|
||||
constructor($async, $state, EndpointService, Notifications, KubernetesResourcePoolService) {
|
||||
constructor($async, $state, ModalService, EndpointService, Notifications, KubernetesResourcePoolService) {
|
||||
this.$async = $async;
|
||||
this.$state = $state;
|
||||
this.ModalService = ModalService;
|
||||
this.Notifications = Notifications;
|
||||
this.KubernetesResourcePoolService = KubernetesResourcePoolService;
|
||||
this.EndpointService = EndpointService;
|
||||
|
@ -26,8 +27,15 @@ export default class KubernetesRegistryAccessController {
|
|||
|
||||
handleRemove(namespaces) {
|
||||
const removeNamespaces = namespaces.map(({ value }) => value);
|
||||
const nsToUpdate = this.savedResourcePools.map(({ value }) => value).filter((value) => !removeNamespaces.includes(value));
|
||||
|
||||
return this.updateNamespaces(this.savedResourcePools.map(({ value }) => value).filter((value) => !removeNamespaces.includes(value)));
|
||||
const displayedMessage =
|
||||
'This registry might be used by one or more applications inside this environment. Removing the registry access could lead to a service interruption for these applications.<br/><br/>Do you wish to continue?';
|
||||
this.ModalService.confirmDeletion(displayedMessage, (confirmed) => {
|
||||
if (confirmed) {
|
||||
return this.updateNamespaces(nsToUpdate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateNamespaces(namespaces) {
|
||||
|
|
|
@ -75,8 +75,7 @@
|
|||
<tbody>
|
||||
<tr
|
||||
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
|
||||
ng-class="{ active: item.Checked }"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '' }"
|
||||
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }"
|
||||
ng-click="$ctrl.expandItem(item, !item.Expanded)"
|
||||
pagination-id="$ctrl.tableKey"
|
||||
>
|
||||
|
@ -92,14 +91,23 @@
|
|||
</td>
|
||||
</tr>
|
||||
<!-- ADMIN + UNMET TAINTS -->
|
||||
<tr ng-if="$ctrl.isAdmin" ng-show="item.Expanded" ng-repeat="taint in item.UnmetTaints" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
ng-if="$ctrl.isAdmin"
|
||||
ng-show="item.Expanded"
|
||||
ng-repeat="taint in item.UnmetTaints"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td colspan="2">
|
||||
This application is missing a toleration for the taint <code>{{ taint.Key }}{{ taint.Value ? '=' + taint.Value : '' }}:{{ taint.Effect }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- !ADMIN + UNMET TAINTS -->
|
||||
<!-- USER + UNMET TAINTS -->
|
||||
<tr ng-if="!$ctrl.isAdmin && item.UnmetTaints.length" ng-show="item.Expanded" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
ng-if="!$ctrl.isAdmin && item.UnmetTaints.length"
|
||||
ng-show="item.Expanded"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td colspan="2">
|
||||
Placement constraint not respected for that node.
|
||||
</td>
|
||||
|
@ -110,7 +118,7 @@
|
|||
ng-if="$ctrl.isAdmin"
|
||||
ng-show="item.Expanded"
|
||||
ng-repeat="label in item.UnmatchedNodeSelectorLabels"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td colspan="2">
|
||||
This application can only be scheduled on a node where the label <code>{{ label.key }}</code> is set to <code>{{ label.value }}</code>
|
||||
|
@ -121,7 +129,7 @@
|
|||
<tr
|
||||
ng-if="!$ctrl.isAdmin && (item.UnmatchedNodeSelectorLabels.length || item.UnmatchedNodeAffinities.length)"
|
||||
ng-show="item.Expanded"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td colspan="2">
|
||||
Placement label not respected for that node.
|
||||
|
@ -129,7 +137,11 @@
|
|||
</tr>
|
||||
<!-- ! USER + UNMET NODE SELECTOR LABELS || UNMET NODE AFFINITIES -->
|
||||
<!-- ADMIN + UNMET NODE AFFINITIES -->
|
||||
<tr ng-if="$ctrl.isAdmin" ng-show="item.Expanded && item.UnmatchedNodeAffinities.length" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
ng-if="$ctrl.isAdmin"
|
||||
ng-show="item.Expanded && item.UnmatchedNodeAffinities.length"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td colspan="2">
|
||||
This application can only be scheduled on nodes respecting one of the following labels combination:
|
||||
</td>
|
||||
|
@ -139,7 +151,7 @@
|
|||
ng-if="$ctrl.isAdmin"
|
||||
ng-show="item.Expanded"
|
||||
ng-repeat="aff in item.UnmatchedNodeAffinities"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td></td>
|
||||
<td>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<kubernetes-view-header title="Create a namespace" state="kubernetes.resourcePools.new" view-ready="ctrl.state.viewReady">
|
||||
<kubernetes-view-header title="Create a namespace" state="kubernetes.resourcePools.new" view-ready="$ctrl.state.viewReady">
|
||||
<a ui-sref="kubernetes.resourcePools">Namespaces</a> > Create a namespace
|
||||
</kubernetes-view-header>
|
||||
|
||||
|
|
|
@ -73,8 +73,7 @@
|
|||
<tbody>
|
||||
<tr
|
||||
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
|
||||
ng-class="{ active: item.Checked }"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '' }"
|
||||
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }"
|
||||
ng-click="$ctrl.expandItem(item, !item.Expanded)"
|
||||
pagination-id="$ctrl.tableKey"
|
||||
>
|
||||
|
@ -84,7 +83,12 @@
|
|||
>{{ item.Name }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr dir-paginate-end ng-show="item.Expanded" ng-repeat="path in item.Paths" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
dir-paginate-end
|
||||
ng-show="item.Expanded"
|
||||
ng-repeat="path in item.Paths"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td>
|
||||
<a style="margin-left: 15px;" ng-href="http://{{ path.Host ? path.Host : path.IP }}{{ path.Path }}" target="_blank">
|
||||
{{ path.Host ? path.Host : path.IP }}{{ path.Path }}
|
||||
|
|
|
@ -185,20 +185,26 @@ class KubernetesResourcePoolController {
|
|||
}
|
||||
|
||||
updateResourcePool() {
|
||||
const willBeDeleted = _.filter(this.formValues.IngressClasses, { WasSelected: true, Selected: false });
|
||||
const ingressesToDelete = _.filter(this.formValues.IngressClasses, { WasSelected: true, Selected: false });
|
||||
const registriesToDelete = _.filter(this.registries, { WasChecked: true, Checked: false });
|
||||
const warnings = {
|
||||
quota: this.hasResourceQuotaBeenReduced(),
|
||||
ingress: willBeDeleted.length !== 0,
|
||||
ingress: ingressesToDelete.length !== 0,
|
||||
registries: registriesToDelete.length !== 0,
|
||||
};
|
||||
|
||||
if (warnings.quota || warnings.ingress) {
|
||||
if (warnings.quota || warnings.ingress || warnings.registries) {
|
||||
const messages = {
|
||||
quota:
|
||||
'Reducing the quota assigned to an "in-use" namespace may have unintended consequences, including preventing running applications from functioning correctly and potentially even blocking them from running at all.',
|
||||
ingress: 'Deactivating ingresses may cause applications to be unaccessible. All ingress configurations from affected applications will be removed.',
|
||||
registries:
|
||||
'Some registries you removed might be used by one or more applications inside this environment. Removing the registries access could lead to a service interruption for these applications.',
|
||||
};
|
||||
const displayedMessage = `${warnings.quota ? messages.quota : ''}${warnings.quota && warnings.ingress ? '<br/><br/>' : ''}
|
||||
${warnings.ingress ? messages.ingress : ''}<br/><br/>Do you wish to continue?`;
|
||||
const displayedMessage = `${warnings.quota ? messages.quota + '<br/><br/>' : ''}
|
||||
${warnings.ingress ? messages.ingress + '<br/><br/>' : ''}
|
||||
${warnings.registries ? messages.registries + '<br/><br/>' : ''}
|
||||
Do you wish to continue?`;
|
||||
this.ModalService.confirmUpdate(displayedMessage, (confirmed) => {
|
||||
if (confirmed) {
|
||||
return this.$async(this.updateResourcePoolAsync, this.savedFormValues, this.formValues);
|
||||
|
@ -322,6 +328,7 @@ class KubernetesResourcePoolController {
|
|||
this.registries.forEach((reg) => {
|
||||
if (reg.RegistryAccesses && reg.RegistryAccesses[this.endpoint.Id] && reg.RegistryAccesses[this.endpoint.Id].Namespaces.includes(namespace)) {
|
||||
reg.Checked = true;
|
||||
reg.WasChecked = true;
|
||||
this.formValues.Registries.push(reg);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<li ng-repeat="summary in $ctrl.state.resources" ng-if="summary.action && summary.kind && summary.name">
|
||||
{{ summary.action }}
|
||||
{{ $ctrl.getArticle(summary.kind, summary.action) }}
|
||||
<span style="color: black; font-weight: 700;">{{ summary.kind }}</span> named <code>{{ summary.name }}</code>
|
||||
<span class="summary">{{ summary.kind }}</span> named <code>{{ summary.name }}</code>
|
||||
<span ng-if="summary.type">
|
||||
of type <code>{{ summary.type }}</code></span
|
||||
>
|
||||
|
|
|
@ -82,8 +82,7 @@
|
|||
<tbody>
|
||||
<tr
|
||||
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
|
||||
ng-class="{ active: item.Checked }"
|
||||
ng-style="{ background: item.Highlighted ? '#d5e8f3' : '' }"
|
||||
ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }"
|
||||
ng-click="$ctrl.expandItem(item, !item.Expanded)"
|
||||
pagination-id="$ctrl.tableKey"
|
||||
>
|
||||
|
@ -95,7 +94,12 @@
|
|||
<td>{{ item.Name }}</td>
|
||||
<td>{{ item.Size }}</td>
|
||||
</tr>
|
||||
<tr dir-paginate-end ng-show="item.Expanded" ng-repeat="vol in item.Volumes" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
|
||||
<tr
|
||||
dir-paginate-end
|
||||
ng-show="item.Expanded"
|
||||
ng-repeat="vol in item.Volumes"
|
||||
ng-class="{ 'datatable-highlighted': item.Highlighted, 'datatable-unhighlighted': !item.Highlighted }"
|
||||
>
|
||||
<td></td>
|
||||
<td>
|
||||
<a ui-sref="kubernetes.volumes.volume({ name: vol.PersistentVolumeClaim.Name, namespace: vol.PersistentVolumeClaim.Namespace })">
|
||||
|
|
|
@ -27,22 +27,27 @@
|
|||
|
||||
.boxselector_wrapper input[type='radio']:not(:disabled) ~ label {
|
||||
cursor: pointer;
|
||||
background-color: var(--bg-boxselector-wrapper-disabled-color);
|
||||
}
|
||||
|
||||
.boxselector_wrapper input[type='radio']:not(:disabled):hover ~ label:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.boxselector_wrapper label {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
background: white;
|
||||
border: 1px solid #333333;
|
||||
background: var(--bg-boxselector-color);
|
||||
border: 1px solid var(--border-boxselector-color);
|
||||
border-radius: 2px;
|
||||
padding: 10px 10px 0 10px;
|
||||
text-align: center;
|
||||
box-shadow: 0 3px 10px -2px rgba(161, 170, 166, 0.5);
|
||||
box-shadow: var(--shadow-boxselector-color);
|
||||
position: relative;
|
||||
}
|
||||
.boxselector_wrapper label.boxselector_disabled {
|
||||
background: #cacaca;
|
||||
background: var(--bg-boxselector-disabled-color) !important;
|
||||
border-color: #787878;
|
||||
color: #787878;
|
||||
cursor: not-allowed;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<button type="button" class="btn btn-sm btn-primary" ui-state="$ctrl.createPath"> <i class="fa fa-plus space-right" aria-hidden="true"></i>Add Custom Template </button>
|
||||
</div>
|
||||
|
||||
<div class="searchBar" style="border-top: 2px solid #f6f6f6;">
|
||||
<div class="searchBar">
|
||||
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.datatable .toolBar {
|
||||
background-color: #f6f6f6;
|
||||
color: #767676;
|
||||
background-color: var(--bg-card-color);
|
||||
color: var(--text-main-color);
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
@ -30,9 +30,10 @@
|
|||
}
|
||||
|
||||
.datatable .searchBar {
|
||||
border-top: 1px solid #d2d1d1;
|
||||
border-bottom: 1px solid #d2d1d1;
|
||||
border-top: 1px solid var(--border-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding: 8px;
|
||||
background: var(--bg-main-color);
|
||||
}
|
||||
|
||||
.datatable .searchInput {
|
||||
|
@ -60,9 +61,10 @@
|
|||
}
|
||||
|
||||
.datatable .footer {
|
||||
background-color: #f6f6f6;
|
||||
color: #767676;
|
||||
background-color: var(--bg-card-color);
|
||||
color: var(--text-main-color);
|
||||
overflow: auto;
|
||||
border-top: 1px solid var(--border-datatable-top-color);
|
||||
}
|
||||
|
||||
.datatable .footer .infoBar {
|
||||
|
@ -152,9 +154,8 @@
|
|||
}
|
||||
|
||||
.md-checkbox label:before {
|
||||
background: #fff;
|
||||
border: 2px solid black;
|
||||
border: 2px solid rgba(0, 0, 0, 0.54);
|
||||
background: var(--bg-main-color);
|
||||
border: 2px solid var(--bg-checkbox-border-color);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
height: 16px;
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
class KubernetesAppGitFormController {
|
||||
/* @ngInject */
|
||||
constructor($async, $state, StackService, ModalService, Notifications) {
|
||||
this.$async = $async;
|
||||
this.$state = $state;
|
||||
this.StackService = StackService;
|
||||
this.ModalService = ModalService;
|
||||
this.Notifications = Notifications;
|
||||
|
||||
this.state = {
|
||||
saveGitSettingsInProgress: false,
|
||||
redeployInProgress: false,
|
||||
showConfig: true,
|
||||
isEdit: false,
|
||||
};
|
||||
|
||||
this.formValues = {
|
||||
RefName: '',
|
||||
RepositoryAuthentication: false,
|
||||
RepositoryUsername: '',
|
||||
RepositoryPassword: '',
|
||||
};
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.onChangeRef = this.onChangeRef.bind(this);
|
||||
}
|
||||
|
||||
onChangeRef(value) {
|
||||
this.onChange({ RefName: value });
|
||||
}
|
||||
|
||||
onChange(values) {
|
||||
this.formValues = {
|
||||
...this.formValues,
|
||||
...values,
|
||||
};
|
||||
}
|
||||
|
||||
async pullAndRedeployApplication() {
|
||||
return this.$async(async () => {
|
||||
try {
|
||||
const confirmed = await this.ModalService.confirmAsync({
|
||||
title: 'Are you sure?',
|
||||
message: 'Any changes to this application will be overriden by the definition in git and may cause a service interruption. Do you wish to continue?',
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: 'Update',
|
||||
className: 'btn-warning',
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
this.state.redeployInProgress = true;
|
||||
await this.StackService.updateKubeGit(this.stack.Id, this.stack.EndpointId, this.namespace, this.formValues);
|
||||
this.Notifications.success('Pulled and redeployed stack successfully');
|
||||
await this.$state.reload();
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Failed redeploying application');
|
||||
} finally {
|
||||
this.state.redeployInProgress = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async saveGitSettings() {
|
||||
return this.$async(async () => {
|
||||
try {
|
||||
this.state.saveGitSettingsInProgress = true;
|
||||
await this.StackService.updateKubeStack({ EndpointId: this.stack.EndpointId, Id: this.stack.Id }, null, this.formValues);
|
||||
this.Notifications.success('Save stack settings successfully');
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to save application settings');
|
||||
} finally {
|
||||
this.state.saveGitSettingsInProgress = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isSubmitButtonDisabled() {
|
||||
return this.state.saveGitSettingsInProgress || this.state.redeployInProgress;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
console.log(this);
|
||||
this.formValues.RefName = this.stack.GitConfig.ReferenceName;
|
||||
if (this.stack.GitConfig && this.stack.GitConfig.Authentication) {
|
||||
this.formValues.RepositoryUsername = this.stack.GitConfig.Authentication.Username;
|
||||
this.formValues.RepositoryAuthentication = true;
|
||||
this.state.isEdit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default KubernetesAppGitFormController;
|
|
@ -0,0 +1,59 @@
|
|||
<form name="$ctrl.redeployGitForm">
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Redeploy from git repository
|
||||
</div>
|
||||
<div class="form-group text-muted">
|
||||
<div class="col-sm-12">
|
||||
<p>
|
||||
Pull the latest manifest from git and redeploy the application.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<p>
|
||||
<a class="small interactive" ng-click="$ctrl.state.showConfig = !$ctrl.state.showConfig">
|
||||
<i ng-class="['fa space-right', { 'fa-minus': $ctrl.state.showConfig, 'fa-plus': !$ctrl.state.showConfig }]" aria-hidden="true"></i>
|
||||
{{ $ctrl.state.showConfig ? 'Hide' : 'Advanced' }} configuration
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<git-form-ref-field ng-if="$ctrl.state.showConfig" value="$ctrl.formValues.RefName" on-change="($ctrl.onChangeRef)"></git-form-ref-field>
|
||||
<git-form-auth-fieldset
|
||||
ng-if="$ctrl.state.showConfig"
|
||||
model="$ctrl.formValues"
|
||||
is-edit="$ctrl.state.isEdit"
|
||||
on-change="($ctrl.onChange)"
|
||||
show-auth-explanation="true"
|
||||
></git-form-auth-fieldset>
|
||||
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Actions
|
||||
</div>
|
||||
<!-- #Git buttons -->
|
||||
<button
|
||||
class="btn btn-sm btn-primary"
|
||||
ng-click="$ctrl.pullAndRedeployApplication()"
|
||||
ng-disabled="$ctrl.isSubmitButtonDisabled() || !$ctrl.redeployGitForm.$valid"
|
||||
style="margin-top: 7px; margin-left: 0;"
|
||||
button-spinner="ctrl.state.redeployInProgress"
|
||||
analytics-on
|
||||
analytics-category="kubernetes"
|
||||
analytics-event="kubernetes-application-edit-git-pull"
|
||||
>
|
||||
<span ng-show="!$ctrl.state.redeployInProgress"> <i class="fa fa-sync space-right" aria-hidden="true"></i> Pull and update application </span>
|
||||
<span ng-show="$ctrl.state.redeployInProgress">In progress...</span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-primary"
|
||||
ng-click="$ctrl.saveGitSettings()"
|
||||
ng-disabled="$ctrl.isSubmitButtonDisabled() || !$ctrl.redeployGitForm.$valid"
|
||||
style="margin-top: 7px; margin-left: 0;"
|
||||
button-spinner="$ctrl.state.saveGitSettingsInProgress"
|
||||
>
|
||||
<span ng-show="!$ctrl.state.saveGitSettingsInProgress"> Save settings </span>
|
||||
<span ng-show="$ctrl.state.saveGitSettingsInProgress">In progress...</span>
|
||||
</button>
|
||||
</form>
|
|
@ -0,0 +1,13 @@
|
|||
import angular from 'angular';
|
||||
import controller from './kubernetes-app-git-form.controller';
|
||||
|
||||
const kubernetesAppGitForm = {
|
||||
templateUrl: './kubernetes-app-git-form.html',
|
||||
controller,
|
||||
bindings: {
|
||||
namespace: '<',
|
||||
stack: '<',
|
||||
},
|
||||
};
|
||||
|
||||
angular.module('portainer.app').component('kubernetesAppGitForm', kubernetesAppGitForm);
|
|
@ -13,7 +13,7 @@
|
|||
* Sidebar
|
||||
*/
|
||||
#sidebar-wrapper {
|
||||
background: #30426a;
|
||||
background: var(--bg-sidebar-wrapper-color);
|
||||
}
|
||||
|
||||
ul.sidebar .sidebar-main a,
|
||||
|
@ -21,7 +21,7 @@ ul.sidebar .sidebar-main a,
|
|||
ul.sidebar .sidebar-list a:hover,
|
||||
#page-wrapper:not(.open) ul.sidebar .sidebar-title.separator {
|
||||
/* Sidebar header and footer color */
|
||||
background: #2d3e63;
|
||||
background: var(--hover-sidebar-color);
|
||||
}
|
||||
|
||||
ul.sidebar {
|
||||
|
@ -63,7 +63,7 @@ ul.sidebar .sidebar-main .menu-icon {
|
|||
}
|
||||
|
||||
ul.sidebar .sidebar-title {
|
||||
color: #738bc0;
|
||||
color: var(--text-sidebar-title-color);
|
||||
font-size: 12px;
|
||||
height: 35px;
|
||||
line-height: 40px;
|
||||
|
@ -74,7 +74,7 @@ ul.sidebar .sidebar-title {
|
|||
ul.sidebar .sidebar-list a {
|
||||
text-indent: 25px;
|
||||
font-size: 15px;
|
||||
color: #b2bfdc;
|
||||
color: var(--text-sidebar-list-color);
|
||||
line-height: 40px;
|
||||
padding-left: 5px;
|
||||
border-left: 3px solid transparent;
|
||||
|
@ -132,7 +132,7 @@ ul.sidebar .sidebar-list .menu-icon {
|
|||
}
|
||||
|
||||
.sidebar-footer div a {
|
||||
color: #b2bfdc;
|
||||
color: var(--text-sidebar-list-color);
|
||||
font-size: 12px;
|
||||
line-height: 43px;
|
||||
}
|
||||
|
@ -172,8 +172,8 @@ ul.sidebar .sidebar-list a {
|
|||
|
||||
ul.sidebar .sidebar-list a.active {
|
||||
color: #fff;
|
||||
border-left-color: #fff;
|
||||
background: #2d3e63;
|
||||
border-left-color: var(--border-sidebar-color);
|
||||
background: var(--hover-sidebar-color);
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
|
@ -181,7 +181,7 @@ ul.sidebar .sidebar-list a.active {
|
|||
list-style: none;
|
||||
text-indent: 20px;
|
||||
font-size: 18px;
|
||||
background: #2d3e63;
|
||||
background: var(--bg-sidebar-header-color);
|
||||
}
|
||||
|
||||
.sidebar-header a {
|
||||
|
@ -255,7 +255,7 @@ ul.sidebar .sidebar-list a.active .menu-icon {
|
|||
ul.sidebar .sidebar-list .sidebar-sublist a {
|
||||
text-indent: 35px;
|
||||
font-size: 12px;
|
||||
color: #b2bfdc;
|
||||
color: var(--text-sidebar-list-color);
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,7 @@ ul.sidebar .sidebar-list .menu-icon {
|
|||
ul.sidebar .sidebar-list .sidebar-sublist a.active {
|
||||
color: #fff;
|
||||
border-left: 3px solid #fff;
|
||||
background: #2d3e63;
|
||||
background: var(--bg-sidebar-color);
|
||||
}
|
||||
|
||||
@media (max-height: 785px) {
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="searchBar" style="border-top: 2px solid #f6f6f6;">
|
||||
<div class="searchBar">
|
||||
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
import { buildOption } from '@/portainer/components/box-selector';
|
||||
|
||||
export default class ThemeSettingsController {
|
||||
/* @ngInject */
|
||||
constructor($async, Authentication, ThemeManager, StateManager, UserService, Notifications) {
|
||||
this.$async = $async;
|
||||
this.Authentication = Authentication;
|
||||
this.ThemeManager = ThemeManager;
|
||||
this.StateManager = StateManager;
|
||||
this.UserService = UserService;
|
||||
this.Notifications = Notifications;
|
||||
|
||||
this.setTheme = this.setTheme.bind(this);
|
||||
}
|
||||
|
||||
/** Theme Settings Panel */
|
||||
async updateTheme() {
|
||||
try {
|
||||
await this.UserService.updateUserTheme(this.state.userId, this.state.userTheme);
|
||||
this.state.themeInProgress = false;
|
||||
this.Notifications.success('Success', 'User theme successfully updated');
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to update user theme');
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(theme) {
|
||||
this.ThemeManager.setTheme(theme);
|
||||
this.state.themeInProgress = true;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
return this.$async(async () => {
|
||||
this.state = {
|
||||
userId: null,
|
||||
userTheme: '',
|
||||
initTheme: '',
|
||||
defaultTheme: 'light',
|
||||
themeInProgress: false,
|
||||
};
|
||||
|
||||
this.state.availableThemes = [
|
||||
buildOption('light', 'fas fa-sun', 'Light Theme', 'Default color mode', 'light'),
|
||||
buildOption('dark', 'fas fa-moon', 'Dark Theme', 'Dark color mode', 'dark'),
|
||||
buildOption('highcontrast', 'fas fa-adjust', 'High Contrast', 'High contrast color mode', 'highcontrast'),
|
||||
];
|
||||
|
||||
this.state.availableTheme = {
|
||||
light: 'light',
|
||||
dark: 'dark',
|
||||
highContrast: 'highcontrast',
|
||||
};
|
||||
|
||||
try {
|
||||
this.state.userId = await this.Authentication.getUserDetails().ID;
|
||||
const data = await this.UserService.user(this.state.userId);
|
||||
this.state.userTheme = data.UserTheme || this.state.defaultTheme;
|
||||
this.state.initTheme = this.state.userTheme;
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to get user details');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
if (this.state.themeInProgress) {
|
||||
this.ThemeManager.setTheme(this.state.initTheme);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<information-panel class="theme-information" title-text="Information">
|
||||
<span class="small text-muted">
|
||||
<p>
|
||||
<i class="fa fa-flask orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Dark and High-contrast theme are experimental. Some UI components might not display properly.
|
||||
</p>
|
||||
</span>
|
||||
</information-panel>
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-palette" title-text="Change user theme"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="theme-panel">
|
||||
<!-- Theme -->
|
||||
<box-selector radio-name="theme" ng-model="$ctrl.state.userTheme" options="$ctrl.state.availableThemes" on-change="($ctrl.setTheme)"></box-selector>
|
||||
<button ng-click="$ctrl.updateTheme()" class="btn btn-primary btn-sm">Update theme</button>
|
||||
<!-- !Theme -->
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
|
@ -0,0 +1,7 @@
|
|||
import angular from 'angular';
|
||||
import controller from './theme-settings.controller';
|
||||
|
||||
angular.module('portainer.app').component('themeSettings', {
|
||||
templateUrl: './theme-settings.html',
|
||||
controller,
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash-es';
|
||||
|
||||
export const KEY_REGEX = /(.+)/.source;
|
||||
export const KEY_REGEX = /(.+?)/.source;
|
||||
export const VALUE_REGEX = /(.*)?/.source;
|
||||
|
||||
const KEY_VALUE_REGEX = new RegExp(`^(${KEY_REGEX})\\s*=(${VALUE_REGEX})$`);
|
||||
|
|
|
@ -2,6 +2,7 @@ export function UserViewModel(data) {
|
|||
this.Id = data.Id;
|
||||
this.Username = data.Username;
|
||||
this.Role = data.Role;
|
||||
this.UserTheme = data.UserTheme;
|
||||
if (data.Role === 1) {
|
||||
this.RoleName = 'administrator';
|
||||
} else {
|
||||
|
|
|
@ -12,6 +12,7 @@ angular.module('portainer.app').factory('Users', [
|
|||
get: { method: 'GET', params: { id: '@id' } },
|
||||
update: { method: 'PUT', params: { id: '@id' }, ignoreLoadingBar: true },
|
||||
updatePassword: { method: 'PUT', params: { id: '@id', entity: 'passwd' } },
|
||||
updateTheme: { method: 'PUT', params: { id: '@id' } },
|
||||
remove: { method: 'DELETE', params: { id: '@id' } },
|
||||
queryMemberships: { method: 'GET', isArray: true, params: { id: '@id', entity: 'memberships' } },
|
||||
checkAdminUser: { method: 'GET', params: { id: 'admin', entity: 'check' }, isArray: true, ignoreLoadingBar: true },
|
||||
|
|
|
@ -137,10 +137,10 @@ angular.module('portainer.app').factory('EndpointService', [
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.createLocalKubernetesEndpoint = function (name = 'local') {
|
||||
service.createLocalKubernetesEndpoint = function (name = 'local', tagIds = []) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
FileUploadService.createEndpoint(name, PortainerEndpointCreationTypes.LocalKubernetesEnvironment, '', '', 1, [], true, true, true)
|
||||
FileUploadService.createEndpoint(name, PortainerEndpointCreationTypes.LocalKubernetesEnvironment, '', '', 1, tagIds, true, true, true)
|
||||
.then(function success(response) {
|
||||
deferred.resolve(response.data);
|
||||
})
|
||||
|
|
|
@ -91,6 +91,10 @@ angular.module('portainer.app').factory('UserService', [
|
|||
return Users.updatePassword({ id: id }, payload).$promise;
|
||||
};
|
||||
|
||||
service.updateUserTheme = function (id, userTheme) {
|
||||
return Users.updateTheme({ id }, { userTheme }).$promise;
|
||||
};
|
||||
|
||||
service.userMemberships = function (id) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ angular.module('portainer.app').factory('Authentication', [
|
|||
'LocalStorage',
|
||||
'StateManager',
|
||||
'EndpointProvider',
|
||||
function AuthenticationFactory($async, $state, Auth, OAuth, jwtHelper, LocalStorage, StateManager, EndpointProvider) {
|
||||
'UserService',
|
||||
'ThemeManager',
|
||||
function AuthenticationFactory($async, $state, Auth, OAuth, jwtHelper, LocalStorage, StateManager, EndpointProvider, UserService, ThemeManager) {
|
||||
'use strict';
|
||||
|
||||
var service = {};
|
||||
|
@ -82,12 +84,20 @@ angular.module('portainer.app').factory('Authentication', [
|
|||
return user;
|
||||
}
|
||||
|
||||
async function setUserTheme() {
|
||||
const data = await UserService.user(user.ID);
|
||||
// Initialize user theme base on Usertheme from database
|
||||
const userTheme = data.UserTheme;
|
||||
ThemeManager.setTheme(userTheme);
|
||||
}
|
||||
|
||||
async function setUser(jwt) {
|
||||
LocalStorage.storeJWT(jwt);
|
||||
var tokenPayload = jwtHelper.decodeToken(jwt);
|
||||
user.username = tokenPayload.username;
|
||||
user.ID = tokenPayload.id;
|
||||
user.role = tokenPayload.role;
|
||||
await setUserTheme();
|
||||
}
|
||||
|
||||
function isAdmin() {
|
||||
|
|
|
@ -54,6 +54,11 @@ angular.module('portainer.app').factory('StateManager', [
|
|||
LocalStorage.storeApplicationState(state.application);
|
||||
};
|
||||
|
||||
manager.updateTheme = function (theme) {
|
||||
state.application.theme = theme;
|
||||
LocalStorage.storeApplicationState(state.application);
|
||||
};
|
||||
|
||||
manager.updateSnapshotInterval = function (interval) {
|
||||
state.application.snapshotInterval = interval;
|
||||
LocalStorage.storeApplicationState(state.application);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
angular.module('portainer.app').service('ThemeManager', ThemeManager);
|
||||
|
||||
/* @ngInject */
|
||||
|
||||
export function ThemeManager(StateManager) {
|
||||
return {
|
||||
setTheme,
|
||||
defaultTheme,
|
||||
};
|
||||
|
||||
function setTheme(theme) {
|
||||
if (!theme) {
|
||||
document.documentElement.removeAttribute('theme');
|
||||
} else {
|
||||
document.documentElement.setAttribute('theme', theme);
|
||||
}
|
||||
StateManager.updateTheme(theme);
|
||||
}
|
||||
|
||||
function defaultTheme() {
|
||||
document.documentElement.removeAttribute('theme');
|
||||
}
|
||||
}
|
|
@ -78,5 +78,6 @@
|
|||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
<theme-settings></theme-settings>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,11 +5,14 @@ angular.module('portainer.app').controller('AccountController', [
|
|||
'UserService',
|
||||
'Notifications',
|
||||
'SettingsService',
|
||||
function ($scope, $state, Authentication, UserService, Notifications, SettingsService) {
|
||||
'StateManager',
|
||||
'ThemeManager',
|
||||
function ($scope, $state, Authentication, UserService, Notifications, SettingsService, StateManager, ThemeManager) {
|
||||
$scope.formValues = {
|
||||
currentPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
userTheme: '',
|
||||
};
|
||||
|
||||
$scope.updatePassword = function () {
|
||||
|
@ -23,8 +26,30 @@ angular.module('portainer.app').controller('AccountController', [
|
|||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
// Update DOM for theme attribute & LocalStorage
|
||||
$scope.setTheme = function (theme) {
|
||||
ThemeManager.setTheme(theme);
|
||||
StateManager.updateTheme(theme);
|
||||
};
|
||||
|
||||
// Rest API Call to update theme with userID in DB
|
||||
$scope.updateTheme = function () {
|
||||
UserService.updateUserTheme($scope.userID, $scope.formValues.userTheme)
|
||||
.then(function success() {
|
||||
Notifications.success('Success', 'User theme successfully updated');
|
||||
$state.reload();
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, err.msg);
|
||||
});
|
||||
};
|
||||
|
||||
async function initView() {
|
||||
$scope.userID = Authentication.getUserDetails().ID;
|
||||
|
||||
const data = await UserService.user($scope.userID);
|
||||
|
||||
$scope.formValues.userTheme = data.Usertheme;
|
||||
SettingsService.publicSettings()
|
||||
.then(function success(data) {
|
||||
$scope.AuthenticationMethod = data.AuthenticationMethod;
|
||||
|
|
|
@ -154,8 +154,9 @@ angular
|
|||
|
||||
$scope.addKubernetesEndpoint = function () {
|
||||
var name = $scope.formValues.Name;
|
||||
var tagIds = $scope.formValues.TagIds;
|
||||
$scope.state.actionInProgress = true;
|
||||
EndpointService.createLocalKubernetesEndpoint(name)
|
||||
EndpointService.createLocalKubernetesEndpoint(name, tagIds)
|
||||
.then(function success(result) {
|
||||
Notifications.success('Endpoint created', name);
|
||||
$state.go('portainer.endpoints.endpoint.kubernetesConfig', { id: result.Id });
|
||||
|
|
|
@ -168,10 +168,14 @@ function EndpointController(
|
|||
payload.URL = 'tcp://' + endpoint.URL;
|
||||
}
|
||||
|
||||
if (endpoint.Type === PortainerEndpointTypes.AgentOnKubernetesEnvironment || endpoint.Type === PortainerEndpointTypes.KubernetesLocalEnvironment) {
|
||||
if (endpoint.Type === PortainerEndpointTypes.AgentOnKubernetesEnvironment) {
|
||||
payload.URL = endpoint.URL;
|
||||
}
|
||||
|
||||
if (endpoint.Type === PortainerEndpointTypes.KubernetesLocalEnvironment) {
|
||||
payload.URL = 'https://' + endpoint.URL;
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
EndpointService.updateEndpoint(endpoint.Id, payload).then(
|
||||
function success() {
|
||||
|
|
|
@ -2,7 +2,7 @@ import angular from 'angular';
|
|||
|
||||
class LogoutController {
|
||||
/* @ngInject */
|
||||
constructor($async, $state, $transition$, $window, Authentication, StateManager, Notifications, LocalStorage, SettingsService) {
|
||||
constructor($async, $state, $transition$, $window, Authentication, StateManager, Notifications, LocalStorage, SettingsService, ThemeManager) {
|
||||
this.$async = $async;
|
||||
this.$state = $state;
|
||||
this.$transition$ = $transition$;
|
||||
|
@ -13,6 +13,7 @@ class LogoutController {
|
|||
this.Notifications = Notifications;
|
||||
this.LocalStorage = LocalStorage;
|
||||
this.SettingsService = SettingsService;
|
||||
this.ThemeManager = ThemeManager;
|
||||
|
||||
this.logo = this.StateManager.getState().application.logo;
|
||||
this.logoutAsync = this.logoutAsync.bind(this);
|
||||
|
@ -28,6 +29,8 @@ class LogoutController {
|
|||
const performApiLogout = this.$transition$.params().performApiLogout;
|
||||
const settings = await this.SettingsService.publicSettings();
|
||||
|
||||
this.ThemeManager.defaultTheme();
|
||||
|
||||
try {
|
||||
await this.Authentication.logout(performApiLogout);
|
||||
} finally {
|
||||
|
|
|
@ -3,6 +3,7 @@ angular.module('portainer.app').controller('MainController', [
|
|||
'LocalStorage',
|
||||
'StateManager',
|
||||
'EndpointProvider',
|
||||
'ThemeManager',
|
||||
function ($scope, LocalStorage, StateManager, EndpointProvider) {
|
||||
/**
|
||||
* Sidebar Toggle & Cookie Control
|
||||
|
|
|
@ -21,7 +21,11 @@ angular.module('portainer.app').controller('RegistriesController', [
|
|||
};
|
||||
|
||||
$scope.removeAction = function (selectedItems) {
|
||||
ModalService.confirmDeletion('Do you want to remove the selected registries?', function onConfirm(confirmed) {
|
||||
const regAttrMsg = selectedItems.length > 1 ? 'hese' : 'his';
|
||||
const registriesMsg = selectedItems.length > 1 ? 'registries' : 'registry';
|
||||
const msg = `T${regAttrMsg} ${registriesMsg} might be used by applications inside one or more endpoints. Removing the ${registriesMsg} could lead to a service interruption for the applications using t${regAttrMsg} ${registriesMsg}. Do you want to remove the selected ${registriesMsg}?`;
|
||||
|
||||
ModalService.confirmDeletion(msg, function onConfirm(confirmed) {
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,57 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
PLATFORM=$1
|
||||
ARCH=$2
|
||||
DOCKER_COMPOSE_VERSION=$3
|
||||
|
||||
if [ "${PLATFORM}" == 'linux' ] && [ "${ARCH}" == 'amd64' ]; then
|
||||
wget -O "dist/docker-compose" "https://github.com/portainer/docker-compose-linux-amd64-static-binary/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose"
|
||||
function download_binary() {
|
||||
local PLATFORM=$1
|
||||
local ARCH=$2
|
||||
local BINARY_VERSION=$3
|
||||
|
||||
if [ "${PLATFORM}" == 'linux' ] && [ "${ARCH}" == 'amd64' ]; then
|
||||
wget -O "dist/docker-compose" "https://github.com/portainer/docker-compose-linux-amd64-static-binary/releases/download/${BINARY_VERSION}/docker-compose"
|
||||
chmod +x "dist/docker-compose"
|
||||
elif [ "${PLATFORM}" == 'mac' ]; then
|
||||
wget -O "dist/docker-compose" "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-Darwin-x86_64"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "${PLATFORM}" == 'mac' ]; then
|
||||
wget -O "dist/docker-compose" "https://github.com/docker/compose/releases/download/${BINARY_VERSION}/docker-compose-Darwin-x86_64"
|
||||
chmod +x "dist/docker-compose"
|
||||
elif [ "${PLATFORM}" == 'win' ]; then
|
||||
wget -O "dist/docker-compose.exe" "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-Windows-x86_64.exe"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "${PLATFORM}" == 'win' ]; then
|
||||
wget -O "dist/docker-compose.exe" "https://github.com/docker/compose/releases/download/${BINARY_VERSION}/docker-compose-Windows-x86_64.exe"
|
||||
chmod +x "dist/docker-compose.exe"
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
function download_plugin() {
|
||||
local PLATFORM=$1
|
||||
local ARCH=$2
|
||||
local PLUGIN_VERSION=$3
|
||||
|
||||
if [ "${PLATFORM}" == 'mac' ]; then
|
||||
PLATFORM="darwin"
|
||||
fi
|
||||
|
||||
FILENAME="docker-compose-${PLATFORM}-${ARCH}"
|
||||
TARGET_FILENAME="docker-compose.plugin"
|
||||
if [[ "$PLATFORM" == "windows" ]]; then
|
||||
FILENAME="$FILENAME.exe"
|
||||
TARGET_FILENAME="$TARGET_FILENAME.exe"
|
||||
fi
|
||||
|
||||
wget -O "dist/$TARGET_FILENAME" "https://github.com/docker/compose-cli/releases/download/v$PLUGIN_VERSION/$FILENAME"
|
||||
chmod +x "dist/$TARGET_FILENAME"
|
||||
}
|
||||
|
||||
if [ "${PLATFORM}" == 'linux' ] && [ "${ARCH}" != 'amd64' ]; then
|
||||
download_plugin "$PLATFORM" "$ARCH" "$DOCKER_COMPOSE_VERSION"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
download_binary "$PLATFORM" "$ARCH" "$DOCKER_COMPOSE_VERSION"
|
26
gruntfile.js
26
gruntfile.js
|
@ -22,6 +22,7 @@ module.exports = function (grunt) {
|
|||
dockerWindowsVersion: '19-03-12',
|
||||
dockerLinuxComposeVersion: '1.27.4',
|
||||
dockerWindowsComposeVersion: '1.28.0',
|
||||
dockerComposePluginVersion: '2.0.0-beta.6',
|
||||
komposeVersion: 'v1.22.0',
|
||||
kubectlVersion: 'v1.18.0',
|
||||
},
|
||||
|
@ -214,13 +215,24 @@ function shell_download_docker_compose_binary(p, a) {
|
|||
var ia = as[a] || a;
|
||||
var binaryVersion = p === 'windows' ? '<%= binaries.dockerWindowsComposeVersion %>' : '<%= binaries.dockerLinuxComposeVersion %>';
|
||||
|
||||
return [
|
||||
'if [ -f dist/docker-compose ] || [ -f dist/docker-compose.exe ]; then',
|
||||
'echo "Docker Compose binary exists";',
|
||||
'else',
|
||||
'build/download_docker_compose_binary.sh ' + ip + ' ' + ia + ' ' + binaryVersion + ';',
|
||||
'fi',
|
||||
].join(' ');
|
||||
// plugin
|
||||
if (p === 'linux' && a !== 'amd64') {
|
||||
if (a === 'arm64') {
|
||||
ia = 'arm64';
|
||||
}
|
||||
|
||||
if (a === 'arm') {
|
||||
ia = 'armv7';
|
||||
}
|
||||
binaryVersion = '<%= binaries.dockerComposePluginVersion %>';
|
||||
}
|
||||
|
||||
return `
|
||||
if [ -f dist/docker-compose ] || [ -f dist/docker-compose.exe ] || [ -f dist/docker-compose.plugin ] || [ -f dist/docker-compose.plugin.exe ]; then
|
||||
echo "Docker Compose binary exists";
|
||||
else
|
||||
build/download_docker_compose_binary.sh ${ip} ${ia} ${binaryVersion};
|
||||
fi`;
|
||||
}
|
||||
|
||||
function shell_download_kompose_binary(p, a) {
|
||||
|
|
Loading…
Reference in New Issue