git.iko.soy/typeable/octopod
on master help sign in
97 files changed+4375−2576
since splitsnapshots
unifiedsplit
.github/actions/common_setup/action.yaml+4−4 .github/workflows/build.yaml+4−4 .nova/Configuration.json+5 .vscode/settings.json+6−1 cabal.project+6 charts/octopod/Chart.yaml+2−2 charts/octopod/index.yaml+37 charts/octopod/templates/ingress-app.yaml+11−5 charts/octopod/templates/ingress-powerapp.yaml+11−5 charts/octopod/templates/ingress-ui.yaml+11−5 charts/octopod/templates/ingress-ws.yaml+11−5 charts/octopod/values.yaml+1−1 dev/default.nix+36−4 docs/en/Overview.md+2−2 helm-control-scripts/Cargo.lock+1−1 helm-control-scripts/Cargo.toml+1−1 helm-control-scripts/src/cleanup.rs−11 helm-control-scripts/src/config_check.rs+7−2 helm-control-scripts/src/lib.rs+12−9 nix/default.nix+1−1 octo-cli/octo-cli.cabal−1 octo-cli/src/Octopod/CLI.hs+8−21 octo-cli/src/Octopod/CLI/Args.hs+2−1 octopod-api/src/Octopod/API/WebSocket.hs+1 octopod-backend/octopod-backend.cabal−1 octopod-backend/src/Control/CacheMap.hs+2−1 octopod-backend/src/Octopod/Server.hs+7−7 octopod-backend/src/Octopod/Server/ControlScriptUtils.hs+2−2 octopod-backend/src/Octopod/Server/Posix.hs+2−2 octopod-common/octopod-common.cabal+3−1 octopod-common/src/Common/Orphans.hs+14−4 octopod-common/src/Common/Types.hs+43−44 octopod-common/src/Control/Searchable.hs+20−1 octopod-common/src/Data/ConfigTree.hs+165 octopod-common/src/Data/Map/Ordered/Strict/Extra.hs−15 octopod-css/default.nix+2 octopod-css/development/layouts/index.html+931−907 octopod-css/development/layouts/staging.html+1159−668 octopod-css/development/markups/_action.html+2−1 octopod-css/development/markups/_bar.html+2−1 octopod-css/development/markups/_break.html+2−1 octopod-css/development/markups/_button.html+2−1 octopod-css/development/markups/_collapse.html+277 octopod-css/development/markups/_dash.html+2−1 octopod-css/development/markups/_drop.html+2−1 octopod-css/development/markups/_expander.html+2−1 octopod-css/development/markups/_external.html+2−1 octopod-css/development/markups/_input.html+36−1 octopod-css/development/markups/_keys-and-values.html+373 octopod-css/development/markups/_listing.html+2−1 octopod-css/development/markups/_loading.html+2−1 octopod-css/development/markups/_notification.html+2−1 octopod-css/development/markups/_null.html+2−1 octopod-css/development/markups/_spot.html+2−1 octopod-css/development/markups/_status.html+2−1 octopod-css/development/markups/_title.html+2−1 octopod-css/development/scripts/_collapse.js+18 octopod-css/development/styles/_collapse.css+95 octopod-css/development/styles/_deployment.css+3 octopod-css/development/styles/_editable-row.css+49 octopod-css/development/styles/_has-changes.css+3 octopod-css/development/styles/_input.css+30−2 octopod-css/development/styles/_key-custom-edited.css+4 octopod-css/development/styles/_key-default-edited.css+5 octopod-css/development/styles/_key-default-pristine.css+4 octopod-css/development/styles/_key-deleted.css+6 octopod-css/development/styles/_overrides.css+7−77 octopod-css/development/styles/_padded.css+3 octopod-css/development/styles/_root.css+2 octopod-css/development/styles/_row.css+3 octopod-css/development/styles/_table.css+5−1 octopod-css/development/styles/_value-deleted.css+5 octopod-css/development/styles/_value-edited.css+4 octopod-css/development/styles/_value-pristine.css+3 octopod-css/development/styles/_value-unknown.css+12 octopod-css/development/styles/style.css+15 octopod-css/development/vectors/collapse-project.svg+3 octopod-frontend/octopod-frontend.cabal+4 octopod-frontend/src/Data/Text/Search.hs+14 octopod-frontend/src/Data/WorkingOverrides.hs+104−76 octopod-frontend/src/Frontend/UIKit.hs+281−115 octopod-frontend/src/Frontend/UIKit/Button/Action.hs+3−3 octopod-frontend/src/Frontend/UIKit/Button/Common.hs+64−12 octopod-frontend/src/Frontend/UIKit/Button/Dash.hs+2−2 octopod-frontend/src/Frontend/UIKit/Button/Expander.hs+3−2 octopod-frontend/src/Frontend/UIKit/Button/Large.hs+3−3 octopod-frontend/src/Frontend/UIKit/Button/Sort.hs+2−2 octopod-frontend/src/Frontend/UIKit/Button/Static.hs+25−12 octopod-frontend/src/Frontend/UIKit/Button/Tree.hs+84 octopod-frontend/src/Frontend/Utils.hs+158−392 octopod-frontend/src/Page/ClassicPopup.hs+3−2 octopod-frontend/src/Page/Deployment.hs+39−34 octopod-frontend/src/Page/Deployments.hs+36−72 octopod-frontend/src/Page/Elements/Links.hs+20−11 octopod-frontend/src/Page/Popup/EditDeployment.hs+1−1 octopod-frontend/src/Page/Popup/NewDeployment.hs+1−1 stack.yaml+3−1
.github/actions/common_setup/action.yaml+4−4
@@ -1,8 +1,8 @@
11name: "Common setup"
22description: "Common setup steps"
33inputs:
4− cachixSigningKey:
5− description: "Cachix signing key"
4+ authToken:
5+ description: "Cachix auth token"
66 required: true
77runs:
88 using: "composite"
@@ -36,5 +36,5 @@ runs:
3636 - name: Login to Cachix
3737 uses: cachix/cachix-action@v10
3838 with:
39− name: octopod
40− signingKey: ${{ inputs.cachixSigningKey }}
39+ name: typeable
40+ authToken: ${{ inputs.authToken }}
.github/workflows/build.yaml+4−4
@@ -29,7 +29,7 @@ jobs:
2929 - uses: cachix/install-nix-action@v12
3030 - name: Run fourmolu
3131 run: |
32− nix-shell nix/ci.nix -j auto --run "git ls-files '*.hs' | xargs fourmolu -m inplace --ghc-opt -XRecursiveDo --ghc-opt -XTypeApplications"
32+ nix-shell nix/ci.nix -j auto --run "git ls-files '*.hs' | xargs fourmolu -m inplace --ghc-opt -XRecursiveDo --ghc-opt -XTypeApplications --ghc-opt -XPatternSynonyms"
3333 git diff --exit-code
3434
3535 octo-macOS:
@@ -60,7 +60,7 @@ jobs:
6060 - name: Common setup
6161 uses: ./.github/actions/common_setup
6262 with:
63− cachixSigningKey: ${{ secrets.CACHIX_SIGNING_KEY }}
63+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
6464 - name: Build
6565 run: nix-build -A projectCross.musl64.hsPkgs.octo-cli.components.exes.octo --arg prod true -j auto
6666 - uses: actions/upload-artifact@v2
@@ -77,7 +77,7 @@ jobs:
7777 - name: Common setup
7878 uses: ./.github/actions/common_setup
7979 with:
80− cachixSigningKey: ${{ secrets.CACHIX_SIGNING_KEY }}
80+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
8181
8282 - name: Build Docker Images
8383 run: nix-build ./nix -j auto
@@ -116,7 +116,7 @@ jobs:
116116 - name: Common setup
117117 uses: ./.github/actions/common_setup
118118 with:
119− cachixSigningKey: ${{ secrets.CACHIX_SIGNING_KEY }}
119+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
120120 - name: Push Docker Release Images to DockerHub
121121 uses: ./.github/actions/push_docker_images
122122 with:
.nova/Configuration.jsonnew file+5
@@ -0,0 +1,5 @@
1+{
2+ "env-generator" : "nix-shell --run env",
3+ "haskell.checkProject" : false,
4+ "haskell.formattingProvider" : "fourmolu"
5+}
.vscode/settings.json+6−1
@@ -1,4 +1,9 @@
11{
22 "nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix",
3− "haskell.formattingProvider": "fourmolu"
3+ "haskell.formattingProvider": "fourmolu",
4+ "haskell.plugin.hlint.diagnosticsOn": false,
5+ "haskell.hlint.logLevel": "none",
6+ "haskell.hlint.run": "never",
7+ "haskell.serverExecutablePath": "haskell-language-server",
8+ "editor.formatOnSave": true
49}
cabal.project+6
@@ -31,5 +31,11 @@ source-repository-package
3131 subdir: lib/executable-config/lookup
3232 --sha256: 0dlk8y6rxc87crw7764zq2py7nqn38lw496ca1y893m9gdq8qdkz
3333
34+source-repository-package
35+ type: git
36+ location: https://github.com/typeable/ordered-containers.git
37+ tag: 3eb05fb2f44fe482e9092aff447e9c68fbd6a7f6
38+ --sha256: 0q3cp3nar41bqh2ldl1ykzaycf0bjxh0n58za5g19x4g7ab8h9gm
39+
3440package reflex-dom
3541 flags: +use-warp
charts/octopod/Chart.yaml+2−2
@@ -2,8 +2,8 @@ apiVersion: v2
22name: octopod
33description: An opensource self-hosted solution for managing multiple deployments in a Kubernetes cluster.
44type: application
5−version: 0.6.5
6−appVersion: 1.4.2
5+version: 0.6.11
6+appVersion: 1.5.2
77keywords:
88 - kubernetes
99 - octopod
charts/octopod/index.yamlnew file+37
@@ -0,0 +1,37 @@
1+apiVersion: v1
2+entries:
3+ postgresql:
4+ - annotations:
5+ category: Database
6+ apiVersion: v2
7+ appVersion: 11.12.0
8+ created: "2022-08-23T14:43:53.959078+03:00"
9+ dependencies:
10+ - name: common
11+ repository: https://charts.bitnami.com/bitnami
12+ version: 1.x.x
13+ description: Chart for PostgreSQL, an object-relational database management system
14+ (ORDBMS) with an emphasis on extensibility and on standards-compliance.
15+ digest: afece60469d73b9cc4b578fff9b7627dd6ae609be50a04dabac5ad0be5105f33
16+ home: https://github.com/bitnami/charts/tree/master/bitnami/postgresql
17+ icon: https://bitnami.com/assets/stacks/postgresql/img/postgresql-stack-220x234.png
18+ keywords:
19+ - postgresql
20+ - postgres
21+ - database
22+ - sql
23+ - replication
24+ - cluster
25+ maintainers:
26+ - email: containers@bitnami.com
27+ name: Bitnami
28+ - email: cedric@desaintmartin.fr
29+ name: desaintmartin
30+ name: postgresql
31+ sources:
32+ - https://github.com/bitnami/bitnami-docker-postgresql
33+ - https://www.postgresql.org/
34+ urls:
35+ - charts/postgresql-10.5.3.tgz
36+ version: 10.5.3
37+generated: "2022-08-23T14:43:53.955624+03:00"
charts/octopod/templates/ingress-app.yaml+11−5
@@ -1,10 +1,13 @@
11{{- if .Values.ingress.enabled -}}
22{{- $fullName := include "octopod.fullname" . -}}
3−{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
3+{{- $kubeVersion := .Capabilities.KubeVersion.Version }}
4+{{ if semverCompare ">= 1.19.0-0" $kubeVersion }}
5+apiVersion: networking.k8s.io/v1
6+{{ else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }}
47apiVersion: networking.k8s.io/v1beta1
5−{{- else -}}
8+{{ else }}
69apiVersion: extensions/v1beta1
7−{{- end }}
10+{{ end }}
811kind: Ingress
912metadata:
1013 name: {{ $fullName }}-app
@@ -41,7 +44,10 @@ spec:
4144 http:
4245 paths:
4346 - path: /
47+ pathType: ImplementationSpecific
4448 backend:
45− serviceName: {{ $fullName }}
46− servicePort: {{ .Values.service.ports.app }}
49+ service:
50+ name: {{ $fullName }}
51+ port:
52+ number: {{ .Values.service.ports.app }}
4753{{- end }}
charts/octopod/templates/ingress-powerapp.yaml+11−5
@@ -1,10 +1,13 @@
11{{- if .Values.ingress.enabled -}}
22{{- $fullName := include "octopod.fullname" . -}}
3−{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
3+{{- $kubeVersion := .Capabilities.KubeVersion.Version }}
4+{{ if semverCompare ">= 1.19.0-0" $kubeVersion }}
5+apiVersion: networking.k8s.io/v1
6+{{ else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }}
47apiVersion: networking.k8s.io/v1beta1
5−{{- else -}}
8+{{ else }}
69apiVersion: extensions/v1beta1
7−{{- end }}
10+{{ end }}
811kind: Ingress
912metadata:
1013 name: {{ $fullName }}-powerapp
@@ -35,7 +38,10 @@ spec:
3538 http:
3639 paths:
3740 - path: /
41+ pathType: ImplementationSpecific
3842 backend:
39− serviceName: {{ $fullName }}
40− servicePort: {{ .Values.service.ports.powerApp }}
43+ service:
44+ name: {{ $fullName }}
45+ port:
46+ number: {{ .Values.service.ports.powerApp }}
4147{{- end }}
charts/octopod/templates/ingress-ui.yaml+11−5
@@ -1,10 +1,13 @@
11{{- if .Values.ingress.enabled -}}
22{{- $fullName := include "octopod.fullname" . -}}
3−{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
3+{{- $kubeVersion := .Capabilities.KubeVersion.Version }}
4+{{ if semverCompare ">= 1.19.0-0" $kubeVersion }}
5+apiVersion: networking.k8s.io/v1
6+{{ else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }}
47apiVersion: networking.k8s.io/v1beta1
5−{{- else -}}
8+{{ else }}
69apiVersion: extensions/v1beta1
7−{{- end }}
10+{{ end }}
811kind: Ingress
912metadata:
1013 name: {{ $fullName }}-ui
@@ -35,7 +38,10 @@ spec:
3538 http:
3639 paths:
3740 - path: /
41+ pathType: ImplementationSpecific
3842 backend:
39− serviceName: {{ $fullName }}
40− servicePort: {{ .Values.service.ports.ui }}
43+ service:
44+ name: {{ $fullName }}
45+ port:
46+ number: {{ .Values.service.ports.ui }}
4147{{- end }}
charts/octopod/templates/ingress-ws.yaml+11−5
@@ -1,10 +1,13 @@
11{{- if .Values.ingress.enabled -}}
22{{- $fullName := include "octopod.fullname" . -}}
3−{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
3+{{- $kubeVersion := .Capabilities.KubeVersion.Version }}
4+{{ if semverCompare ">= 1.19.0-0" $kubeVersion }}
5+apiVersion: networking.k8s.io/v1
6+{{ else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }}
47apiVersion: networking.k8s.io/v1beta1
5−{{- else -}}
8+{{ else }}
69apiVersion: extensions/v1beta1
7−{{- end }}
10+{{ end }}
811kind: Ingress
912metadata:
1013 name: {{ $fullName }}-ws
@@ -35,7 +38,10 @@ spec:
3538 http:
3639 paths:
3740 - path: /
41+ pathType: ImplementationSpecific
3842 backend:
39− serviceName: {{ $fullName }}
40− servicePort: {{ .Values.service.ports.ws }}
43+ service:
44+ name: {{ $fullName }}
45+ port:
46+ number: {{ .Values.service.ports.ws }}
4147{{- end }}
charts/octopod/values.yaml+1−1
@@ -99,7 +99,7 @@ controlScripts:
9999 image:
100100 repository: typeable/octopod-helm-control-scripts
101101 pullPolicy: IfNotPresent
102− tag: 0.2.2
102+ tag: 0.2.4
103103sqitch:
104104 image:
105105 repository: typeable/sqitch
dev/default.nix+36−4
@@ -104,6 +104,7 @@ in
104104 #!${pkgs.bash}/bin/bash
105105
106106 echo "You did something wrong :("
107+ echo "You did something wrong twice :("
107108
108109 1>&2 echo "You did something wrong, but you shouldn't see this."
109110
@@ -115,9 +116,31 @@ in
115116
116117 sleep 4
117118
119+ echo "foo.vat1.fjij.key1,"
120+
121+ for i in {1..10}
122+ do
123+ for j in {1..10}
124+ do
125+ echo "foo.vat$i.fjij.key$j,value"
126+ done
127+ done
128+
129+ for i in {1..10}
130+ do
131+ echo "fjij.key$i,value"
132+ done
133+
134+ exit 0
135+ '';
136+ smallInfoScript = pkgs.writeScript "info.sh" ''
137+ #!${pkgs.bash}/bin/bash
138+
139+ sleep 4
140+
118141 for i in {1..10}
119142 do
120− echo "key$i,value"
143+ echo "fjij.key$i,value"
121144 done
122145
123146 exit 0
@@ -130,7 +153,16 @@ in
130153
131154 for i in {1..10}
132155 do
133− echo "key$i"
156+ echo "foo.vat.fkijf.fjij.key$i"
157+ done
158+ for i in {1..10}
159+ do
160+ echo "foo.vat.fjij.key$i"
161+ done
162+
163+ for i in {1..10}
164+ do
165+ echo "fjij.key$i"
134166 done
135167
136168 exit 0
@@ -162,8 +194,8 @@ in
162194 export CHECKING_COMMAND=${echoScript}
163195 export CLEANUP_COMMAND=${echoScript}
164196 export ARCHIVE_CHECKING_COMMAND=${echoScript}
165− export CONFIG_CHECKING_COMMAND=${echoScript}
166− export INFO_COMMAND=${infoScript}
197+ export CONFIG_CHECKING_COMMAND=${failScript}
198+ export INFO_COMMAND=${smallInfoScript}
167199 export NOTIFICATION_COMMAND=${writeScript}
168200 export DEPLOYMENT_CONFIG_COMMAND=${infoScript}
169201 export DEPLOYMENT_KEYS_COMMAND=${keysScript}
docs/en/Overview.md+2−2
@@ -21,7 +21,7 @@ Octopod aims to extract the mentioned similarity between deploying different sta
2121
2222### 💽 The server
2323
24−You are developing a server, which is accessed through [_nginx_](https://www.nginx.com), and the server needs access to a [*Postgres*](https://www.postgresql.org) database and a [*Redis*](https://redis.io) database
24+You are developing a server, which is accessed through _nginx_, and the server needs access to a [*Postgres*](https://www.postgresql.org) database and a [*Redis*](https://redis.io) database
2525
2626![](../diagrams/images/sample_architecture.png)
2727
@@ -33,7 +33,7 @@ Now imagine that two different developers each completed one of the tasks, and y
3333
3434A way to mitigate this situation is to test each feature separately, in its own staging deployment, and verify which change made the page background pink, and ideally, you would check each feature before merging them into the final product (merging it into the `master` branch, for example).
3535
36−To check each feature before merging would require every developer to build the new version of the server, and set up all required services: [_nginx_](https://www.nginx.com), [*Postgres*](https://www.postgresql.org), [*Redis*](https://redis.io). Developers would also have to manage access to the set up environments ― set up SSL certificates, set up subdomains, make sure databases are not exposed, and make sure the connection between every component is secure and authenticated.
36+To check each feature before merging would require every developer to build the new version of the server, and set up all required services: _nginx_, [*Postgres*](https://www.postgresql.org), [*Redis*](https://redis.io). Developers would also have to manage access to the set up environments ― set up SSL certificates, set up subdomains, make sure databases are not exposed, and make sure the connection between every component is secure and authenticated.
3737
3838This is **a lot** of overhead just to test the color of a button. Note that most of the described work would be identical across the vast majority of features ― changing the deployment architecture is a relatively rare task in most projects. Databases, load balancing, caching, and proxying would be set up in much the same way for the majority of feature-specific stagings. The server itself is probably also compiled in exactly the same way for most features.
3939
helm-control-scripts/Cargo.lock+1−1
@@ -525,7 +525,7 @@ dependencies = [
525525
526526[[package]]
527527name = "helm-control-scripts"
528−version = "0.2.2"
528+version = "0.2.3"
529529dependencies = [
530530 "dkregistry",
531531 "env_logger",
helm-control-scripts/Cargo.toml+1−1
@@ -1,6 +1,6 @@
11[package]
22name = "helm-control-scripts"
3−version = "0.2.2"
3+version = "0.2.3"
44authors = ["Aleksei Sizov <a.sizov@typeable.io>"]
55edition = "2018"
66
helm-control-scripts/src/cleanup.rs−11
@@ -55,17 +55,6 @@ fn main() {
5555 panic!("{:?}", err);
5656 }
5757 }
58− match ingresses_to_secrets(ingresses, old_ingresses) {
59− Some(secrets) => {
60− for secret in secrets {
61− match delete_secret(&namespace, &secret) {
62− Ok(_status) => info!("Successfully deleted secret {}", &secret),
63− Err(error) => error!("Can't delete secret {}\n {}", &secret, error)
64− }
65− }
66− },
67− None => info!("No secrets to delete")
68− }
6958 info!("Success!");
7059 },
7160 Err(status) => {
helm-control-scripts/src/config_check.rs+7−2
@@ -30,11 +30,15 @@ fn main() {
3030 deployment_parameters: deployment_parameters,
3131 overrides: overrides,
3232 };
33+ info!("Generated Helm args: {:?}", &helm_template.args());
3334 match helm_template.run_stdout() {
3435 Ok(status) => {
3536 let (deployments, statefulsets, _ingresses, _old_ingresses, _postgresqls, _kafkas) = match parse_to_k8s(status) {
3637 Ok((deployments, statefulsets, ingresses, old_ingresses, postgresqls, kafkas)) => (deployments, statefulsets, ingresses, old_ingresses, postgresqls, kafkas),
37− Err(err) => panic!("{}", err)
38+ Err(err) => {
39+ println!("Something went wrong: {}", err);
40+ panic!("{}", err);
41+ }
3842 };
3943 match deployments_statefulsets_to_images(deployments, statefulsets) {
4044 Some(images) => {
@@ -52,7 +56,8 @@ fn main() {
5256 }
5357 }
5458 }
55− Err(status) => {
59+ Err((status, err)) => {
60+ println!("{:#}", err);
5661 error!("Error during helm execution");
5762 panic!("{:?}", status);
5863 }
helm-control-scripts/src/lib.rs+12−9
@@ -254,7 +254,7 @@ pub mod lib {
254254 Err(helm.status)
255255 }
256256 }
257− pub fn run_stdout(&self) -> Result<String, ExitStatus> {
257+ pub fn run_stdout(&self) -> Result<String, (ExitStatus, String)> {
258258 let helm = Command::new(&self.name)
259259 .args(&self.args())
260260 .output()
@@ -262,9 +262,11 @@ pub mod lib {
262262 if helm.status.success() {
263263 Ok(String::from_utf8(helm.stdout).unwrap())
264264 } else {
265− info!("helm stdout:\n {}", String::from_utf8(helm.stdout).unwrap());
266− info!("helm stderr:\n {}", String::from_utf8(helm.stderr).unwrap());
267− Err(helm.status)
265+ let stdout = String::from_utf8(helm.stdout).unwrap();
266+ let stderr = String::from_utf8(helm.stderr).unwrap();
267+ info!("helm stdout:\n {}", stdout);
268+ info!("helm stderr:\n {}", stderr);
269+ Err((helm.status, stderr))
268270 }
269271 }
270272 }
@@ -297,11 +299,10 @@ pub mod lib {
297299 replicas: i32
298300 }
299301 fn check_value(value: String) -> Result<String, String> {
300− let split_value = value.split('=').collect::<Vec<_>>();
301− if split_value.len() == 2 {
302− Ok(value)
303− } else {
304− Err(format!("Override value {} is malformed", value))
302+ let re = Regex::new(r"^([^=]*)=(.*)$").unwrap();
303+ match re.captures(&value) {
304+ Some(_) => return Ok(value),
305+ None => return Err(format!("Override value {} is malformed", value)),
305306 }
306307 }
307308 pub fn overrides(cli_opts: &CliOpts, envs: &EnvVars) -> Option<Vec<String>> {
@@ -732,6 +733,7 @@ pub mod lib {
732733 match helm_repo_add.run() {
733734 Ok(_status) => info!("Repo add success!"),
734735 Err(status) => {
736+ println!("Couldn't add repo.");
735737 error!("Error during helm execution");
736738 panic!("{:?}", status);
737739 }
@@ -739,6 +741,7 @@ pub mod lib {
739741 match helm_repo_update.run() {
740742 Ok(_status) => info!("Repo update success!"),
741743 Err(status) => {
744+ println!("Couldn't update repo.");
742745 error!("Error during helm execution");
743746 panic!("{:?}", status);
744747 }
nix/default.nix+1−1
@@ -1,5 +1,5 @@
11{ sources ? import ./sources.nix
2−, octopod-css ? import ../octopod-css { inherit pkgsSrc; }
2+, octopod-css ? import ../octopod-css { inherit pkgsSrc system; }
33, migrations ? ../migrations
44, system ? builtins.currentSystem
55, hsPkgs ? import ./.. { inherit system prod; }
octo-cli/octo-cli.cabal−1
@@ -59,7 +59,6 @@ executable octo
5959 transformers,
6060 table-layout ^>= 0.9.0.0,
6161 servant-auth,
62− ordered-containers,
6362 http-types,
6463 hs-source-dirs: src
6564 default-language: Haskell2010
octo-cli/src/Octopod/CLI.hs+8−21
@@ -13,9 +13,10 @@ import Data.Aeson (decode)
1313import qualified Data.ByteString.Char8 as BSC
1414import qualified Data.ByteString.Lazy.Char8 as LBSC
1515import Data.Coerce
16+import qualified Data.ConfigTree as CT
17+import Data.Foldable
1618import Data.Generics.Labels ()
1719import Data.Generics.Product
18−import qualified Data.Map.Ordered.Strict as OM
1920import Data.Maybe
2021import Data.Proxy
2122import Data.Text (Text)
@@ -123,24 +124,10 @@ handleUpdate ::
123124handleUpdate auth dName dNewAppOvs removedAppOvs dNewDepOvs removedDepOvs = do
124125 clientEnv <- ask
125126 dep <- runClientM' (_fullInfoH auth dName) clientEnv
126− let removeAll :: Ord k => [k] -> OM.OMap k v -> Either k (OM.OMap k v)
127− removeAll [] m = Right m
128− removeAll (k : kk) m =
129− if k `OM.member` m
130− then removeAll kk $ OM.delete k m
131− else Left k
132− removeAllM :: MonadIO m => [Text] -> Overrides l -> m (Overrides l)
133− removeAllM ks (Overrides m) =
134− either
135− (\k -> dieT $ "Override " <> k <> " not present in deployment.")
136− (pure . Overrides)
137− $ removeAll ks m
138− appOverrides' <-
139− fmap (<> dNewAppOvs) $
140− removeAllM removedAppOvs $ dep ^. #deployment . #appOverrides
141− deploymentOverrides' <-
142− fmap (<> dNewDepOvs) $
143− removeAllM removedDepOvs $ dep ^. #deployment . #deploymentOverrides
127+ let removeAll :: [Text] -> Overrides l -> (Overrides l)
128+ removeAll ks (Overrides (CT.toFlatList -> m)) = Overrides $ CT.fromFlatList $ filter (flip elem ks . fst) m
129+ appOverrides' = dNewAppOvs <> (removeAll removedAppOvs $ dep ^. #deployment . #appOverrides)
130+ deploymentOverrides' = dNewDepOvs <> (removeAll removedDepOvs $ dep ^. #deployment . #deploymentOverrides)
144131 liftIO $ do
145132 let dUpdate =
146133 DeploymentUpdate
@@ -295,7 +282,7 @@ printInfo (DeploymentInfo (Deployment _ dAppOvs dStOvs) (DeploymentMetadata dMet
295282 putStrLn $ unlines $ formatOverrides False dStOvs
296283 T.putStrLn ""
297284 T.putStrLn $ "Metadata: "
298− forM_ dMeta $ \m ->
285+ for_ dMeta $ \m ->
299286 T.putStrLn $
300287 " " <> m ^. #name <> ": " <> m ^. #link
301288 T.putStrLn ""
@@ -352,7 +339,7 @@ formatOverrides splitlines (Overrides m) =
352339 ]
353340 unicodeS
354341 def
355− $ showOverride <$> (reverse . OM.assocs) m
342+ $ showOverride <$> (reverse . CT.toFlatList) m
356343 where
357344 showOverride (k, v) =
358345 colsAllG top $ [if splitlines then T.chunksOf 15 k else [k], showValue v]
octo-cli/src/Octopod/CLI/Args.hs+2−1
@@ -68,7 +68,8 @@ readLogOutput _ = Nothing
6868
6969-- | Parses octo CLI subcommands and arguments.
7070parseArgs :: IO Args
71−parseArgs = execParser $ info (commandArgs <**> helper) fullDesc
71+parseArgs =
72+ customExecParser (prefs showHelpOnError) $ info (commandArgs <**> helper) fullDesc
7273
7374-- | Parses octo CLI subcommands.
7475commandArgs :: Parser Args
octopod-api/src/Octopod/API/WebSocket.hs+1
@@ -1,3 +1,4 @@
1+{- ORMOLU_DISABLE -}
12{-# LANGUAGE CPP #-}
23
34module Octopod.API.WebSocket
octopod-backend/octopod-backend.cabal−1
@@ -113,7 +113,6 @@ library
113113 , time
114114 , hasql
115115 , hasql-transaction
116− , ordered-containers
117116 , unordered-containers
118117 , vector
119118 , process
octopod-backend/src/Control/CacheMap.hs+2−1
@@ -12,6 +12,7 @@ import Control.Monad.Base
1212import Control.Monad.Except
1313import Control.Monad.Trans.Control
1414import Data.Fixed
15+import Data.Foldable
1516import Data.IORef.Lifted
1617import Data.Map.Strict (Map)
1718import qualified Data.Map.Strict as M
@@ -81,7 +82,7 @@ lookupBlocking (CacheMap ref createValue update) k = do
8182 res@(Right _) -> do
8283 putMVar var res
8384 pure $ (var, if recompute then Just blank else Nothing)
84− forM_ mwVar $ \wVar -> do
85+ for_ mwVar $ \wVar -> do
8586 fork $ do
8687 v <- (Right <$> createValue k) `catchError` (pure . Left)
8788 putMVar wVar v
octopod-backend/src/Octopod/Server.hs+7−7
@@ -23,6 +23,7 @@ import qualified Data.ByteString.Lazy as BSL
2323import qualified Data.ByteString.Lazy.Char8 as BSLC
2424import Data.Coerce
2525import Data.Conduit (ConduitT, yield)
26+import qualified Data.ConfigTree as CT
2627import qualified Data.Csv as C
2728import Data.Fixed
2829import Data.Foldable
@@ -32,7 +33,6 @@ import Data.Generics.Labels ()
3233import Data.Generics.Product
3334import Data.IORef.Lifted
3435import Data.Int
35−import qualified Data.Map.Ordered.Strict as OM
3636import Data.Maybe
3737import Data.Pool
3838import Data.Text (pack)
@@ -192,7 +192,7 @@ runOctopodServer sha = do
192192 decodeCSVDefaultConfig :: BSL.ByteString -> Either String (DefaultConfig l)
193193 decodeCSVDefaultConfig bs = do
194194 x <- C.decode C.NoHeader bs
195− pure $ DefaultConfig . OM.fromList . V.toList $ x
195+ pure $ DefaultConfig . CT.fromFlatList . V.toList $ x
196196 either500S :: (KatipContext m, MonadError ServerError m) => Either String x -> m x
197197 either500S (Right x) = pure x
198198 either500S (Left err) = do
@@ -478,7 +478,7 @@ getSingleFullInfo dName = do
478478 d <- each deploymentSchema
479479 where_ $ d ^. #name ==. litExpr dName
480480 pure d
481− deployments <- forM deploymentsSchema extractDeploymentFullInfo
481+ deployments <- for deploymentsSchema extractDeploymentFullInfo
482482 logLocM DebugS $ "get deployments: " <> show' deployments
483483 return $ listToMaybe deployments
484484
@@ -489,7 +489,7 @@ getFullInfo = do
489489 deploymentsSchema <-
490490 runStatement . select . orderBy (view #updatedAt >$< desc) $
491491 each deploymentSchema
492− deployments <- forM deploymentsSchema extractDeploymentFullInfo
492+ deployments <- for deploymentsSchema extractDeploymentFullInfo
493493 logLocM DebugS $ "get deployments: " <> show' deployments
494494 return deployments
495495
@@ -739,7 +739,7 @@ transitionToStatus dName s = do
739739 (deps, oldS) <- either throwError pure res
740740 dep <- lift $ ensureOne deps
741741 lift $
742− forM_ (processOutput s) $ \(output, act) ->
742+ for_ (processOutput s) $ \(output, act) ->
743743 createDeploymentLog
744744 dep
745745 act
@@ -748,7 +748,7 @@ transitionToStatus dName s = do
748748 (output ^. #stdout)
749749 (output ^. #stderr)
750750 notificationCmd <- asks notificationCommand
751− forM_ notificationCmd $ \nCmd ->
751+ for_ notificationCmd $ \nCmd ->
752752 runBgWorker . void $
753753 runCommandArgs' nCmd
754754 =<< notificationCommandArgs dName oldS newS
@@ -1307,7 +1307,7 @@ runDeploymentBgWorker newS dName pre post = do
13071307 dName
13081308 (respondSync $ Left err409 {errBody = "The deployment is currently being processed."})
13091309 ( do
1310− let preWithAssert = pre <* forM newS (assertDeploymentTransitionPossibleS dName)
1310+ let preWithAssert = pre <* for newS (assertDeploymentTransitionPossibleS dName)
13111311 result <- catchError (Right <$> preWithAssert) (pure . Left)
13121312 respondSync result
13131313 liftEither result >>= \res -> do
octopod-backend/src/Octopod/Server/ControlScriptUtils.hs+2−2
@@ -37,9 +37,9 @@ import Control.Monad.Base
3737import Control.Monad.Reader
3838import qualified Data.ByteString.Lazy as TL
3939import Data.Coerce
40+import qualified Data.ConfigTree as CT
4041import Data.Fixed
4142import Data.Generics.Product.Typed
42−import qualified Data.Map.Ordered.Strict as MO
4343import qualified Data.Text as T
4444import qualified Data.Text.Encoding as T
4545import Data.Time
@@ -257,7 +257,7 @@ overridesArgs :: forall l. KnownOverrideLevel l => Config l -> ControlScriptArgs
257257overridesArgs (Config cc) =
258258 ControlScriptArgs
259259 . concatMap (\(T.unpack -> k, T.unpack -> v) -> [argumentName, k <> "=" <> v])
260− . MO.assocs
260+ . CT.toFlatList
261261 $ cc
262262 where
263263 argumentName = case knownOverrideLevel @l of
octopod-backend/src/Octopod/Server/Posix.hs+2−2
@@ -1,8 +1,8 @@
11module Octopod.Server.Posix (installShutdownHandler) where
22
3−import Control.Monad
43import Control.Monad.Trans.Control
54import Data.Aeson
5+import Data.Traversable
66import Octopod.Server.Logging
77import System.Posix.Signals
88
@@ -21,7 +21,7 @@ installShutdownHandler ::
2121 m () ->
2222 m [Handler]
2323installShutdownHandler signals action =
24− forM signals $ \signal -> liftBaseWith $ \run ->
24+ for signals $ \signal -> liftBaseWith $ \run ->
2525 installHandler signal (Catch $ run (handler signal)) Nothing
2626 where
2727 handler signal = katipAddNamespace "signal handler" $
octopod-common/octopod-common.cabal+3−1
@@ -18,7 +18,7 @@ library
1818 exposed-modules: Common.Types
1919 , Common.Utils
2020 , Common.Validation
21− , Data.Map.Ordered.Strict.Extra
21+ , Data.ConfigTree
2222 , Control.Searchable
2323 , Common.Orphans
2424 -- other-modules:
@@ -56,6 +56,7 @@ library
5656 , UndecidableInstances
5757 , FunctionalDependencies
5858 , QuantifiedConstraints
59+ , PatternSynonyms
5960 build-depends: base
6061 , aeson
6162 , cassava
@@ -69,6 +70,7 @@ library
6970 , time
7071 , ordered-containers
7172 , deepseq
73+ , these
7274 hs-source-dirs: src
7375 default-language: Haskell2010
7476 ghc-options:
octopod-common/src/Common/Orphans.hs+14−4
@@ -3,8 +3,18 @@
33module Common.Orphans () where
44
55import Control.DeepSeq
6−import Data.Map.Ordered
6+import Data.Aeson
7+import Data.Map.Internal
8+import Data.Map.Ordered.Internal
9+import qualified Data.Map.Ordered.Strict as OM
10+import GHC.Generics (Generic)
711
8−-- better than nothing
9−instance (NFData a, NFData b) => NFData (OMap a b) where
10− rnf = rnf . toMap
12+deriving stock instance Generic (Map k v)
13+
14+deriving stock instance Generic (OMap k v)
15+deriving anyclass instance (NFData k, NFData v) => NFData (OMap k v)
16+instance (ToJSON k, ToJSON v) => ToJSON (OMap k v) where
17+ toJSON = toJSON . OM.assocs
18+
19+instance (FromJSON k, FromJSON v, Ord k) => FromJSON (OMap k v) where
20+ parseJSON = fmap OM.fromList . parseJSON
octopod-common/src/Common/Types.hs+43−44
@@ -12,12 +12,12 @@ import Control.DeepSeq (NFData)
1212import Control.Lens
1313import Control.Searchable
1414import Data.Aeson hiding (Result)
15+import Data.ConfigTree (ConfigTree)
16+import qualified Data.ConfigTree as CT
1517import Data.Csv
1618import Data.Generics.Labels ()
1719import Data.Int
18−import Data.Map.Ordered.Strict (OMap, (<>|))
19−import qualified Data.Map.Ordered.Strict as OM
20−import Data.Map.Ordered.Strict.Extra ()
20+import Data.List.NonEmpty (NonEmpty)
2121import Data.Maybe
2222import Data.Text (Text)
2323import qualified Data.Text as T
@@ -54,21 +54,21 @@ type OverrideValue = OverrideValue' Text
5454
5555type DefaultConfig = DefaultConfig' Text
5656
57−newtype DefaultConfig' te (l :: OverrideLevel) = DefaultConfig (OMap te te)
58− deriving newtype (Eq, Ord, Show, ToJSON, FromJSON)
57+newtype DefaultConfig' te (l :: OverrideLevel) = DefaultConfig (ConfigTree te te)
58+ deriving newtype (Eq, Ord, Show)
59+
60+deriving newtype instance FromJSON (DefaultConfig' Text l)
61+deriving newtype instance ToJSON (DefaultConfig' Text l)
5962
6063instance Searchable t x => Searchable t (DefaultConfig' x l) where
6164 type SearchableConstraint t (DefaultConfig' x l) res = (Ord (Searched x res), SearchableConstraint t x res)
6265 type Searched (DefaultConfig' x l) res = DefaultConfig' (Searched x res) l
63− searchWith f (DefaultConfig oMap) = do
64− oMap' <- searchWith f . OM.assocs $ oMap
65− pure $ DefaultConfig $ OM.fromList oMap'
66+ searchWith f (DefaultConfig ct) = DefaultConfig <$> searchWith f ct
6667 {-# INLINE searchWith #-}
6768
68−lookupDefaultConfig :: DefaultConfig l -> Text -> Maybe Text
69−lookupDefaultConfig (DefaultConfig m) k = OM.lookup k m
69+type ConfigKey = [Text]
7070
71−newtype Config (l :: OverrideLevel) = Config {unConfig :: OMap Text Text}
71+newtype Config (l :: OverrideLevel) = Config {unConfig :: ConfigTree Text Text}
7272 deriving newtype (Eq, Ord, Show, ToJSON, FromJSON)
7373
7474data FullDefaultConfig = FullDefaultConfig
@@ -87,63 +87,58 @@ data FullConfig = FullConfig
8787
8888applyOverrides :: Overrides l -> DefaultConfig l -> Config l
8989applyOverrides (Overrides oo) (DefaultConfig dd) =
90− Config . extract $ oo <>| (ValueAdded <$> dd)
90+ Config . extract $ oo <> (ValueAdded <$> dd)
9191 where
92− extract :: OMap Text OverrideValue -> OMap Text Text
92+ extract :: ConfigTree Text OverrideValue -> ConfigTree Text Text
9393 extract =
9494 fmap
9595 ( \case
9696 ValueAdded v -> v
9797 ValueDeleted -> error "invariant"
9898 )
99− . OM.filter
100− ( \_ -> \case
99+ . CT.filter
100+ ( \case
101101 ValueAdded _ -> True
102102 ValueDeleted -> False
103103 )
104104
105+newtype Overrides' t (l :: OverrideLevel) = Overrides {unOverrides :: ConfigTree t (OverrideValue' t)}
106+ deriving newtype (Eq, Ord, Show, NFData, Semigroup, Monoid)
107+
108+deriving newtype instance FromJSON (Overrides' Text l)
109+deriving newtype instance ToJSON (Overrides' Text l)
110+
105111instance Searchable t x => Searchable t (Overrides' x l) where
106112 type SearchableConstraint t (Overrides' x l) res = (Ord (Searched x res), SearchableConstraint t x res)
107113 type Searched (Overrides' x l) res = Overrides' (Searched x res) l
108− searchWith f (Overrides oMap) = do
109− oMap' <- searchWith f . OM.assocs $ oMap
110− pure $ Overrides $ OM.fromList oMap'
114+ searchWith f (Overrides ct) = Overrides <$> searchWith f ct
111115 {-# INLINE searchWith #-}
112116
113−newtype Overrides' t (l :: OverrideLevel) = Overrides {unOverrides :: OMap t (OverrideValue' t)}
114− deriving newtype (Eq, Ord, Show, ToJSON, FromJSON, NFData)
115−
116117type Overrides = Overrides' Text
117118
118119extractOverrides :: DefaultConfig l -> Config l -> Overrides l
119120extractOverrides (DefaultConfig dCfg) (Config cfg) =
120− Overrides . OM.fromList $ removed <> present
121+ Overrides . CT.fromList $ removed <> present
121122 where
122− present :: [(Text, OverrideValue)]
123− present = mapMaybe processPresent . OM.assocs $ cfg
123+ present :: [(NonEmpty Text, OverrideValue)]
124+ present = mapMaybe processPresent . CT.toList $ cfg
124125
125− processPresent :: (Text, Text) -> Maybe (Text, OverrideValue)
126− processPresent (k, v) = case OM.lookup k dCfg of
126+ processPresent :: (NonEmpty Text, Text) -> Maybe (NonEmpty Text, OverrideValue)
127+ processPresent (k, v) = case CT.lookup k dCfg of
127128 Just v' | v == v' -> Nothing
128129 _ -> Just (k, ValueAdded v)
129130
130− processRemoved :: (Text, Text) -> Maybe (Text, OverrideValue)
131+ processRemoved :: (NonEmpty Text, Text) -> Maybe (NonEmpty Text, OverrideValue)
131132 processRemoved (k, _) =
132− if OM.member k cfg
133+ if CT.member k cfg
133134 then Nothing
134135 else Just (k, ValueDeleted)
135136
136− removed :: [(Text, OverrideValue)]
137− removed = mapMaybe processRemoved . OM.assocs $ dCfg
137+ removed :: [(NonEmpty Text, OverrideValue)]
138+ removed = mapMaybe processRemoved . CT.toList $ dCfg
138139
139−ov :: Text -> OverrideValue -> Overrides l
140−ov k v = Overrides $ OM.singleton (k, v)
141−
142−instance Semigroup (Overrides l) where
143− (Overrides lhs) <> (Overrides rhs) = Overrides $ rhs <>| lhs
144−
145−instance Monoid (Overrides l) where
146− mempty = Overrides OM.empty
140+ov :: NonEmpty Text -> OverrideValue -> Overrides l
141+ov k v = Overrides $ CT.singleton k v
147142
148143newtype DeploymentId = DeploymentId {unDeploymentId :: Int64}
149144 deriving stock (Show)
@@ -243,9 +238,11 @@ data Deployment' t = Deployment
243238 , deploymentOverrides :: Overrides' t 'DeploymentLevel
244239 }
245240 deriving stock (Generic, Show, Eq)
246− deriving (FromJSON, ToJSON) via Snake (Deployment' t)
247241 deriving anyclass (NFData)
248242
243+deriving via Snake (Deployment' Text) instance FromJSON (Deployment' Text)
244+deriving via Snake (Deployment' Text) instance ToJSON (Deployment' Text)
245+
249246instance (Searchable needle t) => Searchable needle (Deployment' t) where
250247 type
251248 SearchableConstraint needle (Deployment' t) res =
@@ -317,9 +314,11 @@ data DeploymentFullInfo' t = DeploymentFullInfo
317314 , updatedAt :: UTCTime
318315 }
319316 deriving stock (Generic, Show, Eq)
320− deriving (FromJSON, ToJSON) via Snake (DeploymentFullInfo' t)
321317 deriving anyclass (NFData)
322318
319+deriving via Snake (DeploymentFullInfo' Text) instance FromJSON (DeploymentFullInfo' Text)
320+deriving via Snake (DeploymentFullInfo' Text) instance ToJSON (DeploymentFullInfo' Text)
321+
323322type DeploymentFullInfo = DeploymentFullInfo' Text
324323
325324isDeploymentArchived :: DeploymentFullInfo' t -> Bool
@@ -386,14 +385,14 @@ parseSetOverrides texts = do
386385 Just x -> Right x
387386 Nothing ->
388387 Left $ "Malformed override key-value pair " <> text <> ", should be similar to FOO=bar"
389− return . Overrides $ OM.fromList pairs'
388+ return . Overrides $ CT.fromList pairs'
390389 where
391− parseSingleOverride :: Text -> Maybe (Text, OverrideValue)
390+ parseSingleOverride :: Text -> Maybe (NonEmpty Text, OverrideValue)
392391 parseSingleOverride t
393392 | Just i <- T.findIndex (== '=') t =
394− let (key, value) = bimap T.strip (T.tail . T.strip) $ T.splitAt i t
393+ let (CT.deconstructConfigKey -> key, value) = bimap T.strip (T.tail . T.strip) $ T.splitAt i t
395394 in Just (key, ValueAdded value)
396395 parseSingleOverride _ = Nothing
397396
398397parseUnsetOverrides :: [Text] -> Overrides l
399−parseUnsetOverrides = Overrides . OM.fromList . fmap (,ValueDeleted)
398+parseUnsetOverrides = Overrides . CT.fromList . fmap ((,ValueDeleted) . CT.deconstructConfigKey)
octopod-common/src/Control/Searchable.hs+20−1
@@ -2,11 +2,14 @@
22
33module Control.Searchable
44 ( Searchable (..),
5+ traverseOMap,
56 )
67where
78
89import Control.Lens
910import Data.Kind
11+import Data.Map.Ordered (OMap)
12+import qualified Data.Map.Ordered.Strict as OM
1013import Data.Text (Text)
1114
1215-- | This says that you can search 'needle's in a 'haystack'. What precisely
@@ -38,10 +41,26 @@ instance Searchable needle x => Searchable needle [x] where
3841 {-# INLINE searchWith #-}
3942
4043instance (Searchable needle a, Searchable needle b) => Searchable needle (a, b) where
41− type SearchableConstraint needle (a, b) res = (SearchableConstraint needle a res, SearchableConstraint needle b res)
44+ type
45+ SearchableConstraint needle (a, b) res =
46+ (SearchableConstraint needle a res, SearchableConstraint needle b res)
4247 type Searched (a, b) res = (Searched a res, Searched b res)
4348 searchWith f (a, b) = do
4449 a' <- searchWith f a
4550 b' <- searchWith f b
4651 pure (a', b')
4752 {-# INLINE searchWith #-}
53+
54+instance Searchable needle haystack => Searchable needle (Maybe haystack) where
55+ type SearchableConstraint needle (Maybe haystack) res = SearchableConstraint needle haystack res
56+ type Searched (Maybe haystack) res = Maybe (Searched haystack res)
57+ searchWith _ Nothing = pure Nothing
58+ searchWith f (Just h) = Just <$> searchWith f h
59+ {-# INLINE searchWith #-}
60+
61+traverseOMap ::
62+ forall h k x y.
63+ Ord k =>
64+ (forall f. Applicative f => (h -> f k) -> (x -> f y) -> OMap h x -> f (OMap k y))
65+traverseOMap kf vf (OM.assocs -> l) =
66+ fmap OM.fromList $ (\(h, x) -> (,) <$> kf h <*> vf x) `traverse` l
octopod-common/src/Data/ConfigTree.hsnew file+165
@@ -0,0 +1,165 @@
1+module Data.ConfigTree
2+ ( ConfigTree (..),
3+ null,
4+ filter,
5+ toList,
6+ singleton,
7+ fromList,
8+ lookup,
9+ member,
10+ deconstructConfigKey,
11+ reconstructConfigKey,
12+ toFlatList,
13+ fromFlatList,
14+ Data.ConfigTree.zip,
15+ catMaybes,
16+ insert,
17+ markValues,
18+ )
19+where
20+
21+import Common.Orphans ()
22+import Control.Applicative
23+import Control.DeepSeq (NFData)
24+import Control.Searchable
25+import Data.Aeson
26+import qualified Data.Bifunctor as Bi
27+import Data.Foldable (fold)
28+import qualified Data.List as L
29+import Data.List.NonEmpty (NonEmpty)
30+import qualified Data.List.NonEmpty as NE
31+import Data.Map.Ordered.Strict (OMap)
32+import qualified Data.Map.Ordered.Strict as OM
33+import Data.Maybe (fromJust, fromMaybe, isJust)
34+import Data.String
35+import Data.Text (Text)
36+import qualified Data.Text as T
37+import Data.These
38+import GHC.Generics (Generic)
39+import Prelude hiding (filter, lookup, null)
40+
41+zip :: Ord k => ConfigTree k v -> ConfigTree k h -> ConfigTree k (These v h)
42+zip (ConfigTree m) (ConfigTree w) =
43+ let intersection =
44+ OM.intersectionWith
45+ ( \_ (mv, vMap) (mh, hMap) ->
46+ ( case (mv, mh) of
47+ (Nothing, Nothing) -> Nothing
48+ (Just v, Nothing) -> Just $ This v
49+ (Nothing, Just h) -> Just $ That h
50+ (Just v, Just h) -> Just $ These v h
51+ , Data.ConfigTree.zip vMap hMap
52+ )
53+ )
54+ m
55+ w
56+ vCT = ConfigTree $ m OM.\\ intersection
57+ hCT = ConfigTree $ w OM.\\ intersection
58+ in fmap This vCT <> ConfigTree intersection <> fmap That hCT
59+
60+newtype ConfigTree k v = ConfigTree (OMap k (Maybe v, ConfigTree k v))
61+ deriving newtype (Eq, Ord, Show, NFData)
62+ deriving stock (Functor, Generic)
63+
64+instance ToJSON v => ToJSON (ConfigTree Text v) where
65+ toJSON = toJSON . toFlatList
66+
67+instance FromJSON v => FromJSON (ConfigTree Text v) where
68+ parseJSON = fmap fromFlatList . parseJSON
69+
70+markValues :: (IsString t, Monoid t, Ord t) => ConfigTree t c -> ConfigTree t (t, c)
71+markValues = fromList . fmap (\(k, v) -> (k, (reconstructConfigKey k, v))) . toList
72+{-# INLINE markValues #-}
73+
74+toFlatList :: (IsString t, Monoid t) => ConfigTree t c -> [(t, c)]
75+toFlatList = fmap (Bi.first reconstructConfigKey) . toList
76+{-# INLINE toFlatList #-}
77+
78+fromFlatList :: [(Text, v)] -> ConfigTree Text v
79+fromFlatList = fromList . fmap (Bi.first deconstructConfigKey)
80+{-# INLINE fromFlatList #-}
81+
82+toList :: ConfigTree k v -> [(NonEmpty k, v)]
83+toList (ConfigTree m) =
84+ OM.assocs m >>= \(k, (mv, s)) ->
85+ maybe id (\v -> (:) (pure k, v)) mv $ Bi.first (NE.cons k) <$> toList s
86+{-# INLINE toList #-}
87+
88+fromList :: Ord k => [(NonEmpty k, v)] -> ConfigTree k v
89+fromList = foldMap $ uncurry singleton
90+{-# INLINE fromList #-}
91+
92+singleton :: Ord k => NonEmpty k -> v -> ConfigTree k v
93+singleton (NE k) v = ConfigTree $ OM.singleton (k, (Just v, mempty))
94+singleton (NECons k ks) v = ConfigTree $ OM.singleton (k, (Nothing, singleton ks v))
95+{-# INLINE singleton #-}
96+
97+lookup :: Ord k => NonEmpty k -> ConfigTree k v -> Maybe v
98+lookup (NE k) (ConfigTree m) = OM.lookup k m >>= fst
99+lookup (NECons k ks) (ConfigTree m) = OM.lookup k m >>= lookup ks . snd
100+{-# INLINE lookup #-}
101+
102+member :: Ord k => NonEmpty k -> ConfigTree k v -> Bool
103+member (NE k) (ConfigTree m) = OM.member k m
104+member (NECons k ks) (ConfigTree m) = maybe False (member ks . snd) $ OM.lookup k m
105+{-# INLINE member #-}
106+
107+null :: ConfigTree l v -> Bool
108+null (ConfigTree m) = OM.null m
109+{-# INLINE null #-}
110+
111+filter :: Ord k => (v -> Bool) -> ConfigTree k v -> ConfigTree k v
112+filter f (ConfigTree m) =
113+ ConfigTree $
114+ OM.filter (\_ (mv, ConfigTree m') -> isJust mv || not (OM.null m'))
115+ . fmap (\(mv, ct) -> (mv >>= (\v -> if f v then Just v else Nothing), filter f ct))
116+ $ m
117+{-# INLINE filter #-}
118+
119+instance Ord k => Semigroup (ConfigTree k v) where
120+ (ConfigTree lMap) <> (ConfigTree rMap) =
121+ ConfigTree $ OM.unionWithR (\_ (lvm, lm) (rvm, rm) -> (lvm <|> rvm, lm <> rm)) lMap rMap
122+ {-# INLINE (<>) #-}
123+
124+instance Ord k => Monoid (ConfigTree k v) where
125+ mempty = ConfigTree OM.empty
126+
127+instance (Searchable needle k, Searchable needle v) => Searchable needle (ConfigTree k v) where
128+ type
129+ SearchableConstraint needle (ConfigTree k v) res =
130+ (SearchableConstraint needle k res, SearchableConstraint needle v res, Ord (Searched k res))
131+ type Searched (ConfigTree k v) res = ConfigTree (Searched k res) (Searched v res)
132+ searchWith f (ConfigTree oMap) = do
133+ oMap' <- traverseOMap (searchWith f) (searchWith f) oMap
134+ pure $ ConfigTree oMap'
135+ {-# INLINE searchWith #-}
136+
137+deconstructConfigKey :: Text -> NonEmpty Text
138+deconstructConfigKey =
139+ fromMaybe (pure "") . NE.nonEmpty . L.filter (not . T.null) . fmap T.strip . T.splitOn "."
140+{-# INLINE deconstructConfigKey #-}
141+
142+reconstructConfigKey :: (IsString t, Monoid t) => NonEmpty t -> t
143+reconstructConfigKey = fold . NE.intersperse "."
144+{-# INLINE reconstructConfigKey #-}
145+
146+pattern NE :: a -> NonEmpty a
147+pattern NE x = x NE.:| []
148+pattern NECons :: a -> NonEmpty a -> NonEmpty a
149+pattern NECons x y <- (NE.uncons -> (x, Just y))
150+{-# COMPLETE NE, NECons #-}
151+
152+catMaybes :: Ord k => ConfigTree k (Maybe v) -> ConfigTree k v
153+catMaybes = fmap fromJust . filter isJust
154+{-# INLINE catMaybes #-}
155+
156+insert :: Ord k => NonEmpty k -> v -> ConfigTree k v -> ConfigTree k v
157+insert (NE k) v (ConfigTree m) = ConfigTree $ (k, (Just v, subCfg)) OM.<| m
158+ where
159+ subCfg = case OM.lookup k m of
160+ Nothing -> mempty
161+ Just (_, m') -> m'
162+insert (NECons k ks) v (ConfigTree m) = ConfigTree $ case OM.lookup k m of
163+ Nothing -> (k, (Nothing, singleton ks v)) OM.<| m
164+ Just (v', m') -> (k, (v', insert ks v m')) OM.<| m
165+{-# INLINE insert #-}
octopod-common/src/Data/Map/Ordered/Strict/Extra.hsdeleted−15
@@ -1,15 +0,0 @@
1−{-# OPTIONS_GHC -Wno-orphans #-}
2−
3−module Data.Map.Ordered.Strict.Extra
4− (
5− )
6−where
7−
8−import Data.Aeson
9−import Data.Map.Ordered.Strict
10−
11−instance (ToJSON k, ToJSON v) => ToJSON (OMap k v) where
12− toJSON = toJSON . assocs
13−
14−instance (FromJSON k, FromJSON v, Ord k) => FromJSON (OMap k v) where
15− parseJSON = fmap fromList . parseJSON
octopod-css/default.nix+2
@@ -1,10 +1,12 @@
11{ pkgsSrc ? (import ./.. { }).pkgsSrc
22, sources ? import ../nix/sources.nix
33, nix-filter ? import sources.nix-filter
4+, system ? builtins.currentSystem
45}:
56let
67 pkgs = pkgsSrc {
78 overlays = [ (self: super: { nodejs = self.nodejs-10_x; }) ];
9+ inherit system;
810 };
911 production-css = pkgs.mkYarnPackage {
1012 name = "octopod-css";
octopod-css/development/layouts/index.html+931−907
@@ -1,1008 +1,1032 @@
11<!DOCTYPE html>
22<html lang="en">
33
4−<head>
5− <meta charset="utf-8">
6− <meta http-equiv="x-ua-compatible" content="ie=edge">
7− <title>Index</title>
8− <meta name="viewport" content="width=device-width, initial-scale=1">
9− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
10− <link rel="stylesheet" href="../styles/style.css">
11−</head>
4+ <head>
5+ <meta charset="utf-8">
6+ <meta http-equiv="x-ua-compatible" content="ie=edge">
7+ <title>Index</title>
8+ <meta name="viewport" content="width=device-width, initial-scale=1">
9+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
10+ <link rel="stylesheet" href="../styles/style.css">
11+ </head>
1212
13−<body>
13+ <body>
1414
15− <!--[if IE]>
16− <div class="browserupgrade">
17− You are using an <strong>outdated</strong> browser.
18− Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
19− </div>
15+ <!--[if IE]>
16+ <div class="browserupgrade">
17+ You are using an <strong>outdated</strong> browser.
18+ Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
19+ </div>
2020 <![endif]-->
2121
22− <header class="header">
23− <div class="header__wrap container">
24− <b class="header__logo">
22+ <header class="header">
23+ <div class="header__wrap container">
24+ <b class="header__logo">
2525 Deployment Manager
2626 </b>
27− <div class="header__project">
28− Project name
29− </div>
30− </div>
31− </header>
27+ <div class="header__project">
28+ Project name
29+ </div>
30+ </div>
31+ </header>
3232
33− <div class="page">
34− <div class="page__wrap container">
35− <div class="page__output notification notification--danger">
36− <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
37− <button class="notification__close" type="button"></button>
38− </div>
39− <div class="page__head">
40− <h1 class="page__heading title">
41− All deployments
42− </h1>
43− <div class="page__note">
44− Updated 5 mins ago
45− </div>
46− <div class="page__action page__action--search input input--search input--has-clear-type">
47− <input class="input__widget" type="text" placeholder="Search for deployments">
48− <button class="input__clear-type spot spot--cancel">Delete</button>
49− </div>
50− <a class="page__action button button--add popup-handler" href="#deployment">
33+ <div class="page">
34+ <div class="page__wrap container">
35+ <div class="page__output notification notification--danger">
36+ <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
37+ <button class="notification__close" type="button"></button>
38+ </div>
39+ <div class="page__head">
40+ <h1 class="page__heading title">
41+ All deployments
42+ </h1>
43+ <div class="page__note">
44+ Updated 5 mins ago
45+ </div>
46+ <div class="page__action page__action--search input input--search input--has-clear-type">
47+ <input class="input__widget" type="text" placeholder="Search for deployments">
48+ <button class="input__clear-type spot spot--cancel">Delete</button>
49+ </div>
50+ <a class="page__action button button--add popup-handler" href="#deployment">
5151 New deployment
5252 </a>
53− </div>
54− <div class="page__body">
55− <div class="data">
56− <div class="data__primary">
57− <div class="table table--deployments table--clickable table--double-click">
58− <table>
59− <thead>
60− <tr>
61− <th>
62− <button class="sort" type="button">Name</button>
63− </th>
64− <th>
65− Links
66− </th>
67− <th>
68− App configuration
69− </th>
70− <th>
71− <button class="sort" type="button">Deployment configuration</button>
72− </th>
73− <th>
74− <button class="sort sort--active sort--asc" type="button">Created</button>
75− </th>
76− <th>
77− <button class="sort" type="button">Changed</button>
78− </th>
79− <th>
80− <span class="visuallyhidden">Menu</span>
81− </th>
82− </tr>
83− </thead>
84− <tbody>
85− <tr class="popup-handler" data-href="#deployment">
86− <td>
87− Feature name
88− <div class="status status--success">
89− Success
90− </div>
91− </td>
92− <td>
93− <div class="listing">
94− <a class="listing__item external bar" href="#">
95− <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
96− </a>
97− <a class="listing__item external bar" href="#">
98− <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
99− </a>
100− </div>
101− </td>
102− <td>
103− <div class="listing listing--for-text">
104− <div class="listing__item">
105− <span class="listing__key">ENVIRONMENT:</span>
106− <span class="listing__value">production</span>
107− </div>
108− <div class="listing__item">
109− <span class="listing__key">app_api_url:</span>
110− <span class="listing__value">http://my-api.my-domain.com</span>
111− </div>
112− <div class="listing__item">
113− <span class="listing__key default">SECRET_CODE:</span>
114− <span class="listing__value">asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen</span>
115− </div>
116− <div class="listing__item">
117− <span class="listing__key default">INFO:</span>
118− <span class="listing__value default">New Project Staging</span>
119− </div>
120− <button class="listing__more expander" type="button">
53+ </div>
54+ <div class="page__body">
55+ <div class="data">
56+ <div class="data__primary">
57+ <div class="table table--deployments table--clickable table--double-click">
58+ <table>
59+ <thead>
60+ <tr>
61+ <th>
62+ <button class="sort" type="button">Name</button>
63+ </th>
64+ <th>
65+ Links
66+ </th>
67+ <th>
68+ App configuration
69+ </th>
70+ <th>
71+ <button class="sort" type="button">Deployment configuration</button>
72+ </th>
73+ <th>
74+ <button class="sort sort--active sort--asc" type="button">Created</button>
75+ </th>
76+ <th>
77+ <button class="sort" type="button">Changed</button>
78+ </th>
79+ <th>
80+ <span class="visuallyhidden">Menu</span>
81+ </th>
82+ </tr>
83+ </thead>
84+ <tbody>
85+ <tr class="popup-handler" data-href="#deployment">
86+ <td>
87+ Feature name
88+ <div class="status status--success">
89+ Success
90+ </div>
91+ </td>
92+ <td>
93+ <div class="listing">
94+ <a class="listing__item external bar" href="#">
95+ <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
96+ </a>
97+ <a class="listing__item external bar" href="#">
98+ <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
99+ </a>
100+ </div>
101+ </td>
102+ <td>
103+ <div class="listing listing--for-text">
104+ <div class="listing__item">
105+ <span class="listing__key">ENVIRONMENT:</span>
106+ <span class="listing__value">production</span>
107+ </div>
108+ <div class="listing__item">
109+ <span class="listing__key">app_api_url:</span>
110+ <span class="listing__value">http://my-api.my-domain.com</span>
111+ </div>
112+ <div class="listing__item">
113+ <span class="listing__key default">SECRET_CODE:</span>
114+ <span class="listing__value">asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen</span>
115+ </div>
116+ <div class="listing__item">
117+ <span class="listing__key default">INFO:</span>
118+ <span class="listing__value default">New Project Staging</span>
119+ </div>
120+ <button class="listing__more expander" type="button">
121121 Show all (5)
122122 </button>
123− </div>
124− </td>
125− <td>
126− <div class="listing listing--for-text">
127− <div class="listing__item">
128− <b>ENVIRONENT:</b> production
129− </div>
130− <div class="listing__item">
131− <b>app_api_url:</b> http://my-api.my-domain.com
132− </div>
133− <div class="listing__item">
134− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
135− </div>
136− <button class="listing__more expander" type="button">
123+ </div>
124+ </td>
125+ <td>
126+ <div class="listing listing--for-text">
127+ <div class="listing__item">
128+ <b>ENVIRONENT:</b> production
129+ </div>
130+ <div class="listing__item">
131+ <b>app_api_url:</b> http://my-api.my-domain.com
132+ </div>
133+ <div class="listing__item">
134+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
135+ </div>
136+ <button class="listing__more expander" type="button">
137137 Show all (5)
138138 </button>
139− </div>
140− </td>
141− <td>
142− 15.05.2020
143− </td>
144− <td>
145− 01.06.2020
146− </td>
147− <td>
148− <div class="drop drop--actions">
149− <button class="drop__handler" type="button">
139+ </div>
140+ </td>
141+ <td>
142+ 15.05.2020
143+ </td>
144+ <td>
145+ 01.06.2020
146+ </td>
147+ <td>
148+ <div class="drop drop--actions">
149+ <button class="drop__handler" type="button">
150150 Actions
151151 </button>
152− <div class="drop__dropdown">
153− <button class="action action--edit" type="button">
152+ <div class="drop__dropdown">
153+ <button class="action action--edit" type="button">
154154 Edit
155155 </button>
156− <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
156+ <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
157157 Move to archive
158158 </button>
159− </div>
160− </div>
161− </td>
162− </tr>
163− <tr class="popup-handler" data-href="#deployment">
164− <td>
165− Feature name
166− <div class="loading loading--status-alike">
167− Loading...
168− </div>
169− </td>
170− <td>
171− <div class="listing">
172− <a class="listing__item external bar" href="#">
173− <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
174− </a>
175− <a class="listing__item external bar" href="#">
176− <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
177− </a>
178− </div>
179− </td>
180− <td>
181− <div class="listing listing--for-text">
182− <div class="listing__item">
183− <b>ENVIRONENT:</b> production
184− </div>
185− <div class="listing__item">
186− <b>app_api_url:</b> http://my-api.my-domain.com
187− </div>
188− <div class="listing__item">
189− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
190− </div>
191− </div>
192− </td>
193− <td>
194− <div class="listing listing--for-text">
195− <div class="listing__item">
196− <b>ENVIRONENT:</b> production
197− </div>
198− <div class="listing__item">
199− <b>app_api_url:</b> http://my-api.my-domain.com
200− </div>
201− <div class="listing__item">
202− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
203− </div>
204− </div>
205− </td>
206− <td>
207− 15.05.2020
208− </td>
209− <td>
210− 01.06.2020
211− </td>
212− <td>
213− <div class="drop drop--actions">
214− <button class="drop__handler" type="button">
159+ </div>
160+ </div>
161+ </td>
162+ </tr>
163+ <tr class="popup-handler" data-href="#deployment">
164+ <td>
165+ Feature name
166+ <div class="loading loading--status-alike">
167+ Loading...
168+ </div>
169+ </td>
170+ <td>
171+ <div class="listing">
172+ <a class="listing__item external bar" href="#">
173+ <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
174+ </a>
175+ <a class="listing__item external bar" href="#">
176+ <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
177+ </a>
178+ </div>
179+ </td>
180+ <td>
181+ <div class="listing listing--for-text">
182+ <div class="listing__item">
183+ <b>ENVIRONENT:</b> production
184+ </div>
185+ <div class="listing__item">
186+ <b>app_api_url:</b> http://my-api.my-domain.com
187+ </div>
188+ <div class="listing__item">
189+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
190+ </div>
191+ </div>
192+ </td>
193+ <td>
194+ <div class="listing listing--for-text">
195+ <div class="listing__item">
196+ <b>ENVIRONENT:</b> production
197+ </div>
198+ <div class="listing__item">
199+ <b>app_api_url:</b> http://my-api.my-domain.com
200+ </div>
201+ <div class="listing__item">
202+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
203+ </div>
204+ </div>
205+ </td>
206+ <td>
207+ 15.05.2020
208+ </td>
209+ <td>
210+ 01.06.2020
211+ </td>
212+ <td>
213+ <div class="drop drop--actions">
214+ <button class="drop__handler" type="button">
215215 Actions
216216 </button>
217− <div class="drop__dropdown">
218− <button class="action action--edit" type="button">
217+ <div class="drop__dropdown">
218+ <button class="action action--edit" type="button">
219219 Edit
220220 </button>
221− <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
221+ <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
222222 Move to archive
223223 </button>
224− </div>
225− </div>
226− </td>
227− </tr>
228− <tr class="popup-handler" data-href="#deployment">
229− <td>
230− Feature name
231− <div class="status status--pending">
232− Pending
233− </div>
234− </td>
235− <td>
236− <div class="listing">
237− <a class="listing__item external bar" href="#">
238− <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
239− </a>
240− <a class="listing__item external bar" href="#">
241− <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
242− </a>
243− </div>
244− </td>
245− <td>
246− <div class="listing listing--for-text">
247− <div class="listing__item">
248− <b>ENVIRONENT:</b> production
249− </div>
250− <div class="listing__item">
251− <b>app_api_url:</b> http://my-api.my-domain.com
252− </div>
253− <div class="listing__item">
254− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
255− </div>
256− </div>
257− </td>
258− <td>
259− <div class="listing listing--for-text">
260− <div class="listing__item">
261− <b>ENVIRONENT:</b> production
262− </div>
263− <div class="listing__item">
264− <b>app_api_url:</b> http://my-api.my-domain.com
265− </div>
266− <div class="listing__item">
267− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
268− </div>
269− <button class="listing__more expander" type="button">
224+ </div>
225+ </div>
226+ </td>
227+ </tr>
228+ <tr class="popup-handler" data-href="#deployment">
229+ <td>
230+ Feature name
231+ <div class="status status--pending">
232+ Pending
233+ </div>
234+ </td>
235+ <td>
236+ <div class="listing">
237+ <a class="listing__item external bar" href="#">
238+ <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
239+ </a>
240+ <a class="listing__item external bar" href="#">
241+ <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
242+ </a>
243+ </div>
244+ </td>
245+ <td>
246+ <div class="listing listing--for-text">
247+ <div class="listing__item">
248+ <b>ENVIRONENT:</b> production
249+ </div>
250+ <div class="listing__item">
251+ <b>app_api_url:</b> http://my-api.my-domain.com
252+ </div>
253+ <div class="listing__item">
254+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
255+ </div>
256+ </div>
257+ </td>
258+ <td>
259+ <div class="listing listing--for-text">
260+ <div class="listing__item">
261+ <b>ENVIRONENT:</b> production
262+ </div>
263+ <div class="listing__item">
264+ <b>app_api_url:</b> http://my-api.my-domain.com
265+ </div>
266+ <div class="listing__item">
267+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
268+ </div>
269+ <button class="listing__more expander" type="button">
270270 Show all (5)
271271 </button>
272− </div>
273− </td>
274− <td>
275− 15.05.2020
276− </td>
277− <td>
278− 01.06.2020
279− </td>
280− <td>
281− <div class="drop drop--actions">
282− <button class="drop__handler" type="button">
272+ </div>
273+ </td>
274+ <td>
275+ 15.05.2020
276+ </td>
277+ <td>
278+ 01.06.2020
279+ </td>
280+ <td>
281+ <div class="drop drop--actions">
282+ <button class="drop__handler" type="button">
283283 Actions
284284 </button>
285− <div class="drop__dropdown">
286− <button class="action action--edit" type="button">
285+ <div class="drop__dropdown">
286+ <button class="action action--edit" type="button">
287287 Edit
288288 </button>
289− <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
289+ <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
290290 Move to archive
291291 </button>
292− </div>
293− </div>
294− </td>
295− </tr>
296− <tr class="popup-handler" data-href="#deployment">
297− <td>
298− Feature name
299− <div class="status status--failure">
300− Failure
301− </div>
302− </td>
303− <td>
304− <div class="listing">
305− <a class="listing__item external bar" href="#">
306− <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
307− </a>
308− <a class="listing__item external bar" href="#">
309− <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
310− </a>
311− </div>
312− </td>
313− <td>
314− <div class="listing listing--for-text">
315− <div class="listing__item">
316− <b>ENVIRONENT:</b> production
317− </div>
318− <div class="listing__item">
319− <b>app_api_url:</b> http://my-api.my-domain.com
320− </div>
321− <div class="listing__item">
322− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
323− </div>
324− </div>
325− </td>
326− <td>
327− <div class="listing listing--for-text">
328− <div class="listing__item">
329− <b>ENVIRONENT:</b> production
330− </div>
331− <div class="listing__item">
332− <b>app_api_url:</b> http://my-api.my-domain.com
333− </div>
334− <div class="listing__item">
335− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
336− </div>
337− </div>
338− </td>
339− <td>
340− 15.05.2020
341− </td>
342− <td>
343− 01.06.2020
344− </td>
345− <td>
346− <div class="drop drop--actions">
347− <button class="drop__handler" type="button">
292+ </div>
293+ </div>
294+ </td>
295+ </tr>
296+ <tr class="popup-handler" data-href="#deployment">
297+ <td>
298+ Feature name
299+ <div class="status status--failure">
300+ Failure
301+ </div>
302+ </td>
303+ <td>
304+ <div class="listing">
305+ <a class="listing__item external bar" href="#">
306+ <b>app</b>.feature-name.project.name.com lorem ipsume dolor sit amen
307+ </a>
308+ <a class="listing__item external bar" href="#">
309+ <b>admin</b>.feature-name.project.name.com lorem ipsume dolor sit amen
310+ </a>
311+ </div>
312+ </td>
313+ <td>
314+ <div class="listing listing--for-text">
315+ <div class="listing__item">
316+ <b>ENVIRONENT:</b> production
317+ </div>
318+ <div class="listing__item">
319+ <b>app_api_url:</b> http://my-api.my-domain.com
320+ </div>
321+ <div class="listing__item">
322+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
323+ </div>
324+ </div>
325+ </td>
326+ <td>
327+ <div class="listing listing--for-text">
328+ <div class="listing__item">
329+ <b>ENVIRONENT:</b> production
330+ </div>
331+ <div class="listing__item">
332+ <b>app_api_url:</b> http://my-api.my-domain.com
333+ </div>
334+ <div class="listing__item">
335+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
336+ </div>
337+ </div>
338+ </td>
339+ <td>
340+ 15.05.2020
341+ </td>
342+ <td>
343+ 01.06.2020
344+ </td>
345+ <td>
346+ <div class="drop drop--actions">
347+ <button class="drop__handler" type="button">
348348 Actions
349349 </button>
350− <div class="drop__dropdown">
351− <button class="action action--edit" type="button">
350+ <div class="drop__dropdown">
351+ <button class="action action--edit" type="button">
352352 Edit
353353 </button>
354− <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
354+ <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">
355355 Move to archive
356356 </button>
357+ </div>
358+ </div>
359+ </td>
360+ </tr>
361+ <tr class="no-table">
362+ <td colspan="8">
363+ <div class="null null--search">
364+ <b class="null__heading">No results found</b>
365+ <div class="null__message">It seems we can’t find any results
366+ <br>based on your search
367+ </div>
368+ </div>
369+ <!-- temp -->
370+ &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
371+ <!--/temp -->
372+ <div class="null null--data">
373+ <b class="null__heading">Cannot retrieve the data</b>
374+ <div class="null__message">Try to reload page</div>
375+ </div>
376+ <!-- temp -->
377+ &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
378+ <!--/temp -->
379+ <div class="loading loading--enlarged loading--alternate">
380+ Loading...
381+ </div>
382+ </td>
383+ </tr>
384+ </tbody>
385+ </table>
386+ </div>
357387 </div>
358− </div>
359− </td>
360− </tr>
361− <tr class="no-table">
362− <td colspan="8">
363− <div class="null null--search">
364− <b class="null__heading">No results found</b>
365− <div class="null__message">It seems we can’t find any results <br>based on your search</div>
366− </div>
367− <!-- temp -->
368− &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
369− <!--/temp -->
370− <div class="null null--data">
371− <b class="null__heading">Cannot retrieve the data</b>
372− <div class="null__message">Try to reload page</div>
373− </div>
374− <!-- temp -->
375− &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
376− <!--/temp -->
377− <div class="loading loading--enlarged loading--alternate">
378− Loading...
379− </div>
380− </td>
381− </tr>
382− </tbody>
383− </table>
384− </div>
385− </div>
386− <button class="data__show-archive expander expander--stand-alone" type="button">
388+ <button class="data__show-archive expander expander--stand-alone" type="button">
387389 Show Archived deployments (2)
388390 </button>
389− <div class="data__archive">
390− <div class="table table--clickable table--deployments">
391− <table>
392− <thead>
393− <tr class="popup-handler" data-href="#deployment">
394− <th>
395− Name
396− </th>
397− <th>
398− Links
399− </th>
400− <th>
401− Tag
402− </th>
403− <th>
404− App configuration
405− </th>
406− <th>
407− Deployment configuration
408− </th>
409− <th>
410− Created
411− </th>
412− <th>
413− Changed
414− </th>
415− <th>
416− <span class="visuallyhidden">Menu</span>
417− </th>
418− </tr>
419− </thead>
420− <tbody>
421− <tr class="popup-handler" data-href="#deployment">
422− <td>
423− Feature name
424− <div class="status status--archived">
425− Archived
426− </div>
427− </td>
428− <td>
429− ...
430− </td>
431− <td>
432− <div class="listing listing--for-text">
433− <div class="listing__item">
434− <b>ENVIRONENT:</b> production
435− </div>
436− <div class="listing__item">
437− <b>app_api_url:</b> http://my-api.my-domain.com
438− </div>
439− <div class="listing__item">
440− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
441− </div>
442− </div>
443− </td>
444− <td>
445− <div class="listing listing--for-text">
446− <div class="listing__item">
447− <b>ENVIRONENT:</b> production
448− </div>
449− <div class="listing__item">
450− <b>app_api_url:</b> http://my-api.my-domain.com
451− </div>
452− <div class="listing__item">
453− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
454− </div>
455− </div>
456− </td>
457− <td>
458− 15.05.2020
459− </td>
460− <td>
461− 01.06.2020
462− </td>
463− <td>
464− <div class="drop drop--actions">
465− <button class="drop__handler" type="button">
391+ <div class="data__archive">
392+ <div class="table table--clickable table--deployments">
393+ <table>
394+ <thead>
395+ <tr class="popup-handler" data-href="#deployment">
396+ <th>
397+ Name
398+ </th>
399+ <th>
400+ Links
401+ </th>
402+ <th>
403+ Tag
404+ </th>
405+ <th>
406+ App configuration
407+ </th>
408+ <th>
409+ Deployment configuration
410+ </th>
411+ <th>
412+ Created
413+ </th>
414+ <th>
415+ Changed
416+ </th>
417+ <th>
418+ <span class="visuallyhidden">Menu</span>
419+ </th>
420+ </tr>
421+ </thead>
422+ <tbody>
423+ <tr class="popup-handler" data-href="#deployment">
424+ <td>
425+ Feature name
426+ <div class="status status--archived">
427+ Archived
428+ </div>
429+ </td>
430+ <td>
431+ ...
432+ </td>
433+ <td>
434+ <div class="listing listing--for-text">
435+ <div class="listing__item">
436+ <b>ENVIRONENT:</b> production
437+ </div>
438+ <div class="listing__item">
439+ <b>app_api_url:</b> http://my-api.my-domain.com
440+ </div>
441+ <div class="listing__item">
442+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
443+ </div>
444+ </div>
445+ </td>
446+ <td>
447+ <div class="listing listing--for-text">
448+ <div class="listing__item">
449+ <b>ENVIRONENT:</b> production
450+ </div>
451+ <div class="listing__item">
452+ <b>app_api_url:</b> http://my-api.my-domain.com
453+ </div>
454+ <div class="listing__item">
455+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
456+ </div>
457+ </div>
458+ </td>
459+ <td>
460+ 15.05.2020
461+ </td>
462+ <td>
463+ 01.06.2020
464+ </td>
465+ <td>
466+ <div class="drop drop--actions">
467+ <button class="drop__handler" type="button">
466468 Actions
467469 </button>
468− <div class="drop__dropdown">
469− <button class="action action--restore" type="button">
470+ <div class="drop__dropdown">
471+ <button class="action action--restore" type="button">
470472 Restore from archive
471473 </button>
472− </div>
473− </div>
474− </td>
475− </tr>
476− <tr>
477− <td>
478− Feature name
479− <div class="status status--archived">
480− Archived
481− </div>
482− </td>
483− <td>
484− ...
485− </td>
486− <td>
487− <div class="listing listing--for-text">
488− <div class="listing__item">
489− <span class="listing__key">
474+ </div>
475+ </div>
476+ </td>
477+ </tr>
478+ <tr>
479+ <td>
480+ Feature name
481+ <div class="status status--archived">
482+ Archived
483+ </div>
484+ </td>
485+ <td>
486+ ...
487+ </td>
488+ <td>
489+ <div class="listing listing--for-text">
490+ <div class="listing__item">
491+ <span class="listing__key">
490492 ENVIRONMENT:
491493 </span>
492− <span class="listing__value">
494+ <span class="listing__value">
493495 production
494496 </span>
495− </div>
496− <div class="listing__item">
497− <span class="listing__key">
497+ </div>
498+ <div class="listing__item">
499+ <span class="listing__key">
498500 app_api_url:
499501 </span>
500− <span class="listing__value">
502+ <span class="listing__value">
501503 http://my-api.my-domain.com
502504 </span>
503− </div>
504− <div class="listing__item">
505− <span class="listing__key item-default">
505+ </div>
506+ <div class="listing__item">
507+ <span class="listing__key item-default">
506508 SECRET_CODE:
507509 </span>
508− <span class="listing__value item-default">
510+ <span class="listing__value item-default">
509511 asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
510512 </span>
511− </div>
512− </div>
513− </td>
514− <td>
515− <div class="listing listing--for-text">
516− <div class="listing__item">
517− <b>ENVIRONENT:</b> production
518− </div>
519− <div class="listing__item">
520− <b>app_api_url:</b> http://my-api.my-domain.com
521− </div>
522− <div class="listing__item">
523− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
524− </div>
525− </div>
526− </td>
527− <td>
528− 15.05.2020
529− </td>
530− <td>
531− 01.06.2020
532− </td>
533− <td>
534− <div class="drop drop--actions">
535− <button class="drop__handler" type="button">
513+ </div>
514+ </div>
515+ </td>
516+ <td>
517+ <div class="listing listing--for-text">
518+ <div class="listing__item">
519+ <b>ENVIRONENT:</b> production
520+ </div>
521+ <div class="listing__item">
522+ <b>app_api_url:</b> http://my-api.my-domain.com
523+ </div>
524+ <div class="listing__item">
525+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
526+ </div>
527+ </div>
528+ </td>
529+ <td>
530+ 15.05.2020
531+ </td>
532+ <td>
533+ 01.06.2020
534+ </td>
535+ <td>
536+ <div class="drop drop--actions">
537+ <button class="drop__handler" type="button">
536538 Actions
537539 </button>
538− <div class="drop__dropdown">
539− <button class="action action--restore" type="button">
540+ <div class="drop__dropdown">
541+ <button class="action action--restore" type="button">
540542 Restore from archive
541543 </button>
542− </div>
543− </div>
544− </td>
545− </tr>
546− </tbody>
547− </table>
548− </div>
549− </div>
550− </div>
551− <!-- или:
552− <div class="no-data">
553− <div class="null null--data">
554− <b class="null__heading">Cannot retrieve the data</b>
555− <div class="null__message">Try to reload page</div>
556− </div>
557− <div class="loading loading--enlarged loading--alternate">
558− Loading...
544+ </div>
545+ </div>
546+ </td>
547+ </tr>
548+ </tbody>
549+ </table>
550+ </div>
559551 </div>
560552 </div>
561− -->
562− </div>
563− </div>
564− </div>
565−
566− <!-- или:
567− <div class="no-page">
568− <div class="no-page__inner">
569− <div class="null null--data">
570− <b class="null__heading">Cannot retrieve the data</b>
571− <div class="null__message">Try to reload page</div>
572− </div>
573− или:
574− <div class="loading loading--enlarged loading--alternate">
575− Loading...
553+ <!-- или:
554+ <div class="no-data">
555+ <div class="null null--data">
556+ <b class="null__heading">Cannot retrieve the data</b>
557+ <div class="null__message">Try to reload page</div>
558+ </div>
559+ <div class="loading loading--enlarged loading--alternate">
560+ Loading...
561+ </div>
562+ </div>
563+ -->
576564 </div>
577565 </div>
578566 </div>
579− -->
580567
581− <div class="popup" id="deployment">
582− <div class="popup__overlay" aria-hidden="true">
583− Close popup
584− </div>
585− <div class="popup__body">
586− <div class="popup__head">
587− <button class="popup__close" type="button">
568+ <!-- или:
569+ <div class="no-page">
570+ <div class="no-page__inner">
571+ <div class="null null--data">
572+ <b class="null__heading">Cannot retrieve the data</b>
573+ <div class="null__message">Try to reload page</div>
574+ </div>
575+ или:
576+ <div class="loading loading--enlarged loading--alternate">
577+ Loading...
578+ </div>
579+ </div>
580+ </div>
581+ -->
582+
583+ <div class="popup" id="deployment">
584+ <div class="popup__overlay" aria-hidden="true">
585+ Close popup
586+ </div>
587+ <div class="popup__body">
588+ <div class="popup__head">
589+ <button class="popup__close" type="button">
588590 Close popup
589591 </button>
590− <h2 class="popup__project">
591− Project name
592− </h2>
593− <div class="popup__operations">
594− <button class="popup__action button button--save" type="button">Save</button>
595− <button class="popup__action button button--save-loading" type="button" disabled>Save</button>
596− <button class="popup__action button button--secondary" type="button">Cancel</button>
597− </div>
598− <div class="popup__menu drop drop--actions">
599− <button class="drop__handler" type="button">
592+ <h2 class="popup__project">
593+ Project name
594+ </h2>
595+ <div class="popup__operations">
596+ <button class="popup__action button button--save" type="button">Save</button>
597+ <button class="popup__action button button--save-loading" type="button" disabled>Save</button>
598+ <button class="popup__action button button--secondary" type="button">Cancel</button>
599+ </div>
600+ <div class="popup__menu drop drop--actions">
601+ <button class="drop__handler" type="button">
600602 Actions
601603 </button>
602− <div class="drop__dropdown">
603− <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">Move to archive</button>
604− <button class="action action--restore classic-popup-handler" type="button" data-href="#dialog">Restore from archive</button>
605− </div>
606− </div>
607− </div>
608− <div class="popup__content">
604+ <div class="drop__dropdown">
605+ <button class="action action--archive classic-popup-handler" type="button" data-href="#dialog">Move to archive</button>
606+ <button class="action action--restore classic-popup-handler" type="button" data-href="#dialog">Restore from archive</button>
607+ </div>
608+ </div>
609+ </div>
610+ <div class="popup__content">
609611
610− <div class="deployment">
611− <div class="deployment__output notification notification--danger">
612− <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
613− <button class="notification__close" type="button"></button>
614− </div>
615− <section class="deployment__section">
616− <h3 class="deployment__sub-heading">
617− Name
618− </h3>
619− <div class="deployment__widget">
620− <div class="tag input">
621− <input class="input__widget" type="text" placeholder="Project name">
622− </div>
623− </div>
624− </section>
625− <section class="deployment__section">
626− <h3 class="deployment__sub-heading">
627− Tag
628− </h3>
629− <div class="deployment__widget">
630− <div class="tag input">
631− <input class="input__widget" type="text" placeholder="key" value="fa3a5bd4cc1134ae259c34d4cf530be0f0996a0b ">
632− </div>
633− </div>
634− </section>
635− <section class="deployment__section">
636− <h3 class="deployment__sub-heading">
637− App configuration
638− </h3>
639− <div class="deployment__widget">
640− <div class="overrides">
641− <button class="overrides__add dash dash--add" type="button">
612+ <div class="deployment">
613+ <div class="deployment__output notification notification--danger">
614+ <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
615+ <button class="notification__close" type="button"></button>
616+ </div>
617+ <section class="deployment__section">
618+ <h3 class="deployment__sub-heading">
619+ Name
620+ </h3>
621+ <div class="deployment__widget">
622+ <div class="tag input">
623+ <input class="input__widget" type="text" placeholder="Project name">
624+ </div>
625+ </div>
626+ </section>
627+ <section class="deployment__section">
628+ <h3 class="deployment__sub-heading">
629+ Tag
630+ </h3>
631+ <div class="deployment__widget">
632+ <div class="tag input">
633+ <input class="input__widget" type="text" placeholder="key" value="fa3a5bd4cc1134ae259c34d4cf530be0f0996a0b ">
634+ </div>
635+ </div>
636+ </section>
637+ <section class="deployment__section">
638+ <h3 class="deployment__sub-heading">
639+ App configuration
640+ </h3>
641+ <div class="deployment__widget">
642+ <div class="overrides">
643+ <button class="overrides__add dash dash--add" type="button">
642644 Add an override
643645 </button>
644− <div class="overrides__item">
645− <div class="overrides__key input">
646− <input class="input__widget" type="text" placeholder="key">
647− </div>
648− <div class="overrides__value input">
649− <input class="input__widget" type="text" placeholder="value">
650− </div>
651− <button class="overrides__delete spot spot--cancel">
652− Delete
653− </button>
654− </div>
655− <div class="overrides__item">
656− <div class="overrides__key input">
657− <input class="input__widget" type="text" placeholder="key" value="ENVIRONMENT">
658− </div>
659− <div class="overrides__value input">
660− <input class="input__widget" type="text" placeholder="value" value="production">
661− </div>
662− <button class="overrides__delete spot spot--cancel">
663− Delete
664− </button>
665− </div>
666− <div class="overrides__item">
667− <div class="overrides__key input">
668− <input class="input__widget" type="text" placeholder="key" value="app_api_url">
669− </div>
670− <div class="overrides__value input">
671− <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com">
672− </div>
673− <button class="overrides__delete spot spot--cancel">
674− Delete
675− </button>
676− </div>
677− <div class="overrides__item">
678− <div class="overrides__key input input--default">
679− <input class="input__widget" type="text" placeholder="key" value="SECRET_CODE">
680− </div>
681− <div class="overrides__value input input--default">
682− <input class="input__widget" type="text" placeholder="value" value="production">
683− </div>
684− <button class="overrides__delete spot spot--cancel">
685− Delete
686− </button>
687− </div>
688− <div class="overrides__item">
689− <div class="overrides__key input input--deleted">
690− <input class="input__widget" type="text" placeholder="key" value="APP_URL" disabled>
691− </div>
692− <div class="overrides__value input input--deleted">
693− <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com" disabled>
694− </div>
695− <button class="overrides__delete spot spot--undo">
696− Delete
697− </button>
698− </div>
699− <div class="overrides__item">
700− <div class="overrides__key input input--disable">
701− <input class="input__widget" type="text" placeholder="key" disabled>
702− </div>
703− <div class="overrides__value input input--disable">
704− <input class="input__widget" type="text" placeholder="value" value="production" disabled>
705− </div>
706− </div>
707− <div class="overrides__item">
708− <div class="overrides__key input">
709− <input class="input__widget" type="text" placeholder="key" value="LiveSearch">
710− <ul class="overrides__search">
711− <li class="overrides__search-item"><b>S</b>ECRET_PASSWORD</li>
712− <li class="overrides__search-item"><b>S</b>ECRET_INFO</li>
713− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
714− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
715− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
716− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
717− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
718− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
719− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
720− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
721− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
722− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
723− <li class="overrides__search-item"><b>S</b>oviet Socialist Republics</li>
724− </ul>
725− </div>
726− <div class="overrides__value input">
727− <input class="input__widget" type="text" placeholder="value" value="Value">
728− </div>
729− <button class="overrides__delete spot spot--cancel">
730− Delete
731− </button>
732− </div>
733− </div>
734− </div>
735− </section>
736− <section class="deployment__section">
737− <h3 class="deployment__sub-heading">
738− Deployment configuration
739− </h3>
740− <div class="deployment__widget">
741− <div class="overrides">
742− <button class="overrides__add dash dash--add" type="button">
646+ <div class="overrides__list">
647+ <div class="editable-row">
648+ <div class="editable-row__key input">
649+ <input class="input__widget" type="text" placeholder="key">
650+ </div>
651+ <div class="editable-row__value input">
652+ <input class="input__widget" type="text" placeholder="value">
653+ </div>
654+ <button class="editable-row__delete spot spot--cancel">
655+ Delete
656+ </button>
657+ </div>
658+ <div class="editable-row">
659+ <div class="editable-row__key input">
660+ <input class="input__widget" type="text" placeholder="key" value="ENVIRONMENT">
661+ </div>
662+ <div class="editable-row__value input">
663+ <input class="input__widget" type="text" placeholder="value" value="production">
664+ </div>
665+ <button class="editable-row__delete spot spot--cancel">
666+ Delete
667+ </button>
668+ </div>
669+ <div class="editable-row">
670+ <div class="editable-row__key input">
671+ <input class="input__widget" type="text" placeholder="key" value="app_api_url">
672+ </div>
673+ <div class="editable-row__value input">
674+ <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com">
675+ </div>
676+ <button class="editable-row__delete spot spot--cancel">
677+ Delete
678+ </button>
679+ </div>
680+ <div class="editable-row">
681+ <div class="editable-row__key input input--default">
682+ <input class="input__widget" type="text" placeholder="key" value="SECRET_CODE">
683+ </div>
684+ <div class="editable-row__value input input--default">
685+ <input class="input__widget" type="text" placeholder="value" value="production">
686+ </div>
687+ <button class="editable-row__delete spot spot--cancel">
688+ Delete
689+ </button>
690+ </div>
691+ <div class="editable-row">
692+ <div class="editable-row__key input input--deleted">
693+ <input class="input__widget" type="text" placeholder="key" value="APP_URL" disabled>
694+ </div>
695+ <div class="editable-row__value input input--deleted">
696+ <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com" disabled>
697+ </div>
698+ <button class="editable-row__delete spot spot--undo">
699+ Delete
700+ </button>
701+ </div>
702+ <div class="editable-row">
703+ <div class="editable-row__key input input--disable">
704+ <input class="input__widget" type="text" placeholder="key" disabled>
705+ </div>
706+ <div class="editable-row__value input input--disable">
707+ <input class="input__widget" type="text" placeholder="value" value="production" disabled>
708+ </div>
709+ </div>
710+ <div class="editable-row">
711+ <div class="editable-row__key input">
712+ <input class="input__widget" type="text" placeholder="key" value="LiveSearch">
713+ <ul class="input__dropdown">
714+ <li class="input__suggest"><b>S</b>ECRET_PASSWORD</li>
715+ <li class="input__suggest"><b>S</b>ECRET_INFO</li>
716+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
717+ </li>
718+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
719+ </li>
720+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
721+ </li>
722+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
723+ </li>
724+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
725+ </li>
726+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
727+ </li>
728+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
729+ </li>
730+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
731+ </li>
732+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
733+ </li>
734+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
735+ </li>
736+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
737+ </li>
738+ </ul>
739+ </div>
740+ <div class="editable-row__value input">
741+ <input class="input__widget" type="text" placeholder="value" value="Value">
742+ </div>
743+ <button class="editable-row__delete spot spot--cancel">
744+ Delete
745+ </button>
746+ </div>
747+ </div>
748+ </div>
749+ </div>
750+ </section>
751+ <section class="deployment__section">
752+ <h3 class="deployment__sub-heading">
753+ Deployment configuration
754+ </h3>
755+ <div class="deployment__widget">
756+ <div class="overrides">
757+ <button class="overrides__add dash dash--add" type="button">
743758 Add an override
744759 </button>
745− <div class="overrides__item">
746− <div class="overrides__key input">
747− <input class="input__widget" type="text" placeholder="key">
748− </div>
749− <div class="overrides__value input">
750− <input class="input__widget" type="text" placeholder="value">
751− </div>
752− <button class="overrides__delete spot spot--cancel">
753− Delete
754− </button>
755− </div>
756− <div class="overrides__item">
757− <div class="overrides__key input">
758− <input class="input__widget" type="text" placeholder="key" value="ENVIRONENT">
759− </div>
760− <div class="overrides__value input">
761− <input class="input__widget" type="text" placeholder="value" value="production">
762− </div>
763− <button class="overrides__delete spot spot--cancel">
764− Delete
765− </button>
766− </div>
767− <div class="overrides__item">
768− <div class="overrides__key input">
769− <input class="input__widget" type="text" placeholder="key" value="app_api_url">
770− </div>
771− <div class="overrides__value input">
772− <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com">
773− </div>
774− <button class="overrides__delete spot spot--cancel">
775− Delete
776− </button>
777− </div>
778− <div class="overrides__item">
779− <div class="overrides__key input">
780− <input class="input__widget input--default" type="text" placeholder="key" value="SECRET_CODE">
781− </div>
782− <div class="overrides__value input">
783− <input class="input__widget" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
784− </div>
785− <button class="overrides__delete spot spot--cancel">
786− Delete
787− </button>
788− </div>
789− <div class="overrides__item loader">
790− <div class="overrides__placeholder"></div>
791− <div class="overrides__placeholder"></div>
792− <div class="overrides__delete spot spot--loader"></div>
793− </div>
794− <div class="overrides__item loader">
795− <div class="overrides__placeholder"></div>
796− <div class="overrides__placeholder"></div>
797− <div class="overrides__delete spot spot--loader"></div>
798− </div>
799− <div class="overrides__item loader">
800− <div class="overrides__placeholder"></div>
801− <div class="overrides__placeholder"></div>
802− <div class="overrides__delete spot spot--loader"></div>
803− </div>
804− <div class="overrides__item">
805− <div class="overrides__key input input--error">
806− <input class="input__widget input--default" type="text" placeholder="key" value="SECRET_CODE">
807− <div class="input__output">Duplicate key values</div>
808− </div>
809− <div class="overrides__value input">
810− <input class="input__widget" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
811− </div>
812− <button class="overrides__delete spot spot--cancel">
813− Delete
814− </button>
815− </div>
816− <div class="overrides__item">
817− <div class="overrides__key input input--error">
818− <input class="input__widget" type="text" placeholder="key" value="ENVIRONMENT">
819− <div class="input__output">Duplicate key values</div>
820− </div>
821− <div class="overrides__value input">
822− <input class="input__widget" type="text" placeholder="value" value="production">
823− </div>
824− <button class="overrides__delete spot spot--cancel">
825− Delete
826− </button>
827− </div>
828− <div class="overrides__item">
829− <div class="overrides__key input input--error">
830− <input class="input__widget" type="text" placeholder="key" value="">
831− <div class="input__output">Empty key value</div>
832− </div>
833− <div class="overrides__value input">
834− <input class="input__widget" type="text" placeholder="value" value="production">
835− </div>
836− <button class="overrides__delete spot spot--cancel">
837− Delete
838− </button>
760+ <div class="overrides__list">
761+ <div class="editable-row">
762+ <div class="editable-row__key input">
763+ <input class="input__widget" type="text" placeholder="key">
764+ </div>
765+ <div class="editable-row__value input">
766+ <input class="input__widget" type="text" placeholder="value">
767+ </div>
768+ <button class="editable-row__delete spot spot--cancel">
769+ Delete
770+ </button>
771+ </div>
772+ <div class="editable-row">
773+ <div class="editable-row__key input">
774+ <input class="input__widget" type="text" placeholder="key" value="ENVIRONENT">
775+ </div>
776+ <div class="editable-row__value input">
777+ <input class="input__widget" type="text" placeholder="value" value="production">
778+ </div>
779+ <button class="editable-row__delete spot spot--cancel">
780+ Delete
781+ </button>
782+ </div>
783+ <div class="editable-row">
784+ <div class="editable-row__key input">
785+ <input class="input__widget" type="text" placeholder="key" value="app_api_url">
786+ </div>
787+ <div class="editable-row__value input">
788+ <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com">
789+ </div>
790+ <button class="editable-row__delete spot spot--cancel">
791+ Delete
792+ </button>
793+ </div>
794+ <div class="editable-row">
795+ <div class="editable-row__key input">
796+ <input class="input__widget input--default" type="text" placeholder="key" value="SECRET_CODE">
797+ </div>
798+ <div class="editable-row__value input">
799+ <input class="input__widget" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
800+ </div>
801+ <button class="editable-row__delete spot spot--cancel">
802+ Delete
803+ </button>
804+ </div>
805+ <div class="editable-row loader">
806+ <div class="editable-row__placeholder"></div>
807+ <div class="editable-row__placeholder"></div>
808+ <div class="editable-row__delete spot spot--loader"></div>
809+ </div>
810+ <div class="editable-row loader">
811+ <div class="editable-row__placeholder"></div>
812+ <div class="editable-row__placeholder"></div>
813+ <div class="editable-row__delete spot spot--loader"></div>
814+ </div>
815+ <div class="editable-row loader">
816+ <div class="editable-row__placeholder"></div>
817+ <div class="editable-row__placeholder"></div>
818+ <div class="editable-row__delete spot spot--loader"></div>
819+ </div>
820+ <div class="editable-row">
821+ <div class="editable-row__key input input--error">
822+ <input class="input__widget input--default" type="text" placeholder="key" value="SECRET_CODE">
823+ <div class="input__output">Duplicate key values</div>
824+ </div>
825+ <div class="editable-row__value input">
826+ <input class="input__widget" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
827+ </div>
828+ <button class="editable-row__delete spot spot--cancel">
829+ Delete
830+ </button>
831+ </div>
832+ <div class="editable-row">
833+ <div class="editable-row__key input input--error">
834+ <input class="input__widget" type="text" placeholder="key" value="ENVIRONMENT">
835+ <div class="input__output">Duplicate key values</div>
836+ </div>
837+ <div class="editable-row__value input">
838+ <input class="input__widget" type="text" placeholder="value" value="production">
839+ </div>
840+ <button class="editable-row__delete spot spot--cancel">
841+ Delete
842+ </button>
843+ </div>
844+ <div class="editable-row">
845+ <div class="editable-row__key input input--error">
846+ <input class="input__widget" type="text" placeholder="key" value="">
847+ <div class="input__output">Empty key value</div>
848+ </div>
849+ <div class="editable-row__value input">
850+ <input class="input__widget" type="text" placeholder="value" value="production">
851+ </div>
852+ <button class="editable-row__delete spot spot--cancel">
853+ Delete
854+ </button>
855+ </div>
856+ </div>
857+ </div>
858+ </div>
859+ </section>
860+ </div>
861+ <!-- temp -->
862+ или:
863+ <!--/temp -->
864+ <div class="no-deployment">
865+ <div class="null null--data">
866+ <div class="null__content">
867+ <b class="null__heading">Cannot retrieve the data</b>
868+ <div class="null__message">Try to reload page</div>
869+ </div>
870+ </div>
871+ <!-- temp -->
872+ &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
873+ <!--/temp -->
874+ <div class="loading loading--enlarged loading--alternate">
875+ Loading...
876+ </div>
877+ </div>
839878 </div>
840− </div>
841879 </div>
842− </section>
843880 </div>
844− <!-- temp -->
845− или:
846− <!--/temp -->
847− <div class="no-deployment">
848− <div class="null null--data">
849− <div class="null__content">
850− <b class="null__heading">Cannot retrieve the data</b>
851− <div class="null__message">Try to reload page</div>
852− </div>
853− </div>
854− <!-- temp -->
855− &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
856− <!--/temp -->
857− <div class="loading loading--enlarged loading--alternate">
858− Loading...
859− </div>
860− </div>
861− </div>
862− </div>
863− </div>
864881
865882
866− <div class="popup" id="log">
867− <div class="popup__overlay" aria-hidden="true">
868− Close popup
869− </div>
870− <div class="popup__body">
871− <div class="popup__head">
872− <button class="popup__close" type="button">
883+ <div class="popup" id="log">
884+ <div class="popup__overlay" aria-hidden="true">
885+ Close popup
886+ </div>
887+ <div class="popup__body">
888+ <div class="popup__head">
889+ <button class="popup__close" type="button">
873890 Close popup
874891 </button>
875− <h2 class="popup__project">
876− Project name, logs
877− </h2>
878− </div>
879− <div class="popup__sub-head">
880− <div class="nav">
881− <button class="nav__link nav__link--current" type="button">stdout</button>
882− <button class="nav__link" type="button">stderr</button>
883− </div>
884− </div>
885− <div class="popup__content">
886− <div class="log">
887− DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/libiserv/dist-install/build:/Users/dr/workspace/ghc/libraries/ghci/dist-install/build:/Users/dr/workspace/ghc/libraries/transformers/dist-install/build:/Users/dr/workspace/ghc/libraries/template-haskell/dist-install/build:/Users/dr/workspace/ghc/libraries/pretty/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-heap/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot-th/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/binary/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
888− >> inplace/lib/bin/ghc-iserv-dyn
889− <br>"rm" -f inplace/bin/runghc
890− <br>echo 'exec "$executablename" ${1+"$@"}' >> inplace/lib/bin/ghc-iserv-dyn
891− <br>echo '#!/bin/sh' >> inplace/bin/runghc
892− <br>chmod +x inplace/lib/bin/ghc-iserv-dyn
893− <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/runghc"' >> inplace/bin/runghc
894− <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
895− <br>/usr/local/bin/ginstall -c -m 755 utils/hpc/dist-install/build/tmp/hpc inplace/lib/bin/hpc
896− <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/runghc
897− <br>"rm" -f inplace/bin/hpc
898− <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
899− <br>echo 'pgmgcc="cc"' >> inplace/bin/runghc
900− <br>echo '#!/bin/sh' >> inplace/bin/hpc
901− <br>echo 'ghcprog="ghc-stage2"' >> "inplace/bin/runghc"
902− <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/hpc"' >> inplace/bin/hpc
903− <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/process/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
904− >> inplace/bin/runghc
905− <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
906− <br>cat utils/runghc/runghc.wrapper >> inplace/bin/runghc
907− <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/hpc
908− <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
909− <br>chmod +x inplace/bin/runghc
910− <br>echo 'pgmgcc="cc"' >> inplace/bin/hpc
911− <br>"rm" -f utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
912− <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/hpc/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
913− >> inplace/bin/hpc
914− <br>echo '#!/bin/sh' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
915− <br>cat utils/hpc/hpc.wrapper >> inplace/bin/hpc
916− <br>echo 'export DYLD_LIBRARY_PATH="libraries/Cabal/Cabal/dist-install/build:libraries/process/dist-install/build:libraries/parsec/dist-install/build:libraries/text/dist-install/build:libraries/template-haskell/dist-install/build:libraries/pretty/dist-install/build:libraries/ghc-boot-th/dist-install/build:libraries/mtl/dist-install/build:libraries/transformers/dist-install/build:libraries/directory/dist-install/build:libraries/unix/dist-install/build:libraries/time/dist-install/build:libraries/filepath/dist-install/build:libraries/binary/dist-install/build:libraries/containers/containers/dist-install/build:libraries/bytestring/dist-install/build:libraries/deepseq/dist-install/build:libraries/array/dist-install/build:libraries/base/dist-install/build:libraries/ghc-bignum/dist-install/build:libraries/ghc-prim/dist-install/build:rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
917− >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
918− <br>chmod +x inplace/bin/hpc
919− <br>echo 'exec "utils/ghc-cabal/dist-install/build/tmp/ghc-cabal" ${1+"$@"}' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
920− <br>chmod +x utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
921− <br>
922− <<ghc: 2787765536 bytes, 171 GCs, 20282449/67935792 avg/max bytes residency (8 samples), 144M in use, 0.000 INIT (0.003 elapsed), 1.738 MUT (2.286 elapsed), 0.567 GC (0.611 elapsed) :ghc>>
923− <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages -i
924− -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
925− -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0 -package-id
926− binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619 -package-id
927− ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id time-1.9.3
928− -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
929− -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/HsToCore.hs -o compiler/stage2/build/GHC/HsToCore.o
930− -dyno compiler/stage2/build/GHC/HsToCore.dyn_o
931− <br>
932− <<ghc: 766891168 bytes, 91 GCs, 14722329/42245856 avg/max bytes residency (6 samples), 91M in use, 0.000 INIT (0.003 elapsed), 0.361 MUT (0.510 elapsed), 0.236 GC (0.258 elapsed) :ghc>>
933− <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
934− -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
935− -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0
936− -package-id binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619
937− -package-id ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id
938− time-1.9.3 -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
939− -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/Iface/Ext/Ast.hs -o compiler/stage2/build/GHC/Iface/Ext/Ast.o
940− -dyno compiler/stage2/build/GHC/Iface/Ext/Ast.dyn_o
941− <br>
942− <<ghc: 3067019736 bytes, 347 GCs, 25353490/71392248 avg/max bytes residency (8 samples), 184M in use, 0.000 INIT (0.002 elapsed), 1.416 MUT (1.823 elapsed), 0.554 GC (0.595 elapsed) :ghc>>
943− <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
944− -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompil...
945− </div>
946− <!-- temp -->
947− или:
948− <!--/temp -->
949− <div class="no-log">
950− <div class="null null--data">
951− <div class="null__content">
952− <b class="null__heading">Cannot retrieve the data</b>
953− <div class="null__message">Try to reload page</div>
892+ <h2 class="popup__project">
893+ Project name, logs
894+ </h2>
895+ </div>
896+ <div class="popup__sub-head">
897+ <div class="nav">
898+ <button class="nav__link nav__link--current" type="button">stdout</button>
899+ <button class="nav__link" type="button">stderr</button>
900+ </div>
901+ </div>
902+ <div class="popup__content">
903+ <div class="log">
904+ DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/libiserv/dist-install/build:/Users/dr/workspace/ghc/libraries/ghci/dist-install/build:/Users/dr/workspace/ghc/libraries/transformers/dist-install/build:/Users/dr/workspace/ghc/libraries/template-haskell/dist-install/build:/Users/dr/workspace/ghc/libraries/pretty/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-heap/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot-th/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/binary/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
905+ >> inplace/lib/bin/ghc-iserv-dyn
906+ <br>"rm" -f inplace/bin/runghc
907+ <br>echo 'exec "$executablename" ${1+"$@"}' >> inplace/lib/bin/ghc-iserv-dyn
908+ <br>echo '#!/bin/sh' >> inplace/bin/runghc
909+ <br>chmod +x inplace/lib/bin/ghc-iserv-dyn
910+ <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/runghc"' >> inplace/bin/runghc
911+ <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
912+ <br>/usr/local/bin/ginstall -c -m 755 utils/hpc/dist-install/build/tmp/hpc inplace/lib/bin/hpc
913+ <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/runghc
914+ <br>"rm" -f inplace/bin/hpc
915+ <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
916+ <br>echo 'pgmgcc="cc"' >> inplace/bin/runghc
917+ <br>echo '#!/bin/sh' >> inplace/bin/hpc
918+ <br>echo 'ghcprog="ghc-stage2"' >> "inplace/bin/runghc"
919+ <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/hpc"' >> inplace/bin/hpc
920+ <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/process/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
921+ >> inplace/bin/runghc
922+ <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
923+ <br>cat utils/runghc/runghc.wrapper >> inplace/bin/runghc
924+ <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/hpc
925+ <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
926+ <br>chmod +x inplace/bin/runghc
927+ <br>echo 'pgmgcc="cc"' >> inplace/bin/hpc
928+ <br>"rm" -f utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
929+ <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/hpc/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
930+ >> inplace/bin/hpc
931+ <br>echo '#!/bin/sh' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
932+ <br>cat utils/hpc/hpc.wrapper >> inplace/bin/hpc
933+ <br>echo 'export DYLD_LIBRARY_PATH="libraries/Cabal/Cabal/dist-install/build:libraries/process/dist-install/build:libraries/parsec/dist-install/build:libraries/text/dist-install/build:libraries/template-haskell/dist-install/build:libraries/pretty/dist-install/build:libraries/ghc-boot-th/dist-install/build:libraries/mtl/dist-install/build:libraries/transformers/dist-install/build:libraries/directory/dist-install/build:libraries/unix/dist-install/build:libraries/time/dist-install/build:libraries/filepath/dist-install/build:libraries/binary/dist-install/build:libraries/containers/containers/dist-install/build:libraries/bytestring/dist-install/build:libraries/deepseq/dist-install/build:libraries/array/dist-install/build:libraries/base/dist-install/build:libraries/ghc-bignum/dist-install/build:libraries/ghc-prim/dist-install/build:rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
934+ >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
935+ <br>chmod +x inplace/bin/hpc
936+ <br>echo 'exec "utils/ghc-cabal/dist-install/build/tmp/ghc-cabal" ${1+"$@"}' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
937+ <br>chmod +x utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
938+ <br>
939+ <
940+ <ghc: 2787765536 bytes, 171 GCs, 20282449
941+ /67935792 avg/max bytes residency (8 samples), 144M in use, 0.000 INIT (0.003 elapsed), 1.738 MUT (2.286 elapsed), 0.567 GC (0.611 elapsed) :ghc>>
942+ <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages -i
943+ -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
944+ -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0 -package-id
945+ binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619 -package-id
946+ ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id time-1.9.3
947+ -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
948+ -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/HsToCore.hs -o compiler/stage2/build/GHC/HsToCore.o
949+ -dyno compiler/stage2/build/GHC/HsToCore.dyn_o
950+ <br>
951+ <
952+ <ghc: 766891168 bytes, 91 GCs, 14722329
953+ /42245856 avg/max bytes residency (6 samples), 91M in use, 0.000 INIT (0.003 elapsed), 0.361 MUT (0.510 elapsed), 0.236 GC (0.258 elapsed) :ghc>>
954+ <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
955+ -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
956+ -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0
957+ -package-id binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619
958+ -package-id ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id
959+ time-1.9.3 -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
960+ -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/Iface/Ext/Ast.hs -o compiler/stage2/build/GHC/Iface/Ext/Ast.o
961+ -dyno compiler/stage2/build/GHC/Iface/Ext/Ast.dyn_o
962+ <br>
963+ <
964+ <ghc: 3067019736 bytes, 347 GCs, 25353490
965+ /71392248 avg/max bytes residency (8 samples), 184M in use, 0.000 INIT (0.002 elapsed), 1.416 MUT (1.823 elapsed), 0.554 GC (0.595 elapsed) :ghc>>
966+ <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
967+ -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompil...
968+ </div>
969+ <!-- temp -->
970+ или:
971+ <!--/temp -->
972+ <div class="no-log">
973+ <div class="null null--data">
974+ <div class="null__content">
975+ <b class="null__heading">Cannot retrieve the data</b>
976+ <div class="null__message">Try to reload page</div>
977+ </div>
978+ </div>
979+ <!-- temp -->
980+ &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
981+ <!--/temp -->
982+ <div class="loading loading--enlarged loading--alternate">
983+ Loading...
984+ </div>
985+ </div>
986+ </div>
954987 </div>
955− </div>
956− <!-- temp -->
957− &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
958− <!--/temp -->
959− <div class="loading loading--enlarged loading--alternate">
960− Loading...
961− </div>
962988 </div>
963− </div>
964− </div>
965− </div>
966989
967− <div class="classic-popup" id="dialog">
968− <div class="classic-popup__container">
969− <div class="classic-popup__viewport">
970− <div class="classic-popup__slot">
990+ <div class="classic-popup" id="dialog">
991+ <div class="classic-popup__container">
992+ <div class="classic-popup__viewport">
993+ <div class="classic-popup__slot">
971994
972− <div class="dialog dialog--archive">
973− <div class="dialog__content">
974− Are you sure you want to archive the
975− <br>‘Feature name’ deployment?
976− </div>
977− <div class="dialog__footer">
978− <button class="dialog__action button" type="submit">Archive</button>
979− <button class="dialog__action button--secondary button" type="button">Cancel</button>
980− </div>
981− </div>
995+ <div class="dialog dialog--archive">
996+ <div class="dialog__content">
997+ Are you sure you want to archive the
998+ <br>‘Feature name’ deployment?
999+ </div>
1000+ <div class="dialog__footer">
1001+ <button class="dialog__action button" type="submit">Archive</button>
1002+ <button class="dialog__action button--secondary button" type="button">Cancel</button>
1003+ </div>
1004+ </div>
9821005
983− <button class="classic-popup__close" type="button">
1006+ <button class="classic-popup__close" type="button">
9841007 Close
9851008 </button>
1009+ </div>
1010+ </div>
1011+ </div>
9861012 </div>
987− </div>
988− </div>
989− </div>
9901013
9911014
992− <!-- jQuery -->
993− <script src="../vendors/jquery/jquery-3.2.1.min.js"></script>
1015+ <!-- jQuery -->
1016+ <script src="../vendors/jquery/jquery-3.2.1.min.js"></script>
9941017
995− <!-- Outline.js -->
996− <script src="../vendors/outline/outline.js"></script>
1018+ <!-- Outline.js -->
1019+ <script src="../vendors/outline/outline.js"></script>
9971020
998− <!-- Temp -->
999− <script src="../scripts/_expander.js"></script>
1000− <script src="../scripts/_drop.js"></script>
1001− <script src="../scripts/_sort.js"></script>
1002− <script src="../scripts/_data.js"></script>
1003− <script src="../scripts/_popup.js"></script>
1004− <script src="../scripts/_classic-popup.js"></script>
1021+ <!-- Temp -->
1022+ <script src="../scripts/_expander.js"></script>
1023+ <script src="../scripts/_drop.js"></script>
1024+ <script src="../scripts/_sort.js"></script>
1025+ <script src="../scripts/_data.js"></script>
1026+ <script src="../scripts/_popup.js"></script>
1027+ <script src="../scripts/_classic-popup.js"></script>
1028+ <script src="../scripts/_collapse.js"></script>
10051029
1006−</body>
1030+ </body>
10071031
1008−</html>
1032+</html>
octopod-css/development/layouts/staging.html+1159−668
@@ -1,738 +1,1229 @@
11<!DOCTYPE html>
22<html lang="en">
33
4−<head>
5− <meta charset="utf-8">
6− <meta http-equiv="x-ua-compatible" content="ie=edge">
7− <title>Deployment</title>
8− <meta name="viewport" content="width=device-width, initial-scale=1">
9− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
10− <link rel="stylesheet" href="../styles/style.css">
11−</head>
4+ <head>
5+ <meta charset="utf-8">
6+ <meta http-equiv="x-ua-compatible" content="ie=edge">
7+ <title>Deployment</title>
8+ <meta name="viewport" content="width=device-width, initial-scale=1">
9+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
10+ <link rel="stylesheet" href="../styles/style.css">
11+ </head>
1212
13−<body>
13+ <body>
1414
15− <!--[if IE]>
16− <div class="browserupgrade">
17− You are using an <strong>outdated</strong> browser.
18− Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
19− </div>
15+ <!--[if IE]>
16+ <div class="browserupgrade">
17+ You are using an <strong>outdated</strong> browser.
18+ Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
19+ </div>
2020 <![endif]-->
2121
22− <header class="header">
23− <div class="header__wrap container">
24− <b class="header__logo">
22+ <header class="header">
23+ <div class="header__wrap container">
24+ <b class="header__logo">
2525 Deployment Manager
2626 </b>
27− <div class="header__project">
28− Project name
29− </div>
30− </div>
31− </header>
27+ <div class="header__project">
28+ Project name
29+ </div>
30+ </div>
31+ </header>
3232
33− <div class="page">
34− <div class="page__wrap container">
35− <div class="page__output notification notification--success">
36− <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
37− <button class="notification__close" type="button"></button>
38− </div>
39− <a class="page__back dash dash--back dash--smaller" href="index.html">
33+ <div class="page">
34+ <div class="page__wrap container">
35+ <div class="page__output notification notification--success">
36+ <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
37+ <button class="notification__close" type="button"></button>
38+ </div>
39+ <a class="page__back dash dash--back dash--smaller" href="index.html">
4040 All deployments
4141 </a>
42− <div class="page__head">
43− <h1 class="page__heading title">
44− Project name
45− </h1>
46− <a class="page__action button button--edit popup-handler" href="#deployment">
42+ <div class="page__head">
43+ <h1 class="page__heading title">
44+ Project name
45+ </h1>
46+ <a class="page__action button button--edit popup-handler" href="#deployment">
4747 Edit deployment
4848 </a>
49− <a class="page__action button button--secondary button--archive classic-popup-handler" href="#dialog">
49+ <a class="page__action button button--secondary button--archive classic-popup-handler" href="#dialog">
5050 Move to archive
5151 </a>
52− <!-- temp -->
53− &nbsp;&nbsp;&nbsp;или для уже архивных:
54− <!--/temp -->
55− <a class="page__action button button--secondary button--restore classic-popup-handler" href="#dialog">
52+ <!-- temp -->
53+ &nbsp;&nbsp;&nbsp;или для уже архивных:
54+ <!--/temp -->
55+ <a class="page__action button button--secondary button--restore classic-popup-handler" href="#dialog">
5656 Recover from archive
5757 </a>
58− </div>
59− <div class="page__body">
60− <div class="deployment">
61− <div class="deployment__output notification notification--danger">
62− <b>Project successfully updated</b>
63− <button class="notification__close" type="button"></button>
64− </div>
65− <div class="deployment__summary">
66− <div class="deployment__stat">
67− <b class="deployment__param">
58+ </div>
59+ <div class="page__body">
60+ <div class="deployment">
61+ <div class="deployment__output notification notification--danger">
62+ <b>Project successfully updated</b>
63+ <button class="notification__close" type="button"></button>
64+ </div>
65+ <div class="deployment__summary">
66+ <div class="deployment__stat">
67+ <b class="deployment__param">
6868 Status
6969 </b>
70− <div class="deployment__value">
71− <div class="status status--success">Success</div>
72− </div>
73− </div>
74− <div class="deployment__stat">
75− <b class="deployment__param">
70+ <div class="deployment__value">
71+ <div class="status status--success">Success</div>
72+ </div>
73+ </div>
74+ <div class="deployment__stat">
75+ <b class="deployment__param">
7676 Created
7777 </b>
78− <div class="deployment__value">
79− 15.05.2020
80− </div>
81− </div>
82− <div class="deployment__stat">
83− <b class="deployment__param">
78+ <div class="deployment__value">
79+ 15.05.2020
80+ </div>
81+ </div>
82+ <div class="deployment__stat">
83+ <b class="deployment__param">
8484 Changed
8585 </b>
86− <div class="deployment__value">
87− 01.06.2020
88− </div>
89− </div>
90− </div>
91− <section class="deployment__section">
92− <h3 class="deployment__sub-heading">
93− Tag
94− </h3>
95− <div class="deployment__widget">
96− H97HF384GKERP39740223
97− </div>
98− </section>
99− <section class="deployment__section">
100− <h3 class="deployment__sub-heading">
101− Links
102− </h3>
103− <div class="deployment__widget">
104− <div class="listing">
105− <a class="listing__item external bar bar--larger" href="#">
86+ <div class="deployment__value">
87+ 01.06.2020
88+ </div>
89+ </div>
90+ </div>
91+ <section class="deployment__section">
92+ <h3 class="deployment__sub-heading">
93+ Tag
94+ </h3>
95+ <div class="deployment__widget">
96+ H97HF384GKERP39740223
97+ </div>
98+ </section>
99+ <section class="deployment__section">
100+ <h3 class="deployment__sub-heading">
101+ Links
102+ </h3>
103+ <div class="deployment__widget">
104+ <div class="listing">
105+ <a class="listing__item external bar bar--larger" href="#">
106106 app.feature-name.project.name.com
107107 </a>
108− <a class="listing__item external bar bar--larger" href="#">
108+ <a class="listing__item external bar bar--larger" href="#">
109109 admin.feature-name.project.name.com
110110 </a>
111− </div>
112− </div>
113− </section>
114− <section class="deployment__section">
115− <h3 class="deployment__sub-heading">
116− App configuration
117− </h3>
118− <div class="deployment__widget">
119− <div class="listing listing--for-text listing--larger">
120− <div class="listing__item">
121− <span class="listing__key">ENVIRONMENT:</span>
122− <span class="listing__value">production</span>
123− </div>
124− <div class="listing__item">
125− <span class="listing__key">app_api_url:</span>
126− <span class="listing__value">http://my-api.my-domain.com</span>
127− </div>
128− <div class="listing__item">
129− <span class="listing__key default">SECRET_CODE:</span>
130− <span class="listing__value">asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen</span>
131− </div>
132− <div class="listing__item deleted">
133− <span class="listing__key default">SECRET_CODE:</span>
134− <span class="listing__value default">asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen</span>
135− </div>
136− <div class="listing__item deleted">
137− <span class="listing__key default">SECRET_CODE:</span>
138− <div class="listing__placeholder"></div>
139− <div class="listing__spinner"></div>
140− </div>
141− <div class="listing__item">
142− <span class="listing__key default">INFO:</span>
143− <span class="listing__value default">New Project Staging</span>
144− </div>
145− </div>
146− </div>
147− </section>
148− <section class="deployment__section">
149− <h3 class="deployment__sub-heading">
150− Deployment configuration
151− </h3>
152− <div class="deployment__widget">
153− <div class="listing listing--for-text listing--larger">
154− <div class="listing__item">
155− <b>ENVIRONENT:</b> production
156− </div>
157− <div class="listing__item">
158− <b>app_api_url:</b> http: //my-api.my-domain.com
159− </div>
160− <div class="listing__item">
161− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij
162− </div>
163− </div>
164− </div>
165− </section>
166− <section class="deployment__section">
167− <h3 class="deployment__sub-heading">
168− Actions
169− </h3>
170− <div class="deployment__widget">
171− <div class="table table--actions">
172− <table>
173− <thead>
174− <tr>
175− <th>
176− Action type
177− </th>
178− <th>
179− App configuration
180− </th>
181− <th>
182− Deployment configuration
183− </th>
184− <th>
185− Exit code
186− </th>
187− <th>
188− <button class="sort sort--active sort--asc" type="button">Created</button>
189− </th>
190− <th>
191− Deployment duration
192− </th>
193− </tr>
194− </thead>
195− <tbody>
196− <tr>
197− <td>
198− Create
199− </td>
200− <td>
201− <div class="listing listing--for-text">
202− <div class="listing__item">
203− <b>ENVIRONENT:</b>
204− <div class="listing__placeholder listing__placeholder__value"></div>
205− <div class="listing__spinner"></div>
206− </div>
207− <div class="listing__item">
208− <b>app_api_url:</b> http://my-api.my-domain.com
209− </div>
210− <div class="listing__item">
211− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
212− </div>
213− <button class="listing__more expander" type="button">
111+ </div>
112+ </div>
113+ </section>
114+ <section class="deployment__section">
115+ <h3 class="deployment__sub-heading">
116+ App overrides
117+ </h3>
118+ <div class="deployment__widget">
119+ <div class="padded">
120+ <div class="row">
121+ <span class="key-custom-edited">ENVIRONENT: </span><span class="value-edited">production</span>
122+ </div>
123+ <div class="row">
124+ <span class="key-custom-edited">Secret_word: </span><span class="value-edited">Hello</span>
125+ </div>
126+ <div class="row">
127+ <span class="key-default-pristine">SECRET_CODE: </span><span class="value-edited">asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij</span>
128+ </div>
129+ <div class="row">
130+ <span class="key-deleted">sso.vaultEnv.hotels-sso.mapping[0].APP_URL </span><span class="value-deleted">http://my-api.my-domain.com</span>
131+ </div>
132+ <div class="row">
133+ <span class="key-deleted">air.vaultEnv.air-sso:</span> <span class="value-unknown">unknown</span>
134+ </div>
135+ <div class="collapse collapse--project">
136+ <button class="collapse__head" type="button">
137+ air
138+ </button>
139+ <div class="collapse__body">
140+ <div class="collapse__inner">
141+ <div class="row">
142+ <span class="key-default-pristine">vaultEngineName: </span><span class="value-pristine">staging</span>
143+ </div>
144+ <div class="collapse collapse--project">
145+ <button class="collapse__head" type="button">
146+ vaultEnv
147+ </button>
148+ <div class="collapse__body">
149+ <div class="collapse__inner">
150+ <div class="row">
151+ <span class="key-default-pristine">air-sso.engineOverride: </span><span class="value-pristine">staging</span>
152+ </div>
153+ <div class="collapse collapse--project">
154+ <button class="collapse__head" type="button">
155+ air-sso.mapping[0]
156+ </button>
157+ <div class="collapse__body">
158+ <div class="collapse__inner">
159+ <div class="row">
160+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
161+ </div>
162+ <div class="row">
163+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
164+ </div>
165+ </div>
166+ <div class="row">
167+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
168+ </div>
169+ </div>
170+ </div>
171+ <div class="collapse collapse--project">
172+ <button class="collapse__head" type="button">
173+ travolutionary.mapping[0]
174+ </button>
175+ <div class="collapse__body">
176+ <div class="collapse__inner">
177+ <div class="row">
178+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
179+ </div>
180+ <div class="row">
181+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
182+ </div>
183+ </div>
184+ </div>
185+ </div>
186+ <div class="collapse collapse--project">
187+ <button class="collapse__head" type="button">
188+ travolutionary.mapping[1]
189+ </button>
190+ <div class="collapse__body">
191+ <div class="collapse__inner">
192+ <div class="row">
193+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
194+ </div>
195+ <div class="row">
196+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
197+ </div>
198+ </div>
199+ </div>
200+ </div>
201+ <div class="row">
202+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
203+ </div>
204+ </div>
205+ </div>
206+ </div>
207+ </div>
208+ <div class="row">
209+ <span class="key-custom-edited">app_api_url: </span><span class="value-edited">http: //my-api.my-domain.com</span>
210+ </div>
211+ </div>
212+ </div>
213+ <div class="collapse collapse--project">
214+ <button class="collapse__head" type="button">
215+ sso
216+ </button>
217+ <div class="collapse__body">
218+ <div class="collapse__inner">
219+ <div class="row">
220+ <span class="key-default-pristine">vaultEngineName: </span><span class="value-pristine">staging</span>
221+ </div>
222+ <div class="collapse collapse--project">
223+ <button class="collapse__head" type="button">
224+ vaultEnv
225+ </button>
226+ <div class="collapse__body">
227+ <div class="collapse__inner">
228+ <div class="row">
229+ <span class="key-default-pristine">air-sso.engineOverride: </span><span class="value-pristine">staging</span>
230+ </div>
231+ <div class="collapse collapse--project">
232+ <button class="collapse__head" type="button">
233+ air-sso.mapping[0]
234+ </button>
235+ <div class="collapse__body">
236+ <div class="collapse__inner">
237+ <div class="row">
238+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
239+ </div>
240+ <div class="row">
241+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
242+ </div>
243+ </div>
244+ <div class="row">
245+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
246+ </div>
247+ </div>
248+ </div>
249+ <div class="collapse collapse--project">
250+ <button class="collapse__head" type="button">
251+ travolutionary.mapping[0]
252+ </button>
253+ <div class="collapse__body">
254+ <div class="collapse__inner">
255+ <div class="row">
256+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
257+ </div>
258+ <div class="row">
259+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
260+ </div>
261+ </div>
262+ </div>
263+ </div>
264+ <div class="collapse collapse--project">
265+ <button class="collapse__head" type="button">
266+ travolutionary.mapping[1]
267+ </button>
268+ <div class="collapse__body">
269+ <div class="collapse__inner">
270+ <div class="row">
271+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
272+ </div>
273+ <div class="row">
274+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
275+ </div>
276+ </div>
277+ </div>
278+ </div>
279+ <div class="row">
280+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
281+ </div>
282+ </div>
283+ </div>
284+ </div>
285+ </div>
286+ <div class="row">
287+ <span class="key-custom-edited">app_api_url: </span><span class="value-edited">http: //my-api.my-domain.com</span>
288+ </div>
289+ </div>
290+ </div>
291+ </div>
292+ </div>
293+ </section>
294+ <section class="deployment__section">
295+ <h3 class="deployment__sub-heading">
296+ Staging overrides
297+ </h3>
298+ <div class="deployment__widget">
299+ <div class="padded">
300+ <div class="row">
301+ <span class="key-custom-edited">ENVIRONENT: </span><span class="value-edited">http://my-api.my-domain.com</span>
302+ </div>
303+ <div class="row">
304+ <span class="key-default-pristine">SECRET_CODE: </span><span class="value-edited">http://my-api.my-domain.com</span>
305+ </div>
306+ <div class="row">
307+ <span class="key-default-pristine">ENVIRONENT: </span><span class="value-pristine">production</span>
308+ </div>
309+ </div>
310+ </div>
311+ </section>
312+ <section class="deployment__section">
313+ <h3 class="deployment__sub-heading">
314+ Actions
315+ </h3>
316+ <div class="deployment__widget">
317+ <div class="table table--actions">
318+ <table>
319+ <thead>
320+ <tr>
321+ <th>
322+ Action type
323+ </th>
324+ <th>
325+ App configuration
326+ </th>
327+ <th>
328+ Deployment configuration
329+ </th>
330+ <th>
331+ Exit code
332+ </th>
333+ <th>
334+ <button class="sort sort--active sort--asc" type="button">Created</button>
335+ </th>
336+ <th>
337+ Deployment duration
338+ </th>
339+ </tr>
340+ </thead>
341+ <tbody>
342+ <tr>
343+ <td>
344+ Create
345+ </td>
346+ <td>
347+ <div class="listing listing--for-text">
348+ <div class="listing__item">
349+ <b>ENVIRONENT:</b>
350+ <div class="listing__placeholder listing__placeholder__value"></div>
351+ <div class="listing__spinner"></div>
352+ </div>
353+ <div class="listing__item">
354+ <b>app_api_url:</b> http://my-api.my-domain.com
355+ </div>
356+ <div class="listing__item">
357+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
358+ </div>
359+ <button class="listing__more expander" type="button">
214360 Show all (5)
215361 </button>
216− </div>
217− </td>
218− <td>
219− <div class="listing listing--for-text">
220− <div class="listing__item">
221− <b>ENVIRONENT:</b> production
222− </div>
223− <div class="listing__item">
224− <b>app_api_url:</b> http://my-api.my-domain.com
225− </div>
226− <div class="listing__item">
227− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
228− </div>
229− <button class="listing__more expander" type="button">
362+ </div>
363+ </td>
364+ <td>
365+ <div class="listing listing--for-text">
366+ <div class="listing__item">
367+ <b>ENVIRONENT:</b> production
368+ </div>
369+ <div class="listing__item">
370+ <b>app_api_url:</b> http://my-api.my-domain.com
371+ </div>
372+ <div class="listing__item">
373+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
374+ </div>
375+ <button class="listing__more expander" type="button">
230376 Show all (5)
231377 </button>
232− </div>
233− </td>
234− <td>
235− 0
236− </td>
237− <td>
238− 2020-05-13 08:06:00 313811+00
239− </td>
240− <td>
241− 1m 95s
242− </td>
243− </tr>
244− <tr>
245− <td>
246− Edit
247− </td>
248− <td>
249− <div class="listing listing--for-text">
250− <div class="listing__item">
251− <b>ENVIRONENT:</b> production
252− </div>
253− <div class="listing__item">
254− <b>app_api_url:</b> http://my-api.my-domain.com
255− </div>
256− <div class="listing__item">
257− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
258− </div>
259− </div>
260− </td>
261− <td>
262− <div class="listing listing--for-text">
263− <div class="listing__item">
264− <b>ENVIRONENT:</b> production
265− </div>
266− <div class="listing__item">
267− <b>app_api_url:</b> http://my-api.my-domain.com
268− </div>
269− <div class="listing__item">
270− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
271− </div>
272− </div>
273− </td>
274− <td>
275− 1
276− </td>
277− <td>
278− 2020-05-13 08:06:00 313811+00
279− </td>
280− <td>
281− 1m 95s
282− </td>
283− </tr>
284− <tr>
285− <td>
286− Update
287− </td>
288− <td>
289− <div class="listing listing--for-text">
290− <div class="listing__item">
291− <b>ENVIRONENT:</b> production
292− </div>
293− <div class="listing__item">
294− <b>app_api_url:</b> http://my-api.my-domain.com
295− </div>
296− <div class="listing__item">
297− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
298− </div>
299− </div>
300− </td>
301− <td>
302− <div class="listing listing--for-text">
303− <div class="listing__item">
304− <b>ENVIRONENT:</b> production
305− </div>
306− <div class="listing__item">
307− <b>app_api_url:</b> http://my-api.my-domain.com
308− </div>
309− <div class="listing__item">
310− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
311− </div>
312− </div>
313− </td>
314− <td>
315− 0
316− </td>
317− <td>
318− 2020-05-13 08:06:00 313811+00
319− </td>
320− <td>
321− 1m 95s
322− </td>
323− </tr>
324− <tr>
325− <td>
326− Delete
327− </td>
328− <td>
329− <div class="listing listing--for-text">
330− <div class="listing__item">
331− <b>ENVIRONENT:</b> production
332− </div>
333− <div class="listing__item">
334− <b>app_api_url:</b> http://my-api.my-domain.com
335− </div>
336− <div class="listing__item">
337− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
338− </div>
339− </div>
340− </td>
341− <td>
342− <div class="listing listing--for-text">
343− <div class="listing__item">
344− <b>ENVIRONENT:</b> production
345− </div>
346− <div class="listing__item">
347− <b>app_api_url:</b> http://my-api.my-domain.com
348− </div>
349− <div class="listing__item">
350− <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
351− </div>
352− </div>
353− </td>
354− <td>
355− 1
356− </td>
357− <td>
358− 2020-05-13 08:06:00 313811+00
359− </td>
360− <td>
361− 1m 95s
362− </td>
363− </tr>
364− <tr class="no-table">
365− <td colspan="7">
378+ </div>
379+ </td>
380+ <td>
381+ 0
382+ </td>
383+ <td>
384+ 2020-05-13 08:06:00 313811+00
385+ </td>
386+ <td>
387+ 1m 95s
388+ </td>
389+ </tr>
390+ <tr>
391+ <td>
392+ Edit
393+ </td>
394+ <td>
395+ <div class="listing listing--for-text">
396+ <div class="listing__item">
397+ <b>ENVIRONENT:</b> production
398+ </div>
399+ <div class="listing__item">
400+ <b>app_api_url:</b> http://my-api.my-domain.com
401+ </div>
402+ <div class="listing__item">
403+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
404+ </div>
405+ </div>
406+ </td>
407+ <td>
408+ <div class="listing listing--for-text">
409+ <div class="listing__item">
410+ <b>ENVIRONENT:</b> production
411+ </div>
412+ <div class="listing__item">
413+ <b>app_api_url:</b> http://my-api.my-domain.com
414+ </div>
415+ <div class="listing__item">
416+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
417+ </div>
418+ </div>
419+ </td>
420+ <td>
421+ 1
422+ </td>
423+ <td>
424+ 2020-05-13 08:06:00 313811+00
425+ </td>
426+ <td>
427+ 1m 95s
428+ </td>
429+ </tr>
430+ <tr>
431+ <td>
432+ Update
433+ </td>
434+ <td>
435+ <div class="listing listing--for-text">
436+ <div class="listing__item">
437+ <b>ENVIRONENT:</b> production
438+ </div>
439+ <div class="listing__item">
440+ <b>app_api_url:</b> http://my-api.my-domain.com
441+ </div>
442+ <div class="listing__item">
443+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
444+ </div>
445+ </div>
446+ </td>
447+ <td>
448+ <div class="listing listing--for-text">
449+ <div class="listing__item">
450+ <b>ENVIRONENT:</b> production
451+ </div>
452+ <div class="listing__item">
453+ <b>app_api_url:</b> http://my-api.my-domain.com
454+ </div>
455+ <div class="listing__item">
456+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
457+ </div>
458+ </div>
459+ </td>
460+ <td>
461+ 0
462+ </td>
463+ <td>
464+ 2020-05-13 08:06:00 313811+00
465+ </td>
466+ <td>
467+ 1m 95s
468+ </td>
469+ </tr>
470+ <tr>
471+ <td>
472+ Delete
473+ </td>
474+ <td>
475+ <div class="listing listing--for-text">
476+ <div class="listing__item">
477+ <b>ENVIRONENT:</b> production
478+ </div>
479+ <div class="listing__item">
480+ <b>app_api_url:</b> http://my-api.my-domain.com
481+ </div>
482+ <div class="listing__item">
483+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
484+ </div>
485+ </div>
486+ </td>
487+ <td>
488+ <div class="listing listing--for-text">
489+ <div class="listing__item">
490+ <b>ENVIRONENT:</b> production
491+ </div>
492+ <div class="listing__item">
493+ <b>app_api_url:</b> http://my-api.my-domain.com
494+ </div>
495+ <div class="listing__item">
496+ <b>SECRET_CODE:</b> asdfaisdjri235868ear7%lorem-ipsum-dolor-sit-amen
497+ </div>
498+ </div>
499+ </td>
500+ <td>
501+ 1
502+ </td>
503+ <td>
504+ 2020-05-13 08:06:00 313811+00
505+ </td>
506+ <td>
507+ 1m 95s
508+ </td>
509+ </tr>
510+ <tr class="no-table">
511+ <td colspan="7">
512+ <div class="null null--data">
513+ <b class="null__heading">Cannot retrieve the data</b>
514+ <div class="null__message">Try to reload page</div>
515+ </div>
516+ <!-- temp -->
517+ &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
518+ <!--/temp -->
519+ <div class="loading loading--enlarged loading--alternate">
520+ Loading...
521+ </div>
522+ </td>
523+ </tr>
524+ </tbody>
525+ </table>
526+ </div>
527+ </div>
528+ </section>
529+ </div>
530+ <!-- temp -->
531+ или:
532+ <!--/temp -->
533+ <div class="no-deployment">
366534 <div class="null null--data">
367− <b class="null__heading">Cannot retrieve the data</b>
368− <div class="null__message">Try to reload page</div>
535+ <div class="null__content">
536+ <b class="null__heading">Cannot retrieve the data</b>
537+ <div class="null__message">Try to reload page</div>
538+ </div>
369539 </div>
370− <!-- temp -->
371− &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
372− <!--/temp -->
540+ или:
373541 <div class="loading loading--enlarged loading--alternate">
374− Loading...
542+ Loading...
375543 </div>
376− </td>
377− </tr>
378− </tbody>
379− </table>
380− </div>
381− </div>
382− </section>
383− </div>
384− <!-- temp -->
385− или:
386− <!--/temp -->
387− <div class="no-deployment">
388− <div class="null null--data">
389− <div class="null__content">
390− <b class="null__heading">Cannot retrieve the data</b>
391− <div class="null__message">Try to reload page</div>
392− </div>
393− </div>
394− или:
395− <div class="loading loading--enlarged loading--alternate">
396− Loading...
397− </div>
398− </div>
399− </div>
400− </div>
401− </div>
402−
403− <!-- или:
404− <div class="no-page">
405− <div class="no-page__inner">
406− <div class="null null--data">
407− <b class="null__heading">Cannot retrieve the data</b>
408− <div class="null__message">Try to reload page</div>
409− </div>
410− или:
411− <div class="loading loading--enlarged loading--alternate">
412− Loading...
544+ </div>
413545 </div>
414546 </div>
415547 </div>
416− -->
417548
418− <div class="popup" id="deployment">
419− <div class="popup__overlay" aria-hidden="true">
420− Close popup
421− </div>
422− <div class="popup__body">
423− <div class="popup__head">
424− <button class="popup__close" type="button">
549+ <!-- или:
550+ <div class="no-page">
551+ <div class="no-page__inner">
552+ <div class="null null--data">
553+ <b class="null__heading">Cannot retrieve the data</b>
554+ <div class="null__message">Try to reload page</div>
555+ </div>
556+ или:
557+ <div class="loading loading--enlarged loading--alternate">
558+ Loading...
559+ </div>
560+ </div>
561+ </div>
562+ -->
563+
564+ <div class="popup" id="deployment">
565+ <div class="popup__overlay" aria-hidden="true">
566+ Close popup
567+ </div>
568+ <div class="popup__body">
569+ <div class="popup__head">
570+ <button class="popup__close" type="button">
425571 Close popup
426572 </button>
427− <h2 class="popup__project">
428− Project name
429− </h2>
430− <div class="popup__operations">
431− <button class="popup__action button button--save" type="button">Save</button>
432− <button class="popup__action button button--secondary" type="button">Cancel</button>
433− </div>
434− <div class="popup__menu drop drop--actions">
435− <button class="drop__handler" type="button">
573+ <h2 class="popup__project">
574+ Project name
575+ </h2>
576+ <div class="popup__operations">
577+ <button class="popup__action button button--save" type="button">Save</button>
578+ <button class="popup__action button button--secondary" type="button">Cancel</button>
579+ </div>
580+ <div class="popup__menu drop drop--actions">
581+ <button class="drop__handler" type="button">
436582 Actions
437583 </button>
438− <div class="drop__dropdown">
439− <button class="action action--archive" type="button">Move to archive</button>
440− <button class="action action--restore" type="button">Restore from archive</button>
441− </div>
442− </div>
443− </div>
444− <div class="popup__content">
584+ <div class="drop__dropdown">
585+ <button class="action action--archive" type="button">Move to archive</button>
586+ <button class="action action--restore" type="button">Restore from archive</button>
587+ </div>
588+ </div>
589+ </div>
590+ <div class="popup__content">
445591
446− <div class="deployment">
447− <div class="deployment__output notification notification--danger">
448− <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
449− <button class="notification__close" type="button"></button>
450− </div>
451− <section class="deployment__section">
452− <h3 class="deployment__sub-heading">
453− Tag
454− </h3>
455− <div class="deployment__widget">
456− <div class="tag input">
457− <input class="input__widget" type="text" placeholder="key" value="H97HF384GKERP39740223">
458− </div>
459− </div>
460− </section>
461− <section class="deployment__section">
462− <h3 class="deployment__sub-heading">
463− App configuration
464− </h3>
465− <div class="deployment__widget">
466− <div class="overrides">
467− <button class="overrides__add dash dash--add" type="button">
592+ <div class="deployment">
593+ <div class="deployment__output notification notification--danger">
594+ <b>System error.</b> Сan not move the deployment to the archive right now. Please try later.
595+ <button class="notification__close" type="button"></button>
596+ </div>
597+ <section class="deployment__section">
598+ <h3 class="deployment__sub-heading">
599+ Tag
600+ </h3>
601+ <div class="deployment__widget">
602+ <div class="tag input">
603+ <input class="input__widget" type="text" placeholder="key" value="H97HF384GKERP39740223">
604+ </div>
605+ </div>
606+ </section>
607+ <section class="deployment__section">
608+ <h3 class="deployment__sub-heading">
609+ App configuration
610+ </h3>
611+ <div class="deployment__widget">
612+ <div class="overrides">
613+ <button class="overrides__add dash dash--add" type="button">
468614 Add an override
469615 </button>
470− <div class="overrides__item">
471− <div class="overrides__key input">
472− <input class="input__widget" type="text" placeholder="key">
473− </div>
474− <div class="overrides__value input">
475− <input class="input__widget" type="text" placeholder="value">
476− </div>
477− <button class="overrides__delete spot spot--cancel">
478− Delete
479− </button>
480− </div>
481− <div class="overrides__item">
482− <div class="overrides__key input">
483− <input class="input__widget" type="text" placeholder="key" value="ENVIRONENT">
484− </div>
485− <div class="overrides__value input">
486− <input class="input__widget" type="text" placeholder="value" value="production">
487− </div>
488− <button class="overrides__delete spot spot--cancel">
489− Delete
490− </button>
491− </div>
492− <div class="overrides__item">
493− <div class="overrides__key input">
494− <input class="input__widget" type="text" placeholder="key" value="app_api_url">
495− </div>
496− <div class="overrides__value input">
497− <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com">
498− </div>
499− <button class="overrides__delete spot spot--cancel">
500− Delete
501− </button>
502− </div>
503− <div class="overrides__item">
504− <div class="overrides__key input">
505− <input class="input__widget" type="text" placeholder="key" value="SECRET_CODE">
506− </div>
507− <div class="overrides__value input">
508− <input class="input__widget" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
509− </div>
510− <button class="overrides__delete spot spot--cancel">
511− Delete
512− </button>
513− </div>
514− </div>
515− </div>
516− </section>
517− <section class="deployment__section">
518− <h3 class="deployment__sub-heading">
519− Deployment configuration
520− </h3>
521− <div class="deployment__widget">
522− <div class="overrides">
523− <button class="overrides__add dash dash--add" type="button">
616+ <div class="overrides__list">
617+ <div class="editable-row">
618+ <div class="editable-row__key input">
619+ <input class="input__widget" type="text" placeholder="key">
620+ </div>
621+ <div class="editable-row__value input">
622+ <input class="input__widget" type="text" placeholder="value">
623+ </div>
624+ <button class="editable-row__delete spot spot--cancel">
625+ Delete
626+ </button>
627+ </div>
628+ <div class="editable-row">
629+ <div class="editable-row__key input">
630+ <input class="input__widget key-custom-edited" type="text" placeholder="key" value="ENVIRONENT">
631+ </div>
632+ <div class="editable-row__value input">
633+ <input class="input__widget value-edited" type="text" placeholder="value" value="production">
634+ </div>
635+ <button class="editable-row__delete spot spot--cancel">
636+ Delete
637+ </button>
638+ </div>
639+ <div class="editable-row">
640+ <div class="editable-row__key input">
641+ <input class="input__widget key-custom-edited" type="text" placeholder="key" value="app_api_url">
642+ </div>
643+ <div class="editable-row__value input">
644+ <input class="input__widget value-edited" type="text" placeholder="value" value="http://my-api.my-domain.com">
645+ </div>
646+ <button class="editable-row__delete spot spot--cancel">
647+ Delete
648+ </button>
649+ </div>
650+ <div class="editable-row">
651+ <div class="editable-row__key input">
652+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
653+ </div>
654+ <div class="editable-row__value input">
655+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
656+ </div>
657+ <button class="editable-row__delete spot spot--cancel">
658+ Delete
659+ </button>
660+ </div>
661+ </div>
662+ <div class="overrides__tree">
663+ <div class="collapse collapse--project">
664+ <button class="collapse__head" type="button">
665+ air
666+ </button>
667+ <div class="collapse__body">
668+ <div class="collapse__inner">
669+ <div class="editable-row">
670+ <div class="editable-row__key input">
671+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
672+ </div>
673+ <div class="editable-row__value input">
674+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
675+ </div>
676+ <button class="editable-row__delete spot spot--cancel">
677+ Delete
678+ </button>
679+ </div>
680+ <div class="collapse collapse--project">
681+ <button class="collapse__head" type="button">
682+ vaultEnv
683+ </button>
684+ <div class="collapse__body">
685+ <div class="collapse__inner">
686+ <div class="editable-row">
687+ <div class="editable-row__key input">
688+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
689+ </div>
690+ <div class="editable-row__value input">
691+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
692+ </div>
693+ <button class="editable-row__delete spot spot--cancel">
694+ Delete
695+ </button>
696+ </div>
697+ <div class="collapse collapse--project">
698+ <button class="collapse__head" type="button">
699+ air-sso.mapping[0]
700+ </button>
701+ <div class="collapse__body">
702+ <div class="collapse__inner">
703+ <div class="editable-row">
704+ <div class="editable-row__key input">
705+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
706+ </div>
707+ <div class="editable-row__value input">
708+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
709+ </div>
710+ <button class="editable-row__delete spot spot--cancel">
711+ Delete
712+ </button>
713+ </div>
714+ <div class="editable-row">
715+ <div class="editable-row__key input">
716+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
717+ </div>
718+ <div class="editable-row__value input">
719+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
720+ </div>
721+ <button class="editable-row__delete spot spot--cancel">
722+ Delete
723+ </button>
724+ </div>
725+ </div>
726+ <div class="editable-row">
727+ <div class="editable-row__key input">
728+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
729+ </div>
730+ <div class="editable-row__value input">
731+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
732+ </div>
733+ <button class="editable-row__delete spot spot--cancel">
734+ Delete
735+ </button>
736+ </div>
737+ </div>
738+ </div>
739+ <div class="collapse collapse--project">
740+ <button class="collapse__head" type="button">
741+ travolutionary.mapping[0]
742+ </button>
743+ <div class="collapse__body">
744+ <div class="collapse__inner">
745+ <div class="editable-row">
746+ <div class="editable-row__key input">
747+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
748+ </div>
749+ <div class="editable-row__value input">
750+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
751+ </div>
752+ <button class="editable-row__delete spot spot--cancel">
753+ Delete
754+ </button>
755+ </div>
756+ <div class="editable-row">
757+ <div class="editable-row__key input">
758+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
759+ </div>
760+ <div class="editable-row__value input">
761+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
762+ </div>
763+ <button class="editable-row__delete spot spot--cancel">
764+ Delete
765+ </button>
766+ </div>
767+ </div>
768+ </div>
769+ </div>
770+ <div class="collapse collapse--project">
771+ <button class="collapse__head" type="button">
772+ travolutionary.mapping[1]
773+ </button>
774+ <div class="collapse__body">
775+ <div class="collapse__inner">
776+ <div class="editable-row">
777+ <div class="editable-row__key input">
778+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
779+ </div>
780+ <div class="editable-row__value input">
781+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
782+ </div>
783+ <button class="editable-row__delete spot spot--cancel">
784+ Delete
785+ </button>
786+ </div>
787+ <div class="editable-row">
788+ <div class="editable-row__key input">
789+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
790+ </div>
791+ <div class="editable-row__value input">
792+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
793+ </div>
794+ <button class="editable-row__delete spot spot--cancel">
795+ Delete
796+ </button>
797+ </div>
798+ </div>
799+ </div>
800+ </div>
801+ <div class="editable-row">
802+ <div class="editable-row__key input">
803+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
804+ </div>
805+ <div class="editable-row__value input">
806+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
807+ </div>
808+ <button class="editable-row__delete spot spot--cancel">
809+ Delete
810+ </button>
811+ </div>
812+ </div>
813+ </div>
814+ </div>
815+ </div>
816+ <div class="editable-row">
817+ <div class="editable-row__key input">
818+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
819+ </div>
820+ <div class="editable-row__value input">
821+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
822+ </div>
823+ <button class="editable-row__delete spot spot--cancel">
824+ Delete
825+ </button>
826+ </div>
827+ </div>
828+ </div>
829+ <div class="collapse collapse--project">
830+ <button class="collapse__head" type="button">
831+ sso
832+ </button>
833+ <div class="collapse__body">
834+ <div class="collapse__inner">
835+ <div class="editable-row">
836+ <div class="editable-row__key input">
837+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
838+ </div>
839+ <div class="editable-row__value input">
840+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
841+ </div>
842+ <button class="editable-row__delete spot spot--cancel">
843+ Delete
844+ </button>
845+ </div>
846+ <div class="collapse collapse--project">
847+ <button class="collapse__head" type="button">
848+ vaultEnv
849+ </button>
850+ <div class="collapse__body">
851+ <div class="collapse__inner">
852+ <div class="editable-row">
853+ <div class="editable-row__key input">
854+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
855+ </div>
856+ <div class="editable-row__value input">
857+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
858+ </div>
859+ <button class="editable-row__delete spot spot--cancel">
860+ Delete
861+ </button>
862+ </div>
863+ <div class="collapse collapse--project">
864+ <button class="collapse__head" type="button">
865+ air-sso.mapping[0]
866+ </button>
867+ <div class="collapse__body">
868+ <div class="collapse__inner">
869+ <div class="editable-row">
870+ <div class="editable-row__key input">
871+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
872+ </div>
873+ <div class="editable-row__value input">
874+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
875+ </div>
876+ <button class="editable-row__delete spot spot--cancel">
877+ Delete
878+ </button>
879+ </div>
880+ <div class="editable-row">
881+ <div class="editable-row__key input">
882+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
883+ </div>
884+ <div class="editable-row__value input">
885+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
886+ </div>
887+ <button class="editable-row__delete spot spot--cancel">
888+ Delete
889+ </button>
890+ </div>
891+ </div>
892+ <div class="editable-row">
893+ <div class="editable-row__key input">
894+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
895+ </div>
896+ <div class="editable-row__value input">
897+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
898+ </div>
899+ <button class="editable-row__delete spot spot--cancel">
900+ Delete
901+ </button>
902+ </div>
903+ </div>
904+ </div>
905+ <div class="collapse collapse--project">
906+ <button class="collapse__head" type="button">
907+ travolutionary.mapping[0]
908+ </button>
909+ <div class="collapse__body">
910+ <div class="collapse__inner">
911+ <div class="editable-row">
912+ <div class="editable-row__key input">
913+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
914+ </div>
915+ <div class="editable-row__value input">
916+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
917+ </div>
918+ <button class="editable-row__delete spot spot--cancel">
919+ Delete
920+ </button>
921+ </div>
922+ <div class="editable-row">
923+ <div class="editable-row__key input">
924+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
925+ </div>
926+ <div class="editable-row__value input">
927+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
928+ </div>
929+ <button class="editable-row__delete spot spot--cancel">
930+ Delete
931+ </button>
932+ </div>
933+ </div>
934+ </div>
935+ </div>
936+ <div class="collapse collapse--project">
937+ <button class="collapse__head" type="button">
938+ travolutionary.mapping[1]
939+ </button>
940+ <div class="collapse__body">
941+ <div class="collapse__inner">
942+ <div class="editable-row">
943+ <div class="editable-row__key input">
944+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
945+ </div>
946+ <div class="editable-row__value input">
947+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
948+ </div>
949+ <button class="editable-row__delete spot spot--cancel">
950+ Delete
951+ </button>
952+ </div>
953+ <div class="editable-row">
954+ <div class="editable-row__key input">
955+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
956+ </div>
957+ <div class="editable-row__value input">
958+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
959+ </div>
960+ <button class="editable-row__delete spot spot--cancel">
961+ Delete
962+ </button>
963+ </div>
964+ </div>
965+ </div>
966+ </div>
967+ <div class="editable-row">
968+ <div class="editable-row__key input">
969+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
970+ </div>
971+ <div class="editable-row__value input">
972+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
973+ </div>
974+ <button class="editable-row__delete spot spot--cancel">
975+ Delete
976+ </button>
977+ </div>
978+ </div>
979+ </div>
980+ </div>
981+ </div>
982+ <div class="editable-row">
983+ <div class="editable-row__key input">
984+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
985+ </div>
986+ <div class="editable-row__value input">
987+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
988+ </div>
989+ <button class="editable-row__delete spot spot--cancel">
990+ Delete
991+ </button>
992+ </div>
993+ </div>
994+ </div>
995+ </div>
996+ </div>
997+ </div>
998+ </section>
999+ <section class="deployment__section">
1000+ <h3 class="deployment__sub-heading">
1001+ Deployment configuration
1002+ </h3>
1003+ <div class="deployment__widget">
1004+ <div class="overrides">
1005+ <button class="overrides__add dash dash--add" type="button">
5241006 Add an override
5251007 </button>
526− <div class="overrides__item">
527− <div class="overrides__key input">
528− <input class="input__widget" type="text" placeholder="key">
529− </div>
530− <div class="overrides__value input">
531− <input class="input__widget" type="text" placeholder="value">
532− </div>
533− <button class="overrides__delete spot spot--cancel">
534− Delete
535− </button>
536− </div>
537− <div class="overrides__item">
538− <div class="overrides__key input">
539− <input class="input__widget" type="text" placeholder="key" value="ENVIRONENT">
540− </div>
541− <div class="overrides__value input">
542− <input class="input__widget" type="text" placeholder="value" value="production">
543− </div>
544− <button class="overrides__delete spot spot--cancel">
545− Delete
546− </button>
547− </div>
548− <div class="overrides__item">
549− <div class="overrides__key input">
550− <input class="input__widget" type="text" placeholder="key" value="app_api_url">
551− </div>
552− <div class="overrides__value input">
553− <input class="input__widget" type="text" placeholder="value" value="http://my-api.my-domain.com">
554− </div>
555− <button class="overrides__delete spot spot--cancel">
556− Delete
557− </button>
558− </div>
559− <div class="overrides__item">
560− <div class="overrides__key input">
561− <input class="input__widget" type="text" placeholder="key" value="SECRET_CODE">
562− </div>
563− <div class="overrides__value input">
564− <input class="input__widget" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
565− </div>
566− <button class="overrides__delete spot spot--cancel">
567− Delete
568− </button>
1008+ <div class="overrides__list">
1009+ <div class="editable-row">
1010+ <div class="editable-row__key input">
1011+ <input class="input__widget" type="text" placeholder="key">
1012+ </div>
1013+ <div class="editable-row__value input">
1014+ <input class="input__widget" type="text" placeholder="value">
1015+ </div>
1016+ <button class="editable-row__delete spot spot--cancel">
1017+ Delete
1018+ </button>
1019+ </div>
1020+ <div class="editable-row">
1021+ <div class="editable-row__key input">
1022+ <input class="input__widget key-custom-edited" type="text" placeholder="key" value="ENVIRONENT">
1023+ </div>
1024+ <div class="editable-row__value input">
1025+ <input class="input__widget value-edited" type="text" placeholder="value" value="production">
1026+ </div>
1027+ <button class="editable-row__delete spot spot--cancel">
1028+ Delete
1029+ </button>
1030+ </div>
1031+ <div class="editable-row">
1032+ <div class="editable-row__key input">
1033+ <input class="input__widget key-custom-edited" type="text" placeholder="key" value="app_api_url">
1034+ </div>
1035+ <div class="editable-row__value input">
1036+ <input class="input__widget value-edited" type="text" placeholder="value" value="http://my-api.my-domain.com">
1037+ </div>
1038+ <button class="editable-row__delete spot spot--cancel">
1039+ Delete
1040+ </button>
1041+ </div>
1042+ <div class="editable-row">
1043+ <div class="editable-row__key input">
1044+ <input class="input__widget key-default-pristine" type="text" placeholder="key" value="SECRET_CODE">
1045+ </div>
1046+ <div class="editable-row__value input">
1047+ <input class="input__widget value-edited" type="text" placeholder="value" value="asdfaisdjri235868ear7%^&IUAK$^%&asdfasdfij">
1048+ </div>
1049+ <button class="editable-row__delete spot spot--cancel">
1050+ Delete
1051+ </button>
1052+ </div>
1053+ </div>
1054+ </div>
1055+ </div>
1056+ </section>
1057+ </div>
1058+ <!-- temp -->
1059+ или:
1060+ <!--/temp -->
1061+ <div class="no-deployment">
1062+ <div class="null null--data">
1063+ <div class="null__content">
1064+ <b class="null__heading">Cannot retrieve the data</b>
1065+ <div class="null__message">Try to reload page</div>
1066+ </div>
1067+ </div>
1068+ <!-- temp -->
1069+ &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
1070+ <!--/temp -->
1071+ <div class="loading loading--enlarged loading--alternate">
1072+ Loading...
1073+ </div>
1074+ </div>
5691075 </div>
570− </div>
5711076 </div>
572− </section>
5731077 </div>
574− <!-- temp -->
575− или:
576− <!--/temp -->
577− <div class="no-deployment">
578− <div class="null null--data">
579− <div class="null__content">
580− <b class="null__heading">Cannot retrieve the data</b>
581− <div class="null__message">Try to reload page</div>
582− </div>
583− </div>
584− <!-- temp -->
585− &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
586− <!--/temp -->
587− <div class="loading loading--enlarged loading--alternate">
588− Loading...
589− </div>
590− </div>
591− </div>
592− </div>
593− </div>
5941078
5951079
596− <div class="popup" id="log">
597− <div class="popup__overlay" aria-hidden="true">
598− Close popup
599− </div>
600− <div class="popup__body">
601− <div class="popup__head">
602− <button class="popup__close" type="button">
1080+ <div class="popup" id="log">
1081+ <div class="popup__overlay" aria-hidden="true">
1082+ Close popup
1083+ </div>
1084+ <div class="popup__body">
1085+ <div class="popup__head">
1086+ <button class="popup__close" type="button">
6031087 Close popup
6041088 </button>
605− <h2 class="popup__project">
606− Project name, logs
607− </h2>
608− </div>
609− <div class="popup__sub-head">
610− <div class="nav">
611− <button class="nav__link nav__link--current" type="button">stdout</button>
612− <button class="nav__link" type="button">stderr</button>
613− </div>
614− </div>
615− <div class="popup__content">
616− <div class="log">
617− DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/libiserv/dist-install/build:/Users/dr/workspace/ghc/libraries/ghci/dist-install/build:/Users/dr/workspace/ghc/libraries/transformers/dist-install/build:/Users/dr/workspace/ghc/libraries/template-haskell/dist-install/build:/Users/dr/workspace/ghc/libraries/pretty/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-heap/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot-th/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/binary/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
618− >> inplace/lib/bin/ghc-iserv-dyn
619− <br>"rm" -f inplace/bin/runghc
620− <br>echo 'exec "$executablename" ${1+"$@"}' >> inplace/lib/bin/ghc-iserv-dyn
621− <br>echo '#!/bin/sh' >> inplace/bin/runghc
622− <br>chmod +x inplace/lib/bin/ghc-iserv-dyn
623− <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/runghc"' >> inplace/bin/runghc
624− <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
625− <br>/usr/local/bin/ginstall -c -m 755 utils/hpc/dist-install/build/tmp/hpc inplace/lib/bin/hpc
626− <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/runghc
627− <br>"rm" -f inplace/bin/hpc
628− <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
629− <br>echo 'pgmgcc="cc"' >> inplace/bin/runghc
630− <br>echo '#!/bin/sh' >> inplace/bin/hpc
631− <br>echo 'ghcprog="ghc-stage2"' >> "inplace/bin/runghc"
632− <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/hpc"' >> inplace/bin/hpc
633− <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/process/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
634− >> inplace/bin/runghc
635− <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
636− <br>cat utils/runghc/runghc.wrapper >> inplace/bin/runghc
637− <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/hpc
638− <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
639− <br>chmod +x inplace/bin/runghc
640− <br>echo 'pgmgcc="cc"' >> inplace/bin/hpc
641− <br>"rm" -f utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
642− <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/hpc/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
643− >> inplace/bin/hpc
644− <br>echo '#!/bin/sh' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
645− <br>cat utils/hpc/hpc.wrapper >> inplace/bin/hpc
646− <br>echo 'export DYLD_LIBRARY_PATH="libraries/Cabal/Cabal/dist-install/build:libraries/process/dist-install/build:libraries/parsec/dist-install/build:libraries/text/dist-install/build:libraries/template-haskell/dist-install/build:libraries/pretty/dist-install/build:libraries/ghc-boot-th/dist-install/build:libraries/mtl/dist-install/build:libraries/transformers/dist-install/build:libraries/directory/dist-install/build:libraries/unix/dist-install/build:libraries/time/dist-install/build:libraries/filepath/dist-install/build:libraries/binary/dist-install/build:libraries/containers/containers/dist-install/build:libraries/bytestring/dist-install/build:libraries/deepseq/dist-install/build:libraries/array/dist-install/build:libraries/base/dist-install/build:libraries/ghc-bignum/dist-install/build:libraries/ghc-prim/dist-install/build:rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
647− >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
648− <br>chmod +x inplace/bin/hpc
649− <br>echo 'exec "utils/ghc-cabal/dist-install/build/tmp/ghc-cabal" ${1+"$@"}' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
650− <br>chmod +x utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
651− <br>
652− <<ghc: 2787765536 bytes, 171 GCs, 20282449/67935792 avg/max bytes residency (8 samples), 144M in use, 0.000 INIT (0.003 elapsed), 1.738 MUT (2.286 elapsed), 0.567 GC (0.611 elapsed) :ghc>>
653− <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages -i
654− -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
655− -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0 -package-id
656− binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619 -package-id
657− ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id time-1.9.3
658− -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
659− -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/HsToCore.hs -o compiler/stage2/build/GHC/HsToCore.o
660− -dyno compiler/stage2/build/GHC/HsToCore.dyn_o
661− <br>
662− <<ghc: 766891168 bytes, 91 GCs, 14722329/42245856 avg/max bytes residency (6 samples), 91M in use, 0.000 INIT (0.003 elapsed), 0.361 MUT (0.510 elapsed), 0.236 GC (0.258 elapsed) :ghc>>
663− <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
664− -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
665− -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0
666− -package-id binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619
667− -package-id ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id
668− time-1.9.3 -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
669− -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/Iface/Ext/Ast.hs -o compiler/stage2/build/GHC/Iface/Ext/Ast.o
670− -dyno compiler/stage2/build/GHC/Iface/Ext/Ast.dyn_o
671− <br>
672− <<ghc: 3067019736 bytes, 347 GCs, 25353490/71392248 avg/max bytes residency (8 samples), 184M in use, 0.000 INIT (0.002 elapsed), 1.416 MUT (1.823 elapsed), 0.554 GC (0.595 elapsed) :ghc>>
673− <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
674− -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompil...
675− </div>
676− <!-- temp -->
677− или:
678− <!--/temp -->
679− <div class="no-log">
680− <div class="null null--data">
681− <div class="null__content">
682− <b class="null__heading">Cannot retrieve the data</b>
683− <div class="null__message">Try to reload page</div>
1089+ <h2 class="popup__project">
1090+ Project name, logs
1091+ </h2>
1092+ </div>
1093+ <div class="popup__sub-head">
1094+ <div class="nav">
1095+ <button class="nav__link nav__link--current" type="button">stdout</button>
1096+ <button class="nav__link" type="button">stderr</button>
1097+ </div>
1098+ </div>
1099+ <div class="popup__content">
1100+ <div class="log">
1101+ DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/libiserv/dist-install/build:/Users/dr/workspace/ghc/libraries/ghci/dist-install/build:/Users/dr/workspace/ghc/libraries/transformers/dist-install/build:/Users/dr/workspace/ghc/libraries/template-haskell/dist-install/build:/Users/dr/workspace/ghc/libraries/pretty/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-heap/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-boot-th/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/binary/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
1102+ >> inplace/lib/bin/ghc-iserv-dyn
1103+ <br>"rm" -f inplace/bin/runghc
1104+ <br>echo 'exec "$executablename" ${1+"$@"}' >> inplace/lib/bin/ghc-iserv-dyn
1105+ <br>echo '#!/bin/sh' >> inplace/bin/runghc
1106+ <br>chmod +x inplace/lib/bin/ghc-iserv-dyn
1107+ <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/runghc"' >> inplace/bin/runghc
1108+ <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
1109+ <br>/usr/local/bin/ginstall -c -m 755 utils/hpc/dist-install/build/tmp/hpc inplace/lib/bin/hpc
1110+ <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/runghc
1111+ <br>"rm" -f inplace/bin/hpc
1112+ <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/runghc
1113+ <br>echo 'pgmgcc="cc"' >> inplace/bin/runghc
1114+ <br>echo '#!/bin/sh' >> inplace/bin/hpc
1115+ <br>echo 'ghcprog="ghc-stage2"' >> "inplace/bin/runghc"
1116+ <br>echo 'executablename="/Users/dr/workspace/ghc/inplace/lib/bin/hpc"' >> inplace/bin/hpc
1117+ <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/process/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
1118+ >> inplace/bin/runghc
1119+ <br>echo 'datadir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
1120+ <br>cat utils/runghc/runghc.wrapper >> inplace/bin/runghc
1121+ <br>echo 'bindir="/Users/dr/workspace/ghc/inplace/bin"' >> inplace/bin/hpc
1122+ <br>echo 'topdir="/Users/dr/workspace/ghc/inplace/lib"' >> inplace/bin/hpc
1123+ <br>chmod +x inplace/bin/runghc
1124+ <br>echo 'pgmgcc="cc"' >> inplace/bin/hpc
1125+ <br>"rm" -f utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
1126+ <br>echo 'export DYLD_LIBRARY_PATH="/Users/dr/workspace/ghc/libraries/hpc/dist-install/build:/Users/dr/workspace/ghc/libraries/directory/dist-install/build:/Users/dr/workspace/ghc/libraries/unix/dist-install/build:/Users/dr/workspace/ghc/libraries/time/dist-install/build:/Users/dr/workspace/ghc/libraries/filepath/dist-install/build:/Users/dr/workspace/ghc/libraries/containers/containers/dist-install/build:/Users/dr/workspace/ghc/libraries/bytestring/dist-install/build:/Users/dr/workspace/ghc/libraries/deepseq/dist-install/build:/Users/dr/workspace/ghc/libraries/array/dist-install/build:/Users/dr/workspace/ghc/libraries/base/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-bignum/dist-install/build:/Users/dr/workspace/ghc/libraries/ghc-prim/dist-install/build:/Users/dr/workspace/ghc/rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
1127+ >> inplace/bin/hpc
1128+ <br>echo '#!/bin/sh' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
1129+ <br>cat utils/hpc/hpc.wrapper >> inplace/bin/hpc
1130+ <br>echo 'export DYLD_LIBRARY_PATH="libraries/Cabal/Cabal/dist-install/build:libraries/process/dist-install/build:libraries/parsec/dist-install/build:libraries/text/dist-install/build:libraries/template-haskell/dist-install/build:libraries/pretty/dist-install/build:libraries/ghc-boot-th/dist-install/build:libraries/mtl/dist-install/build:libraries/transformers/dist-install/build:libraries/directory/dist-install/build:libraries/unix/dist-install/build:libraries/time/dist-install/build:libraries/filepath/dist-install/build:libraries/binary/dist-install/build:libraries/containers/containers/dist-install/build:libraries/bytestring/dist-install/build:libraries/deepseq/dist-install/build:libraries/array/dist-install/build:libraries/base/dist-install/build:libraries/ghc-bignum/dist-install/build:libraries/ghc-prim/dist-install/build:rts/dist/build${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"'
1131+ >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
1132+ <br>chmod +x inplace/bin/hpc
1133+ <br>echo 'exec "utils/ghc-cabal/dist-install/build/tmp/ghc-cabal" ${1+"$@"}' >> utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
1134+ <br>chmod +x utils/ghc-cabal/dist-install/build/tmp/ghc-cabal-bindist
1135+ <br>
1136+ <
1137+ <ghc: 2787765536 bytes, 171 GCs, 20282449
1138+ /67935792 avg/max bytes residency (8 samples), 144M in use, 0.000 INIT (0.003 elapsed), 1.738 MUT (2.286 elapsed), 0.567 GC (0.611 elapsed) :ghc>>
1139+ <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages -i
1140+ -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
1141+ -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0 -package-id
1142+ binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619 -package-id
1143+ ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id time-1.9.3
1144+ -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
1145+ -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/HsToCore.hs -o compiler/stage2/build/GHC/HsToCore.o
1146+ -dyno compiler/stage2/build/GHC/HsToCore.dyn_o
1147+ <br>
1148+ <
1149+ <ghc: 766891168 bytes, 91 GCs, 14722329
1150+ /42245856 avg/max bytes residency (6 samples), 91M in use, 0.000 INIT (0.003 elapsed), 0.361 MUT (0.510 elapsed), 0.236 GC (0.258 elapsed) :ghc>>
1151+ <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
1152+ -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompiler/stage2/build/../rts/dist/build
1153+ -Icompiler/stage2/build/stage2 -optP-DHAVE_INTERNAL_INTERPRETER -optP-DCAN_LOAD_DLL -optP-Iincludes/dist-install/build -optP-include -optPcompiler/stage2/build/./autogen/cabal_macros.h -package-id array-0.5.4.0 -package-id base-4.15.0.0
1154+ -package-id binary-0.8.7.0 -package-id bytestring-0.10.10.0 -package-id containers-0.6.2.1 -package-id deepseq-1.4.4.0 -package-id directory-1.3.6.1 -package-id exceptions-0.10.4 -package-id filepath-1.4.2.1 -package-id ghc-boot-8.11.0.20200619
1155+ -package-id ghc-boot-th-8.11.0.20200619 -package-id ghc-heap-8.11.0.20200619 -package-id ghci-8.11.0.20200619 -package-id hpc-0.6.1.0 -package-id process-1.6.8.2 -package-id template-haskell-2.17.0.0 -package-id terminfo-0.4.1.4 -package-id
1156+ time-1.9.3 -package-id transformers-0.5.6.2 -package-id unix-2.7.2.2 -Wall -Wno-name-shadowing -Wnoncanonical-monad-instances -Wnoncanonical-monoid-instances -this-unit-id ghc -XHaskell2010 -XNoImplicitPrelude -optc-DTHREADED_RTS -Iincludes/dist-install/build
1157+ -Rghc-timing -O0 -Wcpp-undef -Wincomplete-uni-patterns -Wincomplete-record-updates -no-user-package-db -rtsopts -Wnoncanonical-monad-instances -outputdir compiler/stage2/build -dynamic-too -c compiler/./GHC/Iface/Ext/Ast.hs -o compiler/stage2/build/GHC/Iface/Ext/Ast.o
1158+ -dyno compiler/stage2/build/GHC/Iface/Ext/Ast.dyn_o
1159+ <br>
1160+ <
1161+ <ghc: 3067019736 bytes, 347 GCs, 25353490
1162+ /71392248 avg/max bytes residency (8 samples), 184M in use, 0.000 INIT (0.002 elapsed), 1.416 MUT (1.823 elapsed), 0.554 GC (0.595 elapsed) :ghc>>
1163+ <br>"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -O0 -H64m -Wall -Iincludes -Iincludes/dist -Iincludes/dist-derivedconstants/header -Iincludes/dist-ghcconstants/header -this-unit-id ghc-8.11.0.20200619 -hide-all-packages
1164+ -i -icompiler/. -icompiler/stage2/build -Icompiler/stage2/build -icompiler/stage2/build/./autogen -Icompiler/stage2/build/./autogen -Icompiler/. -Icompiler/../rts/dist/build -Icompiler/stage2 -Icompiler/stage2/build/. -Icompil...
1165+ </div>
1166+ <!-- temp -->
1167+ или:
1168+ <!--/temp -->
1169+ <div class="no-log">
1170+ <div class="null null--data">
1171+ <div class="null__content">
1172+ <b class="null__heading">Cannot retrieve the data</b>
1173+ <div class="null__message">Try to reload page</div>
1174+ </div>
1175+ </div>
1176+ <!-- temp -->
1177+ &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
1178+ <!--/temp -->
1179+ <div class="loading loading--enlarged loading--alternate">
1180+ Loading...
1181+ </div>
1182+ </div>
1183+ </div>
6841184 </div>
685− </div>
686− <!-- temp -->
687− &nbsp;&nbsp;&nbsp;&nbsp;или&nbsp;&nbsp;&nbsp;&nbsp;
688− <!--/temp -->
689− <div class="loading loading--enlarged loading--alternate">
690− Loading...
691− </div>
6921185 </div>
693− </div>
694− </div>
695− </div>
6961186
697− <div class="classic-popup" id="dialog">
698− <div class="classic-popup__container">
699− <div class="classic-popup__viewport">
700− <div class="classic-popup__slot">
1187+ <div class="classic-popup" id="dialog">
1188+ <div class="classic-popup__container">
1189+ <div class="classic-popup__viewport">
1190+ <div class="classic-popup__slot">
7011191
702− <div class="dialog dialog--archive">
703− <div class="dialog__content">
704− Are you sure you want to archive the
705− <br>‘Feature name’ deployment?
706− </div>
707− <div class="dialog__footer">
708− <button class="dialog__action button" type="submit">Archive</button>
709− <button class="dialog__action button--secondary button" type="button">Cancel</button>
710− </div>
711− </div>
1192+ <div class="dialog dialog--archive">
1193+ <div class="dialog__content">
1194+ Are you sure you want to archive the
1195+ <br>‘Feature name’ deployment?
1196+ </div>
1197+ <div class="dialog__footer">
1198+ <button class="dialog__action button" type="submit">Archive</button>
1199+ <button class="dialog__action button--secondary button" type="button">Cancel</button>
1200+ </div>
1201+ </div>
7121202
713− <button class="classic-popup__close" type="button">
1203+ <button class="classic-popup__close" type="button">
7141204 Close
7151205 </button>
1206+ </div>
1207+ </div>
1208+ </div>
7161209 </div>
717− </div>
718− </div>
719− </div>
7201210
7211211
722− <!-- jQuery -->
723− <script src="../vendors/jquery/jquery-3.2.1.min.js"></script>
1212+ <!-- jQuery -->
1213+ <script src="../vendors/jquery/jquery-3.2.1.min.js"></script>
7241214
725− <!-- Outline.js -->
726− <script src="../vendors/outline/outline.js"></script>
1215+ <!-- Outline.js -->
1216+ <script src="../vendors/outline/outline.js"></script>
7271217
728− <!-- Temp -->
729− <script src="../scripts/_expander.js"></script>
730− <script src="../scripts/_drop.js"></script>
731− <script src="../scripts/_sort.js"></script>
732− <script src="../scripts/_data.js"></script>
733− <script src="../scripts/_popup.js"></script>
734− <script src="../scripts/_classic-popup.js"></script>
1218+ <!-- Temp -->
1219+ <script src="../scripts/_expander.js"></script>
1220+ <script src="../scripts/_drop.js"></script>
1221+ <script src="../scripts/_sort.js"></script>
1222+ <script src="../scripts/_data.js"></script>
1223+ <script src="../scripts/_popup.js"></script>
1224+ <script src="../scripts/_classic-popup.js"></script>
1225+ <script src="../scripts/_collapse.js"></script>
7351226
736−</body>
1227+ </body>
7371228
738−</html>
1229+</html>
octopod-css/development/markups/_action.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.action</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -104,6 +104,7 @@
104104 <script src="../scripts/_data.js"></script>
105105 <script src="../scripts/_popup.js"></script>
106106 <script src="../scripts/_classic-popup.js"></script>
107+ <script src="../scripts/_collapse.js"></script>
107108
108109 </body>
109110</html>
octopod-css/development/markups/_bar.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.bar</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -53,6 +53,7 @@
5353 <script src="../scripts/_data.js"></script>
5454 <script src="../scripts/_popup.js"></script>
5555 <script src="../scripts/_classic-popup.js"></script>
56+ <script src="../scripts/_collapse.js"></script>
5657
5758 </body>
5859</html>
octopod-css/development/markups/_break.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.break</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111
@@ -76,6 +76,7 @@
7676 <script src="../scripts/_data.js"></script>
7777 <script src="../scripts/_popup.js"></script>
7878 <script src="../scripts/_classic-popup.js"></script>
79+ <script src="../scripts/_collapse.js"></script>
7980
8081
8182 </body>
octopod-css/development/markups/_button.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.button</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111
@@ -128,6 +128,7 @@
128128 <script src="../scripts/_data.js"></script>
129129 <script src="../scripts/_popup.js"></script>
130130 <script src="../scripts/_classic-popup.js"></script>
131+ <script src="../scripts/_collapse.js"></script>
131132
132133
133134 </body>
octopod-css/development/markups/_collapse.htmlnew file+277
@@ -0,0 +1,277 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="utf-8">
5+ <meta http-equiv="x-ua-compatible" content="ie=edge">
6+ <title>.collapse</title>
7+ <meta name="viewport" content="width=device-width, initial-scale=1">
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
9+ <link rel="stylesheet" href="../styles/style.css">
10+ </head>
11+ <body>
12+
13+
14+
15+ <div style="width: 600px; margin: 0 auto;">
16+ <br>
17+ <br>
18+ <br>
19+ <br>
20+ <h1>.collapse</h1>
21+
22+ <p>
23+ Это функциональный блок. Кликаем в <b>.collapse__head</b>
24+ -- раскрывается <b>.collapse__body</b>.
25+ </p>
26+ <p>
27+ Дефолтная версия выглядит никак:
28+ </p>
29+ <br>
30+ <br>
31+
32+
33+ <div class="collapse">
34+ <button class="collapse__head" type="button">
35+ Шапка
36+ </button>
37+ <div class="collapse__body">
38+ Тело
39+ </div>
40+ </div>
41+
42+ <br>
43+ <br>
44+ <br>
45+ <p>
46+ Оформление добавляем модификаторами-скинами (см. ниже).
47+ </p>
48+
49+ <p>
50+ Раскрываем <b>.collapse__body</b> вручную и так же добавляем <b>.collapse--expanded</b>.
51+ </p>
52+
53+
54+
55+
56+
57+ <br>
58+ <br>
59+ <br>
60+ <br>
61+ <h2>.collapse--project</h2>
62+ <p>
63+ Внутри обычно используется <b>.row</b>
64+ </p>
65+
66+ <div class="collapse collapse--project">
67+ <button class="collapse__head" type="button">
68+ travolutionary.mapping[1]
69+ </button>
70+ <div class="collapse__body">
71+ <div class="collapse__inner">
72+ <div class="row">
73+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
74+ </div>
75+ <div class="row">
76+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
77+ </div>
78+ </div>
79+ </div>
80+ </div>
81+
82+
83+ <p>
84+ Можно вкладывать любое количество <b>.collapse</b> и <b>.row</b> друг в друга,
85+ в любом порядке, в любых комбинациях. Ещё можно добавлять<br> класс <b>.collapse__head--has-changes</b>
86+ </p>
87+
88+ <div class="collapse collapse--project">
89+ <button class="collapse__head collapse__head--has-changes" type="button">
90+ air
91+ </button>
92+ <div class="collapse__body">
93+ <div class="collapse__inner">
94+ <div class="row">
95+ <span class="key-default-pristine">vaultEngineName: </span><span class="value-pristine">staging</span>
96+ </div>
97+ <div class="collapse collapse--project">
98+ <button class="collapse__head collapse__head--has-changes" type="button">
99+ vaultEnv
100+ </button>
101+ <div class="collapse__body">
102+ <div class="collapse__inner">
103+ <div class="row">
104+ <span class="key-default-pristine">air-sso.engineOverride: </span><span class="value-pristine">staging</span>
105+ </div>
106+ <div class="collapse collapse--project">
107+ <button class="collapse__head" type="button">
108+ air-sso.mapping[0]
109+ </button>
110+ <div class="collapse__body">
111+ <div class="collapse__inner">
112+ <div class="row">
113+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
114+ </div>
115+ <div class="row">
116+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
117+ </div>
118+ </div>
119+ <div class="row">
120+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
121+ </div>
122+ </div>
123+ </div>
124+ <div class="collapse collapse--project">
125+ <button class="collapse__head collapse__head--has-changes" type="button">
126+ travolutionary.mapping[0]
127+ </button>
128+ <div class="collapse__body">
129+ <div class="collapse__inner">
130+ <div class="row">
131+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
132+ </div>
133+ <div class="row">
134+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
135+ </div>
136+ </div>
137+ </div>
138+ </div>
139+ <div class="collapse collapse--project">
140+ <button class="collapse__head collapse__head--has-changes" type="button">
141+ travolutionary.mapping[1]
142+ </button>
143+ <div class="collapse__body">
144+ <div class="collapse__inner">
145+ <div class="row">
146+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
147+ </div>
148+ <div class="row">
149+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
150+ </div>
151+ </div>
152+ </div>
153+ </div>
154+ <div class="row">
155+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
156+ </div>
157+ </div>
158+ </div>
159+ </div>
160+ </div>
161+ <div class="row">
162+ <span class="key-custom-edited">app_api_url: </span><span class="value-edited">http: //my-api.my-domain.com</span>
163+ </div>
164+ </div>
165+ </div>
166+ <div class="collapse collapse--project">
167+ <button class="collapse__head" type="button">
168+ sso
169+ </button>
170+ <div class="collapse__body">
171+ <div class="collapse__inner">
172+ <div class="row">
173+ <span class="key-default-pristine">vaultEngineName: </span><span class="value-pristine">staging</span>
174+ </div>
175+ <div class="collapse collapse--project">
176+ <button class="collapse__head" type="button">
177+ vaultEnv
178+ </button>
179+ <div class="collapse__body">
180+ <div class="collapse__inner">
181+ <div class="row">
182+ <span class="key-default-pristine">air-sso.engineOverride: </span><span class="value-pristine">staging</span>
183+ </div>
184+ <div class="collapse collapse--project">
185+ <button class="collapse__head" type="button">
186+ air-sso.mapping[0]
187+ </button>
188+ <div class="collapse__body">
189+ <div class="collapse__inner">
190+ <div class="row">
191+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
192+ </div>
193+ <div class="row">
194+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
195+ </div>
196+ </div>
197+ <div class="row">
198+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
199+ </div>
200+ </div>
201+ </div>
202+ <div class="collapse collapse--project">
203+ <button class="collapse__head" type="button">
204+ travolutionary.mapping[0]
205+ </button>
206+ <div class="collapse__body">
207+ <div class="collapse__inner">
208+ <div class="row">
209+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
210+ </div>
211+ <div class="row">
212+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
213+ </div>
214+ </div>
215+ </div>
216+ </div>
217+ <div class="collapse collapse--project">
218+ <button class="collapse__head" type="button">
219+ travolutionary.mapping[1]
220+ </button>
221+ <div class="collapse__body">
222+ <div class="collapse__inner">
223+ <div class="row">
224+ <span class="key-default-edited">name: </span><span class="value-edited">SSO_CLIENT_ID</span>
225+ </div>
226+ <div class="row">
227+ <span class="key-default-pristine">key: </span><span class="value-pristine">clientId</span>
228+ </div>
229+ </div>
230+ </div>
231+ </div>
232+ <div class="row">
233+ <span class="key-default-edited">air-sso.mapping[1].name: </span><span class="value-edited">SSO_CLIENT_SECRET</span>
234+ </div>
235+ </div>
236+ </div>
237+ </div>
238+ </div>
239+ <div class="row">
240+ <span class="key-custom-edited">app_api_url: </span><span class="value-edited">http: //my-api.my-domain.com</span>
241+ </div>
242+ </div>
243+ </div>
244+
245+
246+ <br>
247+ <br>
248+ <br>
249+ <br>
250+ <br>
251+ <br>
252+ <br>
253+ <br>
254+ <br>
255+ <br>
256+ <br>
257+ </div>
258+
259+
260+
261+ <!-- jQuery -->
262+ <script src="../vendors/jquery/jquery-3.2.1.min.js"></script>
263+
264+ <!-- Outline.js -->
265+ <script src="../vendors/outline/outline.js"></script>
266+
267+ <!-- Temp -->
268+ <script src="../scripts/_expander.js"></script>
269+ <script src="../scripts/_drop.js"></script>
270+ <script src="../scripts/_sort.js"></script>
271+ <script src="../scripts/_data.js"></script>
272+ <script src="../scripts/_popup.js"></script>
273+ <script src="../scripts/_classic-popup.js"></script>
274+ <script src="../scripts/_collapse.js"></script>
275+
276+ </body>
277+</html>
octopod-css/development/markups/_dash.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.dash</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111
@@ -121,6 +121,7 @@
121121 <script src="../scripts/_data.js"></script>
122122 <script src="../scripts/_popup.js"></script>
123123 <script src="../scripts/_classic-popup.js"></script>
124+ <script src="../scripts/_collapse.js"></script>
124125
125126
126127 </body>
octopod-css/development/markups/_drop.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.drop</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -104,6 +104,7 @@
104104 <script src="../scripts/_data.js"></script>
105105 <script src="../scripts/_popup.js"></script>
106106 <script src="../scripts/_classic-popup.js"></script>
107+ <script src="../scripts/_collapse.js"></script>
107108
108109 </body>
109110</html>
octopod-css/development/markups/_expander.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.expander</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -88,6 +88,7 @@
8888 <script src="../scripts/_data.js"></script>
8989 <script src="../scripts/_popup.js"></script>
9090 <script src="../scripts/_classic-popup.js"></script>
91+ <script src="../scripts/_collapse.js"></script>
9192
9293 </body>
9394</html>
octopod-css/development/markups/_external.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.external</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -53,6 +53,7 @@
5353 <script src="../scripts/_data.js"></script>
5454 <script src="../scripts/_popup.js"></script>
5555 <script src="../scripts/_classic-popup.js"></script>
56+ <script src="../scripts/_collapse.js"></script>
5657
5758 </body>
5859</html>
octopod-css/development/markups/_input.html+36−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.input</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111
@@ -72,6 +72,40 @@
7272 </div>
7373
7474
75+ <br>
76+ <br>
77+ <br>
78+ <h2>Выпадайка</h2>
79+
80+ <div class="input">
81+ <input class="input__widget" type="text" placeholder="key" value="LiveSearch">
82+ <ul class="input__dropdown">
83+ <li class="input__suggest"><b>S</b>ECRET_PASSWORD</li>
84+ <li class="input__suggest"><b>S</b>ECRET_INFO</li>
85+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
86+ </li>
87+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
88+ </li>
89+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
90+ </li>
91+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
92+ </li>
93+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
94+ </li>
95+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
96+ </li>
97+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
98+ </li>
99+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
100+ </li>
101+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
102+ </li>
103+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
104+ </li>
105+ <li class="input__suggest"><b>S</b>oviet Socialist Republics
106+ </li>
107+ </ul>
108+ </div>
75109
76110 <br>
77111 <br>
@@ -102,6 +136,7 @@
102136 <script src="../scripts/_data.js"></script>
103137 <script src="../scripts/_popup.js"></script>
104138 <script src="../scripts/_classic-popup.js"></script>
139+ <script src="../scripts/_collapse.js"></script>
105140
106141
107142 </body>
octopod-css/development/markups/_keys-and-values.htmlnew file+373
@@ -0,0 +1,373 @@
1+<!DOCTYPE html>
2+<html lang="en">
3+ <head>
4+ <meta charset="utf-8">
5+ <meta http-equiv="x-ua-compatible" content="ie=edge">
6+ <title>Keys and values</title>
7+ <meta name="viewport" content="width=device-width, initial-scale=1">
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
9+ <link rel="stylesheet" href="../styles/style.css">
10+ </head>
11+ <body>
12+
13+
14+
15+ <div style="width: 800px; margin: 0 auto;">
16+ <br>
17+ <br>
18+ <br>
19+ <br>
20+ <h1>Keys and values</h1>
21+
22+
23+ <span class="key-default-pristine">
24+ air.vaultEngineName:
25+ </span>
26+
27+
28+ <br>
29+ <br>
30+ <br>
31+ <h2>Классы</h2>
32+
33+ <div class="table">
34+ <table>
35+ <tbody>
36+ <tr>
37+ <td>
38+ Ключ по умолчанию, значение не изменено:
39+ </td>
40+ <td>
41+ <span class="key-default-pristine">key-default-pristine</span>
42+ </td>
43+ <td>
44+ <span class="value-pristine">value-pristine</span>
45+ </td>
46+ </tr>
47+ <tr>
48+ <td>
49+ Ключ по умолчанию, значение изменено:
50+ </td>
51+ <td>
52+ <span class="key-default-edited">key-default-edited</span>
53+ </td>
54+ <td>
55+ <span class="value-edited">value-edited</span>
56+ </td>
57+ </tr>
58+ <tr>
59+ <td>
60+ Ключ кастомный, значение изменено:
61+ </td>
62+ <td>
63+ <span class="key-custom-edited">key-custom-edited</span>
64+ </td>
65+ <td>
66+ <span class="value-edited">value-edited</span>
67+ </td>
68+ </tr>
69+ <tr>
70+ <td>
71+ Ключ и значение удалены:
72+ </td>
73+ <td>
74+ <span class="key-deleted">key-deleted</span>
75+ </td>
76+ <td>
77+ <span class="value-deleted">value-deleted</span>
78+ </td>
79+ </tr>
80+ <tr>
81+ <td>
82+ Ключ удалён, значение неизвестно:
83+ </td>
84+ <td>
85+ <span class="key-deleted">key-deleted</span>
86+ </td>
87+ <td>
88+ <span class="value-unknown">unknown</span> (value-unknown)
89+ </td>
90+ </tr>
91+ </tbody>
92+ </table>
93+ </div>
94+
95+
96+ <br>
97+ <br>
98+ <h2>Примеры</h2>
99+
100+ <div class="table">
101+ <table>
102+ <tbody>
103+ <tr>
104+ <td>
105+ Ключ по умолчанию, значение не изменено:
106+ </td>
107+ <td>
108+ <span class="key-default-pristine">air.vaultEngineName:</span>
109+ </td>
110+ <td>
111+ <span class="value-pristine">staging</span>
112+ </td>
113+ </tr>
114+ <tr>
115+ <td>
116+ Ключ по умолчанию, значение изменено:
117+ </td>
118+ <td>
119+ <span class="key-default-edited">air.vaultEngineName:</span>
120+ </td>
121+ <td>
122+ <span class="value-edited">staging</span>
123+ </td>
124+ </tr>
125+ <tr>
126+ <td>
127+ Ключ кастомный, значение изменено:
128+ </td>
129+ <td>
130+ <span class="key-custom-edited">app_api_url:</span>
131+ </td>
132+ <td>
133+ <span class="value-edited">http://my-api.my-domain.com</span>
134+ </td>
135+ </tr>
136+ <tr>
137+ <td>
138+ Ключ и значение удалены:
139+ </td>
140+ <td>
141+ <span class="key-deleted">sso.vaultEnv.hotels-sso.mapping[0].APP_URL</span>
142+ </td>
143+ <td>
144+ <span class="value-deleted">http://my-api.my-domain.com</span>
145+ </td>
146+ </tr>
147+ <tr>
148+ <td>
149+ Ключ удалён, значение неизвестно:
150+ </td>
151+ <td>
152+ <span class="key-deleted">air.vaultEnv.air-sso:</span>
153+ </td>
154+ <td>
155+ <span class="value-unknown">unknown</span>
156+ </td>
157+ </tr>
158+ </tbody>
159+ </table>
160+ </div>
161+
162+ <br>
163+ <br>
164+ <p>
165+ Для экономии узлов в DOM-дереве можно не создавать отдельную обёртку &lt;span&gt;...&lt;/span&gt;
166+ а вешать эти классы прям на ячейки таблицы, или на любого другого родителя.
167+ Работает со всеми классами кроме <b>.value-unknown</b> -- это отдельный компонент.
168+ </p>
169+
170+ <div class="table">
171+ <table>
172+ <tbody>
173+ <tr>
174+ <td>
175+ Ключ по умолчанию, значение не изменено:
176+ </td>
177+ <td class="key-default-pristine">
178+ air.vaultEngineName:
179+ </td>
180+ <td class="value-pristine">
181+ staging
182+ </td>
183+ </tr>
184+ <tr>
185+ <td>
186+ Ключ по умолчанию, значение изменено:
187+ </td>
188+ <td class="key-default-edited">
189+ air.vaultEngineName:
190+ </td>
191+ <td class="value-edited">
192+ staging
193+ </td>
194+ </tr>
195+ <tr>
196+ <td>
197+ Ключ кастомный, значение изменено:
198+ </td>
199+ <td class="key-custom-edited">
200+ app_api_url:
201+ </td>
202+ <td class="value-edited">
203+ http://my-api.my-domain.com
204+ </td>
205+ </tr>
206+ <tr>
207+ <td>
208+ Ключ и значение удалены:
209+ </td>
210+ <td class="key-deleted">
211+ sso.vaultEnv.hotels-sso.mapping[0].APP_URL
212+ </td>
213+ <td class="value-deleted">
214+ http://my-api.my-domain.com
215+ </td>
216+ </tr>
217+ <tr>
218+ <td>
219+ Ключ удалён, значение неизвестно:
220+ </td>
221+ <td class="key-deleted">
222+ air.vaultEnv.air-sso:
223+ </td>
224+ <td>
225+ <span class="value-unknown">unknown</span>
226+ </td>
227+ </tr>
228+ </tbody>
229+ </table>
230+ </div>
231+
232+
233+ <br>
234+ <br>
235+ <h2>
236+ Запись в строку
237+ </h2>
238+ <p>
239+ Прост пишем одно за другим, разделяем пробелом:
240+ </p>
241+
242+ <div class="table">
243+ <table>
244+ <tbody>
245+ <tr>
246+ <td>
247+ Ключ по умолчанию, значение не изменено:
248+ </td>
249+ <td>
250+ <span class="key-default-pristine">air.vaultEngineName:</span> <span class="value-pristine">staging</span>
251+ </td>
252+ </tr>
253+ <tr>
254+ <td>
255+ Ключ по умолчанию, значение изменено:
256+ </td>
257+ <td>
258+ <span class="key-default-edited">air.vaultEngineName:</span> <span class="value-edited">staging</span>
259+ </td>
260+ </tr>
261+ <tr>
262+ <td>
263+ Ключ кастомный, значение изменено:
264+ </td>
265+ <td>
266+ <span class="key-custom-edited">app_api_url:</span> <span class="value-edited">http://my-api.my-domain.com</span>
267+ </td>
268+ </tr>
269+ <tr>
270+ <td>
271+ Ключ и значение удалены:
272+ </td>
273+ <td>
274+ <span class="key-deleted">sso.vaultEnv.hotels-sso.mapping[0].APP_URL</span> <span class="value-deleted">http://my-api.my-domain.com</span>
275+ </td>
276+ </tr>
277+ <tr>
278+ <td>
279+ Ключ удалён, значение неизвестно:
280+ </td>
281+ <td>
282+ <span class="key-deleted">air.vaultEnv.air-sso:</span> <span class="value-unknown">unknown</span>
283+ </td>
284+ </tr>
285+ </tbody>
286+ </table>
287+ </div>
288+
289+ <br>
290+ <br>
291+ <p>
292+ Пробел можно положить не между тегами, а внутрь ключа, и тогда подчёркивания сомкнуться
293+ </p>
294+
295+ <div class="table">
296+ <table>
297+ <tbody>
298+ <tr>
299+ <td>
300+ Ключ по умолчанию, значение не изменено:
301+ </td>
302+ <td>
303+ <span class="key-default-pristine">air.vaultEngineName: </span><span class="value-pristine">staging</span>
304+ </td>
305+ </tr>
306+ <tr>
307+ <td>
308+ Ключ по умолчанию, значение изменено:
309+ </td>
310+ <td>
311+ <span class="key-default-edited">air.vaultEngineName: </span><span class="value-edited">staging</span>
312+ </td>
313+ </tr>
314+ <tr>
315+ <td>
316+ Ключ кастомный, значение изменено:
317+ </td>
318+ <td>
319+ <span class="key-custom-edited">app_api_url: </span><span class="value-edited">http://my-api.my-domain.com</span>
320+ </td>
321+ </tr>
322+ <tr>
323+ <td>
324+ Ключ и значение удалены:
325+ </td>
326+ <td>
327+ <span class="key-deleted">sso.vaultEnv.hotels-sso.mapping[0].APP_URL </span><span class="value-deleted">http://my-api.my-domain.com</span>
328+ </td>
329+ </tr>
330+ <tr>
331+ <td>
332+ Ключ удалён, значение неизвестно:
333+ </td>
334+ <td>
335+ <span class="key-deleted">air.vaultEnv.air-sso: </span><span class="value-unknown">unknown</span>
336+ </td>
337+ </tr>
338+ </tbody>
339+ </table>
340+ </div>
341+
342+ <br>
343+ <br>
344+ <br>
345+ <br>
346+ <br>
347+ <br>
348+ <br>
349+ <br>
350+ <br>
351+ <br>
352+ <br>
353+ </div>
354+
355+
356+
357+ <!-- jQuery -->
358+ <script src="../vendors/jquery/jquery-3.2.1.min.js"></script>
359+
360+ <!-- Outline.js -->
361+ <script src="../vendors/outline/outline.js"></script>
362+
363+ <!-- Temp -->
364+ <script src="../scripts/_expander.js"></script>
365+ <script src="../scripts/_drop.js"></script>
366+ <script src="../scripts/_sort.js"></script>
367+ <script src="../scripts/_data.js"></script>
368+ <script src="../scripts/_popup.js"></script>
369+ <script src="../scripts/_classic-popup.js"></script>
370+ <script src="../scripts/_collapse.js"></script>
371+
372+ </body>
373+</html>
octopod-css/development/markups/_listing.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.listing</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -92,6 +92,7 @@
9292 <script src="../scripts/_data.js"></script>
9393 <script src="../scripts/_popup.js"></script>
9494 <script src="../scripts/_classic-popup.js"></script>
95+ <script src="../scripts/_collapse.js"></script>
9596
9697 </body>
9798</html>
octopod-css/development/markups/_loading.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.loading</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -128,6 +128,7 @@
128128 <script src="../scripts/_data.js"></script>
129129 <script src="../scripts/_popup.js"></script>
130130 <script src="../scripts/_classic-popup.js"></script>
131+ <script src="../scripts/_collapse.js"></script>
131132
132133 </body>
133134</html>
octopod-css/development/markups/_notification.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.notification</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -80,6 +80,7 @@
8080 <script src="../scripts/_data.js"></script>
8181 <script src="../scripts/_popup.js"></script>
8282 <script src="../scripts/_classic-popup.js"></script>
83+ <script src="../scripts/_collapse.js"></script>
8384
8485 </body>
8586</html>
octopod-css/development/markups/_null.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.null</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -73,6 +73,7 @@
7373 <script src="../scripts/_data.js"></script>
7474 <script src="../scripts/_popup.js"></script>
7575 <script src="../scripts/_classic-popup.js"></script>
76+ <script src="../scripts/_collapse.js"></script>
7677
7778 </body>
7879</html>
octopod-css/development/markups/_spot.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.spot</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -53,6 +53,7 @@
5353 <script src="../scripts/_data.js"></script>
5454 <script src="../scripts/_popup.js"></script>
5555 <script src="../scripts/_classic-popup.js"></script>
56+ <script src="../scripts/_collapse.js"></script>
5657
5758 </body>
5859</html>
octopod-css/development/markups/_status.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.status</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -75,6 +75,7 @@
7575 <script src="../scripts/_data.js"></script>
7676 <script src="../scripts/_popup.js"></script>
7777 <script src="../scripts/_classic-popup.js"></script>
78+ <script src="../scripts/_collapse.js"></script>
7879
7980 </body>
8081</html>
octopod-css/development/markups/_title.html+2−1
@@ -5,7 +5,7 @@
55 <meta http-equiv="x-ua-compatible" content="ie=edge">
66 <title>.title</title>
77 <meta name="viewport" content="width=device-width, initial-scale=1">
8− <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">-->
8+ <!--<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">-->
99 <link rel="stylesheet" href="../styles/style.css">
1010 </head>
1111 <body>
@@ -52,6 +52,7 @@
5252 <script src="../scripts/_data.js"></script>
5353 <script src="../scripts/_popup.js"></script>
5454 <script src="../scripts/_classic-popup.js"></script>
55+ <script src="../scripts/_collapse.js"></script>
5556
5657 </body>
5758</html>
octopod-css/development/scripts/_collapse.jsnew file+18
@@ -0,0 +1,18 @@
1+(function($) {
2+
3+ var animationTime = 300;
4+
5+ $('.collapse__head').on('click', function () {
6+ var $collapse = $(this).parent('.collapse');
7+
8+ if( ! $collapse.hasClass('collapse--expanded') ) {
9+ $collapse.addClass('collapse--expanded');
10+ $collapse.children('.collapse__body').slideDown(animationTime);
11+ } else {
12+ $collapse.children('.collapse__body').slideUp(animationTime);
13+ $collapse.removeClass('collapse--expanded');
14+ }
15+
16+ });
17+
18+})(jQuery);
octopod-css/development/styles/_collapse.cssnew file+95
@@ -0,0 +1,95 @@
1+.collapse {
2+ position: relative; /* для .collapse__clear */
3+}
4+ .collapse__head {
5+ position: relative;
6+ padding: 0;
7+ background-color: transparent;
8+ border: none;
9+ font-family: inherit;
10+ text-align: left;
11+ cursor: pointer;
12+ -webkit-touch-callout: none;
13+ -webkit-user-select: none;
14+ -khtml-user-select: none;
15+ -moz-user-select: none;
16+ -ms-user-select: none;
17+ user-select: none;
18+ }
19+
20+ .collapse__body {
21+ display: none;
22+ }
23+
24+
25+
26+
27+/* Модификаторы: */
28+
29+
30+.collapse--project {
31+
32+}
33+
34+.collapse--project {
35+ margin-top: 8px;
36+}
37+ .collapse--project > .collapse__head {
38+ position: relative;
39+ display: inline-block;
40+ vertical-align: top;
41+ margin-left: -24px;
42+ padding: 0 9px 0 24px;
43+ background-color: #F3F3F3;
44+ font-weight: 300;
45+ font-size: 16px;
46+ line-height: 24px;
47+ color: var(--dark-grey);
48+ }
49+
50+ .collapse--project > .collapse__head--has-changes {
51+ text-decoration: underline;
52+ }
53+
54+ .collapse--project > .collapse__head:hover {
55+ background-color: #E2E2E2;
56+ color: var(--primary);
57+ }
58+ .collapse--project > .collapse__head::after {
59+ content: "";
60+ flex-shrink: 0;
61+ position: absolute;
62+ left: 5px;
63+ top: 4px;
64+ display: block;
65+ width: 16px;
66+ height: 16px;
67+ background-image: url("../vectors/collapse-project.svg");
68+ background-size: 16px 16px;
69+ background-repeat: no-repeat;
70+ background-position: center center;
71+ transition: transform 0.3s ease;
72+ }
73+
74+ .collapse--project > .collapse__head:hover {
75+
76+ }
77+ .collapse--project > .collapse__head:hover::after {
78+
79+ }
80+
81+ .collapse--project.collapse--expanded > .collapse__head {
82+
83+ }
84+ .collapse--project.collapse--expanded > .collapse__head::after {
85+ transform: rotate(90deg);
86+ }
87+
88+ .collapse--project > .collapse__body {
89+
90+ }
91+ .collapse--project .collapse__inner {
92+ margin-top: 8px;
93+ padding-left: 32px;
94+ border-left: 1px solid #C4C4C4;
95+ }
octopod-css/development/styles/_deployment.css+3
@@ -58,3 +58,6 @@
5858 font-size: 16px;
5959 line-height: 24px;
6060 }
61+ .deployment__widget .row:first-child {
62+ margin-top: 0;
63+ }
octopod-css/development/styles/_editable-row.cssnew file+49
@@ -0,0 +1,49 @@
1+.editable-row {
2+ position: relative;
3+ margin-top: 8px;
4+ display: flex;
5+ align-self: flex-start;
6+}
7+
8+.editable-row:first-child {
9+ margin-top: 0;
10+}
11+ .editable-row__key {
12+ width: 400px;
13+ }
14+
15+ .editable-row__value {
16+ margin-left: 16px;
17+ flex-grow: 1;
18+ }
19+
20+ .editable-row__delete {
21+ margin-left: 2px;
22+ }
23+
24+
25+ .editable-row__placeholder {
26+ position: relative;
27+ width: 400px;
28+ height: 40px;
29+ padding: 14px 0;
30+ box-shadow: inset 0 -1px 0 rgba(176, 176, 176, 0.2);
31+ }
32+
33+ .editable-row__placeholder::before {
34+ position: relative;
35+ content: "";
36+ display: block;
37+ height: 12px;
38+ width: 350px;
39+ border-radius: 2px;
40+ background: rgba(238, 238, 238, 0.5);
41+ }
42+
43+ .editable-row__placeholder:first-child {
44+ margin-right: 16px;
45+ }
46+
47+ .editable-row__placeholder:first-child::before {
48+ width: 200px;
49+ }
octopod-css/development/styles/_has-changes.cssnew file+3
@@ -0,0 +1,3 @@
1+.has-changes {
2+ text-decoration: underline;
3+}
octopod-css/development/styles/_input.css+30−2
@@ -18,8 +18,6 @@
1818 color: rgba(0, 0, 0, 0.87);
1919 }
2020
21−
22−
2321 .input__widget:hover {
2422 box-shadow: inset 0 -1px #326EE6;
2523 }
@@ -43,6 +41,36 @@
4341 /* stylelint-enable */
4442
4543
44+ .input__dropdown {
45+ z-index: 2;
46+ position: absolute;
47+ top: 30px;
48+ background: #FFFFFF;
49+ padding: 8px 0;
50+ list-style: none;
51+ border-radius: 2px;
52+ box-shadow: 0 8px 8px 0 #0000003D, 0 0 8px 0 #0000001F;
53+ max-height: 274px;
54+ overflow-y: auto;
55+ }
56+
57+ .input__suggest {
58+ font-size: 16px;
59+ line-height: 24px;
60+ padding: 12px 16px;
61+ cursor: pointer;
62+ color: rgba(0, 0, 0, 0.87);
63+ font-weight: 400;
64+ }
65+
66+ .input__suggest b {
67+ font-weight: 700;
68+ }
69+
70+ .input__suggest:hover {
71+ background: #F8F8F8;
72+ }
73+
4674
4775.input--has-clear-type {
4876
octopod-css/development/styles/_key-custom-edited.cssnew file+4
@@ -0,0 +1,4 @@
1+.key-custom-edited {
2+ font-weight: 500 !important;
3+ text-decoration: underline !important;
4+}
octopod-css/development/styles/_key-default-edited.cssnew file+5
@@ -0,0 +1,5 @@
1+.key-default-edited {
2+ font-weight: 300 !important;
3+ font-style: italic !important;
4+ text-decoration: underline !important;
5+}
octopod-css/development/styles/_key-default-pristine.cssnew file+4
@@ -0,0 +1,4 @@
1+.key-default-pristine {
2+ font-weight: 300 !important;
3+ font-style: italic !important;
4+}
octopod-css/development/styles/_key-deleted.cssnew file+6
@@ -0,0 +1,6 @@
1+.key-deleted {
2+ font-weight: 300 !important;
3+ font-style: italic !important;
4+ text-decoration: line-through;
5+ color: #D3D3D3;
6+}
octopod-css/development/styles/_overrides.css+7−77
@@ -1,85 +1,15 @@
11.overrides {
22
33}
4− .overrides__item {
5− position: relative;
6− margin-bottom: 8px;
7− display: flex;
8− align-self: flex-start;
9− }
10−
11− .overrides__item:last-child {
12− margin-bottom: 0;
4+ .overrides__add {
5+ padding: 8px 0 8px 24px !important;
136 }
14− .overrides__key {
15− width: 400px;
16− }
17−
18− .overrides__value {
19− margin-left: 16px;
20− width: 400px;
21− }
22−
23− .overrides__delete {
24− margin-left: 2px;
25− }
26−
27− .overrides__search {
28− z-index: 2;
29− position: absolute;
30− top: 30px;
31− background: #FFFFFF;
32− padding: 8px 0;
33− list-style: none;
34− border-radius: 2px;
35− box-shadow: 0 8px 8px 0 #0000003D, 0 0 8px 0 #0000001F;
36− max-height: 274px;
37− overflow-y: auto;
38− }
39−
40− .overrides__search-item {
41− font-size: 16px;
42− line-height: 24px;
43− padding: 12px 16px;
44− cursor: pointer;
45− color: rgba(0, 0, 0, 0.87);
46− font-weight: 400;
47− }
487
49− .overrides__search-item b {
50− font-weight: 700;
51− }
8+ .overrides__list {
529
53− .overrides__search-item:hover {
54− background: #F8F8F8;
55− }
56−
57− .overrides__placeholder {
58− position: relative;
59− width: 400px;
60− height: 40px;
61− padding: 14px 0;
62− box-shadow: inset 0 -1px 0 rgba(176, 176, 176, 0.2);
63− }
64−
65− .overrides__placeholder::before {
66− position: relative;
67− content: "";
68− display: block;
69− height: 12px;
70− width: 350px;
71− border-radius: 2px;
72− background: rgba(238, 238, 238, 0.5);
73− }
74−
75− .overrides__placeholder:first-child {
76− margin-right: 16px;
77− }
78−
79− .overrides__placeholder:first-child::before {
80− width: 200px;
81− }
10+ }
8211
83− .overrides__add {
84− padding: 8px 0 8px 24px !important;
12+ .overrides__tree {
13+ margin-top: 16px;
14+ margin-left: 16px;
8515 }
octopod-css/development/styles/_padded.cssnew file+3
@@ -0,0 +1,3 @@
1+.padded {
2+ padding-left: 24px;
3+}
octopod-css/development/styles/_root.css+2
@@ -17,6 +17,8 @@
1717 --red: #D42A2A;
1818 --green: #0F7F12;
1919
20+ --black: #212121;
21+
2022 --shadow_1: 0 2px 2px rgba(0, 0, 0, 0.24),
2123 0 0 2px rgba(0, 0, 0, 0.12);
2224
octopod-css/development/styles/_row.cssnew file+3
@@ -0,0 +1,3 @@
1+.row {
2+ margin-top: 8px;
3+}
octopod-css/development/styles/_table.css+5−1
@@ -23,6 +23,10 @@
2323 .table tbody tr {
2424 border-top: 1px solid #E0E0E0;
2525 }
26+
27+ .table tbody tr:first-child {
28+ border-top: none;
29+ }
2630 .table th {
2731 vertical-align: middle;
2832 height: 48px;
@@ -57,7 +61,7 @@
5761
5862}
5963 .table--clickable tbody tr {
60− cursor: default;
64+ cursor: pointer;
6165 }
6266
6367 .table--clickable tbody tr:hover {
octopod-css/development/styles/_value-deleted.cssnew file+5
@@ -0,0 +1,5 @@
1+.value-deleted {
2+ font-weight: 300 !important;
3+ text-decoration: line-through;
4+ color: #D3D3D3;
5+}
octopod-css/development/styles/_value-edited.cssnew file+4
@@ -0,0 +1,4 @@
1+.value-edited {
2+ font-weight: 500 !important;
3+ text-decoration: underline !important;
4+}
octopod-css/development/styles/_value-pristine.cssnew file+3
@@ -0,0 +1,3 @@
1+.value-pristine {
2+ font-weight: 300 !important;
3+}
octopod-css/development/styles/_value-unknown.cssnew file+12
@@ -0,0 +1,12 @@
1+.value-unknown {
2+ display: inline-block;
3+ vertical-align: baseline;
4+ width: 92px;
5+ height: 0.5715em;
6+ background-color: #F3F3F3;
7+ border-radius: 2px;
8+ margin-right: 4px;
9+ text-indent: 200%;
10+ white-space: nowrap;
11+ overflow: hidden;
12+}
octopod-css/development/styles/style.css+15
@@ -40,3 +40,18 @@
4040@import url("_no-log.css");
4141@import url("_nav.css");
4242@import url("_break.css");
43+@import url("_key-default-pristine.css");
44+@import url("_key-default-edited.css");
45+@import url("_key-custom-edited.css");
46+@import url("_key-deleted.css");
47+@import url("_value-pristine.css");
48+@import url("_value-edited.css");
49+@import url("_value-deleted.css");
50+@import url("_value-pristine.css");
51+@import url("_value-edited.css");
52+@import url("_collapse.css");
53+@import url("_row.css");
54+@import url("_padded.css");
55+@import url("_has-changes.css");
56+@import url("_editable-row.css");
57+@import url("_value-unknown.css");
octopod-css/development/vectors/collapse-project.svgnew file+3
@@ -0,0 +1,3 @@
1+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<path d="M6.66678 11.3332L10.0001 7.99989L6.66678 4.66655L6.66678 11.3332Z" fill="#212121"/>
3+</svg>
octopod-frontend/octopod-frontend.cabal+4
@@ -52,6 +52,7 @@ executable frontend
5252 , Frontend.UIKit.Button.Static
5353 , Frontend.UIKit.Button.Action
5454 , Frontend.UIKit.Button.Sort
55+ , Frontend.UIKit.Button.Tree
5556 , Reflex.Dom.Renderable
5657 , Reflex.Dom.AsyncEvent
5758 ghc-options:
@@ -103,6 +104,7 @@ executable frontend
103104 , ApplicativeDo
104105 , PartialTypeSignatures
105106 , DeriveAnyClass
107+ , MultiWayIf
106108 build-depends: aeson
107109 , base
108110 , bytestring
@@ -135,5 +137,7 @@ executable frontend
135137 , deepseq
136138 , patch
137139 , reflex-dom-core
140+ , these
141+ , ref-tf
138142 hs-source-dirs: src
139143 default-language: Haskell2010
octopod-frontend/src/Data/Text/Search.hs+14
@@ -21,6 +21,7 @@ import Data.Maybe (listToMaybe)
2121import Data.Ord
2222import Data.Semigroup
2323import Data.Sequence (Seq (..))
24+import Data.String
2425import Data.Text (Text)
2526import qualified Data.Text as T
2627import GHC.Generics (Generic)
@@ -92,6 +93,19 @@ data SearchResult = SearchResult
9293 deriving stock (Eq, Ord, Generic)
9394 deriving anyclass (NFData)
9495
96+instance IsString SearchResult where
97+ fromString s = SearchResult (T.pack s) Nothing
98+
99+instance Semigroup SearchResult where
100+ SearchResult a aRes <> SearchResult b bRes = SearchResult (a <> b) $ case (aRes, bRes) of
101+ (Nothing, Nothing) -> Nothing
102+ (Just a', Nothing) -> Just $ a' :|> NotMatched b
103+ (Nothing, Just b') -> Just $ NotMatched a :<| b'
104+ (Just a', Just b') -> Just $ a' <> b'
105+
106+instance Monoid SearchResult where
107+ mempty = SearchResult mempty Nothing
108+
95109instance Searchable SearchResult SearchResult where
96110 type Searched SearchResult res = res
97111 searchWith f t = f t
octopod-frontend/src/Data/WorkingOverrides.hs+104−76
@@ -1,32 +1,104 @@
11module Data.WorkingOverrides
22 ( WorkingOverrides,
3− WorkingOverride,
4− WorkingOverride',
53 WorkingOverrideKey' (..),
4+ getConfigValueText,
65 WorkingOverrideKey,
76 WorkingOverrideKeyType (..),
8− WorkingOverrideValue' (..),
9− WorkingOverrideValue,
107 destructWorkingOverrides,
118 constructWorkingOverrides,
12− newWorkingOverride,
9+ ConfigValue (..),
10+ CustomKey (..),
11+ CustomConfigValue (..),
12+ WorkingConfigTree,
13+ WorkingOverride,
14+ WorkingOverride',
15+ configTreeHasLeaf,
16+ destructWorkingOverridesDyn,
1317 )
1418where
1519
20+import Common.Orphans ()
1621import Common.Types
17−import qualified Data.List as L
18−import qualified Data.Map.Ordered.Strict as OM
19−import Data.Maybe
22+import Control.Monad.Reader
23+import Control.Monad.Ref
24+import Data.ConfigTree (ConfigTree)
25+import qualified Data.ConfigTree as CT
26+import Data.Foldable
27+import Data.Functor
28+import Data.Map (Map)
29+import qualified Data.Map as M
30+import Data.Maybe (catMaybes)
31+import qualified Data.Maybe as M
2032import Data.Text (Text)
21−import Data.UniqMap
33+import Data.These
34+import GHC.Generics (Generic)
35+import Reflex
36+
37+type WorkingConfigTree k v = ConfigTree k (ConfigValue v)
38+
39+data ConfigValue te
40+ = DefaultConfigValue !te
41+ | CustomConfigValue !(Either (CustomKey te) (CustomConfigValue te))
42+ deriving stock (Show, Generic, Eq, Ord)
43+
44+newtype CustomKey v = CustomKey v
45+ deriving stock (Show, Generic, Eq, Ord)
46+
47+data CustomConfigValue te
48+ = CustomValue !te
49+ | DeletedValue !(Maybe te)
50+ deriving stock (Show, Generic, Eq, Ord)
2251
52+getConfigValueText :: ConfigValue te -> Maybe te
53+getConfigValueText (DefaultConfigValue t) = Just t
54+getConfigValueText (CustomConfigValue (Left (CustomKey t))) = Just t
55+getConfigValueText (CustomConfigValue (Right (CustomValue t))) = Just t
56+getConfigValueText (CustomConfigValue (Right (DeletedValue t))) = t
57+
58+-- Super inefficient but i dont care
59+configTreeHasLeaf ::
60+ forall m kv te.
61+ ( MonadReader (Ref m (Map (Text, ConfigTree kv te) Bool)) m
62+ , MonadRef m
63+ , Ord kv
64+ , Ord te
65+ ) =>
66+ -- | The id of the predicate used for caching
67+ Text ->
68+ (te -> Bool) ->
69+ ConfigTree kv te ->
70+ m Bool
71+configTreeHasLeaf name f = memo (\(_, CT.ConfigTree x) -> go $ toList x) . (name,)
72+ where
73+ go :: [(Maybe te, ConfigTree kv te)] -> m Bool
74+ go [] = pure False
75+ go ((Just y, _) : _) | f y = pure True
76+ go ((_, ct) : rest) =
77+ configTreeHasLeaf name f ct >>= \case
78+ True -> pure True
79+ False -> go rest
80+
81+memo ::
82+ (MonadReader (Ref m (Map x y)) m, Ord x, MonadRef m) =>
83+ (x -> m y) ->
84+ x ->
85+ m y
86+memo f x = do
87+ memoRef <- ask
88+ m <- readRef memoRef
89+ case M.lookup x m of
90+ Just y -> pure y
91+ Nothing -> do
92+ y <- f x
93+ modifyRef memoRef $ M.insert x y
94+ pure y
2395type WorkingOverrides = WorkingOverrides' Text
2496
25−type WorkingOverrides' te = UniqKeyMap (WorkingOverride' te)
97+type WorkingOverrides' te = ConfigTree te (ConfigValue te)
2698
2799type WorkingOverride = WorkingOverride' Text
28100
29−type WorkingOverride' te = (WorkingOverrideKey' te, WorkingOverrideValue' te)
101+type WorkingOverride' te = (te, ConfigValue te)
30102
31103type WorkingOverrideKey = WorkingOverrideKey' Text
32104
@@ -36,75 +108,31 @@ data WorkingOverrideKey' te = WorkingOverrideKey !WorkingOverrideKeyType !te
36108data WorkingOverrideKeyType = CustomWorkingOverrideKey | DefaultWorkingOverrideKey
37109 deriving stock (Show, Eq)
38110
39−type WorkingOverrideValue = WorkingOverrideValue' Text
111+destructWorkingOverridesDyn :: Reflex t => [Dynamic t WorkingOverride] -> Dynamic t (Overrides l)
112+destructWorkingOverridesDyn =
113+ fmap (Overrides . CT.fromFlatList . catMaybes) . sequenceA . (fmap . fmap) (\(k, v) -> (k,) <$> unConfigValue v)
40114
41−data WorkingOverrideValue' te
42− = WorkingCustomValue !te
43− | WorkingDefaultValue !te
44− | WorkingDeletedValue !(Maybe te)
45− deriving stock (Show)
46−
47−destructWorkingOverrides :: WorkingOverrides -> Overrides l
115+destructWorkingOverrides :: [WorkingOverride] -> Overrides l
48116destructWorkingOverrides =
49− Overrides
50− . foldr
51− ( \pair@(k, v) m -> case OM.lookup k m of
52− Just _ | v == ValueDeleted -> m
53− _ -> m OM.|> pair
54− )
55− OM.empty
56− . mapMaybe
57− ( \case
58− (WorkingOverrideKey CustomWorkingOverrideKey k, getWorkingOverrideValue -> v) -> Just (k, v)
59− (WorkingOverrideKey _ k, WorkingCustomValue v) -> Just (k, ValueAdded v)
60− (WorkingOverrideKey _ k, WorkingDeletedValue _) -> Just (k, ValueDeleted)
61− (WorkingOverrideKey DefaultWorkingOverrideKey _, WorkingDefaultValue _) -> Nothing
62− )
63− . elemsUniq
64− where
65− getWorkingOverrideValue :: WorkingOverrideValue -> OverrideValue
66− getWorkingOverrideValue (WorkingCustomValue x) = ValueAdded x
67− getWorkingOverrideValue (WorkingDefaultValue x) = ValueAdded x
68− getWorkingOverrideValue (WorkingDeletedValue _) = ValueDeleted
117+ Overrides . CT.fromFlatList . M.catMaybes . fmap (\(k, v) -> (k,) <$> unConfigValue v)
118+
119+unConfigValue :: ConfigValue te -> Maybe (OverrideValue' te)
120+unConfigValue (DefaultConfigValue _) = Nothing
121+unConfigValue (CustomConfigValue (Left (CustomKey te))) = Just $ ValueAdded te
122+unConfigValue (CustomConfigValue (Right (CustomValue te))) = Just $ ValueAdded te
123+unConfigValue (CustomConfigValue (Right (DeletedValue _))) = Just ValueDeleted
69124
70125constructWorkingOverrides ::
71126 Ord te =>
72− Maybe (DefaultConfig' te l) ->
127+ DefaultConfig' te l ->
73128 Overrides' te l ->
74129 WorkingOverrides' te
75−constructWorkingOverrides (Just (DefaultConfig dCfg)) (Overrides ovsM) =
76− let custom =
77− uniqMapFromList
78− . mapMaybe
79− ( \(k, v) ->
80− let k' = WorkingOverrideKey (if OM.member k dCfg then DefaultWorkingOverrideKey else CustomWorkingOverrideKey) k
81− in case v of
82− ValueAdded x -> Just (k', WorkingCustomValue x)
83− ValueDeleted -> (k',) . WorkingDeletedValue . Just <$> OM.lookup k dCfg
84− )
85− . OM.assocs
86− $ ovsM
87− in L.foldl'
88− ( \m (k, v) ->
89− if OM.member k ovsM
90− then m
91− else
92− fst $
93− insertUniqEnd (WorkingOverrideKey DefaultWorkingOverrideKey k, WorkingDefaultValue v) m
94− )
95− custom
96− (OM.assocs dCfg)
97−constructWorkingOverrides Nothing (Overrides ovsM) =
98− uniqMapFromList
99− . fmap
100− ( \(k, v) ->
101− let k' = WorkingOverrideKey CustomWorkingOverrideKey k
102− in case v of
103− ValueAdded x -> (k', WorkingCustomValue x)
104− ValueDeleted -> (k', WorkingDeletedValue Nothing)
105− )
106− . OM.assocs
107− $ ovsM
108−
109−newWorkingOverride :: WorkingOverride
110−newWorkingOverride = (WorkingOverrideKey CustomWorkingOverrideKey "", WorkingCustomValue "")
130+constructWorkingOverrides (DefaultConfig defCT) (Overrides newCT) =
131+ CT.catMaybes $
132+ CT.zip newCT defCT <&> \case
133+ That x -> Just $ DefaultConfigValue x
134+ This x -> case x of
135+ ValueDeleted -> Nothing
136+ ValueAdded v -> Just $ CustomConfigValue $ Left $ CustomKey v
137+ These ValueDeleted v -> Just $ CustomConfigValue $ Right $ DeletedValue $ Just v
138+ These (ValueAdded v) _ -> Just $ CustomConfigValue $ Right $ CustomValue v
octopod-frontend/src/Frontend/UIKit.hs+281−115
@@ -7,53 +7,63 @@ module Frontend.UIKit
77 octopodTextInputDyn,
88 loadingOverride,
99 loadingOverrides,
10− overrideField,
11− OverrideField (..),
10+ configField,
1211 popupOverlay,
1312 Default (..),
1413 module X,
1514 (.~~),
1615 (?~~),
17− OverrideFieldType (..),
1816 deletedOverride,
19− showNonEditableWorkingOverride,
20− NonEditableWorkingOverrideStyle (..),
2117 untilReadyEv',
2218 untilReady',
2319 runWithReplace',
2420 joinEvM,
21+ showNonEditableWorkingOverrideTree,
22+ showFlatConfig,
23+ ConfigFieldButtonAction (..),
24+ showOverrideTree,
25+ nonEditableLoading,
2526 )
2627where
2728
29+import Common.Types
2830import Control.Lens
29− ( ASetter',
30− (%~),
31− (<>~),
32− (?~),
33− (^.),
34− )
31+import Control.Lens.Extras (is)
3532import Control.Monad
33+import Control.Monad.Reader
34+import Control.Monad.Ref
3635import Data.Align
36+import Data.ConfigTree (ConfigTree (ConfigTree))
37+import qualified Data.ConfigTree as CT
3738import Data.Default
39+import Data.Either
40+import Data.Foldable
3841import Data.Functor
3942import Data.Generics.Labels ()
43+import Data.Generics.Sum
4044import Data.List.NonEmpty
4145import qualified Data.List.NonEmpty as NE
46+import Data.Map (Map)
4247import qualified Data.Map as M
43−import Data.Maybe (isNothing, maybeToList)
48+import qualified Data.Map.Ordered.Strict as OM
49+import Data.Maybe (fromMaybe, isNothing, maybeToList)
50+import Data.Monoid (Endo (..))
4451import Data.Text (Text)
4552import qualified Data.Text as T
4653import Data.Text.Search
4754import Data.These
55+import Data.Traversable
4856import Data.Witherable
4957import Data.WorkingOverrides
5058import Frontend.Classes as X
5159import Frontend.UIKit.Button.Action as X
60+import Frontend.UIKit.Button.Common
5261import Frontend.UIKit.Button.Dash as X
5362import Frontend.UIKit.Button.Expander as X
5463import Frontend.UIKit.Button.Large as X
5564import Frontend.UIKit.Button.Sort as X
5665import Frontend.UIKit.Button.Static as X
66+import Frontend.UIKit.Button.Tree
5767import GHC.Generics (Generic)
5868import Reflex.Dom
5969import Reflex.Dom.AsyncEvent
@@ -85,64 +95,84 @@ errorCommonWidget =
8595 elClass "b" "null__heading" $ text "Cannot retrieve the data"
8696 divClass "null__message" $ text "Try to reload the page"
8797
88−data OverrideField t = OverrideField
98+data ConfigField t = ConfigField
8999 { fieldValue :: Dynamic t Text
90100 , fieldError :: Dynamic t (Maybe (NonEmpty Text))
91− , fieldDisabled :: Dynamic t Bool
92− , fieldType :: Dynamic t OverrideFieldType
101+ , fieldType :: Dynamic t ConfigFieldType
93102 }
94103 deriving stock (Generic)
95104
96−data OverrideFieldType
97− = DefaultOverrideFieldType
98− | EditedOverrideFieldType
105+data ConfigFieldType
106+ = DefaultConfigFieldType
107+ | CustomConfigFieldType
99108 deriving stock (Show)
100109
101−overrideFieldTypeClasses :: OverrideFieldType -> Classes
102−overrideFieldTypeClasses DefaultOverrideFieldType = "input--default"
103−overrideFieldTypeClasses EditedOverrideFieldType = mempty
104−
105−overrideField :: MonadWidget t m => Dynamic t [Text] -> OverrideField t -> OverrideField t -> m (Dynamic t Text, Dynamic t Text, Event t ())
106−overrideField overrideKeyValues keyDyn valueDyn = do
107− elDiv "overrides__item" $ do
108− keyInp <-
110+configField ::
111+ MonadWidget t m =>
112+ Dynamic t [Text] ->
113+ Dynamic t WorkingOverride ->
114+ m (Dynamic t Text, Dynamic t Text, Event t ConfigFieldButtonAction)
115+configField overrideKeyValues (splitDynPure -> (k, v')) = do
116+ let (splitDynPure -> (keyClass, valueClass)) =
117+ v' <&> \case
118+ DefaultConfigValue _ -> ("key-default-pristine", "value-pristine")
119+ CustomConfigValue (Right (CustomValue _)) -> ("key-default-edited", "value-edited")
120+ CustomConfigValue (Right (DeletedValue Just {})) -> ("key-deleted", "value-deleted")
121+ CustomConfigValue (Right (DeletedValue Nothing)) -> ("key-deleted", "value-unknown")
122+ CustomConfigValue (Left _) -> ("key-custom-edited", "value-edited")
123+ valDyn =
124+ v' <&> \case
125+ DefaultConfigValue v -> v
126+ CustomConfigValue (Right (CustomValue v)) -> v
127+ CustomConfigValue (Right (DeletedValue v)) -> fromMaybe "UNKNOWN" v
128+ CustomConfigValue (Left (CustomKey v)) -> v
129+ deletedDyn' = (is (_Ctor' @"CustomConfigValue" . _Right . _Ctor' @"DeletedValue")) <$> v'
130+ deletedDyn <- holdUniqDyn deletedDyn'
131+ let extraDivClasses =
132+ deletedDyn <&> \case
133+ True -> "input--deleted"
134+ False -> mempty
135+ elDiv "editable-row" $ mdo
136+ (value -> keyTextDyn) <-
109137 octopodTextInputDyn
110138 overrideKeyValues
111− (keyDyn ^. #fieldDisabled)
112− ( do
113− t <- keyDyn ^. #fieldType
114− pure $ "overrides__key" <> overrideFieldTypeClasses t
115− )
139+ deletedDyn
140+ (mappend "editable-row__key" <$> extraDivClasses)
141+ keyClass
116142 "key"
117− (keyDyn ^. #fieldValue)
118− (keyDyn ^. #fieldError)
119− let keyTextDyn = value keyInp
143+ k
144+ (pure Nothing)
120145 (value -> valTextDyn) <-
121146 octopodTextInputDyn
122147 (pure [])
123− (valueDyn ^. #fieldDisabled)
124− ( do
125− t <- valueDyn ^. #fieldType
126− pure $ "overrides__value" <> overrideFieldTypeClasses t
127− )
148+ deletedDyn
149+ (mappend "editable-row__value" <$> extraDivClasses)
150+ valueClass
128151 "value"
129− (valueDyn ^. #fieldValue)
130− (valueDyn ^. #fieldError)
131− closeEv <- deleteOverrideButton
152+ valDyn
153+ (valTextDyn <&> \t -> if (T.null . T.strip) t then Just (pure "Value can not be empty") else Nothing)
154+ closeEv <-
155+ networkView >=> switchHold never $
156+ deletedDyn <&> \case
157+ True -> fmap (const ConfigFieldButtonRecover) <$> undoOverrideButton
158+ False -> fmap (const ConfigFieldButtonClear) <$> deleteOverrideButton
132159 pure (keyTextDyn, valTextDyn, closeEv)
133160
161+data ConfigFieldButtonAction = ConfigFieldButtonClear | ConfigFieldButtonRecover
162+ deriving stock (Show)
163+
134164deletedOverride :: MonadWidget t m => Text -> Maybe Text -> m (Event t ())
135165deletedOverride k vM = do
136− elDiv "overrides__item" $ do
137− elDiv "overrides__key input input--deleted" $ field k
166+ elDiv "editable-row" $ do
167+ elDiv "editable-row__key input input--deleted" $ field k
138168 case vM of
139169 Nothing -> do
140− elDiv "overrides__placeholder overrides__value" blank
170+ elDiv "editable-row__placeholder editable-row__value" blank
141171 loadingOverrideSpinner
142172 pure never
143173 Just v -> do
144− elDiv "overrides__value input input--deleted" $ field $ v
145− undoOverrideButton
174+ elDiv "editable-row__value input input--deleted" $ field $ v
175+ (($> ()) <$> undoOverrideButton)
146176 where
147177 field t =
148178 void $
@@ -152,20 +182,20 @@ deletedOverride k vM = do
152182 & initialAttributes .~ ("type" =: "text" <> "class" =: "input__widget")
153183
154184loadingOverrideField :: MonadWidget t m => m ()
155−loadingOverrideField = elDiv "overrides__placeholder" blank
185+loadingOverrideField = elDiv "editable-row__placeholder" blank
156186
157187loadingOverrideSpinner :: MonadWidget t m => m ()
158188loadingOverrideSpinner = elDiv "overrides__delete spot spot--loader" blank
159189
160190loadingOverride :: MonadWidget t m => m ()
161191loadingOverride = do
162− elDiv "overrides__item loader" $ do
192+ elDiv "editable-row loader" $ do
163193 loadingOverrideField
164194 loadingOverrideField
165195 loadingOverrideSpinner
166196
167197loadingOverrides :: MonadWidget t m => m ()
168−loadingOverrides = do
198+loadingOverrides = divClass "padded" $ do
169199 loadingOverride
170200 loadingOverride
171201 loadingOverride
@@ -181,6 +211,8 @@ octopodTextInput' ::
181211 (Dynamic t [Text]) ->
182212 -- | Disabled?
183213 Dynamic t Bool ->
214+ -- | Div classes.
215+ Dynamic t Classes ->
184216 -- | Input field classes.
185217 Dynamic t Classes ->
186218 -- | Placeholder for input field.
@@ -190,14 +222,14 @@ octopodTextInput' ::
190222 -- | Event carrying the error message.
191223 Event t Text ->
192224 m (InputElement EventResult GhcjsDomSpace t, Dynamic t Bool)
193−octopodTextInput' valuesDyn disabledDyn clssDyn placeholder inValDyn' errEv = mdo
225+octopodTextInput' valuesDyn disabledDyn inpClassesDyn clssDyn placeholder inValDyn' errEv = mdo
194226 errDyn <-
195227 holdDyn Nothing $
196228 leftmost
197229 [ Just . pure <$> errEv
198230 , Nothing <$ updated (value inp)
199231 ]
200− inp <- octopodTextInputDyn valuesDyn disabledDyn clssDyn placeholder inValDyn' errDyn
232+ inp <- octopodTextInputDyn valuesDyn disabledDyn inpClassesDyn clssDyn placeholder inValDyn' errDyn
201233 pure (inp, isNothing <$> errDyn)
202234
203235-- | The only text input field that is used in project forms. This input
@@ -208,6 +240,8 @@ octopodTextInputDyn ::
208240 Dynamic t [Text] ->
209241 -- | Disabled?
210242 Dynamic t Bool ->
243+ -- | Div classes.
244+ Dynamic t Classes ->
211245 -- | Input field classes.
212246 Dynamic t Classes ->
213247 -- | Placeholder for input field.
@@ -217,7 +251,7 @@ octopodTextInputDyn ::
217251 -- | Event carrying the error message.
218252 Dynamic t (Maybe (NonEmpty Text)) ->
219253 m (InputElement EventResult GhcjsDomSpace t)
220−octopodTextInputDyn valuesDyn disabledDyn clssDyn placeholder inValDyn' errDyn = mdo
254+octopodTextInputDyn valuesDyn disabledDyn divClasses inpClassesDyn placeholder inValDyn' errDyn = mdo
221255 inValDyn <- holdUniqDyn inValDyn'
222256 let valDyn = value inp
223257 inValEv =
@@ -237,18 +271,22 @@ octopodTextInputDyn valuesDyn disabledDyn clssDyn placeholder inValDyn' errDyn =
237271
238272 let classDyn = do
239273 errClasses <- errorClassesDyn
240− additionalClasses <- clssDyn
274+ additionalClasses <- divClasses
241275 pure . destructClasses $ "input" <> errClasses <> additionalClasses
242276
243277 inVal <- sample . current $ inValDyn
244278 disabled <- sample . current $ disabledDyn
279+ let actualInputClassesDyn = do
280+ inpClass <- inpClassesDyn
281+ pure $ destructClasses $ "input__widget" <> inpClass
282+ clss <- sample . current $ actualInputClassesDyn
245283 (inp, selectedValue) <- elDynClass "div" classDyn $ do
246284 inp' <-
247285 inputElement $
248286 def
249287 & initialAttributes
250288 .~ ( "type" =: "text"
251− <> "class" =: "input__widget"
289+ <> "class" =: clss
252290 <> "placeholder" =: placeholder
253291 <> "spellcheck" =: "false"
254292 )
@@ -260,9 +298,11 @@ octopodTextInputDyn valuesDyn disabledDyn clssDyn placeholder inValDyn' errDyn =
260298 <>~ updated
261299 ( do
262300 disabled' <- disabledDyn
301+ classes <- actualInputClassesDyn
263302 pure $
264− M.singleton "disabled" $
265− if disabled' then Just "disabled" else Nothing
303+ ( "disabled" =: (if disabled' then Just "disabled" else Nothing)
304+ <> "class" =: Just classes
305+ )
266306 )
267307 void $
268308 simpleList ((maybeToList >=> NE.toList) <$> errDyn) $ \err ->
@@ -288,14 +328,14 @@ octopodTextInputDyn valuesDyn disabledDyn clssDyn placeholder inValDyn' errDyn =
288328 searchResultEv <&> \case
289329 [] -> pure never
290330 searchResult -> do
291− elClass "ul" "overrides__search" $ do
331+ elClass "ul" "input__dropdown" $ do
292332 fmap leftmost $
293− forM searchResult $ \(res, initialText) -> do
294− (resEl, ()) <- elClass' "li" "overrides__search-item" $
295− forM_ res $ \case
333+ for searchResult $ \(res, initialText) -> do
334+ (resEl, ()) <- elClass' "li" "input__suggest" $
335+ for_ res $ \case
296336 Matched t -> elAttr "span" ("style" =: "font-weight: bold;") $ text t
297337 NotMatched t -> text t
298− -- Because 'Click' would fire after the text field loses
338+ -- Because 'Click' would fire after the text field looses
299339 -- focus and the popup disappears.
300340 pure $ domEvent Mousedown resEl $> initialText
301341
@@ -307,60 +347,186 @@ popupOverlay :: DomBuilder t m => m ()
307347popupOverlay =
308348 elAttr "div" ("class" =: "popup__overlay" <> "aria-hidden" =: "true") blank
309349
310−data NonEditableWorkingOverrideStyle
311− = RegularNonEditableWorkingOverrideStyle
312− | LargeNonEditableWorkingOverrideStyle
313−
314−nonEditableWorkingOverrideStyleClasses :: NonEditableWorkingOverrideStyle -> Classes
315−nonEditableWorkingOverrideStyleClasses RegularNonEditableWorkingOverrideStyle = mempty
316−nonEditableWorkingOverrideStyleClasses LargeNonEditableWorkingOverrideStyle = "listing--larger"
317−
318−-- | Widget that shows overrides list. It does not depend on their type.
319−showNonEditableWorkingOverride ::
320− (MonadWidget t m, Renderable te) =>
321− -- | Loading?
322− Bool ->
323− -- | Is it fully loaded?
324− Bool ->
325− NonEditableWorkingOverrideStyle ->
326− -- | Overrides list.
327− [WorkingOverride' te] ->
350+showFlatConfig ::
351+ (MonadWidget t m, Renderable tk, Renderable tv) =>
352+ [(tk, OverrideValue' tv)] ->
353+ m ()
354+showFlatConfig l =
355+ for_ l $ \(k, v) ->
356+ let keyClasses = if is (_Ctor' @"ValueDeleted") v then "key-deleted" else "key-default-pristine"
357+ in divClass "row" $ do
358+ elClass "span" (destructClasses keyClasses) $ do
359+ rndr k
360+ text ": "
361+ pure ()
362+ case v of
363+ ValueAdded t -> elClass "span" "value-edited" $ rndr t
364+ ValueDeleted -> elClass "div" "listing__placeholder listing__placeholder__value" $ pure ()
365+ pure ()
366+
367+showNonEditableWorkingOverrideTree ::
368+ (MonadWidget t m, Renderable tk, Renderable tv, Ord tk, Ord (ConfigValue tv)) =>
369+ Dynamic t (WorkingConfigTree tk tv) ->
370+ m ()
371+showNonEditableWorkingOverrideTree treeDyn = do
372+ memoRef <- newRef mempty
373+ flip runReaderT memoRef $
374+ untilReady (lift nonEditableLoading) $
375+ networkView $
376+ treeDyn <&> \tree ->
377+ untilReady (lift nonEditableLoading) $
378+ divClass "padded" $
379+ showWorkingOverrideTree'
380+ (const False)
381+ (is (_Ctor' @"CustomConfigValue"))
382+ (\_ _ -> ())
383+ (\_ k v -> renderRow k v $> pure ())
384+ tree
385+ (pure True)
386+ never
387+ pure ()
388+
389+nonEditableLoading :: DomBuilder t m => m ()
390+nonEditableLoading = for_ [1 :: Int .. 3] $ \_ ->
391+ divClass "padded" $
392+ divClass "row" $ do
393+ elClass "div" "listing__placeholder" $ pure ()
394+ elClass "div" "listing__spinner" $ pure ()
395+
396+showOverrideTree ::
397+ forall m t tv tk x.
398+ ( MonadWidget t m
399+ , Renderable tk
400+ , Show x
401+ , Ord tk
402+ , Ord tv
403+ ) =>
404+ -- | Value should be shown by default
405+ (tv -> Bool) ->
406+ -- | Value is modified
407+ (tv -> Bool) ->
408+ -- | Prepare the fixpoint data
409+ (tk -> tv -> x) ->
410+ -- | Render row
411+ (x -> tk -> tv -> m (Dynamic t x)) ->
412+ ConfigTree tk tv ->
413+ -- | Should we render anything
414+ m [Dynamic t x]
415+showOverrideTree isShown isModified prepareData renderValue ct = do
416+ memoRef <- newRef mempty
417+ flip runReaderT memoRef $
418+ showWorkingOverrideTree' isShown isModified prepareData ((fmap . fmap . fmap) lift renderValue) ct (pure True) never
419+
420+showWorkingOverrideTree' ::
421+ ( MonadWidget t m
422+ , Renderable tk
423+ , Show x
424+ , MonadReader (Ref m (Map (Text, ConfigTree tk tv) Bool)) m
425+ , Ord tv
426+ , Ord tk
427+ ) =>
428+ -- | Value should be shown by default
429+ (tv -> Bool) ->
430+ -- | Value is modified
431+ (tv -> Bool) ->
432+ -- | Prepare the fixpoint data
433+ (tk -> tv -> x) ->
434+ -- | Render row
435+ (x -> tk -> tv -> m (Dynamic t x)) ->
436+ ConfigTree tk tv ->
437+ -- | Parent is open
438+ Dynamic t Bool ->
439+ -- | Force open/close all subtrees
440+ Event t Bool ->
441+ m [Dynamic t x]
442+showWorkingOverrideTree' isShown isModified prepareData renderValue (ConfigTree m) shouldRenderDyn' forceSubtreesEv = do
443+ shouldRenderDyn <- holdUniqDyn shouldRenderDyn'
444+ (appEndo . fold -> f) <- for (OM.assocs m) $ \(k, (mv, _)) -> do
445+ xMaybe <- for mv $ \v -> mdo
446+ let initialData = prepareData k v
447+ x <-
448+ networkView $
449+ shouldRenderDyn <&> \render -> do
450+ lastX <- sample $ current x'
451+ if render
452+ then elClass "div" "row" $ renderValue lastX k v
453+ else pure (pure lastX)
454+ x' <- (join <$> (holdDyn (pure initialData) x))
455+ pure $ x'
456+ pure $ Endo $ maybe id (:) xMaybe
457+ fmap (f . concat) $
458+ for (OM.assocs m) $ \case
459+ (_, (_, subtree)) | CT.null subtree -> pure []
460+ (k, (_, subtree)) -> mdo
461+ let wrapperClass = do
462+ open <- openDyn
463+ pure $
464+ destructClasses $
465+ "collapse--project" <> "collapse"
466+ <> if open
467+ then "collapse--expanded"
468+ else mempty
469+ (ovs, openDyn) <- elDynClass "div" wrapperClass $ do
470+ modified <- configTreeHasLeaf "isModified" isModified subtree
471+ shown <- configTreeHasLeaf "isShown" isShown subtree
472+ (traceEvent "clickEv" -> clickEv) <-
473+ treeButton
474+ TreeButtonConfig
475+ { buttonText = TextBuilder $ rndr k
476+ , subtreeHasChanges = modified
477+ , visible = shouldRenderDyn
478+ , forceState = forceSubtreesEv
479+ }
480+ buttonIsOpen <- holdDyn shown $ leftmost [forceSubtreesEv, fst <$> clickEv]
481+ let selfForceSubtrees = fst <$> ffilter (isRight . snd) clickEv
482+ ovs' <-
483+ divClass "collapse__inner" $
484+ showWorkingOverrideTree'
485+ isShown
486+ isModified
487+ prepareData
488+ renderValue
489+ subtree
490+ ((&&) <$> buttonIsOpen <*> shouldRenderDyn)
491+ (leftmost [selfForceSubtrees, forceSubtreesEv])
492+ pure (ovs', buttonIsOpen)
493+ pure ovs
494+
495+renderRow ::
496+ (DomBuilder t m, Renderable te, Renderable k) =>
497+ k ->
498+ ConfigValue te ->
328499 m ()
329−showNonEditableWorkingOverride loading loaded style cfg =
330− divClass
331− ( destructClasses $
332− "listing" <> "listing--for-text" <> nonEditableWorkingOverrideStyleClasses style
333− )
334− $ do
335− case cfg of
336− [] ->
337− divClass "listing__item" $
338− elClass "span" "listing--info-text" $
339− text $
340− if loaded then "no configuration" else "no custom configuration"
341− _ -> forM_ cfg $ \(WorkingOverrideKey keyType key, val) -> do
342− let wrapper = case val of
343− WorkingDeletedValue _ -> divClass "listing__item deleted"
344− _ -> divClass "listing__item"
345− wrapper $ do
346− let keyWrapper = case keyType of
347− CustomWorkingOverrideKey -> elClass "span" "listing__key"
348− DefaultWorkingOverrideKey -> elClass "span" "listing__key default"
349− keyWrapper $ do
350− rndr key
351− text ": "
352−
353− case val of
354− WorkingCustomValue txt -> elClass "span" "listing__value" $ rndr txt
355− WorkingDefaultValue txt -> elClass "span" "listing__value default" $ rndr txt
356− WorkingDeletedValue (Just txt) -> elClass "span" "listing__value default" $ rndr txt
357− WorkingDeletedValue Nothing -> do
358− elClass "div" "listing__placeholder listing__placeholder__value" $ pure ()
359− when loading $ elClass "div" "listing__spinner" $ pure ()
360− when loading $
361− divClass "listing__item" $ do
362− elClass "div" "listing__placeholder" $ pure ()
363− elClass "div" "listing__spinner" $ pure ()
500+renderRow k v = do
501+ case v of
502+ DefaultConfigValue v' -> do
503+ elClass "span" "key-default-pristine" $ do
504+ rndr k
505+ text ": "
506+ pure ()
507+ elClass "span" "value-pristine" $ rndr v'
508+ pure ()
509+ CustomConfigValue (Left (CustomKey v')) -> do
510+ elClass "span" "key-custom-edited" $ do
511+ rndr k
512+ text ": "
513+ pure ()
514+ elClass "span" "value-edited" $ rndr v'
515+ pure ()
516+ CustomConfigValue (Right (CustomValue v')) -> do
517+ elClass "span" "key-default-edited" $ do
518+ rndr k
519+ text ": "
520+ pure ()
521+ elClass "span" "value-edited" $ rndr v'
522+ pure ()
523+ CustomConfigValue (Right (DeletedValue mv)) -> do
524+ elClass "span" "key-deleted" $ do
525+ rndr k
526+ text ": "
527+ pure ()
528+ elClass "span" "value-deleted" $ rndr `traverse_` mv
529+ pure ()
364530
365531untilReadyEv' ::
366532 (Adjustable t m, PostBuild t m, MonadHold t m) =>
octopod-frontend/src/Frontend/UIKit/Button/Action.hs+3−3
@@ -18,7 +18,7 @@ data ActionButtonConfig t = ActionButtonConfig
1818 { buttonText :: Text
1919 , buttonEnabled :: Dynamic t Bool
2020 , buttonType :: Maybe ActionButtonType
21− , buttonBaseTag :: BaseButtonTag
21+ , buttonBaseTag :: BaseButtonTag t
2222 }
2323 deriving stock (Generic)
2424
@@ -47,7 +47,7 @@ buttonTypeClasses = \case
4747actionButton ::
4848 (DomBuilder t m, PostBuild t m) =>
4949 ActionButtonConfig t ->
50− m (Event t ())
50+ m (Event t (Either () ()))
5151actionButton cfg =
5252 buttonEl
5353 CommonButtonConfig
@@ -58,6 +58,6 @@ actionButton cfg =
5858 , enabledClasses = mempty
5959 , disabledClasses = "action--disabled"
6060 , buttonEnabled = cfg ^. #buttonEnabled
61− , buttonText = pure $ cfg ^. #buttonText
61+ , buttonText = textBuilder $ cfg ^. #buttonText
6262 , buttonBaseTag = cfg ^. #buttonBaseTag
6363 }
octopod-frontend/src/Frontend/UIKit/Button/Common.hs+64−12
@@ -2,48 +2,100 @@ module Frontend.UIKit.Button.Common
22 ( CommonButtonConfig (..),
33 BaseButtonTag (..),
44 buttonEl,
5+ TextBuilder (..),
6+ textBuilder,
57 )
68where
79
8−import Control.Lens
10+import Control.Lens hiding (element)
911import Data.Generics.Labels ()
1012import Data.Map (Map)
13+import Data.Proxy
14+import Data.String
1115import Data.Text (Text)
16+import qualified Data.Text as T
1217import Frontend.Classes
1318import GHC.Generics (Generic)
1419import Reflex.Dom
1520
21+textBuilder :: Text -> TextBuilder t
22+textBuilder t = TextBuilder $ text t
23+
24+newtype TextBuilder t = TextBuilder
25+ { unTextBuilder ::
26+ forall m.
27+ ( DomBuilder t m
28+ , PostBuild t m
29+ ) =>
30+ m ()
31+ }
32+
33+instance IsString (TextBuilder t) where
34+ fromString t = TextBuilder (text . T.pack $ t)
35+
1636data CommonButtonConfig t = CommonButtonConfig
1737 { constantClasses :: Dynamic t Classes
1838 , enabledClasses :: Classes
1939 , disabledClasses :: Classes
2040 , buttonEnabled :: Dynamic t Bool
21− , buttonText :: Dynamic t Text
22− , buttonBaseTag :: BaseButtonTag
41+ , buttonText :: TextBuilder t
42+ , buttonBaseTag :: BaseButtonTag t
2343 }
2444 deriving stock (Generic)
2545
26−data BaseButtonTag = ButtonTag | ATag Text
46+data BaseButtonTag t = ButtonTag | ATag (Dynamic t Text)
2747
28−baseTag :: BaseButtonTag -> (Text, Map Text Text)
29−baseTag ButtonTag = ("button", "type" =: "button")
30−baseTag (ATag url) = ("a", "href" =: url <> "target" =: "_blank")
48+baseTag :: Reflex t => BaseButtonTag t -> (Text, Dynamic t (Map Text Text))
49+baseTag ButtonTag = ("button", pure $ "type" =: "button")
50+baseTag (ATag urlDyn) =
51+ ( "a"
52+ , urlDyn <&> \url -> "href" =: url <> "target" =: "_blank"
53+ )
3154
3255buttonEl ::
56+ forall m t.
3357 (DomBuilder t m, PostBuild t m) =>
3458 CommonButtonConfig t ->
35− m (Event t ())
59+ m (Event t (Either () ()))
3660buttonEl cfg = do
37− let (t, staticAttrs) = baseTag (cfg ^. #buttonBaseTag)
61+ let (t, tagAttrsDyn) = baseTag (cfg ^. #buttonBaseTag)
3862 attrsDyn = do
3963 enabled <- cfg ^. #buttonEnabled
4064 let (enabledClasses, enabledAttrs) = case enabled of
4165 True -> (cfg ^. #enabledClasses, mempty)
4266 False -> (cfg ^. #disabledClasses, "disabled" =: "")
4367 cs <- cfg ^. #constantClasses
68+ tagAttrs <- tagAttrsDyn
4469 pure $
45− staticAttrs
70+ tagAttrs
4671 <> "class" =: destructClasses (enabledClasses <> cs)
4772 <> enabledAttrs
48− (bEl, _) <- elDynAttr' t attrsDyn $ dynText $ cfg ^. #buttonText
49− pure $ domEvent Click bEl
73+ modAttrs <- dynamicAttributesToModifyAttributes attrsDyn
74+ let elCfg =
75+ (def @(ElementConfig EventResult t (DomBuilderSpace m)))
76+ & elementConfig_modifyAttributes .~ fmapCheap mapKeysToAttributeName modAttrs
77+ & elementConfig_eventSpec
78+ %~~ addEventSpecFlags
79+ (Proxy @(DomBuilderSpace m))
80+ Contextmenu
81+ ( const
82+ EventFlags
83+ { _eventFlags_propagation = Propagation_StopImmediate
84+ , _eventFlags_preventDefault = False
85+ }
86+ )
87+ & elementConfig_eventSpec
88+ %~~ addEventSpecFlags
89+ (Proxy @(DomBuilderSpace m))
90+ Click
91+ ( const
92+ EventFlags
93+ { _eventFlags_propagation = Propagation_StopImmediate
94+ , _eventFlags_preventDefault = False
95+ }
96+ )
97+ (bEl, _) <- element t elCfg (unTextBuilder (cfg ^. #buttonText))
98+ pure $ leftmost [Left <$> domEvent Click bEl, Right <$> domEvent Contextmenu bEl]
99+
100+(%~~) :: ASetter' s a -> (a -> a) -> s -> s
101+(%~~) = (%~)
octopod-frontend/src/Frontend/UIKit/Button/Dash.hs+2−2
@@ -54,7 +54,7 @@ buttonTypeClasses = \case
5454dashButton ::
5555 (DomBuilder t m, PostBuild t m) =>
5656 DashButtonConfig t ->
57− m (Event t ())
57+ m (Event t (Either () ()))
5858dashButton cfg =
5959 buttonEl
6060 CommonButtonConfig
@@ -66,6 +66,6 @@ dashButton cfg =
6666 , enabledClasses = mempty
6767 , disabledClasses = "dash--disabled"
6868 , buttonEnabled = cfg ^. #buttonEnabled
69− , buttonText = pure $ cfg ^. #buttonText
69+ , buttonText = textBuilder $ cfg ^. #buttonText
7070 , buttonBaseTag = ButtonTag
7171 }
octopod-frontend/src/Frontend/UIKit/Button/Expander.hs+3−2
@@ -10,6 +10,7 @@ where
1010import Control.Lens
1111import Control.Monad.Fix
1212import Data.Default
13+import Data.Functor
1314import Data.Generics.Labels ()
1415import Data.Text (Text)
1516import Frontend.Classes
@@ -65,7 +66,7 @@ expanderButton ::
6566 ExpanderButtonConfig t ->
6667 m (Dynamic t ExpanderState)
6768expanderButton cfg = mdo
68− stateDyn <- foldDyn (\() -> toggleState) (cfg ^. #buttonInitialState) toggleEv
69+ stateDyn <- foldDyn (\() -> toggleState) (cfg ^. #buttonInitialState) (toggleEv $> ())
6970 let constantClasses =
7071 "expander"
7172 <> maybe mempty buttonTypeClasses (cfg ^. #buttonType)
@@ -79,7 +80,7 @@ expanderButton cfg = mdo
7980 , enabledClasses = mempty
8081 , disabledClasses = mempty
8182 , buttonEnabled = pure True
82− , buttonText = cfg ^. #buttonText
83+ , buttonText = TextBuilder $ dynText $ cfg ^. #buttonText
8384 , buttonBaseTag = ButtonTag
8485 }
8586 pure stateDyn
octopod-frontend/src/Frontend/UIKit/Button/Large.hs+3−3
@@ -23,7 +23,7 @@ data LargeButtonConfig t = LargeButtonConfig
2323 , buttonType :: Dynamic t (Maybe LargeButtonType)
2424 , buttonPriority :: LargeButtonPriority
2525 , buttonStyle :: LargeButtonStyle
26− , buttonBaseTag :: BaseButtonTag
26+ , buttonBaseTag :: BaseButtonTag t
2727 }
2828 deriving stock (Generic)
2929
@@ -77,7 +77,7 @@ buttonTypeClasses LoadingLargeButtonType = "button--save-loading"
7777largeButton ::
7878 (DomBuilder t m, PostBuild t m) =>
7979 LargeButtonConfig t ->
80− m (Event t ())
80+ m (Event t (Either () ()))
8181largeButton cfg =
8282 buttonEl
8383 CommonButtonConfig
@@ -91,6 +91,6 @@ largeButton cfg =
9191 , enabledClasses = mempty
9292 , disabledClasses = "button--disabled"
9393 , buttonEnabled = cfg ^. #buttonEnabled
94− , buttonText = pure $ cfg ^. #buttonText
94+ , buttonText = textBuilder $ cfg ^. #buttonText
9595 , buttonBaseTag = cfg ^. #buttonBaseTag
9696 }
octopod-frontend/src/Frontend/UIKit/Button/Sort.hs+2−2
@@ -41,7 +41,7 @@ buttonSortStateClasses = \case
4141sortButton ::
4242 (DomBuilder t m, PostBuild t m) =>
4343 SortButtonConfig t ->
44− m (Event t ())
44+ m (Event t (Either () ()))
4545sortButton cfg =
4646 buttonEl
4747 CommonButtonConfig
@@ -53,6 +53,6 @@ sortButton cfg =
5353 , enabledClasses = mempty
5454 , disabledClasses = mempty
5555 , buttonEnabled = cfg ^. #buttonEnabled
56− , buttonText = pure $ cfg ^. #buttonText
56+ , buttonText = textBuilder $ cfg ^. #buttonText
5757 , buttonBaseTag = ButtonTag
5858 }
octopod-frontend/src/Frontend/UIKit/Button/Static.hs+25−12
@@ -4,13 +4,14 @@ module Frontend.UIKit.Button.Static
44 closePopupButton,
55 deleteOverrideButton,
66 undoOverrideButton,
7+ dropButton,
78 )
89where
910
1011import Frontend.UIKit.Button.Common
1112import Reflex.Dom
1213
13−closeNotificationButton :: (DomBuilder t m, PostBuild t m) => m (Event t ())
14+closeNotificationButton :: (DomBuilder t m, PostBuild t m) => m (Event t (Either () ()))
1415closeNotificationButton =
1516 buttonEl
1617 CommonButtonConfig
@@ -18,11 +19,11 @@ closeNotificationButton =
1819 , enabledClasses = mempty
1920 , disabledClasses = mempty
2021 , buttonEnabled = pure True
21− , buttonText = pure ""
22+ , buttonText = ""
2223 , buttonBaseTag = ButtonTag
2324 }
2425
25−closeClassicPopupButton :: (DomBuilder t m, PostBuild t m) => m (Event t ())
26+closeClassicPopupButton :: (DomBuilder t m, PostBuild t m) => m (Event t (Either () ()))
2627closeClassicPopupButton =
2728 buttonEl
2829 CommonButtonConfig
@@ -30,11 +31,11 @@ closeClassicPopupButton =
3031 , enabledClasses = mempty
3132 , disabledClasses = mempty
3233 , buttonEnabled = pure True
33− , buttonText = pure ""
34+ , buttonText = ""
3435 , buttonBaseTag = ButtonTag
3536 }
3637
37−closePopupButton :: (DomBuilder t m, PostBuild t m) => m (Event t ())
38+closePopupButton :: (DomBuilder t m, PostBuild t m) => m (Event t (Either () ()))
3839closePopupButton =
3940 buttonEl
4041 CommonButtonConfig
@@ -42,30 +43,42 @@ closePopupButton =
4243 , enabledClasses = mempty
4344 , disabledClasses = mempty
4445 , buttonEnabled = pure True
45− , buttonText = pure ""
46+ , buttonText = ""
4647 , buttonBaseTag = ButtonTag
4748 }
4849
49−deleteOverrideButton :: (DomBuilder t m, PostBuild t m) => m (Event t ())
50+deleteOverrideButton :: (DomBuilder t m, PostBuild t m) => m (Event t (Either () ()))
5051deleteOverrideButton =
5152 buttonEl
5253 CommonButtonConfig
53− { constantClasses = pure "overrides__delete spot spot--cancel"
54+ { constantClasses = pure "editable-row__delete spot spot--cancel"
5455 , enabledClasses = mempty
5556 , disabledClasses = mempty
5657 , buttonEnabled = pure True
57− , buttonText = pure ""
58+ , buttonText = ""
5859 , buttonBaseTag = ButtonTag
5960 }
6061
61−undoOverrideButton :: (DomBuilder t m, PostBuild t m) => m (Event t ())
62+undoOverrideButton :: (DomBuilder t m, PostBuild t m) => m (Event t (Either () ()))
6263undoOverrideButton =
6364 buttonEl
6465 CommonButtonConfig
65− { constantClasses = pure "overrides__delete spot spot--undo"
66+ { constantClasses = pure "editable-row__delete spot spot--undo"
6667 , enabledClasses = mempty
6768 , disabledClasses = mempty
6869 , buttonEnabled = pure True
69− , buttonText = pure ""
70+ , buttonText = ""
71+ , buttonBaseTag = ButtonTag
72+ }
73+
74+dropButton :: (DomBuilder t m, PostBuild t m) => m (Event t (Either () ()))
75+dropButton =
76+ buttonEl
77+ CommonButtonConfig
78+ { constantClasses = pure "drop__handler"
79+ , enabledClasses = mempty
80+ , disabledClasses = mempty
81+ , buttonEnabled = pure True
82+ , buttonText = "Actions"
7083 , buttonBaseTag = ButtonTag
7184 }
octopod-frontend/src/Frontend/UIKit/Button/Tree.hsnew file+84
@@ -0,0 +1,84 @@
1+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
2+
3+{-# HLINT ignore "Use newtype instead of data" #-}
4+module Frontend.UIKit.Button.Tree
5+ ( treeButton,
6+ TreeButtonConfig (..),
7+ TextBuilder (..),
8+ TreeButtonStatus (..),
9+ TreeButtonApply (..),
10+ )
11+where
12+
13+import Control.Lens
14+import Control.Monad
15+import Control.Monad.Fix
16+import Data.Default
17+import Data.Functor
18+import Data.Generics.Labels ()
19+import Frontend.UIKit.Button.Common
20+import GHC.Generics (Generic)
21+import Reflex.Dom
22+import Reflex.Network (networkView)
23+
24+data TreeButtonConfig t = TreeButtonConfig
25+ { buttonText :: TextBuilder t
26+ , subtreeHasChanges :: Bool
27+ , visible :: Dynamic t Bool
28+ , -- | From outside
29+ forceState :: Event t Bool
30+ }
31+ deriving stock (Generic)
32+
33+instance Reflex t => Default (TreeButtonConfig t) where
34+ def =
35+ TreeButtonConfig
36+ { buttonText = ""
37+ , subtreeHasChanges = False
38+ , visible = pure True
39+ , forceState = never
40+ }
41+
42+treeButton ::
43+ (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m) =>
44+ TreeButtonConfig t ->
45+ -- | (<Open?>, <Click>)
46+ m (Event t (Bool, Either () ()))
47+treeButton cfg = mdo
48+ (traceEvent "treeButton" -> clickedEv) <-
49+ networkView >=> switchHold never $
50+ (cfg ^. #visible) <&> \visible ->
51+ if visible
52+ then
53+ buttonEl
54+ CommonButtonConfig
55+ { constantClasses = do
56+ open <- openDyn
57+ pure $
58+ "collapse__head"
59+ <> (if cfg ^. #subtreeHasChanges then "collapse__head--has-changes" else mempty)
60+ <> (if open then mempty else "collapse--expanded")
61+ , buttonText = cfg ^. #buttonText
62+ , buttonBaseTag = ButtonTag
63+ , buttonEnabled = pure True
64+ , disabledClasses = mempty
65+ , enabledClasses = mempty
66+ }
67+ else pure never
68+ openDyn <-
69+ foldDyn
70+ ( \case
71+ Left () -> not
72+ Right x -> const x
73+ )
74+ False
75+ $ (leftmost [Right <$> cfg ^. #forceState, clickedEv $> Left ()])
76+ pure $ coincidence $ (\click -> (,click) <$> updated openDyn) <$> clickedEv
77+
78+data TreeButtonStatus
79+ = TreeButtonClosed
80+ | TreeButtonOpen
81+
82+data TreeButtonApply
83+ = TreeButtonApplyToSelf
84+ | TreeButtonApplyToSubtree
octopod-frontend/src/Frontend/Utils.hs+158−392
@@ -20,60 +20,45 @@ module Frontend.Utils
2020 DeploymentPageNotification (..),
2121 formatPosixToDateTime,
2222 dropdownWidget,
23− dropdownWidget',
2423 deploymentConfigProgressiveComponents,
25− deploymentConfigProgressive,
24+ -- deploymentConfigProgressive,
2625 holdClearingWith,
2726 unitEv,
2827 (<&&>),
29− ProgressiveFullConfig (..),
3028 RequestErrorHandler,
31− deploymentOverridesWidget,
32− deploymentOverridesWidgetSearched,
33− applicationOverridesWidget,
34− applicationOverridesWidgetSearched,
3529 debounceDyn,
3630 catchReturns,
31+ holdDynMaybe,
32+ constructWorkingOverridesEv,
3733 )
3834where
3935
4036import Common.Types as CT
37+import Control.Arrow
4138import Control.Lens
4239import Control.Monad
4340import Control.Monad.Reader
44−import Control.Monad.State.Strict
45−import qualified Data.Bifunctor as Bi
46−import qualified Data.Foldable as F
41+import qualified Data.ConfigTree as CT
4742import Data.Functor
48−import Data.Functor.Misc
4943import Data.Generics.Labels ()
50−import Data.List.NonEmpty (NonEmpty)
51−import Data.Map (Map)
44+import Data.Generics.Sum
5245import qualified Data.Map as M
53−import Data.Map.Monoidal.Strict (MonoidalMap)
54−import qualified Data.Map.Monoidal.Strict as MM
55−import Data.Maybe (fromMaybe, isJust, isNothing)
56−import Data.Monoid
57−import Data.Set (Set)
58−import qualified Data.Set as S
46+import Data.Maybe (fromMaybe)
47+import Data.String
5948import Data.Text as T (Text, null, pack, strip)
60−import Data.Text.Search
61−import Data.These
6249import Data.Time
6350import Data.UniqMap
6451import Data.Unique
6552import Data.Witherable
6653import Data.WorkingOverrides
54+import Debug.Trace
6755import Frontend.API
6856import Frontend.GHCJS
6957import Frontend.UIKit
70−import GHC.Generics (Generic)
7158import GHCJS.DOM
7259import GHCJS.DOM.Element as DOM
7360import GHCJS.DOM.EventM (on, target)
7461import GHCJS.DOM.GlobalEventHandlers as Events (click)
75−import GHCJS.DOM.Node as DOM
76−import Generic.Data (Generically (..))
7762import Reflex.Dom as R
7863import Reflex.Dom.Renderable
7964import Reflex.Network
@@ -90,49 +75,30 @@ elementClick = do
9075 doc <- currentDocumentUnchecked
9176 wrapDomEvent doc (`on` Events.click) $ ClickedElement <$> target
9277
93−-- | Dropdown widget which binds its own @document click@ event.
94−dropdownWidget ::
95− MonadWidget t m =>
96− -- | Button widget which opens the dropdown widget.
97− m () ->
98− -- | Widget with the dropdown list.
99− -- Returns an event carrying the user's selection.
100− m (Event t a) ->
101− m (Event t a)
102−dropdownWidget btn body = mdo
103− clickedEl <- elementClick
104− dropdownWidget' clickedEl btn body
105−
10678-- | Similar to 'dropdownWidget' but uses @document click@ event that may be
10779-- shared between other widgets.
108−dropdownWidget' ::
80+dropdownWidget ::
10981 MonadWidget t m =>
110− -- | Document click event that may be shared between other widgets.
111− Event t ClickedElement ->
112− -- | Button widget which opens the dropdown widget.
113− m () ->
11482 -- | Widget with the dropdown list.
11583 -- Returns an event carrying the user's selection.
11684 m (Event t a) ->
11785 m (Event t a)
118−dropdownWidget' clickedEl btn body = mdo
119− clickInsideEv <- performEvent $
120− ffor clickedEl $ \(ClickedElement clicked) ->
121− DOM.contains (_element_raw btnEl) clicked
122− openedDyn <- foldDyn switchState False $ clickInsideEv
123− let switchState ev cur = ev && not cur
124− wrapperClassDyn = ffor openedDyn $ \case
86+dropdownWidget body = mdo
87+ openedDyn <- toggle False $ btnEl
88+ let wrapperClassDyn = ffor openedDyn $ \case
12589 True -> "class" =: "drop drop--actions drop--expanded"
12690 False -> "class" =: "drop drop--actions"
127− (btnEl, (_, wEv)) <- elDynAttr'
91+ (btnEl, wEv) <- elDynAttr
12892 "div"
12993 wrapperClassDyn
13094 $ do
131− btn
132− elDynAttr'
133− "div"
134− (constDyn $ "class" =: "drop__dropdown")
135− body
95+ clickedEv <- dropButton
96+ aEv <-
97+ elDynAttr
98+ "div"
99+ (constDyn $ "class" =: "drop__dropdown")
100+ body
101+ pure (clickedEv, aEv)
136102 pure wEv
137103
138104showT :: Show a => a -> Text
@@ -214,90 +180,46 @@ octopodTextInput clss lbl placeholder val errEv =
214180 elClass "section" "deployment__section" $ do
215181 elClass "h3" "deployment__sub-heading" $ text lbl
216182 elClass "div" "deployment__widget" $ do
217− (value -> valDyn, validDyn) <- octopodTextInput' (pure []) (pure False) (pure clss) placeholder (pure . fromMaybe "" $ val) errEv
183+ (value -> valDyn, validDyn) <- octopodTextInput' (pure []) (pure False) (pure mempty) (pure clss) placeholder (pure . fromMaybe "" $ val) errEv
218184 pure (valDyn, validDyn)
219185
220186-- | Widget that can show and hide overrides if there are more than 3. This
221187-- widget is used in the deployments table and the deployment action table.
222188overridesWidget ::
223− (MonadWidget t m, Renderable te, Ord te) =>
189+ (MonadWidget t m, Renderable te, IsString te, Monoid te) =>
224190 -- | List of overrides.
225191 Overrides' te l ->
226− (Event t () -> m (Event t (DefaultConfig' te l))) ->
227192 m ()
228−overridesWidget ovs getDef = divClass "listing listing--for-text" $ mdo
229− defMDyn <- getDef firstExpand >>= holdDynMaybe
230− dyn_ $
231− expandState <&> \case
232− ExpandedState ->
233− void $
234− networkView $
235− do
236− defM <- defMDyn
237− pure $
238− showNonEditableWorkingOverride (isNothing defM) (isJust defM) RegularNonEditableWorkingOverrideStyle $
239− elemsUniq $ constructWorkingOverrides defM ovs
240− ContractedState ->
241− let ovsList = elemsUniq $ constructWorkingOverrides Nothing ovs
242− in showNonEditableWorkingOverride False False RegularNonEditableWorkingOverrideStyle $
243− take 3 ovsList
244−
245− expandState <-
246− expanderButton
247− ExpanderButtonConfig
248− { buttonText = do
249− s <- expandState
250− pure $ case s of
251− ExpandedState -> "Hide default configuration"
252− ContractedState -> "Show full configuration"
253− , buttonInitialState = ContractedState
254− , buttonType = Just ListingExpanderButton
255− , buttonStyle = RegularExpanderButtonStyle
256− }
257− firstExpand <- headE $ ($> ()) $ ffilter (== ExpandedState) $ updated expandState
193+overridesWidget (Overrides ovs) = mdo
194+ let l = CT.toFlatList ovs
195+ expandable = length l > 3
196+
197+ if expandable
198+ then mdo
199+ dyn_ $
200+ expandState <&> \s -> do
201+ let l' = case s of
202+ ExpandedState -> l
203+ ContractedState -> take 3 l
204+ showFlatConfig l'
205+ pure ()
206+
207+ expandState <-
208+ expanderButton
209+ ExpanderButtonConfig
210+ { buttonText = do
211+ s <- expandState
212+ pure $ case s of
213+ ExpandedState -> "Hide default configuration"
214+ ContractedState -> "Show full configuration"
215+ , buttonInitialState = ContractedState
216+ , buttonType = Just ListingExpanderButton
217+ , buttonStyle = RegularExpanderButtonStyle
218+ }
219+ pure ()
220+ else showFlatConfig l
258221 pure ()
259222
260−deploymentOverridesWidget ::
261− (MonadWidget t m) =>
262− RequestErrorHandler t m ->
263− Overrides 'DeploymentLevel ->
264− m ()
265−deploymentOverridesWidget hReq depOvs =
266− deploymentOverridesWidgetSearched hReq (wrapResult depOvs)
267−
268−deploymentOverridesWidgetSearched ::
269− (MonadWidget t m) =>
270− RequestErrorHandler t m ->
271− Overrides' SearchResult 'DeploymentLevel ->
272− m ()
273−deploymentOverridesWidgetSearched hReq depOvs =
274− overridesWidget depOvs $ (fmap . fmap . fmap) wrapResult $ defaultDeploymentOverrides >=> hReq
275−
276−applicationOverridesWidget ::
277− MonadWidget t m =>
278− RequestErrorHandler t m ->
279− Overrides 'DeploymentLevel ->
280− Overrides 'ApplicationLevel ->
281− m ()
282−applicationOverridesWidget hReq depOvs appOvs =
283− applicationOverridesWidgetSearched hReq (wrapResult depOvs) (wrapResult appOvs)
284−
285−applicationOverridesWidgetSearched ::
286− MonadWidget t m =>
287− RequestErrorHandler t m ->
288− Overrides' SearchResult 'DeploymentLevel ->
289− Overrides' SearchResult 'ApplicationLevel ->
290− m ()
291−applicationOverridesWidgetSearched hReq depOvs appOvs =
292− overridesWidget appOvs $ \fire -> do
293− depDefEv <- defaultDeploymentOverrides fire >>= hReq
294− fmap switchDyn $
295− (fmap . fmap . fmap) wrapResult $
296− networkHold (pure never) $
297− depDefEv <&> \depDef -> do
298− pb <- getPostBuild
299− defaultApplicationOverrides (pure $ Right $ applyOverrides (deSearch depOvs) depDef) pb >>= hReq
300−
301223-- | Type of notification at the top of pages.
302224data DeploymentPageNotification
303225 = -- | Message text for a \"success\" events.
@@ -351,9 +273,11 @@ deploymentPopupBody ::
351273 m (Dynamic t (Maybe DeploymentUpdate))
352274deploymentPopupBody hReq defAppOv defDepOv errEv = mdo
353275 pb <- getPostBuild
354− (defDepEv, defApp, depCfgEv) <- deploymentConfigProgressiveComponents hReq deploymentOvsDynDebounced
355− defAppM <- holdClearingWith defApp (unitEv deploymentOvsDyn)
356− defDep <- holdDynMaybe defDepEv
276+ (defDepEv, defAppEv, depCfgEv) <-
277+ deploymentConfigProgressiveComponents hReq deploymentOvsDynDebounced
278+
279+ defAppEvM <- holdClearingWith defAppEv (unitEv deploymentOvsDyn)
280+
357281 depKeys <- deploymentOverrideKeys pb >>= hReq
358282
359283 let commandResponseEv = fmapMaybe commandResponse errEv
@@ -361,46 +285,47 @@ deploymentPopupBody hReq defAppOv defDepOv errEv = mdo
361285
362286 let holdDCfg ::
363287 Dynamic t [Text] ->
364− Dynamic t (Maybe (DefaultConfig l)) ->
288+ (DefaultConfig l) ->
365289 Overrides l ->
366− m (Dynamic t (Overrides l), Dynamic t (Overrides l), Dynamic t Bool)
367− holdDCfg values dCfgDyn ovs = mdo
368− ovsDyn <- holdDyn ovs ovsEv
369− ovsDynDebounced <- holdDyn ovs ovsEvDebounced
370− x <- attachDyn (current ovsDyn) dCfgDyn
371− (splitE -> (ovsEvEv, isValidDynEv)) <-
372− (>>= joinEvM) $
373− runWithReplace' loadingOverrides $
374− updated x <&> \(ovs', dCfg) -> untilReady' loadingOverrides $ envVarsInput values dCfg ovs'
375− ovsEv <- joinEvM ovsEvEv
376− ovsEvDebounced <- debounce 2 ovsEv
377− isValid <- join <$> holdDyn (pure False) isValidDynEv
378− pure (ovsDyn, ovsDynDebounced, isValid)
290+ m (Dynamic t (Overrides l), Dynamic t (Overrides l))
291+ holdDCfg (traceDyn "values" -> values) cfgDyn@(DefaultConfig ct) ovs = mdo
292+ let ovs' = constructWorkingOverrides cfgDyn ovs
293+ lookupOverride k = CT.lookup (CT.deconstructConfigKey k) ct
294+ (resCfgDyn :: Dynamic t [Dynamic t WorkingOverride]) <- envVarsInput values lookupOverride ovs'
295+ (resEvDebounced :: Event t [Dynamic t WorkingOverride]) <- debounce 2 $ updated resCfgDyn
296+ let resDyn' = join . fmap destructWorkingOverridesDyn $ resCfgDyn
297+ debouncedResDyn <- fmap join . holdDyn (pure ovs) . fmap destructWorkingOverridesDyn $ resEvDebounced
298+ pure (resDyn', debouncedResDyn)
379299
380300 depKeysDyn <- holdDyn [] depKeys
381− (deploymentOvsDyn, deploymentOvsDynDebounced, depValidDyn) <-
382− deploymentSection "Deployment configuration" $ holdDCfg depKeysDyn defDep defDepOv
301+
302+ (join . fmap fst &&& join . fmap snd -> (deploymentOvsDyn, deploymentOvsDynDebounced)) <-
303+ deploymentSection "Deployment configuration" $
304+ networkHold (loadingOverrides $> (pure defDepOv, pure defDepOv)) $
305+ defDepEv <&> \defDep -> holdDCfg depKeysDyn defDep defDepOv
383306
384307 appKeys <- waitForValuePromptly depCfgEv $ \deploymentCfg -> do
385308 pb' <- getPostBuild
386309 applicationOverrideKeys (pure $ Right deploymentCfg) pb' >>= hReq >>= immediateNothing
310+
387311 appKeysDyn <- holdDyn [] $ catMaybes appKeys
388− (applicationOvsDyn, _, appValidDyn) <- deploymentSection "App configuration" $ holdDCfg appKeysDyn defAppM defAppOv
312+ (join -> applicationOvsMDyn) <-
313+ deploymentSection "App configuration" >=> holdDyn (pure Nothing) . fmap sequenceA $
314+ networkView $
315+ defAppEvM <&> \case
316+ Nothing -> loadingOverrides $> Nothing
317+ Just defApp -> Just . fst <$> holdDCfg appKeysDyn defApp defAppOv
389318
390319 pure $ do
391− depValid <- depValidDyn
392− appValid <- appValidDyn
393− if depValid && appValid
394− then do
395− depCfg <- deploymentOvsDyn
396− appOvs <- applicationOvsDyn
397− pure $
398− Just $
399− DeploymentUpdate
400− { appOverrides = appOvs
401− , deploymentOverrides = depCfg
402− }
403− else pure Nothing
320+ depCfg <- deploymentOvsDyn
321+ appOvsM <- applicationOvsMDyn
322+ pure $ do
323+ appOvs <- appOvsM
324+ Just $
325+ DeploymentUpdate
326+ { appOverrides = appOvs
327+ , deploymentOverrides = depCfg
328+ }
404329
405330deploymentConfigProgressiveComponents ::
406331 MonadWidget t m =>
@@ -427,36 +352,17 @@ deploymentConfigProgressiveComponents hReq depOvsDyn = do
427352 defaultApplicationOverrides (pure $ Right depCfg) pb' >>= hReq
428353 pure (defDepEv, defAppEv, depCfgEv)
429354
430−deploymentConfigProgressive ::
431− MonadWidget t m =>
432− RequestErrorHandler t m ->
433− Dynamic t (Overrides 'DeploymentLevel) ->
434− Dynamic t (Overrides 'ApplicationLevel) ->
435− m (Dynamic t ProgressiveFullConfig)
436−deploymentConfigProgressive hReq depOvsDyn appOvsDyn = do
437− (depCfgEv, defAppEv, _) <- deploymentConfigProgressiveComponents hReq depOvsDyn
438− defAppMDyn <- holdDynMaybe defAppEv
439− defCfgMDyn <- holdDynMaybe depCfgEv
440− pure $ do
441− defAppM <- defAppMDyn
442− appOvs <- appOvsDyn
443− defDepM <- defCfgMDyn
444− depOvs <- depOvsDyn
445− pure
446− ProgressiveFullConfig
447− { appConfig = constructWorkingOverrides defAppM appOvs
448− , appConfigLoading = isNothing defAppM
449− , depConfig = constructWorkingOverrides defDepM depOvs
450− , depConfigLoading = isNothing defDepM
451− }
452−
453−data ProgressiveFullConfig = ProgressiveFullConfig
454− { appConfig :: WorkingOverrides
455− , appConfigLoading :: Bool
456− , depConfig :: WorkingOverrides
457− , depConfigLoading :: Bool
458− }
459− deriving stock (Generic)
355+constructWorkingOverridesEv ::
356+ MonadWidget t m => Event t (DefaultConfig l) -> Dynamic t (Overrides l) -> m (Event t WorkingOverrides)
357+constructWorkingOverridesEv defCfgEv ovsDyn = do
358+ defCfgMDyn <- holdDynMaybe defCfgEv
359+ pure $
360+ catMaybes . updated $ do
361+ defCfgM <- defCfgMDyn
362+ ovs <- ovsDyn
363+ pure $ do
364+ defCfg <- defCfgM
365+ pure $ constructWorkingOverrides defCfg ovs
460366
461367waitForValuePromptly :: (MonadHold t m, Adjustable t m) => Event t x -> (x -> m (Event t y)) -> m (Event t y)
462368waitForValuePromptly ev f = fmap switchPromptlyDyn $ networkHold (pure never) $ f <$> ev
@@ -492,32 +398,23 @@ errorHeader ::
492398 -- | Message text.
493399 Dynamic t Text ->
494400 m ()
495−errorHeader appErr = do
496− divClass "deployment__output notification notification--danger" $ do
401+errorHeader appErr =
402+ elClass "pre" "deployment__output notification notification--danger" $
497403 dynText appErr
498404
499405-- | Widget with override fields. This widget supports adding and
500406-- removing key-value pairs.
501407envVarsInput ::
502− forall l t m.
408+ forall t m.
503409 MonadWidget t m =>
504410 Dynamic t [Text] ->
505− Maybe (DefaultConfig l) ->
411+ (Text -> Maybe Text) ->
506412 -- | Initial deployment overrides.
507− Overrides l ->
508− -- | Updated deployment overrides.
509− m (Event t (Overrides l), Dynamic t Bool)
510−envVarsInput values dCfg ovs = mdo
511− let initialOverrides = constructWorkingOverrides dCfg ovs
512− (envsDyn, addedKeys) <-
513− mapAccumDyn
514− ( \prevOvs -> \case
515− Left () ->
516− Bi.second S.singleton $ insertUniqStart newWorkingOverride prevOvs
517− Right (Endo f) -> (f prevOvs, S.empty)
518− )
519− initialOverrides
520− $ leftmost [Left <$> clickEv, Right <$> updEv]
413+ WorkingOverrides ->
414+ -- | Updated deployment overrides. [(<full deconstructed key>, <value>)]
415+ m (Dynamic t [Dynamic t WorkingOverride])
416+envVarsInput (traceDyn "values" -> values) lookupOverride ovs = divClass "padded" $ mdo
417+ let initialConfig = CT.markValues ovs
521418 clickEv <-
522419 dashButton
523420 DashButtonConfig
@@ -526,187 +423,65 @@ envVarsInput values dCfg ovs = mdo
526423 , buttonType = Just AddDashButtonType
527424 , buttonStyle = OverridesDashButtonStyle
528425 }
529− let workingOverridesWithErrors = validateWorkingOverrides . uniqMap <$> envsDyn
530− erroredOverride = M.filter ((/= mempty) . snd) <$> workingOverridesWithErrors
531− isValid = M.null <$> erroredOverride
532− (_, changedValues) <-
533− mapAccumDyn
534− ( \prev new ->
535− ( fmap (\(v, _) -> (v, mempty)) new
536− , new <> prev
537− )
538− )
539− mempty
540− (updated erroredOverride)
541− let updatedValues = restrictMapEv updatedKeys (updated workingOverridesWithErrors)
542− valChangedEvSelector = fanMap (clearedOvs <> updatedValues <> changedValues)
543− (splitE -> (clearedOvs, deletedOvs)) =
544− alignEventWithMaybe
545− ( \case
546− These keys m ->
547− Just $
548− let cleared = M.restrictKeys m keys
549− in (cleared, M.fromSet (const Nothing) (keys `S.difference` M.keysSet cleared))
550− _ -> Nothing
551− )
552− removedKeys
553− (updated workingOverridesWithErrors)
554− listChange =
555− deletedOvs <> (fmap . fmap) Just (restrictMapEv addedKeys (updated workingOverridesWithErrors))
556−
557− (splitE3 -> (updEv, removedKeys, updatedKeys)) <-
558− switchDyn . fmap F.fold
559− <$> listHoldWithKey
560− (validateWorkingOverrides . uniqMap $ initialOverrides)
561− listChange
562− ( \i val -> do
563− valDyn <- holdDyn val $ select valChangedEvSelector $ Const2 i
564− userActionEv <- envVarInput values valDyn
565− pure $ performUserOverrideAction (lookupDefaultConfig <$> dCfg) i <$> userActionEv
566− )
567− let addingIsEnabled = all (\(WorkingOverrideKey _ x, _) -> not . T.null $ x) . elemsUniq <$> envsDyn
568− case dCfg of
569− Just _ -> pure ()
570− Nothing -> loadingOverrides
571− pure (updated $ destructWorkingOverrides <$> envsDyn, isValid)
572−
573−restrictMapEv :: (Reflex t, Ord k) => Event t (Set k) -> Event t (Map k v) -> Event t (Map k v)
574−restrictMapEv =
575− alignEventWithMaybe
576− ( \case
577− These keys _ | S.null keys -> Nothing
578− These keys m -> Just $ M.restrictKeys m keys
579− _ -> Nothing
580− )
581−
582−validateWorkingOverrides ::
583− forall f.
584− Traversable f =>
585− f WorkingOverride ->
586− f (WorkingOverride, OverrideErrors)
587−validateWorkingOverrides overrides =
588− let (result, keyOccurrences :: MonoidalMap Text (Sum Int)) =
589− flip runState mempty $ forM overrides \override@(WorkingOverrideKey _ key, value') -> do
590− case value' of
591− WorkingDeletedValue _ -> pure ()
592− _ -> modify (<> MM.singleton key (Sum 1))
593− pure . (override,) . mconcat $
594− [ case MM.lookup key keyOccurrences of
595− Just (Sum n)
596− | n > 1 ->
597− overrideKeyErrors "You can not use the same key multiple times."
598− _ -> mempty
599− , if T.null key
600− then overrideKeyErrors "Keys can not be empty."
601− else mempty
602− , case value' of
603− WorkingCustomValue "" -> overrideValueErrors "Values can not be empty."
604− WorkingCustomValue _ -> mempty
605− WorkingDefaultValue "" -> overrideValueErrors "Values can not be empty."
606− WorkingDefaultValue _ -> mempty
607− WorkingDeletedValue _ -> mempty
608− ]
609− in result
610−
611−data OverrideErrors = OverrideErrors
612− { keyErrors :: Maybe (NonEmpty Text)
613− , valueErrors :: Maybe (NonEmpty Text)
614− }
615− deriving stock (Generic, Eq, Show)
616− deriving (Semigroup, Monoid) via Generically OverrideErrors
617−
618−overrideKeyErrors :: Text -> OverrideErrors
619−overrideKeyErrors x = mempty {keyErrors = Just $ pure x}
620−
621−overrideValueErrors :: Text -> OverrideErrors
622−overrideValueErrors x = mempty {valueErrors = Just $ pure x}
426+ let emptyItem = ("", CustomConfigValue $ Left $ CustomKey "")
427+ addedItemsCount <- foldDyn (const (fst . insertUniqStart ())) emptyUniqKeyMap clickEv
428+ addedOvsListDyn <- (fmap . fmap) (fmap snd . M.toList)
429+ <$> list (uniqMap <$> addedItemsCount)
430+ $ \_ ->
431+ envVarInput lookupOverride values emptyItem
432+ treeResCfg <-
433+ showOverrideTree
434+ ((== Just True) . fmap (T.null . T.strip) . getConfigValueText . snd)
435+ (isn't (_Ctor' @"DefaultConfigValue") . snd)
436+ (\_ v -> v)
437+ (\a _ _ -> envVarInput lookupOverride values (trace "a" a))
438+ initialConfig
439+ let resCfg :: Dynamic t [Dynamic t (Text, ConfigValue Text)]
440+ resCfg = (<> treeResCfg) <$> addedOvsListDyn
441+ addingIsEnabled = join $ fmap and . sequenceA . (fmap . fmap) (not . T.null . fst) <$> resCfg
442+ pure resCfg
623443
624444-- | Widget for entering a key-value pair.
625445envVarInput ::
626446 (MonadWidget t m) =>
447+ (Text -> Maybe Text) ->
627448 -- | The key values to suggest to the user
628449 Dynamic t [Text] ->
629450 -- | Current variable key and value.
630− Dynamic t (WorkingOverride, OverrideErrors) ->
631− m (Event t UserOverrideAction)
632−envVarInput values val = untilReadyEv' loadingOverride $ do
633− let kDyn = val <&> fst <&> \(WorkingOverrideKey _ x, _) -> x
634− -- Either <override present> <override deleted>
635− d <-
636− eitherDyn $
637− val <&> snd . fst <&> \case
638− WorkingCustomValue v -> Right (v, EditedOverrideFieldType)
639− WorkingDefaultValue v -> Right (v, DefaultOverrideFieldType)
640− WorkingDeletedValue v -> Left v
641− networkView >=> switchHold never $
642− d <&> \case
643− Right vtDyn -> do
644− let (vDyn, vTypeDyn) = splitDynPure vtDyn
645− (keyTextDyn, valTextDyn, closeEv) <-
646− overrideField
647− values
648− OverrideField
649− { fieldValue = kDyn
650− , fieldError = keyErrors . snd <$> val
651− , fieldDisabled =
652− val <&> fst <&> \(WorkingOverrideKey t _, _) -> t == DefaultWorkingOverrideKey
653− , fieldType =
654− val <&> fst <&> \(WorkingOverrideKey t _, _) -> case t of
655− CustomWorkingOverrideKey -> EditedOverrideFieldType
656− DefaultWorkingOverrideKey -> DefaultOverrideFieldType
657− }
658− OverrideField
659− { fieldValue = vDyn
660− , fieldError = valueErrors . snd <$> val
661− , fieldDisabled = pure False
662− , fieldType = vTypeDyn
663− }
664− pure $
665− leftmost
666− [ UpdateKey <$> updated keyTextDyn
667− , UpdateValue <$> updated valTextDyn
668− , closeEv $> DeleteOverride
669− ]
670− Left vDyn -> do
671− restoreEv <-
672− networkView >=> switchHold never $ do
673− v <- vDyn
674− k <- kDyn
675− pure $ deletedOverride k v
451+ WorkingOverride ->
452+ m (Dynamic t WorkingOverride)
453+envVarInput f keys val = mdo
454+ value' <- holdDyn val (leftmost [buttonValue, updated inputValue])
455+ (keyTextDyn, valTextDyn, buttonPressEv) <- configField keys value'
456+ let inputValue = do
457+ v <- valTextDyn
458+ k <- keyTextDyn
676459 pure $
677− flip push restoreEv $ \() -> do
678− v <- sample . current $ vDyn
679− pure $ UpdateValue <$> v
680−
681−data UserOverrideAction = UpdateKey !Text | UpdateValue !Text | DeleteOverride
682−
683−performUserOverrideAction ::
684− Maybe (Text -> Maybe Text) ->
685− Int ->
686− UserOverrideAction ->
687− -- | (endo, removed/cleared keys, updatedKeys)
688− (Endo WorkingOverrides, Set Int, Set Int)
689−performUserOverrideAction f i (UpdateValue v) = (,S.empty,S.singleton i) $
690− Endo $
691− updateUniq i $ \(k@(WorkingOverrideKey _ kt), _) ->
692− ( k
693− , case f >>= ($ kt) of
694− Just v' | v == v' -> WorkingDefaultValue v
695− _ -> WorkingCustomValue v
696− )
697−performUserOverrideAction _ i (UpdateKey k) = (,S.empty,S.singleton i) $
698− Endo $
699− updateUniq i $
700− \(_, v) -> (WorkingOverrideKey CustomWorkingOverrideKey k, v)
701−performUserOverrideAction f i DeleteOverride = (,S.singleton i,S.empty) $
702− Endo $ \m ->
703− case f of
704− Nothing -> updateUniq i (\(k, _) -> (k, WorkingDeletedValue Nothing)) m
705− Just _ -> case lookupUniq i m of
706− Nothing -> m
707− Just (WorkingOverrideKey DefaultWorkingOverrideKey k, _) ->
708− updateUniq i (const (WorkingOverrideKey DefaultWorkingOverrideKey k, WorkingDeletedValue (f >>= ($ k)))) m
709− Just (WorkingOverrideKey CustomWorkingOverrideKey _, _) -> deleteUniq i m
460+ ( k
461+ , case f k of
462+ Nothing -> CustomConfigValue $ Left $ CustomKey v
463+ Just x | x == v -> DefaultConfigValue v
464+ Just _ -> CustomConfigValue $ Right $ CustomValue v
465+ )
466+ buttonValue = flip push buttonPressEv $ \x ->
467+ Just <$> do
468+ k <- sample . current $ keyTextDyn
469+ (k,) <$> case x of
470+ ConfigFieldButtonClear -> do
471+ v <- case f k of
472+ Nothing -> sample . current $ valTextDyn
473+ Just v -> pure v
474+ pure $ CustomConfigValue $ Right $ DeletedValue $ Just v
475+ ConfigFieldButtonRecover -> do
476+ case f k of
477+ Nothing -> do
478+ -- the value is not in the default config
479+ v <- sample . current $ valTextDyn
480+ pure $ CustomConfigValue $ Left $ CustomKey v
481+ Just v -> do
482+ -- the value is in the default config
483+ pure $ DefaultConfigValue v
484+ pure $ value'
710485
711486holdDynMaybe :: (Reflex t, MonadHold t m) => Event t a -> m (Dynamic t (Maybe a))
712487holdDynMaybe ev = holdDyn Nothing $ fmapCheap Just ev
@@ -716,12 +491,6 @@ immediateNothing ev = do
716491 pb <- getPostBuild
717492 pure $ leftmost [pb $> Nothing, fmapCheap Just ev]
718493
719−attachDyn :: (Reflex t, MonadHold t m) => Behavior t a -> Dynamic t b -> m (Dynamic t (a, b))
720−attachDyn b d = do
721− currD <- sample . current $ d
722− currB <- sample b
723− holdDyn (currB, currD) (attach b $ updated d)
724−
725494holdClearingWith :: (Reflex t, MonadHold t m) => Event t a -> Event t () -> m (Dynamic t (Maybe a))
726495holdClearingWith aEv clear =
727496 holdDyn Nothing $ leftmost [fmapCheap Just aEv, fmapCheap (const Nothing) clear]
@@ -751,6 +520,3 @@ catchReturns :: (DomBuilder t m, MonadFix m) => (Event t () -> m a) -> m a
751520catchReturns f = mdo
752521 (divEl, a) <- el' "div" $ f $ ($> ()) . ffilter (== 13) $ domEvent Keypress divEl
753522 pure a
754−
755−splitE3 :: Reflex t => Event t (a, b, c) -> (Event t a, Event t b, Event t c)
756−splitE3 e = ((\(a, _, _) -> a) <$> e, (\(_, b, _) -> b) <$> e, (\(_, _, c) -> c) <$> e)
octopod-frontend/src/Page/ClassicPopup.hs+3−2
@@ -12,6 +12,7 @@ where
1212
1313import Reflex.Dom
1414
15+import Data.Functor
1516import Data.Generics.Labels ()
1617import Frontend.UIKit
1718
@@ -53,7 +54,7 @@ popupWidget m =
5354 divClass "classic-popup__slot" $ do
5455 (okEv, cancelEv) <- m
5556 closeEv <- closeClassicPopupButton
56− pure $ (okEv, leftmost [cancelEv, closeEv])
57+ pure $ (okEv, leftmost [cancelEv, closeEv $> ()])
5758
5859-- | Popup that requires confirmation of deployment deletion.
5960confirmArchivePopup ::
@@ -77,5 +78,5 @@ confirmArchivePopup showEv txt = do
7778 & #buttonStyle .~~ DialogActionLargeButtonStyle
7879 & #buttonPriority .~~ SecondaryLargeButton
7980 & #buttonText .~~ "Cancel"
80− pure (okEv, cancelEv)
81+ pure (okEv $> (), cancelEv $> ())
8182 classicPopup showEv body
octopod-frontend/src/Page/Deployment.hs+39−34
@@ -5,31 +5,30 @@
55--This module contains the definition of a deployment page.
66module Page.Deployment (deploymentPage) where
77
8−import Control.Lens
9−import Control.Monad
10−import Data.Coerce
11−import Data.Generics.Product (field)
12−import Data.Text as T (Text, pack)
13−import Obelisk.Route.Frontend
14−import Reflex.Dom as R
15−import Servant.Reflex
16−
178import Common.Types as CT
189import Common.Utils
10+import Control.Lens
11+import Control.Monad
1912import Control.Monad.Reader
2013import Data.Align
14+import Data.Coerce
15+import Data.Functor
2116import Data.Generics.Labels ()
17+import Data.Generics.Product (field)
18+import Data.Text as T (Text, pack)
2219import Data.Time
23−import Data.UniqMap
2420import Frontend.API
2521import Frontend.GHCJS
2622import Frontend.Route
2723import Frontend.UIKit
2824import Frontend.Utils
25+import Obelisk.Route.Frontend
2926import Page.ClassicPopup
3027import Page.Elements.Links
3128import Page.Popup.EditDeployment
29+import Reflex.Dom as R
3230import Reflex.Network
31+import Servant.Reflex
3332import Servant.Reflex.Extra
3433
3534-- | The root widget of a deployment page. It requests the deployment data.
@@ -125,7 +124,7 @@ deploymentHead dfiDyn sentEv =
125124 & #buttonStyle .~~ PageActionLargeButtonStyle
126125 & #buttonText .~~ "Recover from archive"
127126 & #buttonEnabled .~~ btnEnabledDyn
128− void $ restoreEndpoint (Right . coerce <$> dname) btnEv
127+ void $ restoreEndpoint (Right . coerce <$> dname) $ btnEv $> ()
129128 pure (never, never)
130129 else mdo
131130 let btnState = not $ isPending . recordedStatus $ dfi ^. field @"status"
@@ -159,10 +158,10 @@ deploymentHead dfiDyn sentEv =
159158 , buttonType = pure $ Just LogsLargeButtonType
160159 , buttonPriority = SecondaryLargeButton
161160 , buttonStyle = PageActionLargeButtonStyle
162− , buttonBaseTag = ATag url
161+ , buttonBaseTag = ATag $ pure url
163162 }
164163 )
165− delEv <- confirmArchivePopup archEv $ do
164+ delEv <- confirmArchivePopup (archEv $> ()) $ do
166165 text "Are you sure you want to archive the"
167166 el "br" blank
168167 dynText dname
@@ -192,7 +191,7 @@ deploymentBody updEv dfiDyn = deploymentBodyWrapper $
192191 wrapRequestErrors $ \hReq -> do
193192 let nameDyn = dfiDyn <^.> dfiName
194193 depDyn = dfiDyn <^.> #deployment
195− cfgDyn <- deploymentConfigProgressive hReq (depDyn <^.> #deploymentOverrides) (depDyn <^.> #appOverrides)
194+ (defDepCfgEv, defAppCfgEv, _) <- deploymentConfigProgressiveComponents hReq (depDyn <^.> #deploymentOverrides)
196195 divClass "deployment__summary" $ do
197196 divClass "deployment__stat" $ do
198197 elClass "b" "deployment__param" $ text "Status"
@@ -213,18 +212,26 @@ deploymentBody updEv dfiDyn = deploymentBodyWrapper $
213212 divClass "deployment__widget" $
214213 divClass "listing" $
215214 void $ simpleList urlsDyn renderMetadataLink
216− void $
217− networkView $
218− cfgDyn <&> \cfg -> do
219− let showVars bL l =
220− divClass "deployment__widget" $
221− showNonEditableWorkingOverride (cfg ^. bL) (not $ cfg ^. bL) LargeNonEditableWorkingOverrideStyle $
222− elemsUniq (cfg ^. l)
223− deploymentSection "Deployment configuration" $ showVars #depConfigLoading #depConfig
224− deploymentSection "App configuration" $ showVars #appConfigLoading #appConfig
215+ deploymentSection "Deployment configuration" $ showVars defDepCfgEv $ depDyn <^.> #deploymentOverrides
216+ deploymentSection "App configuration" $ showVars defAppCfgEv $ depDyn <^.> #appOverrides
225217 deploymentSection "Actions" $
226218 divClass "table table--actions" $
227− actionsTable hReq updEv nameDyn
219+ actionsTable updEv nameDyn
220+
221+showVars ::
222+ MonadWidget t m =>
223+ Event t (DefaultConfig l) ->
224+ Dynamic t (Overrides l) ->
225+ m ()
226+showVars defCfgEv ovsDyn = do
227+ workingOvsEv <- constructWorkingOverridesEv defCfgEv ovsDyn
228+ _ <-
229+ divClass "deployment__widget" $
230+ networkHold nonEditableLoading $
231+ workingOvsEv <&> \x -> do
232+ showNonEditableWorkingOverrideTree (pure x)
233+ pure ()
234+ pure ()
228235
229236-- | Widget with a table of actions that can be performed on a deployment.
230237-- It requests deployment data.
@@ -232,12 +239,11 @@ deploymentBody updEv dfiDyn = deploymentBodyWrapper $
232239-- otherwise it calls 'actionsTableData', passing the received data.
233240actionsTable ::
234241 MonadWidget t m =>
235− RequestErrorHandler t m ->
236242 -- | Event notifying about the need to update data.
237243 Event t () ->
238244 Dynamic t DeploymentName ->
239245 m ()
240−actionsTable hReq updEv nameDyn = do
246+actionsTable updEv nameDyn = do
241247 pb <- getPostBuild
242248 respEv <- infoEndpoint (Right <$> nameDyn) pb
243249 let okEv = join . fmap logs <$> fmapMaybe reqSuccess respEv
@@ -247,7 +253,7 @@ actionsTable hReq updEv nameDyn = do
247253 widgetHold_ actionsTableLoading $
248254 leftmost
249255 [ actionsTableError <$ errEv
250− , actionsTableData hReq updEv nameDyn <$> okEv
256+ , actionsTableData updEv nameDyn <$> okEv
251257 ]
252258
253259-- | Header of the actions table.
@@ -285,25 +291,24 @@ actionsTableError = do
285291-- It updates data every time when the supplied event fires.
286292actionsTableData ::
287293 MonadWidget t m =>
288− RequestErrorHandler t m ->
289294 -- | Event notifying about the need to update data.
290295 Event t () ->
291296 Dynamic t DeploymentName ->
292297 -- | Initial logs.
293298 [DeploymentLog] ->
294299 m ()
295−actionsTableData hReq updEv nameDyn initLogs = do
300+actionsTableData updEv nameDyn initLogs = do
296301 respEv <- infoEndpoint (Right <$> nameDyn) updEv
297302 let okEv = (>>= logs) <$> fmapMaybe reqSuccess respEv
298303 logsDyn <- holdDyn initLogs okEv
299304 el "tbody" $
300305 void $
301306 simpleList logsDyn $ \logDyn -> do
302− dyn_ $ actinRow hReq <$> logDyn
307+ dyn_ $ actionRow <$> logDyn
303308
304309-- | Data row of the actions table.
305−actinRow :: RequestErrorHandler t m -> MonadWidget t m => DeploymentLog -> m ()
306−actinRow hReq DeploymentLog {..} = do
310+actionRow :: MonadWidget t m => DeploymentLog -> m ()
311+actionRow DeploymentLog {..} = do
307312 el "tr" $ do
308313 el "td" $ do
309314 text $ actionToText action
@@ -311,8 +316,8 @@ actinRow hReq DeploymentLog {..} = do
311316 "status "
312317 <> if exitCode == 0 then "status--success" else "status--failure"
313318 divClass statusClass blank
314− el "td" $ deploymentOverridesWidget hReq deploymentDepOverrides
315− el "td" $ applicationOverridesWidget hReq deploymentDepOverrides deploymentAppOverrides
319+ el "td" $ overridesWidget deploymentDepOverrides
320+ el "td" $ overridesWidget deploymentAppOverrides
316321 el "td" $ text $ showT $ exitCode
317322 el "td" $ text $ formatPosixToDateTime createdAt
318323 el "td" $ text $ formatDuration duration
octopod-frontend/src/Page/Deployments.hs+36−72
@@ -24,6 +24,7 @@ import Common.Utils
2424import Control.Applicative
2525import Control.Monad.Reader
2626import Data.Align
27+import Data.Foldable
2728import Data.Functor
2829import qualified Data.Semigroup as S
2930import qualified Data.Text as T
@@ -79,20 +80,19 @@ deploymentsWidget ::
7980 [DeploymentFullInfo] ->
8081 m ()
8182deploymentsWidget updAllEv dfis = do
82− (showNewDeploymentEv, editEv) <- deploymentsWidgetWrapper $
83− wrapRequestErrors $ \hReq -> mdo
84− pageNotification $
85− leftmost
86− [ DPMError
87− "Deployment list update failed, deployment list\
88− \ may be slightly outdated."
89− <$ errUpdEv
90− , DPMClear <$ okUpdEv
91− ]
92− (showNewDeploymentEv', termDyn') <- deploymentsHeadWidget True okUpdEv
93− termDyn <- debounceDyn 0.3 termDyn'
94− (okUpdEv, errUpdEv, editEv) <- deploymentsListWidget hReq updAllEv termDyn dfis
95− pure (showNewDeploymentEv', deSearch <$> editEv)
83+ (showNewDeploymentEv, editEv) <- deploymentsWidgetWrapper $ mdo
84+ pageNotification $
85+ leftmost
86+ [ DPMError
87+ "Deployment list update failed, deployment list\
88+ \ may be slightly outdated."
89+ <$ errUpdEv
90+ , DPMClear <$ okUpdEv
91+ ]
92+ (showNewDeploymentEv', termDyn') <- deploymentsHeadWidget True okUpdEv
93+ termDyn <- debounceDyn 0.3 termDyn'
94+ (okUpdEv, errUpdEv, editEv) <- deploymentsListWidget updAllEv termDyn dfis
95+ pure (showNewDeploymentEv', deSearch <$> editEv)
9696 newDepEv <- newDeploymentPopup showNewDeploymentEv never
9797 setRoute $ newDepEv <&> \newDep -> DashboardRoute :/ Just (newDep ^. #name)
9898
@@ -178,13 +178,12 @@ deploymentsListWidget ::
178178 , SetRoute t (R Routes) m
179179 , MonadReader ProjectConfig m
180180 ) =>
181− RequestErrorHandler t m ->
182181 Event t () ->
183182 Dynamic t Text ->
184183 -- | Initial deployment data
185184 [DeploymentFullInfo] ->
186185 m (Event t (), Event t (), Event t SearchedDeploymentInfo)
187−deploymentsListWidget hReq updAllEv termDyn ds = dataWidgetWrapper $ mdo
186+deploymentsListWidget updAllEv termDyn ds = dataWidgetWrapper $ mdo
188187 retryEv <- delay 10 errUpdEv
189188 updRespEv <- listEndpoint $ leftmost [updAllEv, () <$ retryEv]
190189 let okUpdEv = fmapMaybe reqSuccess updRespEv
@@ -197,9 +196,8 @@ deploymentsListWidget hReq updAllEv termDyn ds = dataWidgetWrapper $ mdo
197196 let (archivedDsDyn, activeDsDyn) =
198197 splitDynPure $ L.partition isDeploymentArchived <$> searchedDyn
199198 searchSorting = termDyn $> Nothing
200− clickedEv <- elementClick
201− editEv <- activeDeploymentsWidget hReq searchSorting clickedEv activeDsDyn
202− archivedDeploymentsWidget hReq searchSorting clickedEv archivedDsDyn
199+ editEv <- activeDeploymentsWidget searchSorting activeDsDyn
200+ archivedDeploymentsWidget searchSorting archivedDsDyn
203201 pure (() <$ okUpdEv, () <$ errUpdEv, editEv)
204202
205203type SearchedDeploymentInfo = DeploymentFullInfo' SearchResult
@@ -210,16 +208,12 @@ activeDeploymentsWidget ::
210208 , SetRoute t (R Routes) m
211209 , MonadReader ProjectConfig m
212210 ) =>
213− RequestErrorHandler t m ->
214211 Dynamic t (Maybe (SortDir DeploymentFullInfo)) ->
215− -- | Event that carries the clicked DOM element. This event is required by
216− -- `dropdownWidget'`.
217− Event t ClickedElement ->
218212 Dynamic t [SearchedDeploymentInfo] ->
219213 -- | Returns an event carrying editable deployment
220214 -- to \"edit deployment\" sidebar.
221215 m (Event t SearchedDeploymentInfo)
222−activeDeploymentsWidget hReq searchSorting clickedEv dsDyn =
216+activeDeploymentsWidget searchSorting dsDyn =
223217 divClass "data__primary" $
224218 tableWrapper (updated searchSorting $> SortingChanged) $ \sortDyn -> do
225219 sorting <- holdDyn Nothing (mergeWith (<|>) [updated sortDyn, updated searchSorting])
@@ -230,7 +224,7 @@ activeDeploymentsWidget hReq searchSorting clickedEv dsDyn =
230224 dyn $
231225 emptyDyn <&> \case
232226 False -> do
233− editEvs <- simpleList dsSortedDyn (activeDeploymentWidget hReq clickedEv)
227+ editEvs <- simpleList dsSortedDyn activeDeploymentWidget
234228 pure $ switchDyn $ leftmost <$> editEvs
235229 True -> do
236230 emptyTableBody noDeploymentsWidget
@@ -250,15 +244,11 @@ activeDeploymentWidget ::
250244 , SetRoute t (R Routes) m
251245 , MonadReader ProjectConfig m
252246 ) =>
253− RequestErrorHandler t m ->
254− -- | Event that carries the clicked DOM element. This event is required by
255− -- `dropdownWidget'`.
256− Event t ClickedElement ->
257247 Dynamic t SearchedDeploymentInfo ->
258248 -- | Returns event carrying editable deployment
259249 -- that is required by \"edit deployment\" sidebar.
260250 m (Event t SearchedDeploymentInfo)
261−activeDeploymentWidget hReq clickedEv dDyn' = do
251+activeDeploymentWidget dDyn' = do
262252 dDyn <- holdUniqDyn dDyn'
263253 editEvEv <- dyn $
264254 ffor dDyn $ \d@DeploymentFullInfo {..} -> do
@@ -270,27 +260,17 @@ activeDeploymentWidget hReq clickedEv dDyn' = do
270260 statusWidget $ constDyn status
271261 el "td" $
272262 divClass "listing" $
273− forM_ (unDeploymentMetadata metadata) (renderMetadataLink . pure)
263+ for_ (unDeploymentMetadata metadata) (renderMetadataLink . pure)
274264 el "td" $
275− deploymentOverridesWidgetSearched hReq (deployment ^. field @"deploymentOverrides" . coerced)
265+ overridesWidget (deployment ^. field @"deploymentOverrides" . coerced)
276266 el "td" $
277− applicationOverridesWidgetSearched
278− hReq
279− (deployment ^. field @"deploymentOverrides" . coerced)
280− (deployment ^. field @"appOverrides" . coerced)
267+ overridesWidget (deployment ^. field @"appOverrides" . coerced)
281268 el "td" $
282269 text $ formatPosixToDate createdAt
283270 el "td" $
284271 text $ formatPosixToDate updatedAt
285272 el "td" $ do
286273 let enabled = not . isPending . recordedStatus $ status
287− btn =
288− elAttr
289− "button"
290− ( "class" =: "drop__handler"
291− <> "type" =: "button"
292− )
293− $ text "Actions"
294274 body = do
295275 btnEditEv <-
296276 actionButton $
@@ -315,13 +295,13 @@ activeDeploymentWidget hReq clickedEv dDyn' = do
315295 def
316296 { buttonText = "Details"
317297 , buttonType = Just LogsActionButtonType
318− , buttonBaseTag = ATag url
298+ , buttonBaseTag = ATag $ pure url
319299 }
320300 )
321301 pure $
322302 leftmost
323303 [ArchiveDeployment <$ btnArcEv, EditDeployment <$ btnEditEv]
324− dropdownWidget' clickedEv btn body
304+ dropdownWidget body
325305 let archEv = () <$ ffilter (is (_Ctor @"ArchiveDeployment")) dropdownEv
326306 editEv = d <$ ffilter (is (_Ctor @"EditDeployment")) dropdownEv
327307 delEv <- confirmArchivePopup archEv $ do
@@ -330,7 +310,7 @@ activeDeploymentWidget hReq clickedEv dDyn' = do
330310 text $ unDeploymentName dName <> " deployment?"
331311 void $ archiveEndpoint (constDyn . Right $ dName) delEv
332312 let route = DashboardRoute :/ Just dName
333− setRoute $ route <$ domEvent Dblclick linkEl
313+ setRoute $ route <$ domEvent Click linkEl
334314 pure editEv
335315 switchHold never editEvEv
336316
@@ -340,14 +320,10 @@ archivedDeploymentsWidget ::
340320 ( MonadWidget t m
341321 , SetRoute t (R Routes) m
342322 ) =>
343− RequestErrorHandler t m ->
344323 Dynamic t (Maybe (SortDir DeploymentFullInfo)) ->
345− -- | Event that carries the clicked DOM element. This event is required by
346− -- `dropdownWidget'`.
347− Event t ClickedElement ->
348324 Dynamic t [SearchedDeploymentInfo] ->
349325 m ()
350−archivedDeploymentsWidget hReq searchSorting clickedEv dsDyn = do
326+archivedDeploymentsWidget searchSorting dsDyn = do
351327 showDyn <- toggleButton
352328 let classDyn = ffor showDyn $ \case
353329 True -> "data__archive data__archive--open"
@@ -364,7 +340,7 @@ archivedDeploymentsWidget hReq searchSorting clickedEv dsDyn = do
364340 void $
365341 simpleList
366342 dsSortedDyn
367− (archivedDeploymentWidget hReq clickedEv)
343+ archivedDeploymentWidget
368344 True -> emptyTableBody noDeploymentsWidget
369345
370346-- | Row with archived deployment.
@@ -372,11 +348,9 @@ archivedDeploymentWidget ::
372348 ( MonadWidget t m
373349 , SetRoute t (R Routes) m
374350 ) =>
375− RequestErrorHandler t m ->
376− Event t ClickedElement ->
377351 Dynamic t SearchedDeploymentInfo ->
378352 m ()
379−archivedDeploymentWidget hReq clickedEv dDyn' = do
353+archivedDeploymentWidget dDyn' = do
380354 dDyn <- holdUniqDyn dDyn'
381355 dyn_ $
382356 ffor dDyn $ \d@DeploymentFullInfo {..} -> do
@@ -388,34 +362,24 @@ archivedDeploymentWidget hReq clickedEv dDyn' = do
388362 statusWidget (pure status)
389363 el "td" $ text "..."
390364 el "td" $
391− deploymentOverridesWidgetSearched hReq (deployment ^. field @"deploymentOverrides" . coerced)
365+ overridesWidget (deployment ^. field @"deploymentOverrides" . coerced)
392366 el "td" $
393− applicationOverridesWidgetSearched
394− hReq
395− (deployment ^. field @"deploymentOverrides" . coerced)
396− (deployment ^. field @"appOverrides" . coerced)
367+ overridesWidget (deployment ^. field @"appOverrides" . coerced)
397368 el "td" $
398369 text $ formatPosixToDate createdAt
399370 el "td" $
400371 text $ formatPosixToDate updatedAt
401372 el "td" $ do
402− let btn =
403− elAttr
404− "button"
405− ( "class" =: "drop__handler"
406− <> "type" =: "button"
407− )
408− $ text "Actions"
409− body =
373+ let body =
410374 actionButton
411375 def
412376 { buttonText = "Restore from archive"
413377 , buttonType = Just ArchiveActionButtonType
414378 }
415− btnEv <- dropdownWidget' clickedEv btn body
416− void $ restoreEndpoint (constDyn $ Right $ dName) btnEv
379+ btnEv <- dropdownWidget body
380+ void $ restoreEndpoint (constDyn $ Right $ dName) (btnEv $> ())
417381 let route = DashboardRoute :/ Just dName
418− setRoute $ route <$ domEvent Dblclick linkEl
382+ setRoute $ route <$ domEvent Click linkEl
419383
420384-- | Sort deployments by the supplied condition.
421385sortDeployments ::
@@ -561,7 +525,7 @@ tableWrapper ::
561525 (Dynamic t (Maybe (SortDir DeploymentFullInfo)) -> m a) ->
562526 m a
563527tableWrapper sChanged ma =
564− divClass "table table--deployments table--clickable table--double-click" $
528+ divClass "table table--deployments table--clickable" $
565529 el "table" $ mdo
566530 ((), sDyn') <- runSortableTableGroup sChanged tableHeader
567531 sDyn <- holdDyn Nothing $ Just <$> sDyn'
octopod-frontend/src/Page/Elements/Links.hs+20−11
@@ -4,8 +4,11 @@ module Page.Elements.Links
44where
55
66import Common.Types
7+import Common.Utils ((<^.>))
78import Control.Lens
9+import Control.Monad
810import qualified Data.Text as T
11+import Frontend.UIKit.Button.Common
912import Reflex.Dom
1013
1114renderMetadataLink ::
@@ -13,14 +16,20 @@ renderMetadataLink ::
1316 Dynamic t DeploymentMetadatum ->
1417 m ()
1518renderMetadataLink metadataD = do
16− let attrDyn =
17− metadataD <&> \metadata ->
18− "class" =: "listing__item external bar bar--larger"
19− <> "href" =: metadata ^. #link
20− <> "target" =: "_blank"
21− elDynAttr "a" attrDyn . dynText $
22− metadataD <&> \case
23− -- If the name is empty, then use the url
24− DeploymentMetadatum {name = name}
25− | (not . T.null . T.strip) name -> name
26− DeploymentMetadatum {link = url} -> url
19+ void $
20+ buttonEl
21+ CommonButtonConfig
22+ { constantClasses = pure $ "listing__item" <> "external" <> "bar" <> "bar--larger"
23+ , enabledClasses = mempty
24+ , disabledClasses = "button--disabled"
25+ , buttonEnabled = pure True
26+ , buttonText =
27+ TextBuilder $
28+ dynText $
29+ metadataD <&> \case
30+ -- If the name is empty, then use the url
31+ DeploymentMetadatum {name = name}
32+ | (not . T.null . T.strip) name -> name
33+ DeploymentMetadatum {link = url} -> url
34+ , buttonBaseTag = ATag $ metadataD <^.> #link
35+ }
octopod-frontend/src/Page/Popup/EditDeployment.hs+1−1
@@ -88,7 +88,7 @@ editDeploymentPopupHeader dname validDyn loadingDyn =
8888 )
8989
9090 divClass "popup__menu drop drop--actions" blank
91− pure (closeEv, saveEv)
91+ pure (closeEv $> (), saveEv $> ())
9292
9393-- | The body of the sidebar containing the edit form. Contains a tag field and
9494-- an override field.
octopod-frontend/src/Page/Popup/NewDeployment.hs+1−1
@@ -83,7 +83,7 @@ newDeploymentPopupHeader enabledDyn loadingDyn =
8383 True -> Just LoadingLargeButtonType
8484 )
8585 divClass "popup__menu drop drop--actions" blank
86− pure (closeEv, saveEv)
86+ pure (closeEv $> (), saveEv $> ())
8787
8888-- | The body of the sidebar contains the creation form. It contains: a name field,
8989-- a tag field and overrides fields. The name field is validated with the regexp:
stack.yaml+3−1
@@ -1,4 +1,4 @@
1−resolver: lts-18.2
1+resolver: lts-18.28
22
33packages:
44 - octo-cli
@@ -10,3 +10,5 @@ extra-deps:
1010 - servant-websockets-2.0.0
1111 - table-layout-0.9.1.0
1212 - data-default-instances-base-0.1.0.1
13+ - git: https://github.com/typeable/ordered-containers.git
14+ commit: 3eb05fb2f44fe482e9092aff447e9c68fbd6a7f6