diff --git a/Gruntfile.js b/Gruntfile.js
index 81fed5af8..c907d1946 100755
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -287,6 +287,7 @@ module.exports = function(grunt) {
var locals = {
version: version,
env: require('./client/config/json/environment.json').environment,
+ intercomAppId: require('./client/config/json/environment.json').intercomAppId,
commitHash: require('./client/config/json/commit.json').commitHash,
commitTime: require('./client/config/json/commit.json').commitTime,
apiHost: require('./client/config/json/api.json').host
@@ -438,6 +439,7 @@ module.exports = function(grunt) {
configObj.userContentDomain = process.env.USER_CONTENT_DOMAIN || 'runnableapp.com';
configObj.corporateUrl = process.env.MARKETING_URL || 'https://runnable.io';
configObj.stripeToken = process.env.STRIPE_TOKEN || 'pk_test_sHr5tQaPtgwiE2cpW6dQkzi8';
+ configObj.siftApiKey = process.env.SIFT_API_KEY || 'eea9746dff';
if (configObj.host.charAt(configObj.host.length - 1) === '/') {
configObj.host = configObj.host.substr(0, configObj.host.length - 1);
@@ -477,7 +479,8 @@ module.exports = function(grunt) {
},
function (cb) {
var configObj = {
- environment: environment || process.env.NODE_ENV || 'development'
+ environment: environment || process.env.NODE_ENV || 'development',
+ intercomAppId: process.env.INTERCOM_APP_ID || 'xs5g95pd'
};
var configJSON = JSON.stringify(configObj);
fs.writeFile(path.join(clientPath, 'config', 'json', 'environment.json'), configJSON, function () {
diff --git a/client/assets/images/confetti.png b/client/assets/images/confetti.png
index 3543e6e78..2d389a041 100644
Binary files a/client/assets/images/confetti.png and b/client/assets/images/confetti.png differ
diff --git a/client/assets/images/favicon-gray.png b/client/assets/images/favicon-gray.png
index 8b1df7bd4..c4e184be6 100644
Binary files a/client/assets/images/favicon-gray.png and b/client/assets/images/favicon-gray.png differ
diff --git a/client/assets/images/favicon-green.png b/client/assets/images/favicon-green.png
index f07b62d6c..b3cabfff6 100644
Binary files a/client/assets/images/favicon-green.png and b/client/assets/images/favicon-green.png differ
diff --git a/client/assets/images/favicon-orange.png b/client/assets/images/favicon-orange.png
index 668f4f364..4038a874d 100644
Binary files a/client/assets/images/favicon-orange.png and b/client/assets/images/favicon-orange.png differ
diff --git a/client/assets/images/favicon-red.png b/client/assets/images/favicon-red.png
index 0dddc9548..64fb0f5e3 100644
Binary files a/client/assets/images/favicon-red.png and b/client/assets/images/favicon-red.png differ
diff --git a/client/assets/images/favicon.png b/client/assets/images/favicon.png
index 38469bdbc..52ca3f0cf 100644
Binary files a/client/assets/images/favicon.png and b/client/assets/images/favicon.png differ
diff --git a/client/assets/images/home/hero-bg.svg b/client/assets/images/home/hero-bg.svg
deleted file mode 100644
index 74536a1ca..000000000
--- a/client/assets/images/home/hero-bg.svg
+++ /dev/null
@@ -1,215 +0,0 @@
-
-
-
-
diff --git a/client/assets/images/home/preview.png b/client/assets/images/home/preview.png
deleted file mode 100644
index 2b0eb794c..000000000
Binary files a/client/assets/images/home/preview.png and /dev/null differ
diff --git a/client/assets/images/logos/logo-icons-wordpress.svg b/client/assets/images/logos/logo-icons-wordpress.svg
new file mode 100644
index 000000000..cfbb01a9b
--- /dev/null
+++ b/client/assets/images/logos/logo-icons-wordpress.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/assets/images/runnabear-head.png b/client/assets/images/runnabear-head.png
index 6baea151d..c74420e9b 100644
Binary files a/client/assets/images/runnabear-head.png and b/client/assets/images/runnabear-head.png differ
diff --git a/client/assets/images/runnabear-waving-1.png b/client/assets/images/runnabear-waving-1.png
new file mode 100644
index 000000000..105906b29
Binary files /dev/null and b/client/assets/images/runnabear-waving-1.png differ
diff --git a/client/assets/images/runnabear-waving-2.png b/client/assets/images/runnabear-waving-2.png
index 7f650ecb9..f0d8b05c2 100644
Binary files a/client/assets/images/runnabear-waving-2.png and b/client/assets/images/runnabear-waving-2.png differ
diff --git a/client/assets/images/runnabear-working.png b/client/assets/images/runnabear-working.png
new file mode 100644
index 000000000..6b8329c7f
Binary files /dev/null and b/client/assets/images/runnabear-working.png differ
diff --git a/client/assets/images/runnabot-comment.png b/client/assets/images/runnabot-comment.png
new file mode 100644
index 000000000..dec4a408b
Binary files /dev/null and b/client/assets/images/runnabot-comment.png differ
diff --git a/client/assets/images/runnabot-head.png b/client/assets/images/runnabot-head.png
new file mode 100644
index 000000000..1e8920e96
Binary files /dev/null and b/client/assets/images/runnabot-head.png differ
diff --git a/client/assets/images/slack-notification.png b/client/assets/images/slack-notification.png
index 08e3e61d4..a10a95318 100644
Binary files a/client/assets/images/slack-notification.png and b/client/assets/images/slack-notification.png differ
diff --git a/client/assets/styles/scss/components/aha-button.scss b/client/assets/styles/scss/components/aha-button.scss
index 707479e41..7908edac5 100644
--- a/client/assets/styles/scss/components/aha-button.scss
+++ b/client/assets/styles/scss/components/aha-button.scss
@@ -9,6 +9,6 @@
.iconnables {
height: 12px;
- width: 12px;
+ width: 100%;
}
}
diff --git a/client/assets/styles/scss/components/aha-guide.scss b/client/assets/styles/scss/components/aha-guide.scss
index 65b278110..a8bf7a48b 100644
--- a/client/assets/styles/scss/components/aha-guide.scss
+++ b/client/assets/styles/scss/components/aha-guide.scss
@@ -1,3 +1,16 @@
+.environment-view-aha-guide {
+ > .aha-guide {
+ margin: 0 auto 15px;
+ max-width: 450px;
+
+ .p-slide {
+ font-size: 15px;
+ position: relative;
+ top: 0;
+ }
+ }
+}
+
.aha-guide {
color: $gray;
overflow: hidden;
@@ -14,7 +27,6 @@
}
// anchor image
- .spinner-wrapper,
.aha-meter {
height: $input-md;
left: 15px;
@@ -96,7 +108,6 @@
.icons-alert {
color: $orange;
- overflow: visible;
padding: 10px 11px 11px;
}
}
@@ -179,3 +190,9 @@
.aha-tips > .iconnables {
margin-left: 6px;
}
+
+.aha-overlay-div {
+ position: absolute;
+ height: 100%;
+ width: 100%;
+}
diff --git a/client/assets/styles/scss/components/aha-modals.scss b/client/assets/styles/scss/components/aha-modals.scss
index ff8112165..f7a87ef0c 100644
--- a/client/assets/styles/scss/components/aha-modals.scss
+++ b/client/assets/styles/scss/components/aha-modals.scss
@@ -23,15 +23,7 @@
}
+ .modal-dialog {
- margin-top: 30px;
-
- @include media(lg) {
- margin-top: 90px;
- }
-
- @media (max-height: $screen-xs), (max-width: $screen-sm) {
- margin-top: 105px;
- }
+ margin-top: 120px;
}
.spinner-wrapper,
diff --git a/client/assets/styles/scss/components/aha-popover.scss b/client/assets/styles/scss/components/aha-popover.scss
deleted file mode 100644
index 19b8fb652..000000000
--- a/client/assets/styles/scss/components/aha-popover.scss
+++ /dev/null
@@ -1,27 +0,0 @@
-.popover.popover-aha {
- left: 75px;
- max-width: none;
- top: 66px;
- width: 450px;
-
- @include media(xxs) {
- left: 15px;
- right: 15px;
- top: 60px;
- width: calc(100vw - 30px);
-
- &.right {
- margin-left: 0;
- }
- }
-
- .arrow {
- @include media(xxs) {
- display: none;
- }
- }
-
- .popover-content {
- @extend %padding-sm;
- }
-}
diff --git a/client/assets/styles/scss/components/aha-sidebar.scss b/client/assets/styles/scss/components/aha-sidebar.scss
index e6db79d31..d038f9efb 100644
--- a/client/assets/styles/scss/components/aha-sidebar.scss
+++ b/client/assets/styles/scss/components/aha-sidebar.scss
@@ -33,11 +33,22 @@
transform: translate3d(100%,0,0);
}
+ .aha-sidebar-header {
+ border-bottom: 1px solid $gray-lightest;
+ height: $input-md;
+ margin-bottom: 15px;
+ padding-bottom: 15px;
+ position: relative;
+ width: 100%;
+ }
+
.icons-close {
- color: $gray;
+ color: $gray-light;
cursor: pointer;
- margin-bottom: 15px;
pointer-events: auto;
+ position: absolute;
+ right: 0;
+ top: 0;
&:hover,
&:active {
@@ -46,13 +57,21 @@
}
.aha-overview {
- animation: slide-left .45s ease-in-out forwards;
border-bottom: 1px solid $gray-lightest;
margin-bottom: 15px;
- padding: 32px 0 42px;
+
+ &:last-child {
+ border-bottom: 0;
+ }
+
+ .p {
+ margin-top: 15px;
+ }
.btn {
- align-self: center;
+ margin-bottom: 30px;
+ margin-left: auto;
+ margin-right: auto;
}
}
diff --git a/client/assets/styles/scss/components/buttons/buttons-group.scss b/client/assets/styles/scss/components/buttons/buttons-group.scss
index 2ba8c2b08..3fb67ba76 100644
--- a/client/assets/styles/scss/components/buttons/buttons-group.scss
+++ b/client/assets/styles/scss/components/buttons/buttons-group.scss
@@ -134,7 +134,7 @@
> .btn:active {
&:not(:first-child):not(:last-child) {
- border-radius: $input-border-radius;
+ border-radius: 0;
}
&:first-child:not(:last-child) {
diff --git a/client/assets/styles/scss/components/buttons/buttons.scss b/client/assets/styles/scss/components/buttons/buttons.scss
index 01241d797..c254c8d7c 100755
--- a/client/assets/styles/scss/components/buttons/buttons.scss
+++ b/client/assets/styles/scss/components/buttons/buttons.scss
@@ -45,7 +45,6 @@
> .spinner-wrapper {
align-items: center;
display: flex;
- float: left;
height: 100%;
&:first-child {
@@ -116,7 +115,7 @@
font-size: 12px;
height: $input-xxs;
line-height: $input-line-height-xxs;
- padding: 0 3px;
+ padding: 0 5px;
}
// .btn-icon
@@ -486,12 +485,10 @@
}
.btn-radio {
- background: $white;
border: $input-border solid transparent;
border-radius: $input-border-radius;
box-shadow: none;
cursor: pointer;
- display: inline-block;
font-size: 16px;
height: 72px;
text-align: center;
@@ -499,44 +496,26 @@
transition: none;
user-select: none;
white-space: nowrap;
- width: 90px;
- &:active,
- &.active {
+ &:hover:not([disabled]) {
+ border-color: $gray-lighter;
+ }
+
+ &:active:not([disabled]),
+ &.active.active {
+ background: lighten($purple-lightest,6%);
+ border-color: $purple-light;
+ box-shadow: inset 0 0 0 1px $purple-light;
color: $purple-light;
- cursor: default;
}
&.active {
- font-weight: $weight-bold;
+ cursor: default;
}
&:focus {
outline: 0;
}
-
- &.btn-lg {
- height: 108px;
- width: 120px;
-
- .img,
- .iconnables {
- margin-bottom: 6px;
- width: 36px;
- }
- }
-
- &:last-child {
- margin-right: 0;
- }
-
- .img,
- .iconnables {
- display: block;
- height: 33px;
- margin: 0 auto;
- width: 18px;
- }
}
// add button
@@ -550,14 +529,10 @@
transition: none;
&.btn-sm {
- right: 15px;
- top: 15px;
width: $input-sm;
}
&.btn-xs {
- right: 6px;
- top: 6px;
width: $input-xs;
}
diff --git a/client/assets/styles/scss/components/cards.scss b/client/assets/styles/scss/components/cards.scss
index 400971183..9037447af 100644
--- a/client/assets/styles/scss/components/cards.scss
+++ b/client/assets/styles/scss/components/cards.scss
@@ -1,5 +1,5 @@
.card {
- border: 2px solid transparent;
+ border: $input-border solid transparent;
border-radius: $input-border-radius-lg;
display: flex;
flex-direction: column;
@@ -148,8 +148,8 @@
}
&:not([disabled]):hover {
- border-color: darken($gray-lighter,6%);
- box-shadow: inset 0 1px 0 darken($gray-lighter,6%);
+ border-color: $gray-light;
+ box-shadow: inset 0 0 0 $gray-light;
&:first-child {
box-shadow: none;
@@ -159,18 +159,14 @@
&:not([disabled]):active {
background: lighten($purple-lightest,6%);
border-color: $purple-light;
- box-shadow: inset 0 1px 0 $purple-light;
+ box-shadow: inset 0 0 0 $purple-light;
&:first-child {
box-shadow: none;
}
- > .small {
- color: lighten($purple-light,18%);
- }
-
.icons-arrow-down {
- color: lighten($purple-light,37%);
+ color: lighten($purple-light,18%);
}
.btn-xxs {
@@ -210,9 +206,9 @@
// description of tool
> .small {
- color: $gray;
display: block;
line-height: 15px;
+ opacity: .6;
}
// notifications
diff --git a/client/assets/styles/scss/components/lists.scss b/client/assets/styles/scss/components/lists.scss
index 381080512..8d108d6cb 100644
--- a/client/assets/styles/scss/components/lists.scss
+++ b/client/assets/styles/scss/components/lists.scss
@@ -81,6 +81,7 @@
&:active:not(.disabled) .btn-add {
@extend %green;
+ color: $white;
.iconnables {
color: $white;
@@ -121,8 +122,8 @@
}
.small {
- color: $gray;
display: block;
+ opacity: .6;
}
.input-checkbox {
@@ -150,11 +151,6 @@
opacity: 0;
position: absolute;
}
-
- // add button
- .btn-add {
- position: absolute;
- }
}
// links
diff --git a/client/assets/styles/scss/components/repository-details-content.scss b/client/assets/styles/scss/components/repository-details-content.scss
index c00d08535..cda3d6365 100644
--- a/client/assets/styles/scss/components/repository-details-content.scss
+++ b/client/assets/styles/scss/components/repository-details-content.scss
@@ -2,6 +2,18 @@
display: flex;
flex-direction: column;
+ &.modal-body {
+ max-height: calc(100vh - 195px);
+
+ @media (max-height: $screen-xs), (max-width: $screen-sm) {
+ max-height: calc(100vh - 165px);
+ }
+
+ @include media(xxxs) {
+ max-height: calc(100vh - 212px);
+ }
+ }
+
> .label {
display: table;
margin: 0 auto 12px;
@@ -15,8 +27,9 @@
}
.list-servers.list-servers {
- flex: 1 1 auto;
+ flex: 0 0 auto;
min-height: 90px;
+ padding: 15px 0;
position: relative;
> .spinner-wrapper {
@@ -26,7 +39,6 @@
.list-item {
@extend %text-overflow;
- font-size: 15px;
padding-right: 36px;
&:active,
@@ -69,10 +81,6 @@
}
}
- &:last-child {
- margin-bottom: 15px;
- }
-
.small {
color: $gray;
}
@@ -91,7 +99,6 @@
border-bottom: 1px solid $gray-lighter;
flex: 0 0 auto;
font-size: 15px;
- margin-bottom: 9px;
padding-right: 48px;
&:not(:first-child) {
diff --git a/client/assets/styles/scss/deprecated/btn-auto-deploy.scss b/client/assets/styles/scss/deprecated/btn-auto-deploy.scss
deleted file mode 100644
index c4deb7d21..000000000
--- a/client/assets/styles/scss/deprecated/btn-auto-deploy.scss
+++ /dev/null
@@ -1,53 +0,0 @@
-.btn-repository.main-btn.deprecated {
- min-height: 127px;
- padding-bottom: ($input-sm + 6px);
-
- .icons-arrow-forward {
- height: calc(100% - 36px);
- }
-}
-
-.btn-auto-deploy-deprecated {
- background: $gray-lightest;
- border-radius: 0;
- border-top: 1px solid $gray-lighter;
- bottom: 0;
- color: $gray;
- cursor: default;
- font-size: 13px;
- height: $input-sm;
- left: 0;
- margin: 2px;
- padding: 0 9px;
- position: absolute;
- right: 0;
- z-index: 1;
-
- .icons-launch {
- filter: grayscale(100%);
- height: 100%;
- margin: 0 6px 0 -3px;
- opacity: .75;
- text-align: center;
- width: 18px;
-
- @include retina() {
- margin-left: 0;
- width: 15px;
- }
- }
-
- .underline {
- line-height: 1.2;
- margin-top: 8px;
- }
-
- .toggle-wrapper {
- top: 9px;
-
- &.disabled {
- cursor: not-allowed;
- opacity: .5;
- }
- }
-}
diff --git a/client/assets/styles/scss/deprecated/instances-list.scss b/client/assets/styles/scss/deprecated/instances-list.scss
index 87a129b66..6170bc7ad 100644
--- a/client/assets/styles/scss/deprecated/instances-list.scss
+++ b/client/assets/styles/scss/deprecated/instances-list.scss
@@ -5,7 +5,7 @@
padding: 0 7px 0 29px;
.icons-gear {
- margin-right: 4px;
+ margin: 0 4px;
}
}
diff --git a/client/assets/styles/scss/deprecated/popover-container-menu.scss b/client/assets/styles/scss/deprecated/popover-container-menu.scss
index b0af5a60e..ad684589b 100644
--- a/client/assets/styles/scss/deprecated/popover-container-menu.scss
+++ b/client/assets/styles/scss/deprecated/popover-container-menu.scss
@@ -1,26 +1,38 @@
//- ************************
//- deprecated file, delete with $root.featureFlags.autoIsolation
-.popover-container-menu .disabled {
+.popover-container-menu {
- .p {
- color: $gray;
+ .well {
font-size: 13px;
- font-weight: $weight-bold;
- margin: 9px 15px 15px;
- }
+ margin-bottom: 6px;
- .list {
- margin: 0 15px;
- padding: 0;
+ .list-item {
+ margin-top: 6px;
+ }
}
- .list-item + .list-item {
- margin-top: 6px;
- }
+ .disabled {
+
+ .p {
+ color: $gray;
+ font-size: 13px;
+ font-weight: $weight-bold;
+ margin: 9px 15px 15px;
+ }
+
+ .list {
+ margin: 0 15px;
+ padding: 0;
+ }
+
+ .list-item + .list-item {
+ margin-top: 6px;
+ }
- .btn-block {
- margin: 15px auto;
- position: static;
+ .btn-block {
+ margin: 15px auto;
+ position: static;
+ }
}
}
//- end deprecated file
diff --git a/client/assets/styles/scss/forms/forms-github.scss b/client/assets/styles/scss/forms/forms-github.scss
new file mode 100644
index 000000000..7ed5f35d6
--- /dev/null
+++ b/client/assets/styles/scss/forms/forms-github.scss
@@ -0,0 +1,74 @@
+// github form
+.form-github {
+
+ > .img.img.img {
+ height: auto;
+ margin-bottom: 30px;
+ margin-top: 30px;
+ max-width: 100%;
+ }
+
+ .btn .iconnables {
+ height: 18px;
+ top: 2px;
+ width: 18px;
+
+ &:first-child {
+ margin-right: 6px;
+ }
+
+ &:last-child {
+ margin-left: 6px;
+ }
+ }
+
+ // the details text
+ .grid-content.small {
+ margin-top: 15px;
+ }
+
+ // success state
+ .runnabot-success {
+ max-width: 215px;
+ overflow: visible;
+ position: relative;
+
+ .well {
+ background: $white;
+ border-color: $gray-lighter;
+ position: relative;
+ }
+
+ .arrow::after {
+ border-right-color: $white;
+ }
+
+ .arrow,
+ .arrow::after {
+ border-color: transparent;
+ border-style: solid;
+ position: absolute;
+ }
+
+ .arrow {
+ border-bottom-width: 10px;
+ border-left-width: 0;
+ border-right: 10px solid darken($gray-lighter,5);
+ border-top-width: 10px;
+ left: -10px;
+ margin-top: -10px;
+ top: 50%;
+
+ &::after {
+ border-bottom-width: 9px;
+ border-left-width: 0;
+ border-right: 9px solid $white;
+ border-top-width: 9px;
+ bottom: -9px;
+ content: '';
+ display: block;
+ left: 1px;
+ }
+ }
+ }
+}
diff --git a/client/assets/styles/scss/forms/forms-inputs.scss b/client/assets/styles/scss/forms/forms-inputs.scss
index 747b37d97..ec25a087f 100644
--- a/client/assets/styles/scss/forms/forms-inputs.scss
+++ b/client/assets/styles/scss/forms/forms-inputs.scss
@@ -116,7 +116,7 @@ input {
&.input-xs {
font-size: 13px;
height: $input-xs;
- line-height: 1;
+ line-height: $input-line-height-xs;
&[type="search"] {
border-radius: $input-xs;
@@ -127,7 +127,7 @@ input {
&.input-xxs {
font-size: 13px;
height: $input-xxs;
- line-height: 1;
+ line-height: $input-line-height-xxs;
&[type="search"] {
border-radius: $input-xxs;
diff --git a/client/assets/styles/scss/forms/forms-payment.scss b/client/assets/styles/scss/forms/forms-payment.scss
index c827b256e..a3f6fd819 100644
--- a/client/assets/styles/scss/forms/forms-payment.scss
+++ b/client/assets/styles/scss/forms/forms-payment.scss
@@ -57,6 +57,7 @@
border: 0;
&:first-child {
+ flex: 0 0 27px;
width: 27px;
}
}
diff --git a/client/assets/styles/scss/forms/forms-plan.scss b/client/assets/styles/scss/forms/forms-plan.scss
index 2c4fb70e5..85d8a2624 100644
--- a/client/assets/styles/scss/forms/forms-plan.scss
+++ b/client/assets/styles/scss/forms/forms-plan.scss
@@ -319,4 +319,9 @@
top: 12px;
}
}
+
+ // spacing after plans
+ .plans-wrapper + .well-summary {
+ margin-top: 15px;
+ }
}
diff --git a/client/assets/styles/scss/forms/forms-toggles.scss b/client/assets/styles/scss/forms/forms-toggles.scss
index 0155907f1..74bf46216 100644
--- a/client/assets/styles/scss/forms/forms-toggles.scss
+++ b/client/assets/styles/scss/forms/forms-toggles.scss
@@ -49,7 +49,7 @@
width: 40px;
&:hover {
- background: #e6e6e6; // warning: unique color
+ background: $gray-lighter; // warning: unique color
}
&:active {
@@ -63,8 +63,8 @@
width: 33px;
&::after {
- height: 17px;
- width: 17px;
+ height: 21px - ($input-border * 2);
+ width: 21px - ($input-border * 2);
}
}
@@ -74,8 +74,8 @@
width: 24px;
&::after {
- height: 11px;
- width: 11px;
+ height: 15px - ($input-border * 2);
+ width: 15px - ($input-border * 2);
}
}
@@ -86,12 +86,12 @@
box-shadow: 1px 1px 3px rgba($black,.05);
content: '';
display: block;
- height: 22px;
+ height: 26px - ($input-border * 2);
left: 0;
position: absolute;
top: 0;
transition: transform .15s ease-in-out;
- width: 22px;
+ width: 26px - ($input-border * 2);
}
}
diff --git a/client/assets/styles/scss/globals/var.scss b/client/assets/styles/scss/globals/var.scss
index 335ef36e2..c3c9d90b8 100755
--- a/client/assets/styles/scss/globals/var.scss
+++ b/client/assets/styles/scss/globals/var.scss
@@ -121,8 +121,7 @@ $z-show: 10000;
// views
$z-views: 1000;
$z-views-active-panel: 1001;
-$z-views-header: 1002;
-$z-views-sidebar: 1003;
+$z-views-sidebar: 1002;
// modals
$z-modal-backdrop: 2000;
@@ -171,7 +170,7 @@ $screen-xl: 1920px + $layout-navigation-width;
$terminal-line-height: 19px;
// button/input sizes
-$input-border: 2px;
+$input-border: 1px;
$input-border-radius: 3px;
$input-border-radius-lg: 6px;
@@ -188,4 +187,4 @@ $input-xs: 24px;
$input-line-height-xs: $input-xs - ($input-border * 2);
$input-xxs: 18px;
-$input-line-height-xxs: $input-xxs - ($input-border * 2);
+$input-line-height-xxs: $input-xxs - 2px;
diff --git a/client/assets/styles/scss/index.scss b/client/assets/styles/scss/index.scss
index 2c197ac9e..8c7c9a441 100755
--- a/client/assets/styles/scss/index.scss
+++ b/client/assets/styles/scss/index.scss
@@ -62,7 +62,6 @@
@import "components/aha-button";
@import "components/aha-guide";
@import "components/aha-modals";
-@import "components/aha-popover";
@import "components/aha-sidebar";
@import "components/animated-panel";
@import "components/badges";
@@ -106,6 +105,7 @@
// form specific
@import "forms/forms-billing";
+@import "forms/forms-github";
@import "forms/forms-payment";
@import "forms/forms-plan";
@import "forms/forms-trial";
@@ -129,6 +129,7 @@
// modal specific
@import "modals/modals-backup";
@import "modals/modals-branch-setup";
+@import "modals/modals-confirm-setup";
@import "modals/modals-edit";
@import "modals/modals-edit-ace";
@import "modals/modals-edit-dockerfile";
@@ -155,7 +156,11 @@
// popover specific
@import "popover/popover-account-menu";
+@import "popover/popover-add-branches";
@import "popover/popover-add-tab";
+@import "popover/popover-aha";
+@import "popover/popover-aha-containers";
+@import "popover/popover-aha-url";
@import "popover/popover-branch-menu";
@import "popover/popover-card-status";
@import "popover/popover-container-menu";
@@ -192,7 +197,6 @@
@import "pages/server-selection";
//deprecated
-@import "deprecated/btn-auto-deploy";
@import "deprecated/card-status";
@import "deprecated/connections";
@import "deprecated/deleted-commit";
diff --git a/client/assets/styles/scss/layout/environment-body.scss b/client/assets/styles/scss/layout/environment-body.scss
index 51fd60bb4..437ff9d35 100644
--- a/client/assets/styles/scss/layout/environment-body.scss
+++ b/client/assets/styles/scss/layout/environment-body.scss
@@ -18,12 +18,12 @@
}
.card {
- height: 461px;
+ height: 466px;
margin-bottom: 15px;
min-width: 0;
&.deprecated {
- height: 439px;
+ height: 444px;
}
// sibling styles must appear first to be overridden by media queries
diff --git a/client/assets/styles/scss/layout/environment-header.scss b/client/assets/styles/scss/layout/environment-header.scss
index 58c3e7cde..b64897332 100644
--- a/client/assets/styles/scss/layout/environment-header.scss
+++ b/client/assets/styles/scss/layout/environment-header.scss
@@ -16,13 +16,8 @@
}
}
- .btn-aha {
- right: 0;
- top: 3px;
- }
-
// new server button
- .green {
+ > .green {
display: table;
margin: 0 auto;
@@ -54,4 +49,9 @@
}
}
}
+
+ .btn-aha {
+ right: 0;
+ top: 3px;
+ }
}
diff --git a/client/assets/styles/scss/layout/instance-header.scss b/client/assets/styles/scss/layout/instance-header.scss
index f4100b12d..0c974dca2 100644
--- a/client/assets/styles/scss/layout/instance-header.scss
+++ b/client/assets/styles/scss/layout/instance-header.scss
@@ -3,7 +3,6 @@
background: $white;
flex: 0 0 auto;
position: relative;
- z-index: $z-views-header;
}
.instance-header-title {
@@ -45,7 +44,6 @@
.green {
margin-left: 9px;
padding: 0 3px 0 0;
- top: -4px;
.iconnables {
height: 100%;
@@ -89,6 +87,7 @@
align-items: top;
display: flex;
padding: 0 12px 12px;
+ position: relative;
width: 100%;
// status, dns mappings, save
@@ -115,7 +114,6 @@
}
.icons-link-external {
- left: 1px;
margin: 0 3px;
top: -1px;
width: 15px;
diff --git a/client/assets/styles/scss/layout/instance-sidebar.scss b/client/assets/styles/scss/layout/instance-sidebar.scss
index d0e99d6f1..014905540 100644
--- a/client/assets/styles/scss/layout/instance-sidebar.scss
+++ b/client/assets/styles/scss/layout/instance-sidebar.scss
@@ -16,7 +16,6 @@
font-size: 15px;
font-weight: $weight-normal;
min-height: 118px;
- padding-right: 24px;
text-align: left;
&.grid-block {
@@ -81,13 +80,6 @@
}
}
- .icons-arrow-forward {
- height: 100%;
- position: absolute;
- right: 3px;
- top: 0;
- }
-
.file-tree {
margin: 0;
}
diff --git a/client/assets/styles/scss/layout/instance.scss b/client/assets/styles/scss/layout/instance.scss
index 33bc08726..1d1092c09 100644
--- a/client/assets/styles/scss/layout/instance.scss
+++ b/client/assets/styles/scss/layout/instance.scss
@@ -2,28 +2,8 @@
.instance-wrapper {
height: 100vh;
overflow: hidden;
- overflow-x: auto;
position: relative;
- &.empty {
- background-color: $gray-lightest;
- background-image: url(/build/images/confetti.png);
- flex-direction: row;
-
- > .instance {
- min-width: 600px;
- }
-
- .instance-header {
- background: transparent;
- flex: 0 0 60px;
- }
- }
-
- > .instance-wrapper {
- min-width: 600px;
- }
-
> .spinner-wrapper {
.modal-open & {
diff --git a/client/assets/styles/scss/layout/instances-list.scss b/client/assets/styles/scss/layout/instances-list.scss
index 3c2ea5b99..9b2d83e54 100644
--- a/client/assets/styles/scss/layout/instances-list.scss
+++ b/client/assets/styles/scss/layout/instances-list.scss
@@ -25,30 +25,10 @@
> .well {
background: $white;
border-color: $gray-lighter;
- margin-bottom: 15px;
- padding-left: 30px;
- padding-right: 30px;
- position: relative;
-
- .icons-branch {
- flex: 0 0 30px;
- height: 30px;
- }
-
- // 'x' button
- .btn-xs {
- color: $gray-light;
- height: 18px;
- position: absolute;
- right: 12px;
- top: 12px;
- width: 18px;
-
- &:hover,
- &:active {
- color: $red;
- }
- }
+ border-radius: $input-border-radius-lg;
+ font-size: 21px;
+ margin-top: 3px;
+ padding: 15px 24px 24px;
}
.a-sref {
@@ -88,8 +68,7 @@
.list-clusters {
padding: 15px 0;
- + .list-clusters,
- .well + & {
+ + .list-clusters {
border-top: 1px solid $gray-lighter;
}
}
@@ -97,18 +76,29 @@
.list-clusters-heading {
height: 27px;
margin: 4px 0;
- padding: 0 10px 0 31px;
+ padding: 0 4px 0 31px;
// repo name
.text-overflow {
padding-right: 9px;
}
- // '+' button
- .btn-xs {
- line-height: initial;
- overflow: hidden;
- width: $input-xs;
+ // 'add…' buttons
+ .btn-xxs {
+ color: lighten($gray,15);
+ font-weight: $weight-normal;
+ height: 20px;
+ top: 1px;
+
+ &:hover {
+ color: $gray;
+ }
+
+ .icons-arrow-forward {
+ height: 12px;
+ margin-right: -3px;
+ width: 12px;
+ }
}
}
diff --git a/client/assets/styles/scss/modals/modals-confirm-setup.scss b/client/assets/styles/scss/modals/modals-confirm-setup.scss
new file mode 100644
index 000000000..0e09120d7
--- /dev/null
+++ b/client/assets/styles/scss/modals/modals-confirm-setup.scss
@@ -0,0 +1,14 @@
+.modal-confirm-setup {
+
+ > .img {
+ height: auto;
+ position: relative;
+ top: 43px;
+ width: 180px;
+ z-index: 1;
+ }
+
+ .modal-dialog {
+ margin-top: 30px;
+ }
+}
diff --git a/client/assets/styles/scss/modals/modals-edit.scss b/client/assets/styles/scss/modals/modals-edit.scss
index a3464b567..b732c2319 100644
--- a/client/assets/styles/scss/modals/modals-edit.scss
+++ b/client/assets/styles/scss/modals/modals-edit.scss
@@ -354,13 +354,25 @@
}
> .btn {
- border-color: $gray-lighter;
flex: 0 1 25%;
font-size: 13px;
height: 90px;
line-height: normal; // reset
padding: 0;
+ &:not(:active):not(.active) {
+ border-color: $gray-lighter;
+
+ &:hover:not([disabled]) {
+ border-color: $gray-light;
+ }
+ }
+
+ &:active,
+ &.active {
+ box-shadow: none;
+ }
+
&:first-child {
border-radius: $input-border-radius 0 0;
}
@@ -389,31 +401,32 @@
}
&.recommended {
+ border-radius: 0;
&::after {
background: $gray-lighter;
- border-radius: $input-border-radius;
+ border-radius: $input-border-radius $input-border-radius 0 0;
color: $gray;
content: 'Recommended';
display: block;
font-size: 11px;
font-weight: $weight-normal;
height: 21px;
- left: -2px;
+ left: -$input-border;
letter-spacing: -.25px;
line-height: 20px;
position: absolute;
- right: -2px;
+ right: -$input-border;
top: -21px;
}
- &:hover::after {
+ &:hover:not([disabled])::after {
background: $gray-light;
color: $white;
}
&.active,
- &:active {
+ &:active:not([disabled]) {
&::after {
background: $purple-light;
@@ -423,6 +436,7 @@
}
.iconnables {
+ display: block;
height: 24px;
margin: 9px auto 6px;
width: 24px;
diff --git a/client/assets/styles/scss/modals/modals-guide.scss b/client/assets/styles/scss/modals/modals-guide.scss
index 1bc1c8491..b3f151f5a 100644
--- a/client/assets/styles/scss/modals/modals-guide.scss
+++ b/client/assets/styles/scss/modals/modals-guide.scss
@@ -16,5 +16,16 @@
.modal-edit .aha-tips {
margin-left: auto;
margin-right: auto;
- max-width: 360px;
+
+ @include media(xxxs) {
+ flex-direction: column;
+ }
+
+ .grid-content + .grid-content {
+ @include media(xxxs) {
+ margin-left: 0;
+ margin-top: 9px;
+ text-align: center;
+ }
+ }
}
diff --git a/client/assets/styles/scss/modals/modals-mirror-dockerfile.scss b/client/assets/styles/scss/modals/modals-mirror-dockerfile.scss
index 4fbfd2e0d..353df1c8b 100644
--- a/client/assets/styles/scss/modals/modals-mirror-dockerfile.scss
+++ b/client/assets/styles/scss/modals/modals-mirror-dockerfile.scss
@@ -70,10 +70,7 @@
// check button
.btn-icon {
border-radius: 50%;
- flex: 0 0 auto;
pointer-events: none; // let the label parent select
- position: static;
- width: $input-xs;
}
}
diff --git a/client/assets/styles/scss/modals/modals-server-select.scss b/client/assets/styles/scss/modals/modals-server-select.scss
index f3b774f6b..25e530c98 100644
--- a/client/assets/styles/scss/modals/modals-server-select.scss
+++ b/client/assets/styles/scss/modals/modals-server-select.scss
@@ -1,10 +1,7 @@
.modal-servers,
.modal-servers .animated-panel {
+ max-width: 100%;
min-width: 100%; // fix animated panel container
-
- @include media(xxxs) {
- max-width: 100%;
- }
}
.modal-server-select {
@@ -32,11 +29,7 @@
}
.btn {
- align-items: center;
- border: $input-border solid transparent;
border-radius: $input-border-radius-lg;
- display: flex;
- font-size: 15px;
height: 60px;
line-height: 1.2;
padding: 0 21px;
@@ -49,21 +42,11 @@
@include media(xxs) {
flex: 1 1 50%;
flex-direction: column;
- height: 96px;
+ height: 94px;
padding: 15px;
white-space: normal;
}
- &:hover {
- border-color: $gray-lighter;
- }
-
- &:active,
- &.active {
- border-color: currentColor;
- color: $purple;
- }
-
+ .btn {
margin-left: 15px;
@@ -125,15 +108,6 @@
.list-servers {
flex: 0 0 auto;
- // add button
- .btn-icon {
- border-radius: $input-border-radius;
- padding: 3px;
- right: 10px;
- top: 10px; // to center
- width: $input-sm;
- }
-
.icons-dockerfile,
.icons-server {
height: 14px;
@@ -150,21 +124,13 @@
}
.list-item {
+ font-size: 18px;
height: 60px;
- overflow: hidden;
-
- // template list
- &.grid-block {
- align-items: center;
-
- .img {
- margin-right: 15px;
- }
- }
+ }
- .spinner-wrapper {
- right: 21px;
- }
+ .btn-add {
+ padding: 0 9px;
+ width: auto;
}
}
@@ -175,9 +141,8 @@
border: $input-border solid transparent;
border-radius: $input-border-radius-lg;
cursor: pointer;
- font-size: 18px;
font-weight: $weight-bold;
- padding: 6px 60px 6px 15px;
+ padding: 6px 15px;
white-space: nowrap; // reset .multi-line default
&:hover:not(.disabled) {
@@ -186,16 +151,15 @@
}
&.disabled {
- color: $gray-light;
cursor: default;
- > .small {
- color: $gray-light;
+ > .small,
+ .btn-icon {
+ opacity: .6;
}
.btn-icon {
cursor: default;
- opacity: .5;
}
}
@@ -205,22 +169,6 @@
background: $white;
border-color: currentColor;
color: $green;
-
- .small {
- color: currentColor;
- }
- }
-
- &.multi-line {
-
- // only if in modal (for templates without descriptions)
- .modal-dialog & {
- min-height: 60px;
- }
- }
-
- &:last-child {
- margin-bottom: 15px;
}
+ .list-item {
@@ -240,18 +188,15 @@
// next arrow
.icons-arrow-down {
- height: 100%;
- position: absolute;
- right: 3px;
- top: 0;
+ height: 36px;
+ padding: 6px;
transform: rotate3d(0,0,1,-90deg);
+ width: 36px;
}
// spinner
.spinner-wrapper {
- position: absolute;
- right: 9px;
- top: 20px;
+ padding: 10px;
}
// tiled view for template containers
diff --git a/client/assets/styles/scss/modals/modals.scss b/client/assets/styles/scss/modals/modals.scss
index 5a4ca4f67..d23d49a13 100755
--- a/client/assets/styles/scss/modals/modals.scss
+++ b/client/assets/styles/scss/modals/modals.scss
@@ -2,26 +2,17 @@
.modal-backdrop {
align-items: center;
animation: fade .15s;
- background: rgba($white,.97);
+ background: rgba($white,.98);
display: flex;
flex-direction: column;
height: 100vh;
overflow: auto;
- padding: 90px 15px;
+ padding: 0 15px;
position: fixed;
top: 0;
width: 100vw;
z-index: $z-modal;
- @include media(lg) {
- padding-bottom: 30px;
- padding-top: 30px;
- }
-
- @media (max-height: $screen-xs), (max-width: $screen-sm) {
- padding: 15px;
- }
-
&.modal-blackout {
background: $white;
}
@@ -36,17 +27,28 @@
.modal-dialog {
animation: scale-in-modal .15s ease-out;
background: $gray-lighterest;
- border: $input-border-radius solid $gray-lighter;
+ border: 2px solid $gray-lighter;
border-radius: $input-border-radius-lg;
display: flex;
flex: 0 0 auto;
flex-direction: column;
- margin-bottom: 15px;
+ margin-bottom: 90px;
+ margin-top: 90px;
min-width: 360px;
position: relative;
transform-origin: 50% 10%;
transition: max-width .3s ease-in-out;
+ @include media(lg) {
+ margin-bottom: 30px;
+ margin-top: 30px;
+ }
+
+ @media (max-height: $screen-xs), (max-width: $screen-sm) {
+ margin-bottom: 15px;
+ margin-top: 15px;
+ }
+
@include media(sm) {
width: 100%;
}
@@ -141,6 +143,11 @@
position: absolute;
top: 18px;
z-index: 2; // fix overlap with container-title-wrapper
+
+ &.disabled {
+ color: $gray-lighter;
+ cursor: not-allowed;
+ }
}
.modal-header > .icons-close,
@@ -169,11 +176,11 @@
> .icons-arrow-backward {
left: 15px;
- &:hover {
+ &:hover:not(.disabled) {
color: $gray;
}
- &:active {
+ &:active:not(.disabled) {
color: $purple-light;
}
}
@@ -281,25 +288,21 @@
}
.btn-radio {
- background: none;
- border: 1px solid transparent;
border-radius: $input-border-radius-lg;
- color: $gray;
- display: flex;
flex: 0 0 90px;
font-weight: $weight-normal;
padding: 9px 3px 6px;
+ width: 90px;
- &:hover {
- border-color: $gray-lighter;
+ &:not(.active):not(:active) {
+ color: $gray;
}
- &:active,
- &.active {
- background: lighten($purple-lightest,6%);
- border-color: currentColor;
- box-shadow: inset 0 0 0 1px $purple-light;
- color: $purple-light;
+ .iconnables {
+ display: block;
+ height: 18px;
+ margin: 0 auto;
+ width: 18px;
}
// animation start state
@@ -325,10 +328,6 @@
margin-left: $tab-margin;
}
- .iconnables {
- height: 21px;
- }
-
.btn-text {
align-items: center;
display: flex;
diff --git a/client/assets/styles/scss/pages/grace-period.scss b/client/assets/styles/scss/pages/grace-period.scss
index 0e6a43198..c7cf410b8 100644
--- a/client/assets/styles/scss/pages/grace-period.scss
+++ b/client/assets/styles/scss/pages/grace-period.scss
@@ -71,7 +71,6 @@
.btn-add {
border-radius: 50%;
flex: 0 0 auto;
- position: static;
}
}
diff --git a/client/assets/styles/scss/popover/popover-add-branches.scss b/client/assets/styles/scss/popover/popover-add-branches.scss
new file mode 100644
index 000000000..b66aa4410
--- /dev/null
+++ b/client/assets/styles/scss/popover/popover-add-branches.scss
@@ -0,0 +1,7 @@
+.popover-add-branches {
+ max-width: 330px;
+
+ .btn-menu {
+ margin-left: 15px;
+ }
+}
diff --git a/client/assets/styles/scss/popover/popover-aha-containers.scss b/client/assets/styles/scss/popover/popover-aha-containers.scss
new file mode 100644
index 000000000..c60f948bf
--- /dev/null
+++ b/client/assets/styles/scss/popover/popover-aha-containers.scss
@@ -0,0 +1,19 @@
+.popover.popover-aha-containers {
+ left: 75px;
+ top: 72px;
+
+ @include media(xxs) {
+ left: 7px;
+ margin-left: 0;
+ top: 234px;
+ width: calc(100vw - 22px);
+ }
+
+ .arrow {
+ @include media(xxs) {
+ left: 30px;
+ top: -6px;
+ transform: rotate(90deg);
+ }
+ }
+}
diff --git a/client/assets/styles/scss/popover/popover-aha-url.scss b/client/assets/styles/scss/popover/popover-aha-url.scss
new file mode 100644
index 000000000..da26b56f7
--- /dev/null
+++ b/client/assets/styles/scss/popover/popover-aha-url.scss
@@ -0,0 +1,18 @@
+.popover.popover-aha-url {
+ left: auto;
+ position: fixed;
+ right: 12px;
+ top: 96px;
+
+ @media (max-width: 810px) {
+ max-width: calc(100vw - 30px);
+ right: 15px;
+ top: 15px;
+ }
+
+ .arrow {
+ @media (max-width: 810px) {
+ display: none;
+ }
+ }
+}
diff --git a/client/assets/styles/scss/popover/popover-aha.scss b/client/assets/styles/scss/popover/popover-aha.scss
new file mode 100644
index 000000000..5283b3797
--- /dev/null
+++ b/client/assets/styles/scss/popover/popover-aha.scss
@@ -0,0 +1,25 @@
+.popover.popover-aha {
+ max-width: none;
+ width: 450px;
+
+ &.popover-sm {
+ color: $gray;
+ line-height: $input-xs;
+ max-width: none;
+ width: auto;
+
+ .float-left + .float-right {
+ margin-left: 15px;
+
+ @include media(xxs) {
+ float: left;
+ margin-left: 0;
+ margin-top: 3px;
+ }
+ }
+ }
+
+ .popover-content {
+ @extend %padding-sm;
+ }
+}
diff --git a/client/assets/styles/scss/popover/popover-arrows.scss b/client/assets/styles/scss/popover/popover-arrows.scss
index fa527f837..6a1b290b0 100644
--- a/client/assets/styles/scss/popover/popover-arrows.scss
+++ b/client/assets/styles/scss/popover/popover-arrows.scss
@@ -31,7 +31,7 @@
.arrow {
background: transparent;
border-color: $gray-lighter;
- border-width: 13px;
+ border-width: 12px;
z-index: $z-popover-arrow;
// reset bg
@@ -75,7 +75,7 @@
border-bottom-width: 0;
border-left-color: transparent;
border-right-color: transparent;
- bottom: -13px;
+ bottom: -12px;
left: 50%;
margin-left: -11px;
@@ -83,7 +83,7 @@
border-bottom-width: 0;
border-left-color: transparent;
border-right-color: transparent;
- bottom: 3px;
+ bottom: 2px;
margin-left: -10px;
}
}
@@ -98,8 +98,8 @@
border-bottom-color: transparent;
border-left-width: 0;
border-top-color: transparent;
- left: -13px;
- margin-top: -13px;
+ left: -12px;
+ margin-top: -12px;
top: 50%;
&::after {
@@ -107,7 +107,7 @@
border-left-width: 0;
border-top-color: transparent;
bottom: -10px;
- left: 3px;
+ left: 2px;
}
}
}
@@ -121,15 +121,15 @@
border-right-color: transparent;
border-top-width: 0;
left: 50%;
- margin-left: -13px;
- top: -13px;
+ margin-left: -12px;
+ top: -12px;
&::after {
border-left-color: transparent;
border-right-color: transparent;
border-top-width: 0;
margin-left: -10px;
- top: 3px;
+ top: 2px;
}
}
}
@@ -142,8 +142,8 @@
border-bottom-color: transparent;
border-right-width: 0;
border-top-color: transparent;
- margin-top: -13px;
- right: -13px;
+ margin-top: -12px;
+ right: -12px;
top: 50%;
&::after {
diff --git a/client/assets/styles/scss/popover/popover-branch-menu.scss b/client/assets/styles/scss/popover/popover-branch-menu.scss
index 4b4a8021d..1ed58dce3 100644
--- a/client/assets/styles/scss/popover/popover-branch-menu.scss
+++ b/client/assets/styles/scss/popover/popover-branch-menu.scss
@@ -1,16 +1,71 @@
-.popover-branch-menu {
- max-width: 330px;
- min-height: 150px;
+.popover-branch-menu,
+.popover-template-menu {
+ max-width: 360px;
width: 100%;
+ .popover-content.popover-content {
+ max-height: 375px;
+ min-height: 105px;
+ overflow-y: auto;
+ }
+
+ .list-item {
+ border: 1px solid transparent;
+
+ &:hover:not(.disabled) {
+ background: $gray-lighterest;
+ border-color: $gray-lighter;
+ }
+
+ &:active:not(.disabled),
+ &.active:not(.disabled) {
+ background: $white;
+ border-color: currentColor;
+ color: $green;
+ }
+
+ &.active {
+ cursor: default;
+ }
+
+ // loading state
+ &.disabled {
+ cursor: not-allowed;
+ opacity: .5;
+ }
+
+ .spinner-wrapper {
+ padding: 4px;
+ }
+ }
+
+ .btn-add {
+ padding: 0 6px;
+ width: auto;
+ }
+}
+
+.popover-branch-menu {
+
+ .aha-guide {
+ border-bottom: 1px solid $gray-lighter;
+ font-size: 15px;
+ margin-top: 6px;
+ padding-bottom: 21px;
+ }
+
.well {
- margin-bottom: 6px;
+ margin-bottom: 15px;
}
- .popover-content.popover-content {
- max-height: 330px;
- min-height: 90px;
- overflow-y: auto;
+ .popover-list-item {
+ padding-right: 9px;
+
+ .iconnables.icons-branch {
+ color: $gray-light;
+ height: 18px;
+ margin-right: 0;
+ }
}
// empty state
@@ -25,9 +80,43 @@
font-size: 15px;
}
}
+}
+
+.popover-template-menu {
+
+ .popover-header {
+ display: flex;
+ height: auto;
+ padding: 15px;
+ }
+
+ .btn-radio {
+ border-radius: $input-border-radius-lg;
+ flex: 0 1 50%;
+ font-size: 13px;
+ font-weight: $weight-bold;
+ height: auto;
+ line-height: 1.4;
+ padding: 9px 15px;
+ text-align: left;
+
+ + .btn-radio {
+ margin-left: 12px;
+ }
+
+ .small {
+ font-size: 12px;
+ opacity: .6;
+ }
+ }
+
+ .list-item .iconnables.icons-repository {
+ margin-left: 3px;
+ margin-right: 18px;
+ width: 18px;
+ }
- // pagination
- .list-pagination {
- padding: 6px;
+ .btn-add {
+ margin-left: 15px;
}
}
diff --git a/client/assets/styles/scss/popover/popover-files.scss b/client/assets/styles/scss/popover/popover-files.scss
index de368daf5..d6f5bb534 100644
--- a/client/assets/styles/scss/popover/popover-files.scss
+++ b/client/assets/styles/scss/popover/popover-files.scss
@@ -31,8 +31,7 @@
.list-servers {
.list-item {
- font-size: 15px;
- padding: 6px 21px 6px 9px;
+ padding: 6px 3px 6px 9px;
&:active,
&.active {
@@ -40,10 +39,6 @@
color: $purple-light;
}
}
-
- .spinner-wrapper {
- top: 18px;
- }
}
// forms
diff --git a/client/assets/styles/scss/popover/popover-primary-options.scss b/client/assets/styles/scss/popover/popover-primary-options.scss
index 95c6bef6a..e6960d2a5 100644
--- a/client/assets/styles/scss/popover/popover-primary-options.scss
+++ b/client/assets/styles/scss/popover/popover-primary-options.scss
@@ -17,13 +17,9 @@
padding-bottom: 6px;
padding-top: 6px;
- &:active .small {
- color: currentColor;
- }
-
.small {
- color: $gray;
margin-left: 27px;
+ opacity: .6;
}
}
}
diff --git a/client/assets/styles/scss/popover/popover.scss b/client/assets/styles/scss/popover/popover.scss
index 976a6c2f3..1a9a806b4 100755
--- a/client/assets/styles/scss/popover/popover.scss
+++ b/client/assets/styles/scss/popover/popover.scss
@@ -259,8 +259,7 @@
background: rgba($purple-lightest,.9);
color: $purple-light;
- .iconnables,
- .small {
+ .iconnables {
color: $purple-light;
}
diff --git a/client/assets/styles/scss/views/views-toolbar.scss b/client/assets/styles/scss/views/views-toolbar.scss
index 8276c1150..cbe359918 100644
--- a/client/assets/styles/scss/views/views-toolbar.scss
+++ b/client/assets/styles/scss/views/views-toolbar.scss
@@ -133,9 +133,9 @@
// web error button
.btn-web-state {
- color: rgba($orange,.75);
cursor: default;
font-family: $sans-serif;
+ opacity: .5;
padding: 0;
.icons-alert {
diff --git a/client/config/routes.js b/client/config/routes.js
index 182ada309..250f5827f 100755
--- a/client/config/routes.js
+++ b/client/config/routes.js
@@ -73,6 +73,10 @@ module.exports = [
},
whitelistedOrgs: function (fetchWhitelistForDockCreated) {
return fetchWhitelistForDockCreated();
+ },
+ booted: function (eventTracking, user) {
+ eventTracking.boot(user);
+ eventTracking.visitedOrgSelectPage();
}
}
}, {
@@ -194,20 +198,56 @@ module.exports = [
url: '^/:userName/configure',
templateUrl: 'environmentView',
controller: 'EnvironmentController',
- controllerAs: 'EC'
+ controllerAs: 'EC',
+ resolve: {
+ instancesByPod: function (fetchInstancesByPod, $stateParams, $state) {
+ $state.params.userName = $stateParams.userName;
+ return fetchInstancesByPod();
+ }
+ }
}, {
state: 'base.instances',
abstract: false,
url: '^/:userName/',
templateUrl: 'viewInstances',
controller: 'ControllerInstances',
- controllerAs: 'CIS'
+ controllerAs: 'CIS',
+ resolve: {
+ instancesByPod: function (fetchInstancesByPod, $stateParams, $state) {
+ $state.params.userName = $stateParams.userName;
+ return fetchInstancesByPod();
+ },
+ hasConfirmedSetup: function (
+ $rootScope,
+ $state,
+ $stateParams,
+ $timeout,
+ ahaGuide,
+ featureFlags,
+ populateCurrentOrgService // Unused, but required so things are properly populated!
+ ) {
+ if (featureFlags.flags.aha && ahaGuide.isInGuide() && !ahaGuide.hasConfirmedSetup()) {
+ $timeout(function () {
+ $state.go('base.config', {
+ userName: $stateParams.userName
+ });
+ });
+ }
+ }
+ }
}, {
state: 'base.instances.instance',
abstract: false,
url: '^/:userName/:instanceName',
templateUrl: 'viewInstance',
- controller: 'ControllerInstance'
+ controller: 'ControllerInstance',
+ controllerAs: 'CI',
+ resolve: {
+ instancesByPod: function (fetchInstancesByPod, $stateParams, $state) {
+ $state.params.userName = $stateParams.userName;
+ return fetchInstancesByPod();
+ }
+ }
}
];
Object.freeze(module.exports);
diff --git a/client/controllers/controllerApp.js b/client/controllers/controllerApp.js
index db58e0f89..c90b31d71 100755
--- a/client/controllers/controllerApp.js
+++ b/client/controllers/controllerApp.js
@@ -3,7 +3,6 @@
require('app')
.controller('ControllerApp', ControllerApp);
-
function ControllerApp(
$localStorage,
$ocLazyLoad,
@@ -12,6 +11,7 @@ function ControllerApp(
$state,
$timeout,
$window,
+ ahaGuide,
configAPIHost,
configEnvironment,
configLoginURL,
@@ -22,20 +22,19 @@ function ControllerApp(
keypather,
ModalService,
pageName,
+ patchOrgMetadata,
+ promisify,
currentOrg,
-
user,
orgs,
activeAccount
) {
// Load ace after 10 seconds. Should improve user experience overall..
- $timeout(function () {
- $ocLazyLoad.load('ui.ace');
- }, 10000);
-
this.activeAccount = activeAccount;
this.user = user;
var CA = this;
+ CA.ahaGuide = ahaGuide;
+ CA.currentOrg = currentOrg;
fetchInstancesByPod()
.then(function (instancesByPod) {
@@ -74,10 +73,11 @@ function ControllerApp(
actions: {},
state: $state
};
-
- if (user.socket) {
- user.socket.joinOrgRoom(activeAccount.oauthId());
- }
+ $scope.$watch('dataApp.data.activeAccount', function (activeAccount) {
+ if (user.socket) {
+ user.socket.joinOrgRoom(activeAccount.oauthId());
+ }
+ });
$rootScope.pageName = pageName;
@@ -99,6 +99,40 @@ function ControllerApp(
}
});
+ CA.showAhaNavPopover = false;
+ $scope.$on('launchAhaNavPopover', function () {
+ CA.showAhaNavPopover = !keypather.get(currentOrg, 'poppa.attrs.metadata.hasConfirmedSetup');
+ });
+
+ CA.showAhaConfirmation = function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ CA.showAhaNavPopover = false;
+ $rootScope.$broadcast('showAddServicesPopover', false);
+ ModalService.showModal({
+ controller: 'ConfirmationModalController',
+ controllerAs: 'CMC',
+ templateUrl: 'confirmSetupView'
+ })
+ .then(function(modal) {
+ return modal.close;
+ })
+ .then(function(confirmed) {
+ if (confirmed) {
+ return patchOrgMetadata(currentOrg.poppa.id(), {
+ metadata: {
+ hasConfirmedSetup: true
+ }
+ })
+ .then(function(updatedOrg) {
+ ahaGuide.updateCurrentOrg(updatedOrg);
+ $state.go('base.instances', {userName: CA.activeAccount.oauthName()});
+ });
+ }
+ })
+ .catch(errs.handler);
+ };
+
/**
* broadcast to child scopes when click event propagates up
* to top level controller scope.
diff --git a/client/controllers/controllerInstance.js b/client/controllers/controllerInstance.js
index a3ae04e7e..35a7f0a26 100644
--- a/client/controllers/controllerInstance.js
+++ b/client/controllers/controllerInstance.js
@@ -12,7 +12,8 @@ function ControllerInstance(
$state,
$stateParams,
$timeout,
- OpenItems,
+ ahaGuide,
+ currentOrg,
errs,
eventTracking,
favico,
@@ -20,13 +21,26 @@ function ControllerInstance(
fetchDockerfileForContextVersion,
fetchInstances,
fetchSettings,
+ fetchUser,
getCommitForCurrentlyBuildingBuild,
keypather,
- fetchUser,
+ loading,
+ OpenItems,
+ instancesByPod,
pageName,
- setLastInstance,
- loading
+ setLastInstance
) {
+
+ var CIS = this;
+ CIS.showSidebar = false;
+ CIS.isInGuide = ahaGuide.isInGuide;
+ CIS.toggleSidebar = function (end) {
+ if (end === 'end') {
+ ahaGuide.endGuide();
+ }
+ CIS.showSidebar = !CIS.showSidebar;
+ };
+ $scope.$on('showAhaSidebar', CIS.toggleSidebar);
var dataInstance = $scope.dataInstance = {
data: {
unsavedAcvs: []
@@ -98,8 +112,8 @@ function ControllerInstance(
setLastInstance($stateParams.instanceName);
loading('main', false);
})
- .catch(function (err) { // We ONLY want to handle errors related to fetching instances so this catch is nested.
- errs.handler(err);
+ .catch(function () {
+ // Don't handle the instance fetch err, because it's super annoying
loading('main', false);
setLastInstance(false);
$state.go('base.instances', {
@@ -200,4 +214,17 @@ function ControllerInstance(
favico.setInstanceState(keypather.get($scope, 'dataInstance.data.instance'));
});
});
+
+ if (ahaGuide.isInGuide()) {
+ if (keypather.get(instancesByPod, 'models.length')) {
+ if (instancesByPod.models.some(function (instance) {
+ return instance.attrs.hasAddedBranches || keypather.get(instance, 'children.models.length');
+ })) {
+ // timeout for the animation
+ $timeout(function () {
+ CIS.showSidebar = true;
+ });
+ }
+ }
+ }
}
diff --git a/client/controllers/controllerInstances.js b/client/controllers/controllerInstances.js
index b0fe4c04d..98feb56de 100644
--- a/client/controllers/controllerInstances.js
+++ b/client/controllers/controllerInstances.js
@@ -8,35 +8,68 @@ require('app')
function ControllerInstances(
$filter,
$localStorage,
+ $rootScope,
+ $scope,
$state,
- keypather,
- setLastOrg,
+ activeAccount,
+ ahaGuide,
+ currentOrg,
errs,
- ModalService,
fetchInstancesByPod,
- activeAccount,
+ fetchRepoBranches,
+ keypather,
+ loading,
+ ModalService,
+ promisify,
+ setLastOrg,
user
) {
- var self = this;
+ var CIS = this;
var userName = $state.params.userName;
- self.searchBranches = null;
- self.$storage = $localStorage.$default({
+ CIS.isInGuide = ahaGuide.isInGuide;
+ CIS.isAddingFirstBranch = ahaGuide.isAddingFirstBranch;
+ CIS.isSettingUpRunnabot = ahaGuide.isSettingUpRunnabot;
+ CIS.currentOrg = currentOrg;
+ CIS.showAutofork = null;
+ CIS.searchBranches = null;
+ CIS.instanceBranches = null;
+ CIS.unbuiltBranches = null;
+ CIS.branchQuery = null;
+ CIS.$storage = $localStorage.$default({
instanceListIsClosed: false
});
+
+ CIS.shouldShowPopover = true;
+ $scope.$on('popover-closed', function (event, pop) {
+ if (keypather.get(pop, 'data') === 'branchSelect') {
+ CIS.shouldShowPopover = true;
+ }
+ });
+
+ $scope.$on('popover-opened', function (event, pop) {
+ if (keypather.get(pop, 'data') === 'branchSelect') {
+ CIS.shouldShowPopover = false;
+ }
+ });
+
+ $scope.$on('showAutoLaunchPopover', function() {
+ CIS.showAutofork = true;
+ });
+
fetchInstancesByPod()
.then(function (instancesByPod) {
- // If the state has already changed don't continue with old data. Let the new one execute.
+ // If the state has already changed don' t continue with old data. Let the new one execute.
if (userName !== $state.params.userName) {
return;
}
- self.instancesByPod = instancesByPod;
- self.activeAccount = activeAccount;
+ CIS.instancesByPod = instancesByPod;
+ CIS.activeAccount = activeAccount;
var instances = instancesByPod;
var lastViewedInstance = keypather.get(user, 'attrs.userOptions.uiState.previousLocation.instance');
- function isInstanceMatch (instance, nameMatch) {
+ function isInstanceMatch(instance, nameMatch) {
if (instance.destroyed || !instance.id()) {
return false;
}
@@ -84,63 +117,124 @@ function ControllerInstances(
})
.catch(errs.handler);
+ this.filterMatchedAnything = function () {
+ if (!CIS.searchBranches) {
+ return true;
+ }
+ if (!CIS.instancesByPod) {
+ return true;
+ }
+
+ return CIS.instancesByPod.models.some(function (masterPod) {
+ return CIS.filterMasterInstance(masterPod) || CIS.shouldShowParent(masterPod);
+ });
+ };
+
this.filterMasterInstance = function (masterPod) {
- if (!self.searchBranches) {
+ if (!CIS.searchBranches) {
return true;
}
- var searchQuery = self.searchBranches.toLowerCase();
+ var searchQuery = CIS.searchBranches.toLowerCase();
var instanceName = masterPod.getRepoAndBranchName() + masterPod.attrs.lowerName;
return instanceName.toLowerCase().indexOf(searchQuery) !== -1;
};
this.getFilteredInstanceList = function () {
- if (!self.instancesByPod) {
+ if (!CIS.instancesByPod) {
return null;
}
- if (!self.searchBranches) {
- return self.instancesByPod;
+ if (!CIS.searchBranches) {
+ return CIS.instancesByPod.models;
}
- var searchQuery = self.searchBranches.toLowerCase();
- return self.instancesByPod
- .filter(function (masterPod) {
- var instanceName = masterPod.getRepoAndBranchName() + masterPod.attrs.lowerName;
- return instanceName.toLowerCase().indexOf(searchQuery) !== -1 ||
- self.getFilteredChildren(masterPod).length > 0;
- });
+ return CIS.instancesByPod.models
+ .filter(CIS.filterMasterInstance);
};
- this.getFilteredChildren = function (masterPod) {
- if (!self.searchBranches) {
- return masterPod.children.models;
+ this.getFilteredBranches = function () {
+ if (!CIS.branchQuery) {
+ return CIS.instanceBranches;
}
- var searchQuery = self.searchBranches.toLowerCase();
- return masterPod.children.models.filter(function (child) {
- return child.attrs.lowerName.indexOf(searchQuery) !== -1;
+ var branchName;
+ var searchQuery = CIS.branchQuery.toLowerCase();
+ return CIS.instanceBranches.filter(function (branch) {
+ branchName = branch.attrs.name.toLowerCase();
+ return branchName.includes(searchQuery);
});
};
this.shouldShowChild = function (childInstance) {
- if (!self.searchBranches) {
+ if (!CIS.searchBranches) {
return true;
}
- var searchQuery = self.searchBranches.toLowerCase();
- return childInstance.attrs.lowerName.indexOf(searchQuery) !== -1;
+ var searchQuery = CIS.searchBranches.toLowerCase();
+ return childInstance.getBranchName().toLowerCase().indexOf(searchQuery) !== -1;
};
this.shouldShowParent = function (masterPod) {
- if (!self.searchBranches) {
+ if (!CIS.searchBranches) {
return true;
}
- var searchQuery = self.searchBranches.toLowerCase();
-
- var instanceName = masterPod.getRepoAndBranchName() + masterPod.attrs.lowerName;
- if (instanceName.indexOf(searchQuery) !== -1) {
- return true;
+ if (!masterPod.children) {
+ return false;
}
+ return masterPod.children.models.some(CIS.shouldShowChild);
+ };
- return !!masterPod.children.models.find(function (child) {
- return child.attrs.lowerName.indexOf(searchQuery) !== -1;
+ this.getUnbuiltBranches = function (instance, branches) {
+ var branchName;
+ var childInstances = instance.children.models.reduce(function (childHash, child) {
+ branchName = child.getBranchName();
+ childHash[branchName] = branchName;
+ return childHash;
+ }, {});
+ var instanceBranchName = instance.getBranchName();
+ childInstances[instanceBranchName] = instanceBranchName;
+ var unbuiltBranches = branches.models.filter(function (branch) {
+ branchName = keypather.get(branch, 'attrs.name');
+ return !childInstances[branchName];
});
+ return unbuiltBranches;
+ };
+
+ this.popInstanceOpen = function (instance, open) {
+ CIS.instanceBranches = null;
+ CIS.poppedInstance = instance;
+ loading('fetchingBranches', true);
+ return CIS.getAllBranches(instance)
+ .then(function (branches) {
+ CIS.totalInstanceBranches = branches.models.length;
+ CIS.instanceBranches = CIS.getUnbuiltBranches(instance, branches);
+ loading('fetchingBranches', false);
+ });
+ };
+
+ this.getAllBranches = function (instance) {
+ return promisify(currentOrg.github, 'fetchRepo')(instance.getRepoName())
+ .then(function (repo) {
+ return fetchRepoBranches(repo);
+ });
+ };
+
+ this.forkBranchFromInstance = function (branch, closePopover) {
+ var sha = branch.attrs.commit.sha;
+ var branchName = branch.attrs.name;
+ loading(branchName, true);
+ loading('buildingForkedBranch', true);
+ promisify(CIS.poppedInstance, 'fork')(branchName, sha)
+ .then(function (instance) {
+ var newInstances = instance.children.models.filter(function(childInstance) {
+ return childInstance.attrs.name === branchName + '-' + instance.attrs.name;
+ });
+ loading(branchName, false);
+ loading('buildingForkedBranch', false);
+ closePopover();
+ if (newInstances.length) {
+ $state.go('base.instances.instance', {
+ instanceName: newInstances[0].attrs.name
+ });
+ }
+ })
+ .catch(errs.handler);
};
this.editInstance = function (instance) {
@@ -157,28 +251,21 @@ function ControllerInstances(
.catch(errs.handler);
};
- this.openInviteAdminModal = function (instance) {
- ModalService.showModal({
- controller: 'InviteAdminModalController',
- controllerAs: 'IAMC',
- templateUrl: 'inviteAdminModalView',
- inputs: {
- instance: instance,
- isFromAutoDeploy: false
- }
- })
- .catch(errs.handler);
- };
-
- this.openEnableBranchesModal = function (instance) {
- ModalService.showModal({
- controller: 'EnableBranchesModalController',
- controllerAs: 'EBMC',
- templateUrl: 'enableBranchesModalView',
- inputs: {
- instance: instance
- }
- })
- .catch(errs.handler);
+ this.setAutofork = function () {
+ CIS.poppedInstance.attrs.shouldNotAutofork = !CIS.poppedInstance.attrs.shouldNotAutofork;
+ if (CIS.isInGuide() && !CIS.poppedInstance.attrs.shouldNotAutofork) {
+ var childWatcher = $scope.$watch('CIS.poppedInstance.children.models.length', function (length) {
+ if (length) {
+ $rootScope.$broadcast('showAhaSidebar');
+ childWatcher();
+ }
+ });
+ } else if (!CIS.poppedInstance.attrs.shouldNotAutofork) {
+ CIS.showAutofork = false;
+ }
+ promisify(CIS.poppedInstance, 'update')({ shouldNotAutofork: CIS.poppedInstance.attrs.shouldNotAutofork })
+ .catch(function () {
+ CIS.poppedInstance.attrs.shouldNotAutofork = !CIS.poppedInstance.attrs.shouldNotAutofork;
+ });
};
}
diff --git a/client/controllers/featureFlagsController.js b/client/controllers/featureFlagsController.js
index fb413d6c5..29c74dad4 100644
--- a/client/controllers/featureFlagsController.js
+++ b/client/controllers/featureFlagsController.js
@@ -4,7 +4,11 @@ require('app')
.controller('FeatureFlagsController', FeatureFlagsController);
function FeatureFlagsController(
- $localStorage
+ $localStorage,
+ ahaGuide
) {
this.$localStorage = $localStorage;
+ this.resetAha = function() {
+ ahaGuide.resetGuide();
+ };
}
diff --git a/client/controllers/indexController.js b/client/controllers/indexController.js
index e2ccf25cb..98d81e2d2 100755
--- a/client/controllers/indexController.js
+++ b/client/controllers/indexController.js
@@ -4,6 +4,7 @@ require('app')
.controller('IndexController', IndexController);
function IndexController(
+ $localStorage,
$ocLazyLoad,
$rootScope,
$scope,
diff --git a/client/directives/accountsSelect/popoverAccountMenu/viewPopoverAccountMenu.jade b/client/directives/accountsSelect/popoverAccountMenu/viewPopoverAccountMenu.jade
index 5a2a9fd0b..7abd8b489 100644
--- a/client/directives/accountsSelect/popoverAccountMenu/viewPopoverAccountMenu.jade
+++ b/client/directives/accountsSelect/popoverAccountMenu/viewPopoverAccountMenu.jade
@@ -57,6 +57,15 @@
| Settings
//- $root.featureFlags.billing
//- *****************
+ li.list-item.popover-list-item(
+ ng-click = "actions.openSettingsModal('githubIntegration')"
+ ng-if = "$root.featureFlags.gitHubIntegration"
+ )
+ svg.iconnables
+ use(
+ xlink:href = "#icons-octicons-github-gray"
+ )
+ | PR Bot
li.list-item.popover-list-item(
ng-click = "actions.openSettingsModal('slackIntegration')"
)
@@ -173,6 +182,16 @@
style = "background-position: 6px center !important; padding-left: 24px !important;"
type = "search"
)
+ label.list-item.popover-list-item.text-overflow(
+ style = "display: block; padding: 0 39px 0 15px;"
+ ) Reset Aha Guide
+ .toggle-wrapper(
+ style = "position: absolute; right: 12px; top: 11px;"
+ )
+ input.toggle-input(
+ ng-click = "FFC.resetAha()"
+ type = "button"
+ )
label.list-item.popover-list-item.text-overflow(
ng-repeat = "(flag, value) in $root.featureFlags"
ng-show = "!searchText || flag.indexOf(searchText) > -1"
diff --git a/client/directives/activePanel/tabs/logs/termController.js b/client/directives/activePanel/tabs/logs/termController.js
index 22518e048..97d9a60c4 100644
--- a/client/directives/activePanel/tabs/logs/termController.js
+++ b/client/directives/activePanel/tabs/logs/termController.js
@@ -11,6 +11,17 @@ function TermController(
$timeout,
WatchOnlyOnce
) {
+ if (!$scope.tabItem) {
+ $scope.tabItem = {
+ attrs: {
+ terminalId: null
+ },
+ state: {
+ saveState: function() {return null;}
+ }
+ };
+ }
+
var termOnFn;
var watchOnlyOnce = new WatchOnlyOnce($scope);
$scope.termOpts = {
diff --git a/client/directives/activePanel/tabs/viewTabs.jade b/client/directives/activePanel/tabs/viewTabs.jade
index 1eda8cd45..268291835 100755
--- a/client/directives/activePanel/tabs/viewTabs.jade
+++ b/client/directives/activePanel/tabs/viewTabs.jade
@@ -40,7 +40,7 @@ button.btn.btn-xs.btn-add-tab(
pop-over-actions = "popoverAddTab.actions"
pop-over-active = "popoverAddTab.data.show"
pop-over-data = "popoverAddTab.data"
- pop-over-options = "{\"right\":-7,\"top\":37}"
+ pop-over-options = "{\"right\":-5,\"top\":37}"
pop-over-template = "viewPopoverAddTab"
)
svg.iconnables.icons-add
diff --git a/client/directives/activePanel/toolbar/webViewToolbarView.jade b/client/directives/activePanel/toolbar/webViewToolbarView.jade
index 51e0af583..b54e9ecba 100644
--- a/client/directives/activePanel/toolbar/webViewToolbarView.jade
+++ b/client/directives/activePanel/toolbar/webViewToolbarView.jade
@@ -1,23 +1,17 @@
small.small.sans-serif.label-url.hidden-xxxs URL:
a.p.monospace.text-overflow(
- href = "//praful-staging-codenow.runnableapp.com"
+ ng-href = "http://{{SMC.state.instance.getContainerHostname()}}"
target = "_blank"
-) praful-staging-codenow.runnableapp.com
+) {{SMC.state.instance.getContainerHostname()}}
svg.iconnables.icons-external
use(
xlink:href = "#icons-link-external"
)
.grid-block.shrink.align-center.btn.btn-xs.btn-web-state(
- ng-click = "state.error = !state.error"
+ ng-if = "!SMC.hasOpenPorts()"
)
svg.iconnables.icons-alert
use(
xlink:href = "#icons-alert-alt"
)
- | {{state.error ? 'No exposed ports.' : ''}}
- | {{!state.error ? 'Bind to all interfaces.' : ''}}
- |
- a.link(
- href = "#"
- target = "_blank"
- ) Learn More
+ | No exposed ports.
diff --git a/client/directives/components/ahaGuide/AhaGuideController.js b/client/directives/components/ahaGuide/AhaGuideController.js
new file mode 100644
index 000000000..ca2bdc9e5
--- /dev/null
+++ b/client/directives/components/ahaGuide/AhaGuideController.js
@@ -0,0 +1,220 @@
+
+'use strict';
+
+require('app')
+ .controller('AhaGuideController', AhaGuideController);
+
+function AhaGuideController(
+ $scope,
+ $rootScope,
+ ahaGuide,
+ currentOrg,
+ errs,
+ eventTracking,
+ fetchInstancesByPod,
+ keypather,
+ patchOrgMetadata
+) {
+ var AGC = this;
+ var animatedPanelListener = angular.noop;
+ // dismiss add service popover if open
+ $rootScope.$broadcast('showAddServicesPopover', false);
+
+ if (keypather.has(currentOrg, 'poppa.attrs.id') && ahaGuide.isAddingFirstRepo()) {
+ fetchInstancesByPod()
+ .then(function (instances) {
+ if (instances.models.length) {
+ var config = checkContainerInstances(instances);
+ if (!config.workingRepoInstance) {
+ AGC.showError = true;
+ AGC.errorState = 'nonRunningContainer';
+ updateCaption('exitedEarly');
+ $rootScope.$broadcast('ahaGuideEvent', {
+ error: AGC.errorState
+ });
+ } else if (ahaGuide.isAddingFirstRepo()) {
+ if (AGC.subStepIndex === 7) {
+ callPopover(config, instances);
+ updateCaption('success');
+ }
+ }
+ } else {
+ ahaGuide.furthestSubstep(ahaGuide.steps.ADD_FIRST_REPO, 'addRepository');
+ }
+ })
+ .catch(errs.handler);
+ }
+
+ $scope.$on('alert', function (event, alert) {
+ // alerts on container creation success
+ if (alert.text === 'Container Created' && alert.type === 'success') {
+ updateCaption('logs');
+ fetchInstancesByPod()
+ .then(function (instances) {
+ var config = checkContainerInstances(instances);
+ if (config) {
+ callPopover(config, instances);
+ }
+ })
+ .catch(errs.handler);
+ }
+ });
+
+ var buildLogListener = $scope.$on('buildStatusUpdated', function(event, buildStatus) {
+ if (ahaGuide.isAddingFirstRepo()) {
+ handleBuildUpdate(buildStatus);
+ }
+ });
+
+ $scope.$on('ahaGuideEvent', function(event, info) {
+ if (info.error === 'exitedEarly') {
+ AGC.showError = true;
+ AGC.errorState = info.error;
+ updateCaption('exitedEarly');
+ } else if (info.error === 'nonRunningContainer') {
+ AGC.showError = true;
+ AGC.errorState = info.error;
+ } else if (info.error === 'buildFailed') {
+ AGC.showError = true;
+ AGC.errorState = info.error;
+ } else if (info.isClear) {
+ AGC.showError = false;
+ AGC.errorState = null;
+ }
+ });
+
+ var stopTabUpdate = $scope.$on('updatedTab', function(event, tabName) {
+ if (AGC.subStepIndex > 5) {
+ stopTabUpdate();
+ } else {
+ updateCaption(tabName);
+ }
+ });
+
+ AGC.ahaGuide = ahaGuide;
+ AGC.configSteps = ahaGuide.stepList[ahaGuide.steps.ADD_FIRST_REPO].configSubsteps;
+ AGC.errorState = $scope.errorState;
+ AGC.hasConfirmedSetup = ahaGuide.hasConfirmedSetup;
+ AGC.isBuildSuccessful = false;
+ AGC.isInGuide = ahaGuide.isInGuide;
+ AGC.skipBranchMilestone = ahaGuide.skipBranchMilestone;
+
+ // get the current milestone
+ var currentMilestone = ahaGuide.stepList[ahaGuide.getCurrentStep()];
+
+ AGC.title = currentMilestone.title;
+ updateCaption(AGC.subStep);
+
+ // update steps and initiate digest loop
+ function updateCaption(status) {
+ if (!currentMilestone.subSteps[status]) {
+ return;
+ }
+ if (status === 'dockLoaded') {
+ animatedPanelListener();
+ }
+ AGC.subStep = status;
+ AGC.className = currentMilestone.subSteps[status].className;
+ AGC.subStepIndex = currentMilestone.subSteps[status].step;
+ ahaGuide.furthestSubstep(ahaGuide.steps.ADD_FIRST_REPO, status);
+
+ // tracking
+ switch (AGC.subStep) {
+ case 'containerSelection':
+ eventTracking.milestone2SelectTemplate();
+ break;
+ case 'repository':
+ eventTracking.milestone2VerifyRepositoryTab();
+ break;
+ case 'commands':
+ eventTracking.milestone2VerifyCommandsTab();
+ break;
+ case 'logs':
+ eventTracking.milestone2Building();
+ break;
+ case 'success':
+ eventTracking.milestone2BuildSuccess();
+ break;
+ }
+ }
+
+ function handleBuildUpdate(update) {
+ var buildStatus = update.status;
+ if (buildStatus === 'buildFailed' || buildStatus === 'stopped' || buildStatus === 'crashed') {
+ AGC.showError = true;
+ AGC.errorState = 'nonRunningContainer';
+ $rootScope.$broadcast('ahaGuideEvent', {
+ error: 'buildFailed'
+ });
+ } else if (buildStatus === 'starting') {
+ AGC.showError = false;
+ // as long as the build was successful that's ok
+ $rootScope.$broadcast('ahaGuideEvent', {
+ isClear: true
+ });
+ AGC.isBuildSuccessful = true;
+ } else if (buildStatus === 'running') {
+ updateCaption('success');
+ }
+ AGC.buildStatus = buildStatus;
+ AGC.caption = currentMilestone.buildStatus[buildStatus] || AGC.caption;
+ }
+ /** this checks all instances and whether there is a built repo instance and non repo instance
+ * @param {object} instances an object containing a collection of instances
+ * @return {object} config an object with two boolean properties, nonRepoInstance and workingRepoInstance
+ */
+ function checkContainerInstances (instances) {
+ if (!instances) {
+ return null;
+ }
+ var config = {};
+ var status;
+ var repoName;
+ instances.forEach(function(instance) {
+ status = instance.status();
+ repoName = instance.getRepoName();
+ if (repoName && status !== 'building' && status !== 'buildFailed') {
+ config.workingRepoInstance = true;
+ } else if (!repoName) {
+ config.nonRepoInstance = true;
+ }
+ });
+ return config;
+ }
+
+ /** this only calls popovers for one specific group. they have built a repo and nonrepo instance only.
+ * @param {object} config an object with two boolean properties, nonRepoInstance and workingRepoInstance
+ * @param {object} instances an object containing a collection of instances
+ */
+ function callPopover(config, instances) {
+ if (config.workingRepoInstance && instances.models.length === 2) {
+ $rootScope.$broadcast('launchAhaNavPopover');
+ AGC.showAhaNavPopover = true;
+ } else if (config.workingRepoInstance && instances.models.length === 1) {
+ $rootScope.$broadcast('showAddServicesPopover', true);
+ }
+ }
+
+ $scope.$on('$destroy', function () {
+ animatedPanelListener();
+ if (AGC.subStepIndex === 7 && !AGC.isBuildSuccessful) {
+ $rootScope.$broadcast('ahaGuideEvent', {
+ error: 'exitedEarly'
+ });
+ } else if (ahaGuide.isAddingFirstRepo() && AGC.isBuildSuccessful && !AGC.showAhaNavPopover) {
+ $rootScope.$broadcast('showAddServicesPopover', true);
+ }
+ });
+
+ animatedPanelListener = $rootScope.$on('changed-animated-panel', function (e, panel) {
+ updateCaption(panel);
+ });
+
+ AGC.popoverActions = {
+ endGuide: ahaGuide.endGuide,
+ showSidebar: function () {
+ $rootScope.$broadcast('close-popovers');
+ $rootScope.$broadcast('showAhaSidebar');
+ }
+ };
+}
diff --git a/client/directives/components/ahaGuide/addBranchGuide/addBranchGuideDirective.js b/client/directives/components/ahaGuide/addBranchGuide/addBranchGuideDirective.js
new file mode 100644
index 000000000..51c54a9e0
--- /dev/null
+++ b/client/directives/components/ahaGuide/addBranchGuide/addBranchGuideDirective.js
@@ -0,0 +1,22 @@
+'use strict';
+
+require('app')
+ .directive('addBranchGuide', addBranchGuide);
+
+function addBranchGuide(
+ ahaGuide
+) {
+ return {
+ restrict: 'A',
+ templateUrl: 'addBranchGuideView',
+ scope: true,
+ link: function ($scope, elem, attrs) {
+ $scope.ahaGuide = {
+ steps: ahaGuide.steps,
+ getCurrentStep: ahaGuide.getCurrentStep
+ };
+ $scope.subStep = $scope.AGC.subStep;
+ ahaGuide.furthestSubstep(ahaGuide.steps.ADD_FIRST_BRANCH, $scope.subStep);
+ }
+ };
+}
diff --git a/client/directives/components/ahaGuide/addBranchGuide/addBranchGuideView.jade b/client/directives/components/ahaGuide/addBranchGuide/addBranchGuideView.jade
new file mode 100644
index 000000000..aaf5d102d
--- /dev/null
+++ b/client/directives/components/ahaGuide/addBranchGuide/addBranchGuideView.jade
@@ -0,0 +1,48 @@
+.grid-block.shrink.aha-meter(
+ ng-class = "{\
+ 'aha-error': AGC.errorState || AGC.showError,\
+ 'aha-meter-33': AGC.ahaGuide.isAddingFirstBranch(),\
+ 'aha-meter-66': AGC.ahaGuide.isAddingFirstBranch() && subStep === 'selectBranch',\
+ 'aha-meter-100': AGC.ahaGuide.getCurrentStep() > ahaGuide.steps.ADD_FIRST_BRANCH\
+ }"
+)
+ svg.iconnables(
+ ng-if = "!AGC.showError && !AGC.errorState"
+ )
+ use(
+ ng-if = "AGC.ahaGuide.isAddingFirstBranch()"
+ xlink:href = "#icons-octicons-branch"
+ )
+ use(
+ ng-if = "AGC.ahaGuide.getCurrentStep() > AGC.ahaGuide.steps.ADD_FIRST_BRANCH"
+ xlink:href = "#icons-check"
+ )
+
+ svg.iconnables.icons-alert(
+ ng-if = "AGC.errorState || AGC.showError"
+ )
+ use(
+ xlink:href = "#icons-alert-alt"
+ )
+
+.grid-block.vertical.aha-text
+ p.p.small.text-gray-light Step 3: Add a Branch
+ p.p(
+ ng-if = "subStep === 'addBranch'"
+ ) Click the ‘Add Branch’ button next to any repo name.
+ p.p(
+ ng-if = "subStep === 'selectBranch'"
+ ) Select a branch to add.
+ //- show in the branch menu if the repository has no branches.
+ p.p(
+ ng-if = "subStep === 'noBranches'"
+ ) Aw, no branches! Try another repository or
+ a.link(
+ ng-click = "AGC.skipBranchMilestone()"
+ target = "_blank"
+ ) skip this step
+ | .
+ //- show in the branch menu if the repository has no branches.
+ p.p(
+ ng-if = "subStep === 'deletedTemplate'"
+ ) You've deleted your repository template. Create another one to continue.
diff --git a/client/directives/components/ahaGuide/ahaGuideDirective.js b/client/directives/components/ahaGuide/ahaGuideDirective.js
new file mode 100644
index 000000000..86fd00e14
--- /dev/null
+++ b/client/directives/components/ahaGuide/ahaGuideDirective.js
@@ -0,0 +1,24 @@
+'use strict';
+
+require('app')
+ .directive('ahaGuide', ahaGuide);
+
+/**
+ * @ngInject
+ */
+function ahaGuide(
+
+) {
+ return {
+ restrict: 'A',
+ templateUrl: 'ahaGuideView',
+ controller: 'AhaGuideController',
+ controllerAs: 'AGC',
+ bindToController: true,
+ scope: {
+ subStep: '@?',
+ subStepIndex: '=?',
+ errorState: '@?'
+ }
+ };
+}
diff --git a/client/directives/components/ahaGuide/ahaGuideMenuPopoverView.jade b/client/directives/components/ahaGuide/ahaGuideMenuPopoverView.jade
index 324ed00b4..f4e910b38 100644
--- a/client/directives/components/ahaGuide/ahaGuideMenuPopoverView.jade
+++ b/client/directives/components/ahaGuide/ahaGuideMenuPopoverView.jade
@@ -6,6 +6,8 @@
.popover-content
ul.list.popover-list
li.list-item.popover-list-item(
- ng-click = "$root.featureFlags.ahaSidebar = true"
+ ng-click = "actions.showSidebar()"
) View All
- li.list-item.popover-list-item End Guide
+ li.list-item.popover-list-item(
+ ng-click = "actions.endGuide()"
+ ) End Guide
diff --git a/client/directives/components/ahaGuide/ahaGuideView.jade b/client/directives/components/ahaGuide/ahaGuideView.jade
index 55c86a34c..d5d27a181 100644
--- a/client/directives/components/ahaGuide/ahaGuideView.jade
+++ b/client/directives/components/ahaGuide/ahaGuideView.jade
@@ -1,30 +1,35 @@
.grid-block.align-center(
- ng-if = "state.showStep === 0"
+ ng-if = "AGC.ahaGuide.isChoosingOrg()"
ng-include = "'createSandboxGuideView'"
)
.grid-block.align-center(
- ng-if = "state.showStep === 1"
+ ng-if = "staticAddRepo || showAhaNavPopover"
+ ng-include = "'staticAhaGuideTemplates'"
+)
+
+.grid-block.align-center(
+ ng-if = "AGC.ahaGuide.isAddingFirstRepo()"
ng-include = "'setUpRepositoryGuideView'"
- ng-mouseenter = "state.showControls = true"
- ng-mouseleave = "state.showControls = false"
)
.grid-block.align-center(
- ng-if = "state.showStep === 2"
- ng-include = "'addBranchGuideView'"
+ ng-if = "AGC.ahaGuide.isAddingFirstBranch()"
+ add-branch-guide
)
.grid-block.align-center(
- ng-if = "state.showStep === 3"
+ ng-if = "showAutofork"
ng-include = "'setUpRunnabotGuideView'"
)
button.btn.btn-xs.white.btn-menu(
ng-class = "{'active': ahaMenuGuidePopover.data.show}"
- ng-if = "!state.hideMenu"
+ ng-if = "(AGC.isInGuide() && !AGC.ahaGuide.isChoosingOrg()) || staticAddRepo"
pop-over
+ pop-over-actions = "AGC ? AGC.popoverActions : EC.actions"
pop-over-active = "ahaMenuGuidePopover.data.show"
+ pop-over-no-broadcast = "true"
pop-over-options = "{\"centered\":true,\"top\":36}"
pop-over-template = "ahaGuideMenuPopoverView"
)
diff --git a/client/directives/components/ahaGuide/ahaPopoverView.jade b/client/directives/components/ahaGuide/ahaPopoverView.jade
index 13702aa13..a99f6da91 100644
--- a/client/directives/components/ahaGuide/ahaPopoverView.jade
+++ b/client/directives/components/ahaGuide/ahaPopoverView.jade
@@ -2,7 +2,9 @@
.popover-content
.grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
ng-include = "'ahaGuideView'"
- ng-init = "state.showStep = 1"
+ ng-init = "showAhaNavPopover = true"
)
.grid-block.justify-right.popover-footer
- button.grid-block.shrink.btn.btn-sm.green Got It
+ button.grid-block.shrink.btn.btn-sm.green(
+ ng-click = "CA.showAhaNavPopover = false"
+ ) Got It
diff --git a/client/directives/components/ahaGuide/ahaSidebar/ahaSidebarDirective.js b/client/directives/components/ahaGuide/ahaSidebar/ahaSidebarDirective.js
new file mode 100644
index 000000000..392e82798
--- /dev/null
+++ b/client/directives/components/ahaGuide/ahaSidebar/ahaSidebarDirective.js
@@ -0,0 +1,25 @@
+'use strict';
+
+require('app')
+ .directive('ahaSidebar', ahaSidebar);
+
+function ahaSidebar(
+ ahaGuide
+) {
+ return {
+ restrict: 'A',
+ templateUrl: 'ahaSidebarView',
+ scope: {
+ toggleSidebar: '=',
+ showOverview: '='
+ },
+ link: function ($scope) {
+ $scope.steps = ahaGuide.steps;
+ $scope.getCurrentStep = ahaGuide.getCurrentStep;
+ $scope.isSettingUpRunnabot = ahaGuide.isSettingUpRunnabot;
+ $scope.isAddingFirstRepo = ahaGuide.isAddingFirstRepo;
+ $scope.isAddingFirstBranch = ahaGuide.isAddingFirstBranch;
+ $scope.getFurthestSubstep = ahaGuide.furthestSubstep;
+ }
+ };
+}
diff --git a/client/directives/components/ahaGuide/ahaSidebar/ahaSidebarView.jade b/client/directives/components/ahaGuide/ahaSidebar/ahaSidebarView.jade
new file mode 100644
index 000000000..b59dc1d37
--- /dev/null
+++ b/client/directives/components/ahaGuide/ahaSidebar/ahaSidebarView.jade
@@ -0,0 +1,122 @@
+.grid-block.shrink(
+ ng-if = "!showOverview"
+)
+ header.grid-block.align-center.justify-center.aha-sidebar-header
+ h4.grid-content.strong.text-center.h4(
+ ng-if = "!isSettingUpRunnabot()"
+ )
+ //- During ahas 1-3:
+ | Setup Guide
+ h4.grid-content.strong.text-center.h4(
+ ng-if = "isSettingUpRunnabot() && !$root.featureFlags.ahaBranchUrlStep"
+ )
+ //- During aha 4:
+ | You did it! 👏
+ h4.grid-content.strong.text-center.h4(
+ ng-if = "isSettingUpRunnabot() && $root.featureFlags.ahaBranchUrlStep"
+ )
+ //- During aha 4:
+ | One more thing…
+ svg.grid-content.shrink.iconnables.icons-close(
+ ng-click = "toggleSidebar()"
+ ng-if = "!showOverview && !isSettingUpRunnabot()"
+ )
+ use(
+ xlink:href = "#icons-close"
+ )
+
+ svg.grid-content.shrink.iconnables.icons-close(
+ ng-click = "toggleSidebar('end')"
+ ng-if = "!showOverview && isSettingUpRunnabot()"
+ )
+ use(
+ xlink:href = "#icons-close"
+ )
+
+//- At the start of milestone 2:
+.grid-block.vertical.shrink.aha-overview(
+ ng-if = "showOverview"
+)
+ header.grid-block.vertical.shrink.align-center.justify-center.aha-sidebar-header
+ h4.grid-content.shrink.text-center.h4 Let‘s get running! 👋
+ .grid-block.shrink.vertical.padding-sm
+ p.grid-content.shrink.text-center.p It takes just 3 steps to get everything set up. But don’t worry — we’re here to help!
+ button.grid-content.shrink.btn.btn-md.green(
+ data-event-name = "Milestone 2: Started"
+ ng-click = "toggleSidebar()"
+ ) Get Started
+
+//- During ahas 1-3
+.grid-block.shrink.vertical.aha-guide-wrapper(
+ ng-if = "!isSettingUpRunnabot()"
+)
+ .grid-block.shrink.align-center.padding-sm.aha-guide.disabled
+ .grid-block.shrink.aha-meter.aha-meter-100
+ svg.iconnables
+ use(
+ xlink:href = "#icons-check"
+ )
+ .grid-block.vertical.aha-text
+ p.p.strong Step 1: Choose your Organization
+ p.small This is the first step to success.
+
+ .grid-block.shrink.align-center.padding-sm.aha-guide(
+ ng-class = "{\
+ disabled: !isAddingFirstRepo(),\
+ active: isAddingFirstRepo()\
+ }"
+ )
+ .grid-block.shrink.aha-meter(
+ ng-class = "{\
+ 'aha-meter-11': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'addRepository',\
+ 'aha-meter-22': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'containerSelection',\
+ 'aha-meter-33': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'dockerfileMirroring',\
+ 'aha-meter-44': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'nameContainer',\
+ 'aha-meter-55': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'repository',\
+ 'aha-meter-66': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'commands',\
+ 'aha-meter-77': isAddingFirstRepo() && (getFurthestSubstep(steps.ADD_FIRST_REPO) === 'buildfiles' || getFurthestSubstep(steps.ADD_FIRST_REPO) === 'default' || getFurthestSubstep(steps.ADD_FIRST_REPO) === 'env' || getFurthestSubstep(steps.ADD_FIRST_REPO) === 'files' || getFurthestSubstep(steps.ADD_FIRST_REPO) === 'filesMirror' || getFurthestSubstep(steps.ADD_FIRST_REPO) === 'ports' || getFurthestSubstep(steps.ADD_FIRST_REPO) === 'translation'),\
+ 'aha-meter-88': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'logs',\
+ 'aha-meter-88': isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'exitedEarly',\
+ 'aha-meter-100': (isAddingFirstRepo() && getFurthestSubstep(steps.ADD_FIRST_REPO) === 'success') || getCurrentStep() > steps.ADD_FIRST_REPO,\
+ }"
+ )
+ svg.iconnables
+ use(
+ ng-if = "getFurthestSubstep(steps.ADD_FIRST_REPO) !== 'success' && isAddingFirstRepo()"
+ xlink:href = "#icons-octicons-repo"
+ )
+ use(
+ ng-if = "getFurthestSubstep(steps.ADD_FIRST_REPO) === 'success' || getCurrentStep() > steps.ADD_FIRST_REPO"
+ xlink:href = "#icons-check"
+ )
+ .grid-block.vertical.aha-text
+ p.p.strong Step 2: Configure your Application
+ p.small Add your templates and get them running!
+
+ .grid-block.shrink.align-center.padding-sm.aha-guide(
+ ng-class = "{'disabled': getCurrentStep() !== steps.ADD_FIRST_BRANCH}"
+ )
+ .grid-block.shrink.aha-meter(
+ ng-class = "{\
+ 'aha-meter-33': isAddingFirstBranch() && getFurthestSubstep(steps.ADD_FIRST_BRANCH) === 'addBranch',\
+ 'aha-meter-66': isAddingFirstBranch() && getFurthestSubstep(steps.ADD_FIRST_BRANCH) === 'dockLoading',\
+ 'aha-meter-100': getCurrentStep() > steps.ADD_FIRST_BRANCH\
+ }"
+ )
+ svg.iconnables
+ use(
+ ng-if = "getCurrentStep() <= steps.ADD_FIRST_BRANCH"
+ xlink:href = "#icons-octicons-branch"
+ )
+ use(
+ ng-if = "getCurrentStep() > steps.ADD_FIRST_BRANCH"
+ xlink:href = "#icons-check"
+ )
+ .grid-block.vertical.aha-text
+ p.p.strong Step 3: Add a Branch
+ p.small Your branches will update on every commit you make.
+
+.grid-block.vertical.align-center.form-github(
+ ng-if = "isSettingUpRunnabot()"
+ github-integration
+)
diff --git a/client/directives/components/ahaGuide/ahaSidebarView.jade b/client/directives/components/ahaGuide/ahaSidebarView.jade
deleted file mode 100644
index 2123f5f67..000000000
--- a/client/directives/components/ahaGuide/ahaSidebarView.jade
+++ /dev/null
@@ -1,108 +0,0 @@
-.grid-block.shrink.align-center.justify-right
- svg.iconnables.icons-close(
- ng-click = "$root.featureFlags.ahaSidebar = false"
- ng-if = "!$root.featureFlags.ahaOverview"
- )
- use(
- xlink:href = "#icons-close"
- )
-.grid-block.vertical.shrink.justify-center.text-center.aha-overview(
- ng-if = "$root.featureFlags.ahaOverview"
-)
- .grid-content.strong Welcome to your Sandbox! 👋
- | It’ll take a few steps to get everything set up. But don’t worry — we’re here to help!
- button.grid-content.btn.btn-sm.green(
- ng-click = "\
- $root.featureFlags.ahaOverview = false;\
- $root.featureFlags.ahaSidebar = false;\
- "
- ) Get Started
-.grid-block.vertical
- .grid-block.shrink.align-center.padding-sm.aha-guide(
- ng-class = "{'disabled': $root.featureFlags.aha1 || $root.featureFlags.aha2 || $root.featureFlags.aha3}"
- )
- .grid-block.shrink.aha-meter(
- ng-class = "{\
- 'aha-meter-50': $root.featureFlags.aha0,\
- 'aha-meter-100': $root.featureFlags.aha1 || $root.featureFlags.aha2 || $root.featureFlags.aha3\
- }"
- )
- svg.iconnables
- use(
- ng-if = "$root.featureFlags.aha1 || $root.featureFlags.aha2 || $root.featureFlags.aha3"
- xlink:href = "#icons-check"
- )
- .grid-block.vertical.aha-text
- p.p.strong Create your Sandbox
- p.small This is the first step to success.
-
- .grid-block.shrink.align-center.padding-sm.aha-guide(
- ng-class = "{'disabled': $root.featureFlags.aha0 || $root.featureFlags.aha2 || $root.featureFlags.aha3}"
- )
- .grid-block.shrink.aha-meter(
- ng-class = "{\
- 'aha-error': state.showError,\
- 'aha-meter-10': state.showSubStep === 0,\
- 'aha-meter-20': state.showSubStep === 1,\
- 'aha-meter-30': state.showSubStep === 2,\
- 'aha-meter-40': state.showSubStep === 3,\
- 'aha-meter-50': state.showSubStep === 4,\
- 'aha-meter-60': state.showSubStep === 5,\
- 'aha-meter-70': state.showSubStep === 6,\
- 'aha-meter-80': state.showSubStep === 7,\
- 'aha-meter-90': state.showSubStep === 8,\
- 'aha-meter-100': $root.featureFlags.aha2 || $root.featureFlags.aha3\
- }"
- )
- svg.iconnables
- use(
- ng-if = "$root.featureFlags.aha1 && (!$root.featureFlags.aha2 || !$root.featureFlags.aha3)"
- xlink:href = "#icons-octicons-repo"
- )
- use(
- ng-if = "$root.featureFlags.aha2 || $root.featureFlags.aha3"
- xlink:href = "#icons-check"
- )
- .grid-block.vertical.aha-text
- p.p.strong Add your First Repository
- p.small Configure your project and get it running!
-
- .grid-block.shrink.align-center.padding-sm.aha-guide(
- ng-class = "{'disabled': $root.featureFlags.aha0 || $root.featureFlags.aha1 || $root.featureFlags.aha3}"
- )
- .grid-block.shrink.aha-meter(
- ng-class = "{\
- 'aha-meter-33': $root.featureFlags.aha2,\
- 'aha-meter-100': $root.featureFlags.aha3\
- }"
- )
- svg.iconnables
- use(
- ng-if = "!$root.featureFlags.aha3"
- xlink:href = "#icons-octicons-branch"
- )
- use(
- ng-if = "$root.featureFlags.aha3"
- xlink:href = "#icons-check"
- )
- .grid-block.vertical.aha-text
- p.p.strong Add your First Branch
- p.small Your branches will update on every commit you make.
-
- .grid-block.shrink.align-center.padding-sm.aha-guide(
- ng-class = "{'disabled': $root.featureFlags.aha0 || $root.featureFlags.aha1 || $root.featureFlags.aha2}"
- )
- .grid-block.shrink.aha-meter(
- ng-class = "{'aha-meter-50': $root.featureFlags.aha3}"
- )
- svg.iconnables
- use(
- xlink:href = "#icons-runnabot"
- )
- //- if complete
- //- use(
- //- xlink:href = "#icons-check"
- //- )
- .grid-block.vertical.aha-text
- p.p.strong Set Up Runnabot
- p.small Receive notifications on pull requests when your container is ready.
diff --git a/client/directives/components/ahaGuide/components/addBranchGuideView.jade b/client/directives/components/ahaGuide/components/addBranchGuideView.jade
deleted file mode 100644
index 6680148e8..000000000
--- a/client/directives/components/ahaGuide/components/addBranchGuideView.jade
+++ /dev/null
@@ -1,18 +0,0 @@
-.grid-block.shrink.aha-meter(
- ng-class = "{\
- 'aha-meter-33': $root.featureFlags.aha2,\
- 'aha-meter-100': $root.featureFlags.aha3\
- }"
-)
- svg.iconnables
- use(
- ng-if = "!$root.featureFlags.aha3"
- xlink:href = "#icons-octicons-branch"
- )
- use(
- ng-if = "$root.featureFlags.aha3"
- xlink:href = "#icons-check"
- )
-.grid-block.vertical.aha-text
- p.p.small.text-gray-light Add your First Branch
- p.p You can start adding branches by clicking the + button next to the name of the repository.
diff --git a/client/directives/components/ahaGuide/components/createSandboxGuideView.jade b/client/directives/components/ahaGuide/components/createSandboxGuideView.jade
index dac339141..5ee21981f 100644
--- a/client/directives/components/ahaGuide/components/createSandboxGuideView.jade
+++ b/client/directives/components/ahaGuide/components/createSandboxGuideView.jade
@@ -1,22 +1,25 @@
.grid-block.shrink.aha-meter(
- ng-class = "{\
- 'aha-meter-33': $root.featureFlags.aha0 && state.showSubStep === 0,\
- 'aha-meter-66': $root.featureFlags.aha0 && state.showSubStep === 1,\
- 'aha-meter-100': $root.featureFlags.aha1 || $root.featureFlags.aha2 || $root.featureFlags.aha3\
- }"
+ ng-class = "\
+ AGC.className\
+ "
)
svg.iconnables
use(
- ng-if = "$root.featureFlags.aha0"
+ ng-if = "AGC.subStep !== 'dockLoaded'"
xlink:href = "#icons-cog"
)
use(
- ng-if = "$root.featureFlags.aha1 || $root.featureFlags.aha2 || $root.featureFlags.aha3"
+ ng-if = "AGC.subStep === 'dockLoaded'"
xlink:href = "#icons-check"
)
.grid-block.vertical.aha-text
- p.p.small.text-gray-light Create your Sandbox
- p.p
- {{state.showSubStep === 0 ? 'Choose an organization to create your sandbox for.' : ''}}
- {{state.showSubStep === 1 ? 'Hang tight!' : ''}}
- {{state.showSubStep === 2 ? 'Continue to start configuring your project.' : ''}}
+ p.p.small.text-gray-light {{ AGC.title }}
+ p.p(
+ ng-if = "AGC.subStep === 'orgSelection'"
+ ) Select the organization you want to use with Runnable.
+ p.p(
+ ng-if = "AGC.subStep === 'dockLoading'"
+ ) Bear with us!
+ p.p(
+ ng-if = "AGC.subStep === 'dockLoaded'"
+ ) Continue to start configuring your project.
diff --git a/client/directives/components/ahaGuide/components/setUpRepositoryGuideView.jade b/client/directives/components/ahaGuide/components/setUpRepositoryGuideView.jade
deleted file mode 100644
index 270e4752d..000000000
--- a/client/directives/components/ahaGuide/components/setUpRepositoryGuideView.jade
+++ /dev/null
@@ -1,135 +0,0 @@
-.grid-block.align-center.shrink.spinner-wrapper.spinner-md.spinner-gray.in.js-animate(
- ng-if = "state.showVerification"
- ng-include = "'spinner'"
-)
-
-.grid-block.shrink.aha-meter.js-animate(
- ng-class = "{\
- 'aha-error': state.showError,\
- 'aha-meter-10': state.showSubStep === 0,\
- 'aha-meter-20': state.showSubStep === 1,\
- 'aha-meter-30': state.showSubStep === 2,\
- 'aha-meter-40': state.showSubStep === 3,\
- 'aha-meter-50': state.showSubStep === 4,\
- 'aha-meter-60': state.showSubStep === 5,\
- 'aha-meter-70': state.showSubStep === 6,\
- 'aha-meter-80': state.showSubStep === 7,\
- 'aha-meter-90': state.showSubStep === 8,\
- 'aha-meter-100': $root.featureFlags.aha2 || $root.featureFlags.aha3\
- }"
- ng-if = "!state.showVerification"
-)
- svg.iconnables(
- ng-if = "!state.showError"
- )
- use(
- ng-if = "$root.featureFlags.aha1 && !$root.featureFlags.aha2 && !$root.featureFlags.aha3 && state.showSubStep != 9"
- xlink:href = "#icons-octicons-repo"
- )
- use(
- ng-if = "$root.featureFlags.aha2 || $root.featureFlags.aha3"
- xlink:href = "#icons-check"
- )
- svg.iconnables.icons-alert(
- ng-if = "state.showError"
- )
- use(
- xlink:href = "#icons-alert-alt"
- )
-
-.grid-block.vertical.aha-text
- .grid-block(
- ng-if = "$root.canEditFeatureFlags() && state.showSubStep > 0"
- ng-show = "state.showControls"
- style = "position: absolute; right: 0; top: 0;"
- )
- a.grid-content.shrink.red.small.link(
- ng-click = "state.showVerification = !state.showVerification"
- ng-if = "state.showSubStep === 7"
- ) Verify
- a.grid-content.shrink.red.small.link(
- ng-click = "\
- state.showError = !state.showError;\
- state.showErrorType = 'CMD';\
- "
- ng-if = "state.showSubStep === 7"
- ) CMDErr
- a.grid-content.shrink.red.small.link(
- ng-click = "\
- state.showError = !state.showError;\
- state.showErrorType = 'build';\
- "
- ng-if = "state.showSubStep === 7"
- ) BuildErr
- a.grid-content.shrink.red.small.link(
- ng-click = "\
- $root.featureFlags.aha1 = false;\
- $root.featureFlags.aha2 = true;\
- "
- ng-if = "state.showSubStep === 8"
- ) NextMile
- a.grid-content.shrink.red.small.link(
- ng-click = "state.showSubStep = state.showSubStep - 1"
- ng-if = "state.showSubStep < 9 && state.showSubStep > 1"
- ) Prev
- a.grid-content.shrink.red.small.link(
- ng-click = "state.showSubStep = state.showSubStep + 1"
- ng-if = "state.showSubStep < 8"
- ) Next
- p.p.small.text-gray-light Add your First Repository
- p.p(
- ng-if = "state.showSubStep === 0 && !state.showError && !state.showVerification"
- ) Add your repository by clicking ‘Add Configuration’.
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 1 && !state.showError && !state.showVerification"
- ) Select a repository to configure.
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 2 && !state.showError && !state.showVerification"
- ) How would you like to configure your repo?
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 3 && !state.showError && !state.showVerification"
- ) Give your configuration a name.
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 4 && !state.showError && !state.showVerification"
- ) What does your repository run?
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 5 && !state.showError && !state.showVerification"
- ) Choose commands and packages.
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 6 && !state.showError && !state.showVerification"
- )
- | {{!state.fromMirroring ? 'If your app needs additional configuration…' : ''}}
- | {{state.fromMirroring ? 'We‘ve imported your dockerfile, click ‘Save & Build’ to build it!' : ''}}
- //- | FROM BLANK DOCKERFILE: When you‘re done editing your dockerfile, click ‘Save & Build’ to build it!
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 7"
- )
- | {{!state.showError && !state.showVerification ? 'Now building. Build time varies depending on your configuration.' : ''}}
- | {{state.showVerification ? 'Verifying Configuration…' : ''}}
- | {{state.showErrorType === 'build' && state.showError ? 'Your build failed. Inspect your build logs for more information.' : ''}}
- | {{state.showErrorType === 'CMD' && state.showError ? 'Your container failed to run. Inspect your CMD logs for more information.' : ''}}
- //- | IF DETENTION ERROR: Your container is running! But it looks like something is misconfigured.
- span.span(
- ng-if = "state.showErrorType === 'exitedEarly'"
- ) Your repository isn‘t running yet! Check the logs to debug any issues. If you‘re stumped,
- //- this link should open in intercom with the prefilled message:
- "I’m having trouble getting my first container up and running."
- a.link ask our engineers
- | !
-
- p.p(
- ng-class = "{'p-slide js-animate': state.showSubStep}"
- ng-if = "state.showSubStep === 8 && !state.showError && !state.showVerification"
- ) Your build is looking good! Check out its URL and click ‘Done’ if it looks good to you.
-
- //- in the popover
- p.p(
- ng-if = "$root.featureFlags.aha2"
- ) Add more containers if your project requires it. Once you’re done, head to your containers to start adding branches.
diff --git a/client/directives/components/ahaGuide/components/setUpRunnabotGuideView.jade b/client/directives/components/ahaGuide/components/setUpRunnabotGuideView.jade
index 6d7575e11..bc352c4a5 100644
--- a/client/directives/components/ahaGuide/components/setUpRunnabotGuideView.jade
+++ b/client/directives/components/ahaGuide/components/setUpRunnabotGuideView.jade
@@ -1,14 +1,2 @@
-.grid-block.shrink.aha-meter(
- ng-class = "{'aha-meter-50': $root.featureFlags.aha3}"
-)
- svg.iconnables
- use(
- xlink:href = "#icons-runnabot"
- )
- //- if complete
- //- use(
- //- xlink:href = "#icons-check"
- //- )
-.grid-block.vertical.aha-text
- p.p.small.text-gray-light Set Up Runnabot
- p.p Set up auto-branching before configuring Runnabot.
+.grid-block.vertical.runnabot-text
+ p.p Get the most out of Runnabot by adding branches automatically.
diff --git a/client/directives/components/ahaGuide/setupRepositoryGuide/setUpRepositoryGuideView.jade b/client/directives/components/ahaGuide/setupRepositoryGuide/setUpRepositoryGuideView.jade
new file mode 100644
index 000000000..31b31bb3f
--- /dev/null
+++ b/client/directives/components/ahaGuide/setupRepositoryGuide/setUpRepositoryGuideView.jade
@@ -0,0 +1,129 @@
+.grid-block.shrink.aha-meter.js-animate(
+ ng-class = "{\
+ 'aha-error': AGC.showError || AGC.errorState,\
+ 'aha-meter-11': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'addRepository',\
+ 'aha-meter-22': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'containerSelection',\
+ 'aha-meter-33': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'dockerfileMirroring',\
+ 'aha-meter-44': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'nameContainer',\
+ 'aha-meter-55': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'repository',\
+ 'aha-meter-66': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'commands',\
+ 'aha-meter-77': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'buildfiles' || AGC.ahaGuide.furthestStep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'default' || AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'env' || AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'files' || AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'filesMirror' || AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'ports' || AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'translation',\
+ 'aha-meter-88': AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'logs' || AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'exitedEarly',\
+ 'aha-meter-100': (AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'success') || getCurrentStep() > steps.ADD_FIRST_REPO,\
+ }"
+)
+ svg.iconnables(
+ ng-if = "!AGC.showError && !AGC.errorState"
+ )
+ use(
+ ng-if = "AGC.ahaGuide.isAddingFirstRepo() && AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) !== 'success'"
+ xlink:href = "#icons-octicons-repo"
+ )
+ use(
+ ng-if = "AGC.ahaGuide.furthestSubstep(AGC.ahaGuide.steps.ADD_FIRST_REPO) === 'success' || AGC.ahaGuide.getCurrentStep() > AGC.ahaGuide.steps.ADD_FIRST_REPO"
+ xlink:href = "#icons-check"
+ )
+ svg.iconnables.icons-alert(
+ ng-if = "AGC.showError || AGC.errorState"
+ )
+ use(
+ xlink:href = "#icons-alert-alt"
+ )
+
+.grid-block.shrink.aha-meter.js-animate(
+ class = "aha-meter-100"
+ ng-class = "{'aha-error': AGC.showError || AGC.errorState}"
+ ng-if = "!state.showVerification && AGC.ahaGuide.getCurrentStep() > AGC.ahaGuide.steps.ADD_FIRST_REPO"
+)
+ svg.iconnables(
+ ng-if = "!AGC.showError"
+ )
+ use(
+ ng-if = "AGC.subStep === 'success' || AGC.isBuildSuccessful"
+ xlink:href = "#icons-check"
+ )
+ svg.iconnables.icons-alert(
+ ng-if = "AGC.showError"
+ )
+ use(
+ xlink:href = "#icons-alert-alt"
+ )
+
+.grid-block.vertical.aha-text(
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.ahaGuide.isAddingFirstRepo()"
+)
+ p.p.small.text-gray-light {{ AGC.title }}
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'addRepository'"
+ ) First, add your repository by clicking ‘Create Template’.
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'containerSelection'"
+ ) Select a service to configure.
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'dockerfileMirroring'"
+ ) How would you like to configure your repository?
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'nameContainer'"
+ ) Give your template a name.
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'repository'"
+ ) What does your repository run?
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'commands'"
+ ) Configure commands and packages.
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.configSteps.includes(AGC.subStep)"
+ ) Configure additional settings (if necessary).
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'buildfiles'"
+ ) When you’re done editing your Dockerfile, click ‘Save and Build’.
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'filesMirror'"
+ ) We’ve imported your Dockerfile. Click ‘Save & Build’ to build it!
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'logs'"
+ ) We‘re building! Build time varies depending on your build commands.
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && AGC.subStep === 'success'"
+ ) Your build finished! Verify that it looks good, then click ‘Done’.
+
+
+.grid-block.vertical.aha-text(
+ ng-if = "AGC.isInGuide() && AGC.showError && AGC.subStepIndex > 5"
+)
+ p.p.small.text-gray-light {{ AGC.title }}
+ p.p(
+ ng-if = "AGC.isInGuide() && AGC.showError && AGC.errorState === 'buildFailed' && AGC.subStep === 'logs'"
+ ) Uh oh, there was an error! Inspect your logs for debug info.
+
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && (AGC.errorState === 'nonRunningContainer' || AGC.subStep === 'exitedEarly')"
+ ) Your template isn’t running yet! Check the logs to debug any issues. If you’re stumped,
+ a.link(
+ href = "https://support.runnable.com/hc/en-us/articles/212930166"
+ target = "_blank"
+ ) chat with our devs
+ | .
+
+
+.grid-block.vertical.aha-text(
+ class = "{{ AGC.className }}"
+ ng-if = "AGC.isInGuide() && !AGC.showError && !AGC.ahaGuide.isAddingFirstRepo()"
+)
+ p.p.small.text-gray-light {{ AGC.title }}
+ p.p(
+ ng-class = "{'p-slide js-animate': AGC.subStepIndex}"
+ ng-if = "AGC.isInGuide() && !AGC.showError"
+ ) Choose a template to configure.
diff --git a/client/directives/components/ahaGuide/setupRepositoryGuide/setupRepositoryGuideDirective.js b/client/directives/components/ahaGuide/setupRepositoryGuide/setupRepositoryGuideDirective.js
new file mode 100644
index 000000000..29a7fa48b
--- /dev/null
+++ b/client/directives/components/ahaGuide/setupRepositoryGuide/setupRepositoryGuideDirective.js
@@ -0,0 +1,26 @@
+'use strict';
+
+require('app')
+ .directive('setupRepositoryGuide', setupRepositoryGuide);
+
+function setupRepositoryGuide(
+ ahaGuide
+) {
+ return {
+ restrict: 'A',
+ templateUrl: 'setupRepositoryGuideView',
+ scope: true,
+ link: function ($scope, elem, attrs) {
+ $scope.ahaGuide = {
+ steps: ahaGuide.steps,
+ getCurrentStep: ahaGuide.getCurrentStep
+ };
+ $scope.askEngineers = function () {
+ window.Intercom(
+ 'showNewMessage',
+ 'I’m having trouble getting my first container up and running.'
+ );
+ };
+ }
+ };
+}
diff --git a/client/directives/components/ahaGuide/setupRepositoryGuide/staticAhaGuideTemplates.jade b/client/directives/components/ahaGuide/setupRepositoryGuide/staticAhaGuideTemplates.jade
new file mode 100644
index 000000000..53e06546a
--- /dev/null
+++ b/client/directives/components/ahaGuide/setupRepositoryGuide/staticAhaGuideTemplates.jade
@@ -0,0 +1,25 @@
+.grid-block.shrink.aha-meter.js-animate(
+ ng-class = "{\
+ 'aha-meter-10': staticAddRepo,\
+ 'aha-meter-100': showAhaNavPopover\
+ }"
+)
+ svg.iconnables(
+ )
+ use(
+ ng-if = "staticAddRepo"
+ xlink:href = "#icons-octicons-repo"
+ )
+ use(
+ ng-if = "showAhaNavPopover"
+ xlink:href = "#icons-check"
+ )
+
+.grid-block.vertical.aha-text
+ p.p.small.text-gray-light Step 2: Configure your Application
+ p.p(
+ ng-if = "staticAddRepo"
+ ) Add your repository by clicking ‘Create Template’.
+ p.p(
+ ng-if = "showAhaNavPopover"
+ ) Once you’re done configuring, head to your containers to start adding branches.
diff --git a/client/directives/components/buildLogs/buildLogsView.jade b/client/directives/components/buildLogs/buildLogsView.jade
index 89404ad7d..dbec4ecaa 100644
--- a/client/directives/components/buildLogs/buildLogsView.jade
+++ b/client/directives/components/buildLogs/buildLogsView.jade
@@ -11,11 +11,11 @@
)
p.p(
ng-if = "!BLC.showNoDockerfileError"
- ) Sorry, we ran into an issue trying to build your container.
+ ) Sorry, we ran into an issue while building.
p.p(
ng-if = "BLC.showNoDockerfileError"
)
- | We couldn't find a Dockerfile to build your container with.
+ | We couldn't find a Dockerfile to build.
| Does it exist in your repository?
button.btn.btn-sm.purple(
ng-click = "BLC.actions.rebuildWithoutCache()"
@@ -24,7 +24,7 @@
| or
a.link.icons-intercom(
ng-click = "BLC.actions.openIntercom()"
- ) chat with a dev
+ ) chat with our devs
.pre.build-log(
ng-if = "\
diff --git a/client/directives/components/buildLogs/viewPopoverDebug.jade b/client/directives/components/buildLogs/viewPopoverDebug.jade
index 4365d1a84..a5e954d4d 100644
--- a/client/directives/components/buildLogs/viewPopoverDebug.jade
+++ b/client/directives/components/buildLogs/viewPopoverDebug.jade
@@ -1,10 +1,10 @@
.popover.menu.bottom.popover-debug(
- ng-class = "{in: active}"
+ ng-class = "{'in': active}"
ng-style = "popoverStyle.getStyle()"
style = "transform-origin: 90% 0;"
)
.arrow.white(
- style = "left: auto; right: 1px;"
+ style = "left: auto; right: 3px;"
)
.popover-content
.list.popover-list
diff --git a/client/directives/components/containerStatusButton/containerStatusButtonView.jade b/client/directives/components/containerStatusButton/containerStatusButtonView.jade
index 888a345e2..d13e26da3 100644
--- a/client/directives/components/containerStatusButton/containerStatusButtonView.jade
+++ b/client/directives/components/containerStatusButton/containerStatusButtonView.jade
@@ -19,7 +19,7 @@ button.btn.btn-md.btn-status(
pop-over-actions = "CSBC.actions"
pop-over-active = "CSBC.popoverActive"
pop-over-controller = "CSBC"
- pop-over-options = "{\"centered\":true,\"top\":45}"
+ pop-over-options = "{\"centered\":true,\"top\":46}"
pop-over-template = "containerStatusOptionsPopoverView"
pop-over-trigger = "activeAttr"
)
diff --git a/client/directives/components/containerStatusButton/containerStatusOptionsPopoverView.jade b/client/directives/components/containerStatusButton/containerStatusOptionsPopoverView.jade
index 0891951c9..755511ba1 100644
--- a/client/directives/components/containerStatusButton/containerStatusOptionsPopoverView.jade
+++ b/client/directives/components/containerStatusButton/containerStatusOptionsPopoverView.jade
@@ -31,7 +31,7 @@
ng-if = "!CSBC.instance.isMigrating() && !CSBC.isTesting() && ['running', 'stopped', 'crashed'].includes(CSBC.instance.status())"
)
- //- rebuild without cache when no new config exists for this container
+ //- rebuild without cache when no new template exists for this container
li.popover-list-item.multi-line(
ng-click = "\
(!CSBC.instance.attrs.isolated && !CSBC.doesMatchMasterPod()) ? \
@@ -43,19 +43,19 @@
| {{CSBC.isTesting() ? 'Rerun Test' : 'Rebuild'}}
.small {{CSBC.isTesting() ? 'Will rerun tests without cache.' : 'Will rebuild without cache.'}}
- //- rebuild without cache when no new config exists for this container
+ //- rebuild without cache when no new template exists for this container
li.popover-list-item.multi-line(
ng-if = "$root.featureFlags.allowIsolatedUpdate && CSBC.instance.attrs.isolated && !CSBC.doesMatchMasterPod()"
ng-click = "actions.updateConfigToMatchMaster()"
)
.icons-status.orange
- | Update Config and Rebuild
- .small Will rebuild and update the configuration.
+ | Update Template and Rebuild
+ .small Will rebuild and update the template.
.well.well-popover.orange.text-center.padding-xxs.small(
ng-if = "(!CSBC.instance.attrs.isolated || $root.featureFlags.allowIsolatedUpdate) && !CSBC.doesMatchMasterPod()"
- ) This container’s configuration has been changed. Rebuild to update.
+ ) This container’s template has been changed. Rebuild to update.
- //- only show if the configuration has not been changed
+ //- only show if the template has not been changed
.well.well-popover.orange.text-center.padding-xxs.small(
ng-if = "['buildFailed', 'neverStarted'].includes(CSBC.instance.status()) && CSBC.doesMatchMasterPod()"
) Having build problems? Some errors can be resolved by rebuilding.
diff --git a/client/directives/components/dnsConfiguration/dnsConfigurationPopoverView.jade b/client/directives/components/dnsConfiguration/dnsConfigurationPopoverView.jade
index d4c0cce5b..316affea6 100644
--- a/client/directives/components/dnsConfiguration/dnsConfigurationPopoverView.jade
+++ b/client/directives/components/dnsConfiguration/dnsConfigurationPopoverView.jade
@@ -99,7 +99,7 @@
ul.list.popover-list(
ng-if = "isActivePanel() && DCC.nonRepoDependencies.length !== 0"
)
- li.list-item.small Service Containers
+ li.list-item.small Non-repository Containers
li.list-item.popover-list-item.multi-line.disabled.grid-block.vertical.align-start(
ng-repeat = "dependency in DCC.nonRepoDependencies"
)
diff --git a/client/directives/components/editRepoCommit/autoDeployTooltip.jade b/client/directives/components/editRepoCommit/autoDeployTooltip.jade
index 9f0f4e580..c928f143a 100644
--- a/client/directives/components/editRepoCommit/autoDeployTooltip.jade
+++ b/client/directives/components/editRepoCommit/autoDeployTooltip.jade
@@ -4,4 +4,4 @@
)
.arrow
//- if disabled: Enable auto-deploy to automatically rebuild your container when new commits are pushed to GitHub.
- .small.text-center Your container will rebuild when new commits are pushed to GitHub.
+ .small.text-center Will rebuild when new commits are pushed to GitHub.
diff --git a/client/directives/components/editRepoCommit/editRepoCommitView.jade b/client/directives/components/editRepoCommit/editRepoCommitView.jade
index d4d8e1055..a23d7e43a 100644
--- a/client/directives/components/editRepoCommit/editRepoCommitView.jade
+++ b/client/directives/components/editRepoCommit/editRepoCommitView.jade
@@ -3,7 +3,6 @@
ng-class = "{\
'grid-block align-center justify-center': !activeCommit.attrs.commit.message,\
'main-btn': !acv.attrs.additionalRepo,\
- 'deprecated': !acv.attrs.additionalRepo && !$root.featureFlags.testingFeature\
}"
ng-click = "actions.openRepoDetailsModal()"
)
@@ -47,7 +46,7 @@
ng-include = "'userButtonView'"
pop-over
pop-over-active = "state.active"
- pop-over-options = "{\"left\":-24,\"top\":26}"
+ pop-over-options = "{\"left\":-23,\"top\":26}"
pop-over-template = "userPopoverView"
)
span.small(
@@ -57,16 +56,12 @@
span.small(
ng-if = "!$root.featureFlags.inviteFlows"
) {{activeCommit.attrs.commit.author.date | timeFrom}}
- svg.iconnables.icons-arrow-forward
- use(
- xlink:href = "#icons-arrow-down"
- )
//- auto-deploy w/ commit syncing
//- show alternate text in autoDeployTooltip.jade if disabled
.btn.btn-xs.btn-auto-deploy(
ng-class = "{'btn-permissions': autoDeploy()}"
- ng-if = "!acv.attrs.additionalRepo && $root.featureFlags.testingFeature"
+ ng-if = "!acv.attrs.additionalRepo"
pop-over
pop-over-hover-trigger
pop-over-options = "{\"top\":30,\"centered\":true}"
@@ -82,36 +77,4 @@
ng-if = "autoDeploy()"
xlink:href = "#icons-alert-alt"
)
- | {{autoDeploy() ? 'Auto-Deploy Disabled' : 'Auto-Deploying'}}
-
-//- auto-deploy w/o commit syncing
-.btn.btn-sm.btn-auto-deploy-deprecated(
- ng-if = "!acv.attrs.additionalRepo && !$root.featureFlags.testingFeature"
-)
- .iconnables.icons-launch.float-left 🚀
- span.underline.float-left(
- tooltip = "Automatically rebuild your container when new commits are made."
- tooltip-options = "{\"class\":\"bottom center text-center tooltip-definition\",\"left\":-85,\"top\":18}"
- ) Auto-Deploy
- button.btn.btn-xs.btn-permissions.float-right(
- internal-modal-helper = "inviteAdminModalView"
- ng-if = "$root.featureFlags.webhooks"
- )
- svg.iconnables.icons-alert.float-left
- use(
- xlink:href = "#icons-alert-alt"
- )
- | Permissions
- label.toggle-wrapper.float-right
- //- this would not be enabled when an webhooks admin is not present
- input.toggle-input(
- ng-disabled = "$root.isLoading.autoDeploy || $root.featureFlags.webhooks"
- ng-false-value = "true"
- ng-model = "autoDeploy"
- ng-model-options = "{getterSetter: true}"
- ng-true-value = "false"
- type = "checkbox"
- )
- .toggle-group.toggle-xs(
- ng-if = "!$root.featureFlags.webhooks || $root.featureFlags.webhooksAdminPresent"
- )
+ | {{autoDeploy() ? 'Auto-Deploy Disabled' : 'Auto-Deploy Enabled'}}
diff --git a/client/directives/components/explorer/explorerSectionHeading.jade b/client/directives/components/explorer/explorerSectionHeading.jade
index a58fa70da..8c061f0b9 100644
--- a/client/directives/components/explorer/explorerSectionHeading.jade
+++ b/client/directives/components/explorer/explorerSectionHeading.jade
@@ -5,7 +5,7 @@ button.btn.gray.btn-xs.btn-icon(
pop-over-actions = "FPC.actions"
pop-over-active = "filePopover.data.show"
pop-over-data = "filePopover.data"
- pop-over-options = "{\"top\":36,\"centered\":true}"
+ pop-over-options = "{\"top\":35,\"centered\":true}"
pop-over-template = "viewFileTreePopoverFileExplorerMenu"
)
svg.iconnables.icons-add
diff --git a/client/directives/components/explorer/explorerView.jade b/client/directives/components/explorer/explorerView.jade
index ebccd4302..f2fac6139 100644
--- a/client/directives/components/explorer/explorerView.jade
+++ b/client/directives/components/explorer/explorerView.jade
@@ -15,7 +15,7 @@
pop-over
pop-over-actions = "FPC.actions"
pop-over-data = "filePopover.data"
- pop-over-options = "{\"left\":-84,\"top\":35}"
+ pop-over-options = "{\"top\":35,\"centered\":true}"
pop-over-template = "viewFileTreePopoverFileExplorerMenu"
pop-over-active = "filePopover.data.show"
)
diff --git a/client/directives/components/explorer/fileTreeDirDirective.js b/client/directives/components/explorer/fileTreeDirDirective.js
index e7794e600..d810c696c 100755
--- a/client/directives/components/explorer/fileTreeDirDirective.js
+++ b/client/directives/components/explorer/fileTreeDirDirective.js
@@ -37,7 +37,6 @@ function fileTreeDir(
link: function ($scope, element) {
var actions = $scope.actions = {};
- $scope.data = {};
var inputElement = element[0].querySelector('input.tree-input');
$scope.editFolderName = false;
diff --git a/client/directives/components/explorer/fileTreeDirItemView.jade b/client/directives/components/explorer/fileTreeDirItemView.jade
index fda349ca7..bc2e5ce92 100644
--- a/client/directives/components/explorer/fileTreeDirItemView.jade
+++ b/client/directives/components/explorer/fileTreeDirItemView.jade
@@ -84,7 +84,7 @@ li.file(
ng-readonly = "!fs.state.renaming"
select-on = "fs.state.renaming"
value = "{{fs.attrs.name}}"
- ) {{fs.attrs.name}}
+ )
span.item-name {{fs.attrs.name}}
li.folder.in(
diff --git a/client/directives/components/explorer/fileTreeDirView.jade b/client/directives/components/explorer/fileTreeDirView.jade
index c8490b331..f96ec2c34 100755
--- a/client/directives/components/explorer/fileTreeDirView.jade
+++ b/client/directives/components/explorer/fileTreeDirView.jade
@@ -45,7 +45,7 @@ li.folder(
pop-over-actions = "popoverFilesRepositoryCommitToggle.actions"
pop-over-active = "state.showAddRepo"
pop-over-data = "popoverFilesRepositoryCommitToggle.data"
- pop-over-options = "{\"left\":207,\"top\":-222}"
+ pop-over-options = "{\"left\":203,\"top\":-220}"
pop-over-template = "viewPopoverFilesRepositoryCommitToggle"
pop-over-trigger = "activeAttr"
)
@@ -79,7 +79,7 @@ li.folder(
pop-over-actions = "popoverFilesRepositoryCommitToggle.actions"
pop-over-active = "acv.editing"
pop-over-data = "popoverEditRepoCommit.data"
- pop-over-options = "{\"left\":207,\"top\":-222}"
+ pop-over-options = "{\"left\":203,\"top\":-220}"
pop-over-template = "viewPopoverFilesRepositoryCommitToggle"
pop-over-trigger = "activeAttr"
)
diff --git a/client/directives/components/gitHubIntegration/githubIntegrationController.js b/client/directives/components/gitHubIntegration/githubIntegrationController.js
new file mode 100644
index 000000000..fc8114367
--- /dev/null
+++ b/client/directives/components/gitHubIntegration/githubIntegrationController.js
@@ -0,0 +1,60 @@
+'use strict';
+
+require('app')
+ .controller('GithubIntegrationController', GithubIntegrationController);
+/**
+ * @ngInject
+ */
+function GithubIntegrationController(
+ $interval,
+ $q,
+ $scope,
+ ahaGuide,
+ currentOrg,
+ errs,
+ fetchGithubUserIsAdminOfOrg,
+ isRunnabotPartOfOrg,
+ keypather,
+ loading
+) {
+ var GIC = this;
+ var org = keypather.get(currentOrg, 'github.attrs.login');
+ GIC.organizationName = org;
+
+ function checkRunnabot() {
+ return isRunnabotPartOfOrg(org)
+ .then(function (hasRunnabot) {
+ GIC.hasRunnabot = hasRunnabot;
+ if (hasRunnabot) {
+ if (GIC.pollingInterval) {
+ $interval.cancel(GIC.pollingInterval);
+ }
+ return ahaGuide.hasRunnabot();
+ }
+ })
+ .catch(errs.handler);
+ }
+
+ loading.reset('checkRunnabot');
+ loading('checkRunnabot', true);
+ $q.all({
+ isAdmin: fetchGithubUserIsAdminOfOrg(org),
+ hasRunnabot: checkRunnabot()
+ })
+ .then(function (results) {
+ GIC.isAdmin = results.isAdmin;
+ })
+ .catch(errs.handler)
+ .finally(function () {
+ loading('checkRunnabot', false);
+ });
+
+ GIC.pollCheckRunnabot = function () {
+ GIC.pollingInterval = $interval(checkRunnabot, 2000);
+ };
+
+ $scope.$on('$destroy', function () {
+ $interval.cancel(GIC.pollingInterval);
+ });
+}
+
diff --git a/client/directives/components/gitHubIntegration/githubIntegrationDirective.js b/client/directives/components/gitHubIntegration/githubIntegrationDirective.js
new file mode 100644
index 000000000..0e9610c0f
--- /dev/null
+++ b/client/directives/components/gitHubIntegration/githubIntegrationDirective.js
@@ -0,0 +1,20 @@
+'use strict';
+
+require('app')
+ .directive('githubIntegration', githubIntegration);
+/**
+ * @ngInject
+ */
+function githubIntegration(
+) {
+ return {
+ restrict: 'A',
+ templateUrl: 'githubIntegrationView',
+ controller: 'GithubIntegrationController',
+ controllerAs: 'GIC',
+ bindToController: true,
+ scope: {
+ state: '='
+ }
+ };
+}
diff --git a/client/directives/components/gitHubIntegration/githubIntegrationView.jade b/client/directives/components/gitHubIntegration/githubIntegrationView.jade
new file mode 100644
index 000000000..1519f6365
--- /dev/null
+++ b/client/directives/components/gitHubIntegration/githubIntegrationView.jade
@@ -0,0 +1,73 @@
+p.grid-content.shrink.p.text-center(
+ ng-if = "!$root.featureFlags.ahaBranchUrlStep"
+) Now you can invite our bot to your GitHub org to get notifications on your pull requests:
+
+p.grid-content.shrink.p.text-center(
+ ng-if = "$root.featureFlags.ahaBranchUrlStep"
+) Invite our bot to your GitHub org to get notifications on your pull requests:
+
+img.grid-content.shrink.img.img-comment(
+ alt = "Runnabot sample comment on a GitHub pull request."
+ height = "206"
+ src = "/build/images/runnabot-comment.png"
+ width = "358"
+)
+
+//- if checking whether the user is an admin, or checking whether runnabot has been enabled
+.grid-content.spinner-wrapper.spinner-md.spinner-gray(
+ ng-if = "$root.isLoading.checkRunnabot"
+ ng-include = "'spinner'"
+)
+
+//- add 'disabled' attr if inviting runnabot, or if user isn't an admin
+ hide after successfully inviting runnabot
+a.grid-content.shrink.btn.btn-md.green(
+ ng-disabled = "!GIC.isAdmin"
+ ng-click = "GIC.pollCheckRunnabot()"
+ ng-hide = "$root.isLoading.checkRunnabot || GIC.hasRunnabot"
+ ng-href = "https://github.com/orgs/{{GIC.organizationName}}/invitations/runnabot/edit"
+ target = "_blank"
+)
+ svg.iconnables.icons-octicons-github
+ use(
+ xlink:href = "#icons-octicons-github"
+ )
+ | Invite Runnabot
+ svg.iconnables.icons-link-external
+ use(
+ xlink:href = "#icons-link-external"
+ )
+
+//- show after successfully inviting runnabot
+.grid-block.align-center.shrink.runnabot-success(
+ ng-show = "GIC.hasRunnabot && !$root.isLoading.checkRunnabot"
+)
+ img.grid-content.shrink.img(
+ height = "36"
+ src = "/build/images/runnabot-head.png"
+ width = "36"
+ )
+ .grid-content.well.padding-xs.ignore-margin
+ .arrow
+ p.small.text-gray.text-left Thanks! See you soon on your pull requests.
+
+.grid-content.shrink.small.text-center(
+ ng-hide = "$root.isLoading.checkRunnabot"
+ ng-class = "{\
+ 'text-gray': GIC.isAdmin,\
+ 'text-red': !GIC.isAdmin\
+ }"
+)
+ span(
+ ng-if = "GIC.isAdmin"
+ ) This may affect your GitHub bill.
+ span(
+ ng-if = "!GIC.isAdmin"
+ ) Sorry, you’ll need help from an admin
+ br
+ | of your org to invite Runnabot.
+
+ //- hiding until praful writes his doc
+ //- span
+ br
+ a.small.link More about Runnabot
diff --git a/client/directives/components/instanceNavigtion/confirmBranchRemoveView.jade b/client/directives/components/instanceNavigtion/confirmBranchRemoveView.jade
index 36f0a51bb..4a952bb19 100644
--- a/client/directives/components/instanceNavigtion/confirmBranchRemoveView.jade
+++ b/client/directives/components/instanceNavigtion/confirmBranchRemoveView.jade
@@ -1,8 +1,12 @@
.modal-backdrop.in
.modal-dialog.modal-sm.modal-alert
header.modal-body
- p.p.strong Are you sure you want to remove this branch from your sandbox?
- p.p You can add this branch again later, but any configuration changes will not be saved.
+ p.p.strong Are you sure you want to remove this branch from Runnable?
+ p.p You can add this branch again later, but any changes you’ve made will not be saved.
footer.modal-footer.clearfix
- button.btn.btn-sm.gray.float-left Cancel
- button.btn.btn-sm.red.float-right Delete Branch
\ No newline at end of file
+ button.btn.btn-sm.gray.float-left(
+ ng-click = "CMC.actions.cancel()"
+ ) Cancel
+ button.btn.btn-sm.red.float-right(
+ ng-click = "CMC.actions.confirm()"
+ ) Remove Branch
diff --git a/client/directives/components/instanceNavigtion/confirmConfigDiscardView.jade b/client/directives/components/instanceNavigtion/confirmConfigDiscardView.jade
index f68f8b8b9..88e95b41c 100644
--- a/client/directives/components/instanceNavigtion/confirmConfigDiscardView.jade
+++ b/client/directives/components/instanceNavigtion/confirmConfigDiscardView.jade
@@ -1,8 +1,8 @@
.modal-backdrop.in
.modal-dialog.modal-sm.modal-alert
header.modal-body
- p.p.strong Are you sure you want to discard this configuration?
- p.p You will lose any changes you have made, and this container will rebuild using the master configuration.
+ p.p.strong Are you sure you want to discard your changes?
+ p.p You will lose any changes you‘ve made, and this container will rebuild with the template configuration.
footer.modal-footer.clearfix
button.btn.btn-sm.gray.float-left Cancel
- button.btn.btn-sm.red.float-right Discard Configuration
\ No newline at end of file
+ button.btn.btn-sm.red.float-right Discard Changes
diff --git a/client/directives/components/instanceNavigtion/instanceNavigationController.js b/client/directives/components/instanceNavigtion/instanceNavigationController.js
index a9e4fb9c7..30d69d25b 100644
--- a/client/directives/components/instanceNavigtion/instanceNavigationController.js
+++ b/client/directives/components/instanceNavigtion/instanceNavigationController.js
@@ -127,6 +127,23 @@ function InstanceNavigationController(
.catch(errs.handler);
};
+ INC.removeBranch = function () {
+ $rootScope.$broadcast('close-popovers');
+ ModalService.showModal({
+ controller: 'ConfirmationModalController',
+ controllerAs: 'CMC',
+ templateUrl: 'confirmBranchRemoveView'
+ })
+ .then(function (modal) {
+ modal.close.then(function (confirmed) {
+ if (confirmed) {
+ promisify(INC.instance, 'destroy')();
+ }
+ });
+ })
+ .catch(errs.handler);
+ };
+
this.editInstance = function (event) {
$rootScope.$broadcast('close-popovers');
event.stopPropagation();
diff --git a/client/directives/components/instanceNavigtion/instanceNavigationInternalsView.jade b/client/directives/components/instanceNavigtion/instanceNavigationInternalsView.jade
index 87608f684..5997439a0 100644
--- a/client/directives/components/instanceNavigtion/instanceNavigationInternalsView.jade
+++ b/client/directives/components/instanceNavigtion/instanceNavigationInternalsView.jade
@@ -13,18 +13,18 @@ a.grid-block.align-center.a-sref(
)
//- show repo names for repo containers in the master cluster
span(
- ng-if = "INC.instance.attrs.masterPod && INC.instance.getBranchName() && $root.featureFlags.autoIsolation"
+ ng-if = "INC.instance.attrs.masterPod && INC.instance.getBranchName() && $root.featureFlags.addBranches"
) {{INC.instance.getName()}}/
//- branch name or service name
| {{getNavigationName()}}
.grid-block.shrink.btn.btn-xxs.btn-badge(
- ng-if = "INC.instance.attrs.isIsolationGroupMaster && !$root.featureFlags.autoIsolation"
+ ng-if = "INC.instance.attrs.isIsolationGroupMaster && !$root.featureFlags.addBranches"
) Isolated
svg.grid-block.shrink.iconnables.icons-overflow(
ng-class = "{'active': INC.popoverShown}"
- ng-if = "!$root.featureFlags.autoIsolation && ((INC.masterInstance !== INC.instance && INC.instance.getBranchName()) || (!INC.instance.attrs.isIsolationGroupMaster && INC.instance.attrs.isolated))"
+ ng-if = "!$root.featureFlags.addBranches && ((INC.masterInstance !== INC.instance && INC.instance.getBranchName()) || (!INC.instance.attrs.isIsolationGroupMaster && INC.instance.attrs.isolated))"
pop-over
pop-over-active = "INC.popoverShown"
pop-over-controller = "INC"
@@ -42,23 +42,23 @@ a.grid-block.align-center.a-sref(
pop-over-controller = "INC"
pop-over-options = "{\"verticallyCentered\":true,\"left\":28}"
pop-over-template = "instanceNavigationPopoverView"
- ng-if = "$root.featureFlags.autoIsolation"
+ ng-if = "$root.featureFlags.addBranches"
)
svg.iconnables
- //- if this container's configuration is *not* modified
use(
+ ng-if = "$root.featureFlags.addBranches && !INC.instance.attrs.isIsolationGroupMaster"
xlink:href = "#icons-gear"
)
- //- if this container's configuration *is* modified
- //- use(
- //- xlink:href = "#icons-gear-modified"
- //- )
+ use(
+ ng-if = "$root.featureFlags.addBranches && INC.instance.attrs.isIsolationGroupMaster || INC.instance.attrs.isolated"
+ xlink:href = "#icons-gear-modified"
+ )
//- config button for non-repo containers (pre auto-isolation)
svg.grid-block.shrink.iconnables.icons-gear(
ng-click="INC.editInstance($event)"
- ng-if = "$root.featureFlags.editAnyInstance || INC.instance.attrs.masterPod && !INC.instance.getBranchName() && !INC.instance.attrs.isolated && !$root.featureFlags.autoIsolation"
- title = "Configure"
+ ng-if = "$root.featureFlags.editAnyInstance || INC.instance.attrs.masterPod && !INC.instance.getBranchName() && !INC.instance.attrs.isolated && !$root.featureFlags.addBranches"
+ title = "Configure Template"
)
use(
xlink:href = "#icons-gear"
diff --git a/client/directives/components/instanceNavigtion/instanceNavigationPopoverView.jade b/client/directives/components/instanceNavigtion/instanceNavigationPopoverView.jade
index 390700048..94709d496 100644
--- a/client/directives/components/instanceNavigtion/instanceNavigationPopoverView.jade
+++ b/client/directives/components/instanceNavigtion/instanceNavigationPopoverView.jade
@@ -6,19 +6,37 @@
.popover-content(
ng-if = "$root.featureFlags.autoIsolation"
)
- ul.list.popover-list
-
- //- if this is a container in the master cluster
- //- li.list-item.popover-list-item.multi-line
+ ul.list.popover-list(
+ ng-if = "INC.instance.attrs.masterPod"
+ )
+ li.list-item.popover-list-item.multi-line(
+ ng-click = "INC.editInstance($event)"
+ )
svg.iconnables.icons-gear
use(
xlink:href = "#icons-gear"
)
- | Configure
- .small Affects all [config-name] containers.
+ | Configure Template
+ .small Affects all non-isolated [config-name] containers.
+ li.divider(
+ ng-if = "$root.featureFlags.containersViewTemplateControls"
+ )
+ li.list-item.popover-list-item(
+ internal-modal-helper = "confirmDeleteServerView"
+ ng-if = "$root.featureFlags.containersViewTemplateControls"
+ )
+ svg.iconnables.icons-delete
+ use(
+ xlink:href = "#icons-delete"
+ )
+ | Delete Template
- //- if this is a container that is not part of the master cluster
- li.list-item.popover-list-item.multi-line
+ ul.list.popover-list(
+ ng-if = "!INC.instance.attrs.masterPod"
+ )
+ li.list-item.popover-list-item.multi-line(
+ ng-click = "INC.editInstance($event)"
+ )
svg.iconnables.icons-gear
use(
xlink:href = "#icons-gear-modified"
@@ -26,7 +44,7 @@
| Configure
.small Affects only this container.
- //- if this container has a modified configuration
+ //- if this container has a modified template
//- li.list-item.popover-list-item.multi-line(
//- internal-modal-helper = "confirmConfigDiscardView"
//- )
@@ -34,14 +52,16 @@
use(
xlink:href = "#icons-gear-delete"
)
- | Discard Configuration
- .small Restores master configuration.
+ | Discard Changes
+ .small To restore template configuration
- //- if this is the primary container of an isolated cluster
- //- li.list-item.popover-list-item.divider
- //- li.list-item.popover-list-item(
- //- internal-modal-helper = "confirmBranchRemoveView"
- //- )
+ li.list-item.popover-list-item.divider(
+ ng-if = "INC.instance.attrs.isIsolationGroupMaster"
+ )
+ li.list-item.popover-list-item(
+ ng-click = "INC.removeBranch()"
+ ng-if = "INC.instance.attrs.isIsolationGroupMaster"
+ )
svg.iconnables
use(
xlink:href = "#icons-delete"
@@ -49,27 +69,117 @@
| Remove Branch
.popover-content(
- ng-if = "!$root.featureFlags.autoIsolation"
+ ng-if = "$root.featureFlags.addBranches && !$root.featureFlags.autoIsolation"
+ )
+ ul.list.popover-list(
+ ng-if = "INC.instance.attrs.masterPod"
+ )
+ li.list-item.popover-list-item.multi-line(
+ ng-click = "INC.editInstance($event)"
+ )
+ svg.iconnables.icons-gear
+ use(
+ xlink:href = "#icons-gear"
+ )
+ | Configure Template
+ .small Affects all non-isolated {{ INC.instance.attrs.name }} containers.
+ li.divider(
+ ng-if = "$root.featureFlags.containersViewTemplateControls"
+ )
+ li.list-item.popover-list-item(
+ internal-modal-helper = "confirmDeleteServerView"
+ ng-if = "$root.featureFlags.containersViewTemplateControls"
+ )
+ svg.iconnables.icons-delete
+ use(
+ xlink:href = "#icons-delete"
+ )
+ | Delete Template
+
+ ul.list.popover-list(
+ ng-if = "!INC.instance.attrs.masterPod"
+ )
+ .well.gray.padding-xs(
+ ng-if = "!INC.instance.attrs.isolated"
+ ) Isolating a branch allows you to…
+ ul.list.list-bulleted
+ li.list-item Create a separate environment to use with this branch.
+ li.list-item Configure this branch independently from your template.
+ li.list-item.popover-list-item(
+ ng-click = "INC.setupIsolation()"
+ ng-if = "!INC.instance.attrs.isolated"
+ )
+ svg.iconnables.icons-gear
+ use(
+ xlink:href = "#icons-gear-modified"
+ )
+ | Isolate Branch
+ span(
+ ng-if = "INC.shouldShowSetupModal"
+ ) …
+
+ li.list-item.popover-list-item.multi-line(
+ ng-click = "INC.editInstance($event)"
+ ng-if = "INC.instance.attrs.isolated"
+ )
+ svg.iconnables.icons-gear
+ use(
+ xlink:href = "#icons-gear-modified"
+ )
+ | Configure
+ .small Affects only this container.
+
+ li.divider
+ li.list-item.popover-list-item(
+ ng-click = "INC.disableIsolation()"
+ ng-if = "INC.instance.attrs.isIsolationGroupMaster"
+ )
+ svg.iconnables
+ use(
+ xlink:href = "#icons-delete"
+ )
+ | Disable Isolation
+ li.list-item.popover-list-item(
+ ng-click = "INC.deleteContainer()"
+ ng-if = "INC.instance.attrs.isolated && !INC.instance.attrs.isIsolationGroupMaster"
+ )
+ svg.iconnables
+ use(
+ xlink:href = "#icons-isolation-disable"
+ )
+ | Delete from Isolation
+ li.list-item.popover-list-item(
+ ng-click = "INC.removeBranch()"
+ ng-if = "!INC.instance.attrs.isolated"
+ )
+ svg.iconnables
+ use(
+ xlink:href = "#icons-delete"
+ )
+ | Remove Branch
+
+ .popover-content(
+ ng-if = "!$root.featureFlags.addBranches && !$root.featureFlags.autoIsolation"
)
//- menu items:
- for an isolated branch:
- - Configure Container
+ - Configure Template
- (divider)
- Add Container to Isolation
- (divider)
- Hide
- for an isolated branch's containers:
- - Configure Container
+ - Configure Template
ul.list.popover-list
li.list-item.popover-list-item(
- ng-if = "INC.instance.attrs.isolated"
ng-click = "INC.editInstance($event)"
+ ng-if = "INC.instance.attrs.isolated"
)
svg.iconnables
use(
xlink:href = "#icons-gear"
)
- | Configure Container
+ | Configure Template
li.divider(
ng-if = "INC.instance.attrs.isolated"
)
@@ -78,11 +188,8 @@
)
p.p Isolating a branch allows you to…
ul.list.list-bulleted.small
- //- while we can only isolate with service containers:
- li.list-item Copy your service containers to use with this branch.
- //- once we can isolate with service containers and repo containers:
- - li.list-item Create a separate stack of your containers to use with this branch.
- li.list-item Configure this branch differently from your default.
+ li.list-item Create a separate environment to use with this branch.
+ li.list-item Configure this branch independently from your template.
.btn.btn-sm.btn-block.green(
ng-click = "INC.setupIsolation()"
) Enter Isolation
@@ -94,8 +201,8 @@
ng-if = "INC.shouldShowSetupModal"
) …
li.list-item.popover-list-item(
- ng-if = "INC.instance.attrs.isIsolationGroupMaster"
ng-click = "INC.disableIsolation()"
+ ng-if = "INC.instance.attrs.isIsolationGroupMaster"
)
svg.iconnables
use(
@@ -103,14 +210,14 @@
)
| Disable Isolation
li.list-item.popover-list-item(
- ng-if = "INC.instance.attrs.isolated && !INC.instance.attrs.isIsolationGroupMaster"
ng-click = "INC.deleteContainer()"
+ ng-if = "INC.instance.attrs.isolated && !INC.instance.attrs.isIsolationGroupMaster"
)
svg.iconnables
use(
xlink:href = "#icons-isolation-disable"
)
- | Delete Container from Isolation
+ | Delete from Isolation
//- navListFilter
li.divider(
diff --git a/client/directives/components/isolationConfiguration/isolationConfigurationModalView.jade b/client/directives/components/isolationConfiguration/isolationConfigurationModalView.jade
index c98ecebf4..be2123431 100644
--- a/client/directives/components/isolationConfiguration/isolationConfigurationModalView.jade
+++ b/client/directives/components/isolationConfiguration/isolationConfigurationModalView.jade
@@ -11,7 +11,7 @@
section.modal-body
.grid-block.vertical.shrink.text-center.well.gray.small.padding-sm
//- while we can only isolate with service containers:
- | Select containers to create and isolate with
+ | Selected templates will be used to create containers for each branch of
//- once we can isolate with service containers and repo containers:
- | Selected containers will be isolated with
.text-overflow(
@@ -20,7 +20,7 @@
h4.grid-block.shrink.h4.text-gray.small.padding-xs(
ng-if = "ICMC.repoInstances.length"
- ) Repository Containers
+ ) Repository Templates
.grid-block.vertical.shrink.list.list-bordered(
ng-if = "ICMC.repoInstances.length"
)
@@ -56,7 +56,7 @@
)
| {{instance.getMasterPodName()}}
- //- this should get the class 'modded' if the selected branch uses a modified configuration
+ //- this should get the class 'modded' if the selected branch uses a modified template
//- selecting this should automatically check the checkbox
fancy-select.btn-xs.gray(
value = "ICMC.instanceBranchMapping[instance.attrs.contextVersion.context]"
@@ -70,12 +70,12 @@
ng-repeat = "child in $parent.instance.children.models"
value = "child"
) {{$parent.child.getBranchName()}}
- //- this element should only appear if the selected branch uses a modified configuration
- //- small.small Branch uses a modified configuration
+ //- this element should only appear if the selected branch uses a modified template
+ //- small.small Branch uses a modified template
h4.grid-block.shrink.h4.text-gray.small.padding-xs(
ng-if = "ICMC.nonRepoInstances.length"
- ) Non-Repository Containers
+ ) Non-Repository Templates
.grid-block.vertical.shrink.list.list-bordered(
ng-if = "ICMC.nonRepoInstances.length"
)
@@ -92,7 +92,7 @@
)
| {{instance.getDisplayName()}}
- section.modal-footer.clearfix
+ footer.modal-footer.clearfix
button.btn.btn-md.white.float-left(
ng-click = "ICMC.close()"
ng-disabled = "$root.isLoading.createIsolation"
@@ -100,4 +100,9 @@
button.btn.btn-md.green.float-right(
ng-disabled = "$root.isLoading.createIsolation"
ng-click = "ICMC.createIsolation()"
- ) {{$root.isLoading.createIsolation ? 'Isolating...' : 'Enter Isolation'}}
+ )
+ .spinner-wrapper.spinner-white.spinner-sm.float-left(
+ ng-if = "$root.isLoading.createIsolation"
+ ng-include = "'spinner'"
+ )
+ span Isolate Branch
diff --git a/client/directives/components/lists/branchCommitSelector/branchCommitSelectorView.jade b/client/directives/components/lists/branchCommitSelector/branchCommitSelectorView.jade
index 5ca6ed0cd..aebf69d08 100644
--- a/client/directives/components/lists/branchCommitSelector/branchCommitSelectorView.jade
+++ b/client/directives/components/lists/branchCommitSelector/branchCommitSelectorView.jade
@@ -26,7 +26,7 @@ label.toggle-wrapper(
.toggle-group.toggle-sm
label.toggle-wrapper(
- ng-if = "$root.featureFlags.testingFeature && BCSC.data.acv && !BCSC.data.acv.attrs.additionalRepo"
+ ng-if = "BCSC.data.acv && !BCSC.data.acv.attrs.additionalRepo"
)
.strong Auto-Deploy
.small Rebuild when new commits are pushed to GitHub.
diff --git a/client/directives/components/mirrorDockerfile/mirrorDockerfileView.jade b/client/directives/components/mirrorDockerfile/mirrorDockerfileView.jade
index d08dc9380..ade231cda 100644
--- a/client/directives/components/mirrorDockerfile/mirrorDockerfileView.jade
+++ b/client/directives/components/mirrorDockerfile/mirrorDockerfileView.jade
@@ -21,7 +21,7 @@
use(
xlink:href = "#icons-file-new"
)
- .grid-content Configure with Runnable
+ .grid-content Start with our setup guide
//- if there is only one, [check] by default
input.checkbox(
name = "dockerfile"
@@ -31,7 +31,7 @@
value = "new"
)
- button.btn.btn-xs.btn-icon.btn-add
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add
svg.iconnables.icons-check
use(
xlink:href = "#icons-check"
@@ -39,13 +39,13 @@
small.small.text-gray.padding-xxs.label-from(
ng-if = "!$root.isLoading.mirrorDockerfile && MDC.state.repo.dockerfiles.length > 0"
-) Advanced Configuration
+) Advanced Setup
.grid-content.shrink.list.list-bordered(
- ng-if = "$root.featureFlags.blankDockerfile"
+ ng-if = "$root.featureFlags.blankDockerfile && MDC.state.tabName === 'repos'"
)
label.grid-block.list-item(
- ng-class = "{'active': MDC.state.dockerfile === false}"
+ ng-class = "{'active': MDC.state.dockerfile === 'blank'}"
ng-disabled = "$root.isLoading[MDC.name + 'SingleRepo']"
)
svg.grid-content.shrink.iconnables.icons-dockerfile
@@ -56,10 +56,11 @@ small.small.text-gray.padding-xxs.label-from(
//- if there is only one, [check] by default
input.checkbox(
ng-disabled = "$root.isLoading[MDC.name + 'SingleRepo']"
- ng-value = "false"
+ ng-model = 'MDC.state.configurationMethod'
type = "radio"
+ value = "blankDockerfile"
)
- button.btn.btn-xs.btn-icon.btn-add
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add
svg.iconnables.icons-check
use(
xlink:href = "#icons-check"
@@ -71,9 +72,9 @@ small.small.text-gray.padding-xxs.label-from(
//- 'thisDockerfile' should be the name of the Dockerfile (ie. 'Dockerfile.prod', or 'Dockerfile.staging') to suppot multiple dockerfiles
//- add .disabled class to the not selected item if loading
label.grid-block.list-item(
+ ng-class="{'active': MDC.state.configurationMethod === 'dockerfile'}"
ng-disabled = "$root.isLoading[MDC.name + 'SingleRepo']"
ng-repeat = "dockerfile in MDC.state.repo.dockerfiles"
- ng-class="{'active': MDC.state.configurationMethod === 'dockerfile'}"
)
svg.grid-content.shrink.iconnables.icons-dockerfile
use(
@@ -94,7 +95,7 @@ small.small.text-gray.padding-xxs.label-from(
type = "radio"
value = "dockerfile"
)
- button.btn.btn-xs.btn-icon.btn-add
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add
svg.iconnables.icons-check
use(
xlink:href = "#icons-check"
@@ -112,7 +113,7 @@ small.grid-block.shrink.align-center.small.text-gray.padding-xxs(
.grid-block.vertical.shrink.well.gray.padding-sm.well-add-dockerfile(
add-dockerfile
branch-name = "MDC.branchName"
- full-repo = "MDC.fullRepo"
+ full-repo = "MDC.getFullRepo()"
ng-if = "viewState.showAddDockerfile"
view-state = "viewState"
)
diff --git a/client/directives/components/readOnlySwitch/confirmRollbackModalView.jade b/client/directives/components/readOnlySwitch/confirmRollbackModalView.jade
index 885a7d469..3c81f3f0b 100644
--- a/client/directives/components/readOnlySwitch/confirmRollbackModalView.jade
+++ b/client/directives/components/readOnlySwitch/confirmRollbackModalView.jade
@@ -2,7 +2,7 @@
.modal-dialog.modal-sm.modal-alert
header.modal-body
p.p.strong Disable Dockerfile editing?
- p.p Changes made to your Dockerfile will be discarded and your configuration will be restored to the state it was in before Dockerfile editing was enabled.
+ p.p Changes made to your Dockerfile will be discarded and your template will be restored to the state it was in before Dockerfile editing was enabled.
footer.modal-footer.clearfix
button.btn.btn-sm.gray.float-left(
ng-click = "CMC.actions.cancel()"
diff --git a/client/directives/components/readOnlySwitch/confirmSwitchToSimpleModeView.jade b/client/directives/components/readOnlySwitch/confirmSwitchToSimpleModeView.jade
index 19ead6c79..6040d3f2d 100644
--- a/client/directives/components/readOnlySwitch/confirmSwitchToSimpleModeView.jade
+++ b/client/directives/components/readOnlySwitch/confirmSwitchToSimpleModeView.jade
@@ -7,8 +7,8 @@
use(
xlink:href = "#icons-close"
)
- p.p.strong.popover-title Disable editing and restore past configuration?
- p.p Disabling will restore your container’s configuration from when editing was initially enabled. You can’t undo this action.
+ p.p.strong.popover-title Disable editing and restore past template?
+ p.p Disabling will restore your template from when editing was initially enabled. You can’t undo this action.
footer.modal-footer.clearfix
button.btn.btn-sm.gray.float-left(
ng-click = "CMC.actions.cancel()"
diff --git a/client/directives/components/readOnlySwitch/readOnlySwitchView.jade b/client/directives/components/readOnlySwitch/readOnlySwitchView.jade
index 6f0a33690..0d21a8f50 100644
--- a/client/directives/components/readOnlySwitch/readOnlySwitchView.jade
+++ b/client/directives/components/readOnlySwitch/readOnlySwitchView.jade
@@ -7,6 +7,6 @@ input.toggle-input(
.toggle-group.toggle-sm(
tooltip
tooltip-disabled = "!ROSC.state.instance || !ROSC.readOnly() || (ROSC.state.repo && ROSC.state.instance.attrs.lastBuiltSimpleContextVersion)"
- tooltip-eval = "ROSC.state.repo ? 'We’re unable to disable editing. To resolve this, delete and re-create your container.' : 'Editing is always enabled on non-repository containers.'"
+ tooltip-eval = "ROSC.state.repo ? 'We’re unable to disable editing. To resolve this, delete and re-create your template.' : 'Editing is always enabled on non-repository templates.'"
tooltip-options = "{\"class\":\"bottom bottom-arrow-right\",\"right\":0,\"top\":21}"
)
diff --git a/client/directives/components/saveOpenItemsButton/saveOpenItemsButtonView.jade b/client/directives/components/saveOpenItemsButton/saveOpenItemsButtonView.jade
index 8804ef37c..4e6f6bfdf 100644
--- a/client/directives/components/saveOpenItemsButton/saveOpenItemsButtonView.jade
+++ b/client/directives/components/saveOpenItemsButton/saveOpenItemsButtonView.jade
@@ -24,7 +24,7 @@
pop-over
pop-over-active = "SOIBC.popoverActive"
pop-over-controller = "SOIBC"
- pop-over-options = "{\"right\":1,\"top\":47}"
+ pop-over-options = "{\"right\":-6,\"top\":47}"
pop-over-template = "saveOpenItemsOptionsPopoverView"
type = "button"
)
diff --git a/client/directives/components/saveOpenItemsButton/saveOpenItemsOptionsPopoverView.jade b/client/directives/components/saveOpenItemsButton/saveOpenItemsOptionsPopoverView.jade
index 79d15f7db..601041448 100644
--- a/client/directives/components/saveOpenItemsButton/saveOpenItemsOptionsPopoverView.jade
+++ b/client/directives/components/saveOpenItemsButton/saveOpenItemsOptionsPopoverView.jade
@@ -4,7 +4,7 @@
style = "transform-origin: 95% 0;"
)
.arrow.white(
- style = "left: auto; right: -1px;"
+ style = "left: auto; right: 6px;"
)
.popover-content
ul.popover-list
diff --git a/client/directives/environment/environmentBody/serverCards/popoverServerOptions/serverOptionsCardPopover.jade b/client/directives/environment/environmentBody/serverCards/popoverServerOptions/serverOptionsCardPopover.jade
index 4de4a76a4..7a877ce53 100644
--- a/client/directives/environment/environmentBody/serverCards/popoverServerOptions/serverOptionsCardPopover.jade
+++ b/client/directives/environment/environmentBody/serverCards/popoverServerOptions/serverOptionsCardPopover.jade
@@ -31,7 +31,7 @@
use(
xlink:href = "#icons-server-modify"
)
- | Rename Container
+ | Rename Template
//- trigger delete confirm modal
li.list-item.popover-list-item(
ng-click = "actions.deleteServer()"
@@ -40,4 +40,4 @@
use(
xlink:href = "#icons-server-delete"
)
- | Delete Container
+ | Delete Template
diff --git a/client/directives/environment/environmentBody/serverCards/serverCardDirective.js b/client/directives/environment/environmentBody/serverCards/serverCardDirective.js
index e23dba236..4c6f2892f 100644
--- a/client/directives/environment/environmentBody/serverCards/serverCardDirective.js
+++ b/client/directives/environment/environmentBody/serverCards/serverCardDirective.js
@@ -10,7 +10,6 @@ require('app')
createServerObjectFromInstance,
fetchDockerfileForContextVersion,
fetchStackAnalysis,
- helpCards,
keypather,
ModalService,
parseDockerfileForCardInfoFromInstance,
@@ -23,8 +22,7 @@ require('app')
scope: {
data: '=',
actions: '=',
- instance: '=',
- helpCard: '=?'
+ instance: '='
},
link: function ($scope, ele) {
var listeners = [];
@@ -79,114 +77,11 @@ require('app')
return '—';
};
- $scope.helpCards = helpCards;
$scope.server = {};
$scope.activeAccount = currentOrg.github; // I'm unsure if this is used.
- function scrollIntoView() {
- $document.scrollToElement(ele, 100, 200);
- }
-
- function calculateHelpCardsForRepoInstance (instance) {
- if (instance.attrs.owner.username !== $state.params.userName) { return; }
- // This may be a newInstance... just a placeholder
- helpCards.removeByInstance(instance);
-
- var fullRepoName = keypather.get($scope.server.instance, 'contextVersion.getMainAppCodeVersion().attrs.repo');
-
- return $q.all({
- stackAnalysis: fetchStackAnalysis(fullRepoName),
- dependencies: promisify(instance, 'fetchDependencies', true)()
- })
- .then(function (res) {
- var stackAnalysis = res.stackAnalysis;
- var dependencies = res.dependencies;
- if (!stackAnalysis.serviceDependencies) { return; }
-
- stackAnalysis.serviceDependencies.forEach(function (dependency) {
- var matchedInstance = $scope.data.instances.find(function (instance) {
- return instance.attrs.lowerName === dependency;
- });
- if (matchedInstance) {
- var matchedDependency = dependencies.find(function (dep) {
- return dep.attrs.shortHash === matchedInstance.attrs.shortHash;
- });
- if (matchedDependency) { return; }
- return helpCards.triggerCard('missingAssociation', {
- instance: $scope.server.instance,
- association: matchedInstance.attrs.name
- })
- .then(function (helpCard) {
- if (!helpCard) { return; }
- addListener(helpCard, 'refresh', calculateHelpCardsForRepoInstance.bind(null, instance));
- addListener(helpCard, 'activate', scrollIntoView);
- }).catch(errs.handler);
- }
- // Missing Dependency
- return helpCards.triggerCard('missingDependency', {
- instance: $scope.server.instance,
- dependency: dependency
- })
- .then(function (helpCard) {
- if (!helpCard) { return; }
- addListener(helpCard, 'refresh', calculateHelpCardsForRepoInstance.bind(null, instance));
- }).catch(errs.handler);
- });
- })
- .catch(errs.handler);
- }
-
- function calculateHelpCardsForNonRepoContainers (instance) {
- return $q.when($scope.data.instances)
- .then(function (instances) {
- return $q.all(instances.filter(function (instance) {
- return instance !== $scope.server.instance && keypather.get(instance, 'attrs._id');
- })
- .map(function (instance) {
- if (keypather.get(instance, 'dependencies.models.length')) {
- return $q.when(instance.dependencies);
- }
- return promisify(instance, 'fetchDependencies')();
- }));
- })
- .then(function (dependencyList) {
- return dependencyList.find(function (depList) {
- return depList.find(function (dep) {
- return dep.attrs.name === $scope.server.instance.attrs.name;
- });
- });
- })
- .then(function (foundMatch) {
- if (foundMatch) { return; }
- var foundInstanceWithMainACV = $scope.data.instances.find(function (instance) {
- return keypather.get(instance, 'contextVersion.getMainAppCodeVersion()');
- });
- if (!foundInstanceWithMainACV) { return; }
- if (instance.attrs.owner.username !== $state.params.userName) { return; }
- return helpCards.triggerCard('missingMapping', {
- mapping: $scope.server.instance.attrs.name
- })
- .then(function (helpCard) {
- if (!helpCard) { return; }
- addListener(helpCard, 'refresh', calculateHelpCardsForNonRepoContainers.bind(null, instance));
- })
- .catch(errs.handler);
- });
- }
-
- function addListener (helpCard, name, cb) {
- listeners.push({
- obj: helpCard,
- key: name,
- value: cb
- });
- helpCard
- .on(name, cb);
- }
-
function handleNewInstanceUpdate (instance) {
// This may be a newInstance... just a placeholder
- helpCards.removeByInstance(instance);
angular.extend($scope.server, createServerObjectFromInstance(instance));
if (!instance.contextVersion) { return; }
@@ -201,11 +96,6 @@ require('app')
}
$scope.server.building = false;
- var fullRepoName = keypather.get($scope.server.instance, 'contextVersion.getMainAppCodeVersion().attrs.repo');
- if (fullRepoName) {
- return calculateHelpCardsForRepoInstance(instance);
- }
- return calculateHelpCardsForNonRepoContainers(instance);
}
$scope.$watchCollection('instance.attrs', function (n) {
@@ -267,7 +157,6 @@ require('app')
listeners.forEach(function (watcher) {
watcher.obj.removeListener(watcher.key, watcher.value);
});
- helpCards.removeByInstance($scope.server.instance);
});
}
};
diff --git a/client/directives/environment/environmentBody/serverCards/serverCardView.jade b/client/directives/environment/environmentBody/serverCards/serverCardView.jade
index 52f11cbb6..293ef7468 100644
--- a/client/directives/environment/environmentBody/serverCards/serverCardView.jade
+++ b/client/directives/environment/environmentBody/serverCards/serverCardView.jade
@@ -29,7 +29,6 @@ ul.card-body.load(
//- repository
li.btn.white(
ng-click = "openEditServerModal('repository')"
- ng-class = "{'btn-hint': helpCards.cardIsActiveOnThisContainer(instance) && helpCards.getActiveCard().targets.repository}"
ng-if = "server.repo && !server.advanced"
)
svg.iconnables
@@ -47,7 +46,6 @@ ul.card-body.load(
//- commands
li.btn.white(
ng-click = "openEditServerModal('commands')"
- ng-class = "{'btn-hint': helpCards.cardIsActiveOnThisContainer(instance) && helpCards.getActiveCard().targets.commands}"
ng-if = "server.repo && !server.advanced"
)
svg.iconnables
@@ -65,7 +63,6 @@ ul.card-body.load(
//- exposed ports
li.btn.white(
ng-click = "openEditServerModal('ports')"
- ng-class = "{'btn-hint': helpCards.cardIsActiveOnThisContainer(instance) && helpCards.getActiveCard().targets.exposedPorts}"
ng-if = "server.repo && !server.advanced"
)
svg.iconnables
@@ -82,7 +79,6 @@ ul.card-body.load(
li.btn.white(
ng-click = "openEditServerModal('env')"
ng-class = "{\
- 'btn-hint': helpCards.cardIsActiveOnThisContainer(instance) && helpCards.getActiveCard().targets.environmentVariables,\
'active-notification': $root.featureFlags.hostnameNotifications\
}"
)
@@ -103,7 +99,6 @@ ul.card-body.load(
//- container files
li.btn.white(
ng-click = "openEditServerModal('files')"
- ng-class = "{'btn-hint': helpCards.cardIsActiveOnThisContainer(instance) && helpCards.getActiveCard().targets.containerFiles}"
ng-if = "server.repo && !server.advanced"
)
svg.iconnables
@@ -119,7 +114,6 @@ ul.card-body.load(
//- find & replace
li.btn.white(
ng-click = "openEditServerModal('translation')"
- ng-class = "{'btn-hint': helpCards.cardIsActiveOnThisContainer(instance) && helpCards.getActiveCard().targets.findAndReplace}"
ng-if = "\
server.repo && \
!server.instance.hasDockerfileMirroring() \
diff --git a/client/directives/environment/environmentBody/serverStatusCardHeaderDirective.js b/client/directives/environment/environmentBody/serverStatusCardHeaderDirective.js
index 0e95f885b..66706a7ed 100644
--- a/client/directives/environment/environmentBody/serverStatusCardHeaderDirective.js
+++ b/client/directives/environment/environmentBody/serverStatusCardHeaderDirective.js
@@ -8,7 +8,6 @@ require('app')
function serverStatusCardHeader(
$rootScope,
errs,
- helpCards,
ModalService,
promisify
) {
@@ -63,7 +62,6 @@ function serverStatusCardHeader(
});
})
.catch(errs.handler);
- helpCards.refreshAllCards();
}
return confirmed;
});
diff --git a/client/directives/environment/environmentBody/viewCardGrid.jade b/client/directives/environment/environmentBody/viewCardGrid.jade
index cc1b8a98c..8249c3951 100644
--- a/client/directives/environment/environmentBody/viewCardGrid.jade
+++ b/client/directives/environment/environmentBody/viewCardGrid.jade
@@ -8,23 +8,25 @@
)
//- empty state
-.card.gray.disabled.load.empty(
+.card.gray.disabled.load.empty.p(
ng-class = "{'deprecated': !$root.featureFlags.cardStatus}"
- ng-if = "data.instances && !$root.isLoading.sidebar && !data.instances.models.length"
+ ng-if = "$root.featureFlags.aha && !EC.isInGuide() && !$root.isLoading.sidebar && data.instances && !data.instances.models.length"
)
- svg.iconnables(
- ng-click = "EC.triggerModal.newContainer()"
- )
- use(
- xlink:href = "#icons-new-repository-server"
- )
- p.p Add your first repository container to get started.
+ h1.h1 😐
+ | You don’t have any templates.
+ br
+ | Click the button above to create one.
+
+//- empty state
+.card.gray.disabled.load.empty.p(
+ ng-class = "{'deprecated': !$root.featureFlags.cardStatus}"
+ ng-if = "!$root.featureFlags.aha && !$root.isLoading.sidebar && data.instances && !data.instances.models.length"
+) Create a repository template to get started!
//- server card
.card.gray.disabled.load(
actions = "actions"
data = "data"
- help-card = "state.helpCard"
instance = "instance"
ng-class = "{\
'deprecated': !$root.featureFlags.cardStatus,\
diff --git a/client/directives/environment/environmentController.js b/client/directives/environment/environmentController.js
index 041a3a3be..21b7c9a32 100755
--- a/client/directives/environment/environmentController.js
+++ b/client/directives/environment/environmentController.js
@@ -14,13 +14,13 @@ function EnvironmentController(
$scope,
$state,
$timeout,
- $window,
+ ahaGuide,
+ currentOrg,
favico,
- fetchUser,
fetchDockerfileForContextVersion,
- fetchInstancesByPod,
fetchOrgMembers,
- helpCards,
+ fetchUser,
+ instancesByPod,
keypather,
ModalService,
pageName
@@ -28,6 +28,17 @@ function EnvironmentController(
var EC = this;
EC.showInviteButton = false;
+ EC.isAddingFirstRepo = ahaGuide.isAddingFirstRepo;
+ EC.isInGuide = ahaGuide.isInGuide;
+ EC.showCreateTemplate = true;
+ EC.showOverview = true;
+ $scope.$on('ahaGuideEvent', function(event, info) {
+ if (info.isClear) {
+ EC.errorState = null;
+ } else {
+ EC.errorState = info.error;
+ }
+ });
var unbindUpdateTeammateInvitation = $rootScope.$on('updateTeammateInvitations', function (event, invitesCreated) {
if (invitesCreated) {
@@ -36,7 +47,7 @@ function EnvironmentController(
});
$scope.$on('$destroy', unbindUpdateTeammateInvitation);
- function updateShowInviteButton () {
+ function updateShowInviteButton() {
return $q.all({
user: fetchUser(),
members: fetchOrgMembers($state.params.userName)
@@ -53,6 +64,7 @@ function EnvironmentController(
EC.triggerModal = {
newContainer: function () {
+ $rootScope.$broadcast('close-popovers');
return ModalService.showModal({
controller: 'NewContainerModalController',
controllerAs: 'MC', // Shared
@@ -82,64 +94,37 @@ function EnvironmentController(
$scope.$state = $state;
favico.reset();
pageName.setTitle('Configure - Runnable');
- $scope.data = {
- helpCards: helpCards
- };
- fetchInstancesByPod($state.userName)
- .then(function (instancesCollection) {
- $scope.data.instances = instancesCollection;
- // Asynchronously fetch the Dockerfile
- instancesCollection.forEach(function (instance) {
- if (instance.hasDockerfileMirroring()) {
- return fetchDockerfileForContextVersion(instance.contextVersion)
- .then(function (dockerfile) {
- instance.mirroredDockerfile = dockerfile;
- });
- }
- // Differentiate between non-fetched and non-existing
- instance.mirroredDockerfile = null;
- });
- });
+ $scope.data = { };
+ $scope.data.instances = instancesByPod;
+
+ var isAddFirstRepo = ahaGuide.isAddingFirstRepo();
+
+ if (isAddFirstRepo && instancesByPod.models.length === 0) {
+ EC.showCreateTemplate = false;
+ EC.showSidebar = true;
+ }
+
+ // Asynchronously fetch the Dockerfile and check for working instances
+ instancesByPod.forEach(function (instance) {
+ if (instance.hasDockerfileMirroring()) {
+ return fetchDockerfileForContextVersion(instance.contextVersion)
+ .then(function (dockerfile) {
+ instance.mirroredDockerfile = dockerfile;
+ });
+ }
+ // Differentiate between non-fetched and non-existing
+ instance.mirroredDockerfile = null;
+ });
$scope.state = {
validation: {
env: {}
},
- helpCard: null,
newServerButton: {
active: false
}
};
- $scope.help = helpCards.cards;
- $scope.helpCards = helpCards;
-
- helpCards.clearAllCards();
-
- $scope.helpUndock = false;
-
- var scrollHelper = function () {
- var newVal = false;
- if ($window.scrollY > 60) {
- newVal = true;
- }
- if ($scope.helpUndock !== newVal) {
- $scope.helpUndock = newVal;
- $timeout(angular.noop);
- }
- };
- $scope.$on('helpCardScroll:enable', function () {
- $window.addEventListener('scroll', scrollHelper);
- scrollHelper();
- });
- $scope.$on('helpCardScroll:disable', function () {
- $window.removeEventListener('scroll', scrollHelper);
- });
-
- $scope.$on('$destroy', function () {
- $window.removeEventListener('scroll', scrollHelper);
- });
-
EC.alert = null;
$scope.$on('alert', function (evt, data) {
@@ -166,20 +151,30 @@ function EnvironmentController(
subTab: 'billingForm'
}
});
- }
+ },
+ showSidebar: function () {
+ EC.showSidebar = !EC.showSidebar;
+ EC.showCreateTemplate = true;
+ },
+ endGuide: ahaGuide.endGuide
};
- $scope.helpPopover = {
- data: $scope.help,
- actions: {
- ignoreHelp: function (help) {
- helpCards.ignoreCard(help);
- },
- getHelp: function (help) {
- helpCards.setActiveCard(help);
- $rootScope.$broadcast('close-popovers');
+
+ $scope.$on('showAhaSidebar', EC.actions.showSidebar);
+ $scope.$on('showAddServicesPopover', function(event, toggle) {
+ EC.showAddServicePopover = toggle;
+ });
+
+ if (ahaGuide.isInGuide()) {
+ if (keypather.get(instancesByPod, 'models.length')) {
+ if (instancesByPod.models.some(function (instance) {
+ return instance.attrs.hasAddedBranches || keypather.get(instance, 'children.models.length');
+ })) {
+ // timeout for the animation
+ $timeout(function () {
+ EC.showSidebar = true;
+ });
}
}
- };
-
+ }
}
diff --git a/client/directives/environment/environmentHeader/viewEnvironmentHeader.jade b/client/directives/environment/environmentHeader/viewEnvironmentHeader.jade
index 9389432ce..10179e918 100644
--- a/client/directives/environment/environmentHeader/viewEnvironmentHeader.jade
+++ b/client/directives/environment/environmentHeader/viewEnvironmentHeader.jade
@@ -1,71 +1,37 @@
-button.grid-block.shrink.btn.btn-md.btn-icon.btn-help(
- data-badge-count = "{{helpCards.cards.triggered.length}}"
- ng-class = "{\
- 'active': state.helpButton.active || !state.helpButton.active && helpCards.cards.triggered.length > 0 && !helpCards.getActiveCard(),\
- 'badge': helpCards.cards.triggered.length > 0,\
- 'badge-blue': helpCards.cards.triggered.length > 0\
- }"
- ng-click = "state.helpButton.active = true"
- ng-if = "!$root.featureFlags.aha"
- pop-over
- pop-over-actions = "helpPopover.actions"
- pop-over-active = "state.helpButton.active"
- pop-over-data = "helpPopover.data"
- pop-over-options = "{\"left\":60}"
- pop-over-template = "viewHelpPopover"
- pop-over-trigger = "activeAttr"
- title = "Help Center"
-)
- svg.iconnables
- use(
- xlink:href = "#icons-help"
- )
-
-.help.help-top-card(
- ng-if = "!state.helpButton.active && helpCards.cards.triggered.length > 0 && !helpCards.getActiveCard()"
-)
- .help-lists-wrapper
- ul.triggered-help-list
- li.grid-block.triggered-help-item.clearfix
- button.btn.btn-icon.btn-icon-xs(
- ng-click = "helpPopover.actions.ignoreHelp(helpCards.cards.triggered[0])"
- )
- svg.iconnables
- use(
- xlink:href = "#icons-close"
- )
- p.p.grid-content(
- ng-bind-html = "helpCards.cards.triggered[0].label"
- )
- button.btn.btn-xs.blue.grid-content.shrink(
- ng-click = "helpPopover.actions.getHelp(helpCards.cards.triggered[0])"
- ) Show Me
- button.btn(
- ng-click = "state.helpButton.active = true"
- ) More Help
- svg.iconnables
- use(
- xlink:href = "#icons-arrow-down"
- )
-
//- new server button
button.grid-block.shrink.btn.btn-md.green(
- ng-class = "{\
- 'scale': helpCards.getActiveCard().targets.newContainer,\
- 'scale-in-modal': $root.featureFlags.aha1\
- }"
+ ng-class = "{ 'scale-in-modal': EC.isAddingFirstRepo() }"
ng-click = "EC.triggerModal.newContainer()"
- ng-if = "!$root.featureFlags.ahaOverview"
)
svg.iconnables.icons-add.float-left
use(
xlink:href = "#icons-add"
)
- | Add Configuration
+ | Create Template
+
+.popover.bottom.in.popover-aha(
+ ng-if = "$root.featureFlags.aha && EC.showAddServicePopover"
+ style = "left: 0; margin: 0 auto; right: 0; top: 54px;"
+)
+ .arrow.white
+ .popover-content
+ .grid-block.shrink.align-center.justify-center.padding-sm.aha-guide
+ .grid-block.shrink.aha-meter.js-animate.aha-meter-100
+ svg.iconnables
+ use(
+ xlink:href = "#icons-check"
+ )
+ .grid-block.vertical.aha-text
+ p.p.small.text-gray-light Step 2: Configure your Application
+ p.p To add a database or other service to your application, click ‘Create Template’.
+ .grid-block.justify-right.popover-footer
+ button.grid-block.shrink.btn.btn-sm.green(
+ ng-click = "EC.showAddServicePopover = false"
+ ) Got It
button.grid-block.shrink.btn.btn-sm.gray.btn-aha(
- ng-click = "$root.featureFlags.ahaSidebar = true"
- ng-if = "$root.featureFlags.aha && !$root.featureFlags.ahaSidebar"
+ ng-click = "EC.actions.showSidebar()"
+ ng-if = "$root.featureFlags.aha && EC.isInGuide()"
tooltip = "Setup Guide"
tooltip-options = "{\"class\":\"left\",\"right\":42,\"top\":0}"
)
diff --git a/client/directives/environment/environmentView.jade b/client/directives/environment/environmentView.jade
index 07a87d401..c89bf7988 100755
--- a/client/directives/environment/environmentView.jade
+++ b/client/directives/environment/environmentView.jade
@@ -42,76 +42,44 @@
//- environment page
.grid-block.environment-wrapper(
- ng-class = "{'empty': $root.featureFlags.aha && $root.featureFlags.aha1}"
+ ng-class = "{'empty': EC.isInGuide() && EC.isAddingFirstRepo() && data.instances.models.length === 0}"
)
-
header.grid-block.align-center.environment-header(
ng-include = "'viewEnvironmentHeader'"
ng-init = "state.helpButton = {active: false}"
+ ng-if = "!EC.isInGuide() || EC.showCreateTemplate"
)
- .grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
- ng-if = "$root.featureFlags.aha1ExitedEarly"
- ng-include = "'ahaGuideView'"
- ng-init = "\
- state.showStep = 1;\
- state.showSubStep = 7;\
- state.showError = true;\
- state.showErrorType = 'exitedEarly';\
- "
+ .environment-view-aha-guide(
+ ng-if = "$root.featureFlags.aha && EC.isInGuide()"
)
+ .grid-block.align-center.justify-center.padding-sm.aha-guide(
+ ng-show = "EC.isAddingFirstRepo() && EC.errorState && data.instances.models.length"
+ aha-guide
+ error-state = "EC.errorState"
+ sub-step-index = 7
+ )
- .grid-block.environment-body.justify-center.clearfix(
- ng-class = "{'align-center justify-center': $root.featureFlags.aha1}"
- )
- .help-container(
- ng-class = "{\
- 'fixed': helpUndock,\
- 'top': helpUndock\
- }"
- ng-if = "helpCards.getActiveCard() && !$root.featureFlags.aha"
+ .grid-block.align-center.justify-center.padding-sm.aha-guide(
+ ng-if = "EC.isInGuide() && !EC.isAddingFirstRepo() && !data.instances.models.length"
+ aha-guide
+ error-state = "EC.errorState"
+ sub-step = "deletedTemplate"
)
- .help(
- ng-if = "helpCards.getActiveCard().targets.newContainer && state.newServerButton.active"
- )
- button.btn.btn-xs.btn-icon(
- ng-click = "helpCards.hideActiveCard()"
- )
- svg.iconnables.icons-close
- use(
- xlink:href = "#icons-close"
- )
- span(
- ng-bind-html = "helpCards.getActiveCard().helpPopover.newContainer"
- )
- .help(
- ng-if = "!(helpCards.getActiveCard().targets.newContainer && state.newServerButton.active)"
- )
- button.btn.btn-xs.btn-icon(
- ng-click = "helpCards.hideActiveCard()"
- )
- svg.iconnables.icons-close
- use(
- xlink:href = "#icons-close"
- )
- span(
- ng-bind-html = "helpCards.getActiveCard().helpTop"
- )
+ .grid-block.environment-body.justify-center.clearfix(
+ ng-class = "{'align-center justify-center': EC.showCreateTemplate && !data.instances.models.length}"
+ )
.modal-dialog.modal-sm(
- ng-if = "$root.featureFlags.aha1 && !$root.featureFlags.ahaOverview"
+ ng-if = "$root.featureFlags.aha && EC.isInGuide() && EC.isAddingFirstRepo() && EC.showCreateTemplate && !data.instances.models.length"
)
.grid-block.align-center.aha-guide.padding-md(
ng-include = "'ahaGuideView'"
- ng-init = "\
- state.showStep = 1;\
- state.showSubStep = 0;\
- "
+ ng-init = "staticAddRepo = true"
)
.grid-block.card-grid.clearfix(
- ng-class = "{'padding-top': helpCards.getActiveCard().helpTop}"
- ng-if = "!$root.featureFlags.aha1"
+ ng-if = "!$root.featureFlags.aha || data.instances.models.length > 0 || !EC.isInGuide()"
ng-include = "'viewCardGrid'"
)
@@ -126,9 +94,11 @@
xlink:href = "#icons-team-invite"
)
| Invite a teammate
- | to help you set up your stack.
+ | to help you set up your project.
.grid-block.vertical.aha-sidebar.padding-sm.js-animate(
- ng-include = "'ahaSidebarView'"
- ng-if = "$root.featureFlags.aha && $root.featureFlags.ahaSidebar"
+ aha-sidebar
+ toggle-sidebar = "EC.actions.showSidebar"
+ show-overview = "!EC.showCreateTemplate"
+ ng-if = "$root.featureFlags.aha && EC.isInGuide() && EC.showSidebar"
)
diff --git a/client/directives/environment/modals/confirmDeleteServerView.jade b/client/directives/environment/modals/confirmDeleteServerView.jade
index fd09b74dd..4ee6ed169 100644
--- a/client/directives/environment/modals/confirmDeleteServerView.jade
+++ b/client/directives/environment/modals/confirmDeleteServerView.jade
@@ -1,12 +1,12 @@
.modal-backdrop.in
.modal-dialog.modal-sm.modal-alert
header.modal-body
- p.p.strong Are you sure you want to delete this container?
- p.p Deleting this container cannot be undone.
+ p.p.strong Are you sure you want to delete this template?
+ p.p All containers that belong to this template will be deleted. This cannot be undone.
footer.modal-footer.clearfix
button.btn.btn-sm.gray.float-left(
ng-click = "CMC.actions.cancel()"
) Cancel
button.btn.btn-sm.red.float-right(
ng-click = "CMC.actions.confirm()"
- ) Delete Container
\ No newline at end of file
+ ) Delete Template
diff --git a/client/directives/environment/modals/confirmDiscardServerView.jade b/client/directives/environment/modals/confirmDiscardServerView.jade
index f78c038fd..f4939cd69 100644
--- a/client/directives/environment/modals/confirmDiscardServerView.jade
+++ b/client/directives/environment/modals/confirmDiscardServerView.jade
@@ -1,7 +1,7 @@
.modal-backdrop.in
.modal-dialog.modal-sm.modal-alert
header.modal-body
- p.p.strong Are you sure you want to discard this container?
+ p.p.strong Are you sure you want to discard this template?
footer.modal-footer.clearfix
button.btn.btn-sm.gray.float-left(
ng-click = "CMC.actions.cancel()"
diff --git a/client/directives/environment/modals/confirmSetupView.jade b/client/directives/environment/modals/confirmSetupView.jade
new file mode 100644
index 000000000..5379fde30
--- /dev/null
+++ b/client/directives/environment/modals/confirmSetupView.jade
@@ -0,0 +1,34 @@
+.modal-backdrop.modal-confirm-setup
+ img.img(
+ src = "/build/images/runnabear-working.png"
+ )
+ .modal-dialog.modal-md
+ .modal-body
+ svg.iconnables.icons-close(
+ ng-click = "CMC.actions.cancel()"
+ )
+ use(
+ xlink:href = "#icons-close"
+ )
+ .grid-block.vertical.padding-md
+ h3.grid-content.h3.text-center Is your application set up?
+ p.grid-content.p.text-center.text-gray Go back to resolve any configuration issues or to add any other templates. Need more help? Head over to our
+ a.link(
+ href = "https://support.runnable.com/"
+ target = "_blank"
+ ) docs
+ | or
+ //- Opens Intercom chat, and starts with "I need help setting up!":
+ a.link(
+ href = "https://support.runnable.com/hc/en-us/articles/212930166"
+ target = "_blank"
+ ) chat
+ | with our devs.
+ p.grid-content.p.text-center.text-gray If you’re done, continue to the Containers page.
+ footer.modal-footer.clearfix
+ button.btn.btn-md.btn-cancel.gray.float-left(
+ ng-click = "CMC.actions.cancel()"
+ ) Go Back
+ button.btn.btn-md.green.float-right(
+ ng-click = "$root.$broadcast('confirmedSetup');CMC.actions.confirm()"
+ ) Continue
diff --git a/client/directives/environment/modals/forms/backupForm/backupFormView.jade b/client/directives/environment/modals/forms/backupForm/backupFormView.jade
index a0aeca638..42bd59e54 100644
--- a/client/directives/environment/modals/forms/backupForm/backupFormView.jade
+++ b/client/directives/environment/modals/forms/backupForm/backupFormView.jade
@@ -47,8 +47,8 @@
ng-class = "{'disabled': false}"
) Back Up Now
//- disable the above button and add tooltip if the container is down
- //- tooltip = "You can’t back up while the container isn’t running."
- //- tooltip-options = "{\"class\":\"bottom bottom-arrow-right\",\"right\":0,\"top\":30}"
+ tooltip = "You can’t back up while the container isn’t running."
+ tooltip-options = "{\"class\":\"bottom bottom-arrow-right\",\"right\":0,\"top\":24}"
.ace-container.ace-backup(
ng-class = "{\
diff --git a/client/directives/environment/modals/forms/formBuildfiles/viewFormBuildfiles.jade b/client/directives/environment/modals/forms/formBuildfiles/viewFormBuildfiles.jade
index 7d6a9647d..e1afecb78 100644
--- a/client/directives/environment/modals/forms/formBuildfiles/viewFormBuildfiles.jade
+++ b/client/directives/environment/modals/forms/formBuildfiles/viewFormBuildfiles.jade
@@ -1,18 +1,3 @@
-.help-container(
- ng-if = "SMC.helpCards.getActiveCard().helpPopover.containerFiles"
-)
- .help
- button.btn.btn-xs.btn-icon(
- ng-click = "SMC.helpCards.hideActiveCard()"
- )
- svg.iconnables.icons-close
- use(
- xlink:href = "#icons-close"
- )
- span(
- ng-bind-html = "SMC.helpCards.getActiveCard().helpPopover.containerFiles"
- )
-
.grid-block.shrink.align-center.well.well-600.gray.can-disable.padding-sm(
ng-if = "!SMC.state.advanced"
)
diff --git a/client/directives/environment/modals/forms/formEnvironmentVariables/viewFormEnvironmentVariables.jade b/client/directives/environment/modals/forms/formEnvironmentVariables/viewFormEnvironmentVariables.jade
index 78e5aeb28..b3d9f8211 100644
--- a/client/directives/environment/modals/forms/formEnvironmentVariables/viewFormEnvironmentVariables.jade
+++ b/client/directives/environment/modals/forms/formEnvironmentVariables/viewFormEnvironmentVariables.jade
@@ -1,20 +1,3 @@
-//- help things
-.help-container(
- ng-if = "SMC.helpCards.getActiveCard().helpPopover.environmentVariables && SMC.helpCards.cardIsActiveOnThisContainer(SMC.instance)"
- ng-hide = "$root.featureFlags.fullScreen"
-)
- .help
- button.btn.btn-xs.btn-icon(
- ng-click = "SMC.helpCards.hideActiveCard()"
- )
- svg.iconnables.icons-close
- use(
- xlink:href = "#icons-close"
- )
- span(
- ng-bind-html = "SMC.helpCards.getActiveCard().helpPopover.environmentVariables"
- )
-
//- begin form
.label-description.clearfix(
ng-hide = "$root.featureFlags.fullScreen"
diff --git a/client/directives/environment/modals/forms/formFiles/containerFilesController.js b/client/directives/environment/modals/forms/formFiles/containerFilesController.js
index b734ffe60..c73e35b60 100644
--- a/client/directives/environment/modals/forms/formFiles/containerFilesController.js
+++ b/client/directives/environment/modals/forms/formFiles/containerFilesController.js
@@ -3,6 +3,7 @@
require('app').controller('ContainerFilesController', ContainerFilesController);
function ContainerFilesController(
+ $q,
loadingPromises,
promisify,
errs,
@@ -161,25 +162,39 @@ function ContainerFilesController(
},
deleteFile: function (containerFile) {
$rootScope.$broadcast('close-popovers');
-
- var file = containerFile.fileModel || self.state.contextVersion.rootDir.contents.models.find(function (fileModel) {
- return fileModel.attrs.name === containerFile.name;
- });
- if (file) {
- var containerIndex = self.state.containerFiles.indexOf(containerFile);
- if (containerIndex > -1) {
- self.state.containerFiles.splice(containerIndex, 1);
- }
-
- return loadingPromises.add('editServerModal',
- promisify(file, 'destroy')()
- .then(function () {
- return updateDockerfileFromState(self.state);
- })
- .catch(errs.handler)
- );
- }
-
+ return loadingPromises.add(
+ 'editServerModal',
+ $q.when()
+ .then(function () {
+ if (containerFile.fileModel) {
+ return containerFile.fileModel;
+ }
+ return promisify(self.state.contextVersion.rootDir.contents, 'fetch')()
+ .then(function () {
+ return self.state.contextVersion.rootDir.contents.models.find(function (fileModel) {
+ return fileModel.attrs.name === containerFile.name;
+ });
+ });
+ })
+ .then(function (file) {
+ if (file) {
+ return promisify(file, 'destroy')()
+ .then(function () {
+ return promisify(self.state.contextVersion.rootDir.contents, 'fetch')();
+ });
+ }
+ })
+ .then(function () {
+ var containerIndex = self.state.containerFiles.indexOf(containerFile);
+ if (containerIndex > -1) {
+ self.state.containerFiles.splice(containerIndex, 1);
+ }
+ })
+ .then(function () {
+ return updateDockerfileFromState(self.state);
+ })
+ .catch(errs.handler)
+ );
}
},
data: {}
@@ -233,33 +248,7 @@ function ContainerFilesController(
);
$rootScope.$broadcast('close-popovers');
},
- remove: function (sshKeyFile) {
- var file = sshKeyFile.fileModel || self.state.contextVersion.rootDir.contents.models.find(function (fileModel) {
- return fileModel.attrs.name === sshKeyFile.name;
- });
- var containerIndex = self.state.containerFiles.indexOf(sshKeyFile);
- if (containerIndex > -1) {
- self.state.containerFiles.splice(containerIndex, 1);
- }
-
- if (file) {
- loadingPromises.add(
- 'editServerModal',
- promisify(file, 'destroy')()
- .then(function () {
- return promisify(self.state.contextVersion.rootDir.contents, 'fetch')();
- })
- .then(function () {
- return updateDockerfileFromState(self.state);
- })
- .catch(errs.handler)
- );
- } else {
- loadingPromises.add('editServerModal', updateDockerfileFromState(self.state))
- .catch(errs.handler);
- }
- $rootScope.$broadcast('close-popovers');
- }
+ remove: this.fileUpload.actions.deleteFile
}
},
getFileDate: function (sshKeyFile) {
diff --git a/client/directives/environment/modals/forms/formFiles/viewFormFiles.jade b/client/directives/environment/modals/forms/formFiles/viewFormFiles.jade
index e7dca402c..85d5de481 100644
--- a/client/directives/environment/modals/forms/formFiles/viewFormFiles.jade
+++ b/client/directives/environment/modals/forms/formFiles/viewFormFiles.jade
@@ -1,18 +1,3 @@
-.help-container(
- ng-if = "SMC.helpCards.getActiveCard().helpPopover.containerFiles && SMC.helpCards.cardIsActiveOnThisContainer(SMC.instance)"
-)
- .help
- button.btn.btn-xs.btn-icon(
- ng-click = "SMC.helpCards.hideActiveCard()"
- )
- svg.iconnables.icons-close
- use(
- xlink:href = "#icons-close"
- )
- span(
- ng-bind-html = "SMC.helpCards.getActiveCard().helpPopover.containerFiles"
- )
-
.ng-hide(
pop-over
pop-over-actions = "CFC.repositoryPopover.actions"
diff --git a/client/directives/environment/modals/forms/formLogs/viewFormLogs.jade b/client/directives/environment/modals/forms/formLogs/viewFormLogs.jade
index 669b5756d..eb4cab684 100644
--- a/client/directives/environment/modals/forms/formLogs/viewFormLogs.jade
+++ b/client/directives/environment/modals/forms/formLogs/viewFormLogs.jade
@@ -1,20 +1,3 @@
-.grid-block.shrink.justify-center.align-center.padding-xs.well.gray.aha-tips(
- ng-if = "\
- !$root.isLoading.setupServerModalIsBuilding && \
- !SMC.isDirty() && \
- SMC.instance.status() === 'buildFailed' \
- "
-)
- svg.grid-content.shrink.iconnables
- use(
- xlink:href = "#icons-life-preserver"
- )
- .grid-content.vertical
- small.grid-content.small Having build problems? Some errors can be resolved by rebuilding the container.
- button.btn.btn-xxs.orange(
- ng-click = "SMC.rebuild(true, true)"
- ) Rebuild Without Cache
-
//- tabs
.btn-group.btn-toggle.btn-toggle-xs(
ng-hide = "$root.featureFlags.fullScreen"
@@ -31,7 +14,7 @@
button.btn.btn-xs.white(
ng-class = "{'active': SMC.page === 'terminal'}"
ng-click = "SMC.page = 'terminal'"
- ng-disabled = "!SMC.instance.containers.models.length"
+ ng-disabled = "!SMC.instance.containers.models.length || SMC.instance.status() !== 'running'"
ng-if = "$root.featureFlags.configTerminal"
) Terminal
@@ -62,24 +45,68 @@ pre.pre.log-wrapper(
ng-if = "SMC.page === 'run' && !SMC.showDebugCmd && $root.featureFlags.webToolbar"
)
+ .popover.bottom.padding-sm.popover-aha.popover-sm.in.sans-serif(
+ ng-if = "SMC.showUrlToolbar && SMC.page === 'run' && !SMC.showDebugCmd && $root.featureFlags.webToolbar"
+ style = "left: 12px; top: 60px;"
+ )
+ .arrow.white
+ small.small.text-gray.float-left Use this URL to check out your application.
+ button.btn.btn-xs.gray.float-right(
+ ng-click = "SMC.showUrlToolbar = false"
+ ) Dismiss
+
//- build logs page
.build-log-wrapper(
build-logs
- instance = 'SMC.instance'
+ scroll-glue
+ instance = "SMC.instance"
ng-if = "SMC.instance"
ng-show = "SMC.page === 'build'"
ng-style = "($root.featureFlags.themeToggle || $root.featureFlags.fullScreenToggle) && {'padding-right': '42px'}"
- scroll-glue
)
//- cmd logs page
.term-js.term-log(
controller = "BoxLogController"
- instance = 'SMC.instance'
+ instance = "SMC.instance"
log-term
ng-if = "SMC.instance.containers.models.length"
ng-show = "SMC.page === 'run'"
)
+ //- terminal
+ .term-js(
+ controller = "TermController"
+ debug-container = "debugContainer"
+ instance = "SMC.instance"
+ tab-item = "item"
+ log-term
+ ng-if = "SMC.instance.containers.models.length"
+ ng-show = "SMC.page === 'terminal'"
+ )
.floating-controls(
ng-include = "'viewFloatingControls'"
)
+
+.grid-block.shrink.justify-center.align-center.padding-xs.well.gray.aha-tips(
+ ng-if = "\
+ !$root.isLoading.setupServerModalIsBuilding && \
+ !SMC.isDirty() && \
+ SMC.instance.status() === 'buildFailed' \
+ "
+)
+ svg.grid-content.shrink.iconnables
+ use(
+ xlink:href = "#icons-life-preserver"
+ )
+ small.grid-content.small
+ //- If build error:
+ | Build problems? Sometimes rebuilding the container can resolve errors, otherwise inspect your build logs.
+ //- IF CMD error:
+ //- | Your container is having trouble running. Check the CMD Logs and your CMD Command.
+ a.link(
+ href = "https://support.runnable.com"
+ target = "_blank"
+ ) View Documentation
+ button.grid-content.shrink.btn.btn-xs.orange(
+ ng-click = "SMC.rebuild(true, true)"
+ ) Rebuild
diff --git a/client/directives/environment/modals/forms/formRepository/repositoryFormDirective.js b/client/directives/environment/modals/forms/formRepository/repositoryFormDirective.js
index 09f20e7f4..426353d3c 100644
--- a/client/directives/environment/modals/forms/formRepository/repositoryFormDirective.js
+++ b/client/directives/environment/modals/forms/formRepository/repositoryFormDirective.js
@@ -9,8 +9,7 @@ require('app')
updateDockerfileFromState,
parseDockerfileForDefaults,
report,
- watchOncePromise,
- helpCards
+ watchOncePromise
) {
return {
restrict: 'A',
@@ -23,7 +22,6 @@ require('app')
startCommandCanDisable: '=?'
},
link: function ($scope, element, attrs) {
- $scope.helpCards = helpCards;
$scope.data = { };
watchOncePromise($scope, 'state.containerFiles', true)
.then(function (containerFiles) {
diff --git a/client/directives/environment/modals/forms/formRepository/viewFormRepository.jade b/client/directives/environment/modals/forms/formRepository/viewFormRepository.jade
index 0730a1cc7..b5993cb03 100644
--- a/client/directives/environment/modals/forms/formRepository/viewFormRepository.jade
+++ b/client/directives/environment/modals/forms/formRepository/viewFormRepository.jade
@@ -1,18 +1,3 @@
-.help-container(
- ng-if = "helpCards.getActiveCard().helpPopover.repositories"
-)
- .help
- button.btn.btn-xs.btn-icon(
- ng-click = "helpCards.hideActiveCard()"
- )
- svg.iconnables.icons-close
- use(
- xlink:href = "#icons-close"
- )
- span(
- ng-bind-html = "helpCards.getActiveCard().helpPopover.repositories"
- )
-
label.label.clearfix
.label-col Packages
small.small (optional)
diff --git a/client/directives/environment/modals/forms/formStack/viewFormStack.jade b/client/directives/environment/modals/forms/formStack/viewFormStack.jade
index 9173ef411..99b578486 100644
--- a/client/directives/environment/modals/forms/formStack/viewFormStack.jade
+++ b/client/directives/environment/modals/forms/formStack/viewFormStack.jade
@@ -19,7 +19,7 @@
)
.grid-block.shrink.align-center.well.well-600.gray.padding-sm
.grid-content
- .strong.text-gray-dark This is a test container.
+ .strong.text-gray-dark This is a test template.
small.small We’ll report your test results on your pull-requests on GitHub.
label.toggle-wrapper.shrink
input.toggle-input(
diff --git a/client/directives/environment/modals/forms/formTranslation/translationRulesDirective.js b/client/directives/environment/modals/forms/formTranslation/translationRulesDirective.js
index ec546ff61..602af3822 100644
--- a/client/directives/environment/modals/forms/formTranslation/translationRulesDirective.js
+++ b/client/directives/environment/modals/forms/formTranslation/translationRulesDirective.js
@@ -7,8 +7,7 @@ require('app')
parseDiffResponse,
promisify,
testAllTransformRules,
- $document,
- helpCards
+ $document
) {
return {
restrict: 'A',
@@ -19,7 +18,6 @@ require('app')
data: '=?'
},
link: function ($scope, elem, attrs) {
- $scope.helpCards = helpCards;
$scope.$watch('state.contextVersion', function (contextVersion) {
if (contextVersion &&
(keypather.get(contextVersion, 'getMainAppCodeVersion().attrs.transformRules.replace.length') ||
diff --git a/client/directives/environment/modals/forms/formTranslation/viewFormTranslation.jade b/client/directives/environment/modals/forms/formTranslation/viewFormTranslation.jade
index 3fd69d1ec..69b054251 100644
--- a/client/directives/environment/modals/forms/formTranslation/viewFormTranslation.jade
+++ b/client/directives/environment/modals/forms/formTranslation/viewFormTranslation.jade
@@ -1,18 +1,3 @@
-.help-container(
- ng-if = "helpCards.getActiveCard().helpPopover.findAndReplace && helpCards.cardIsActiveOnThisContainer(instance)"
-)
- .help
- button.btn.btn-xs.btn-icon(
- ng-click = "helpCards.hideActiveCard()"
- )
- svg.iconnables.icons-close
- use(
- xlink:href = "#icons-close"
- )
- span(
- ng-bind-html = "helpCards.getActiveCard().helpPopover.findAndReplace"
- )
-
.btn-group.btn-toggle.btn-toggle-xs(
ng-init = "page = 'rules'"
)
diff --git a/client/directives/environment/modals/forms/guideForm/guideFormView.jade b/client/directives/environment/modals/forms/guideForm/guideFormView.jade
index 229b434da..7ee073646 100644
--- a/client/directives/environment/modals/forms/guideForm/guideFormView.jade
+++ b/client/directives/environment/modals/forms/guideForm/guideFormView.jade
@@ -1,8 +1,9 @@
-p.p.grid-content.shrink.text-center.text-gray.padding-sm You have the basic parts of your application configured! Many applications require additional configuration. Use our tools to configure options specific to your application before building.
+p.p.grid-content.shrink.text-center.text-gray.padding-sm You have the basic parts of your application set up and ready to build! If your application requires additional configuration, use our tools to change options before building.
a.grid-content.shrink.link.small.text-gray(
- href = "#"
+ href = "https://support.runnable.com/hc/en-us/categories/201194573-Quickstarts"
+ target = "_blank"
) View Setup Guide
svg.iconnables.icons-external
use(
xlink:href= "#icons-link-external"
- )
\ No newline at end of file
+ )
diff --git a/client/directives/environment/modals/forms/whitelistForm/whitelistFormView.jade b/client/directives/environment/modals/forms/whitelistForm/whitelistFormView.jade
index 7864ca67e..aa0b1fd2a 100644
--- a/client/directives/environment/modals/forms/whitelistForm/whitelistFormView.jade
+++ b/client/directives/environment/modals/forms/whitelistForm/whitelistFormView.jade
@@ -2,7 +2,7 @@
.grid-block.shrink.align-center.well.well-600.gray.padding-sm
.grid-content
.strong.text-gray-dark Block External Access
- small.small Prevents external access to this container. Internal access between containers is still allowed.
+ small.small Prevents external access to this template. Internal access between containers is still allowed.
label.grid-content.toggle-wrapper.shrink
input.toggle-input(
ng-disabled = "WFC.isIsolationGroupMaster"
diff --git a/client/directives/environment/modals/modalEditServer/editServerModalController.js b/client/directives/environment/modals/modalEditServer/editServerModalController.js
index 17b70323f..f870b7fb7 100644
--- a/client/directives/environment/modals/modalEditServer/editServerModalController.js
+++ b/client/directives/environment/modals/modalEditServer/editServerModalController.js
@@ -12,7 +12,6 @@ function EditServerModalController(
cleanStartCommand,
errs,
fetchInstancesByPod,
- helpCards,
instance,
isTabNameValid,
keypather,
@@ -24,7 +23,6 @@ function EditServerModalController(
close
) {
var SMC = this;
- SMC.helpCards = helpCards;
var parentController = $controller('ServerModalController as SMC', { $scope: $scope });
angular.extend(SMC, {
@@ -34,6 +32,7 @@ function EditServerModalController(
'enableMirrorMode': parentController.enableMirrorMode.bind(SMC),
'getNumberOfOpenTabs': parentController.getNumberOfOpenTabs.bind(SMC),
'getUpdatePromise': parentController.getUpdatePromise.bind(SMC),
+ 'hasOpenPorts': parentController.hasOpenPorts.bind(SMC),
'insertHostName': parentController.insertHostName.bind(SMC),
'isDirty': parentController.isDirty.bind(SMC),
'openDockerfile': parentController.openDockerfile.bind(SMC),
diff --git a/client/directives/environment/modals/modalRename/viewModalRename.jade b/client/directives/environment/modals/modalRename/viewModalRename.jade
index 61022489b..16ff2ff31 100644
--- a/client/directives/environment/modals/modalRename/viewModalRename.jade
+++ b/client/directives/environment/modals/modalRename/viewModalRename.jade
@@ -11,7 +11,7 @@
name = "rename"
)
label.label.clearfix
- .label-col Rename Container
+ .label-col Rename Template
.input-col
div(
ng-class = "{\
@@ -32,7 +32,7 @@
)
ul.list.list-bulleted.list-validation
- li.list-item Choose a unique name in your Sandbox
+ li.list-item Choose a unique name for this template
li.list-item(
ng-class = "{'ng-invalid': rename.$error.pattern}"
) Use letters, numbers, and hyphens (-)
@@ -55,4 +55,4 @@
) Cancel
button.btn.btn-md.green.float-right(
ng-disabled = "!rename.newName.$viewValue.length || rename.$invalid"
- ) Rename Container
\ No newline at end of file
+ ) Rename Template
diff --git a/client/directives/environment/modals/modalSetupServer/pages/newRepositorySelectionView.jade b/client/directives/environment/modals/modalSetupServer/pages/newRepositorySelectionView.jade
index ee4896a27..1e0d0a131 100644
--- a/client/directives/environment/modals/modalSetupServer/pages/newRepositorySelectionView.jade
+++ b/client/directives/environment/modals/modalSetupServer/pages/newRepositorySelectionView.jade
@@ -30,7 +30,7 @@
)
.p.empty
.h3.strong Uh oh!
- | We couldn’t find any repositories for this organization. If you think you think this is a mistake,
+ | We couldn’t find any repositories for this organization. If you think this is a mistake,
a.link(
intercom-link
intro-message = "This thing wont fetch my GitHub repos."
@@ -51,56 +51,55 @@ ul.list.list-servers(
| ‘{{MC.repoFilter}}’.
//- add active class when loading
- li.list-item.multi-line.text-overflow(
+ li.grid-block.align-center.list-item.multi-line.text-overflow(
ng-disabled = "$root.isLoading[MC.name + 'SingleRepo']"
ng-click = "!$root.isLoading[MC.name + 'SingleRepo'] && MC.setRepo(repo, goToPanel)"
ng-repeat = "\
repo in MC.githubRepos.models | \
repos: MC.repoFilter | \
- orderBy: '-attrs.updated_at' as noResults\
+ orderBy: '-attrs.pushed_at' as noResults\
"
ng-class = "{ \
'active': repo.loading, \
'disabled': $root.isLoading[MC.name + 'SingleRepo'] \
}"
- ) {{ repo.attrs.name }}
- .row.row-author(
- ng-if = "$root.featureFlags.inviteFlows"
- )
- //- if invite flows...
- .btn-user.text-overflow(
- ng-class = "{'active': MC.state.active}"
- ng-include = "'userButtonView'"
- pop-over
- pop-over-active = "MC.state.active"
- pop-over-options = "{\"left\":-24,\"top\":26}"
- pop-over-template = "userPopoverView"
- )
- span.small(
+ )
+ .grid-content.text-overflow(
+ title = "{{ repo.attrs.name }}"
+ ) {{ repo.attrs.name }}
+ .row.row-author(
ng-if = "$root.featureFlags.inviteFlows"
- ) {{repo.attrs.updated_at | timeFrom}}
- small.small(
- ng-if = "!$root.featureFlags.inviteFlows"
- ) {{repo.attrs.updated_at | timeFrom}}
- svg.iconnables.icons-server(
- ng-if = "$root.featureFlags.multipleRepositoryContainers"
- pop-over
- pop-over-hover-trigger
- pop-over-options = "{\"top\":27,\"centered\":true}"
- pop-over-template = "viewCountainerTooltip"
- pop-over-trigger = "hover"
)
- use(
- xlink:href = "#icons-server"
+ //- if invite flows...
+ .btn-user.text-overflow(
+ ng-class = "{'active': MC.state.active}"
+ ng-include = "'userButtonView'"
+ pop-over
+ pop-over-active = "MC.state.active"
+ pop-over-options = "{\"left\":-22,\"top\":26}"
+ pop-over-template = "userPopoverView"
)
- button.btn.btn-sm.btn-icon.btn-add(
- ng-if = "!repo.loading"
- )
- svg.iconnables.icons-add
- use(
- xlink:href = "#icons-add"
+ span.small(
+ ng-if = "$root.featureFlags.inviteFlows"
+ ) {{repo.attrs.pushed_at | timeFrom}}
+ small.small(
+ ng-if = "!$root.featureFlags.inviteFlows"
+ ) {{repo.attrs.pushed_at | timeFrom}}
+ svg.iconnables.icons-server(
+ ng-if = "$root.featureFlags.multipleRepositoryContainers"
+ pop-over
+ pop-over-hover-trigger
+ pop-over-options = "{\"top\":27,\"centered\":true}"
+ pop-over-template = "viewCountainerTooltip"
+ pop-over-trigger = "hover"
)
- .spinner-wrapper.spinner-sm.spinner-green.in(
+ use(
+ xlink:href = "#icons-server"
+ )
+ button.grid-content.shrink.btn.btn-sm.btn-icon.btn-add(
+ ng-if = "!repo.loading"
+ ) Select
+ .grid-content.shrink.spinner-wrapper.spinner-sm.spinner-green.in(
ng-if = "repo.loading"
ng-include = "'spinner'"
)
diff --git a/client/directives/environment/modals/modalSetupServer/pages/templateSelectSectionView.jade b/client/directives/environment/modals/modalSetupServer/pages/templateSelectSectionView.jade
index b10d6f94d..74c931a8b 100644
--- a/client/directives/environment/modals/modalSetupServer/pages/templateSelectSectionView.jade
+++ b/client/directives/environment/modals/modalSetupServer/pages/templateSelectSectionView.jade
@@ -19,7 +19,7 @@
ul.list.list-servers(
ng-if = "!$root.isLoading.newContainerModalTemplates"
)
- li.list-item.grid-block(
+ li.grid-block.align-center.list-item(
ng-click = "MC.setTemplate(dependency, goToPanel)"
ng-repeat = "\
dependency in MC.templateServers.models | \
@@ -28,14 +28,10 @@ ul.list.list-servers(
orderBy:'attrs.name'\
"
)
- img.img(
+ img.grid-content.shrink.img(
height = "36"
ng-src = "/build/images/logos/logo-icon-{{dependency.attrs.name.toLowerCase()}}.png"
width = "36"
)
- | {{dependency.attrs.name}}
- button.btn.btn-sm.btn-icon.btn-add
- svg.iconnables.icons-add
- use(
- xlink:href = "#icons-add"
- )
+ .grid-content {{dependency.attrs.name}}
+ button.grid-content.shrink.btn.btn-sm.btn-icon.btn-add Select
diff --git a/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalController.js b/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalController.js
index 7ef90175e..bd5813748 100644
--- a/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalController.js
+++ b/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalController.js
@@ -4,34 +4,33 @@ require('app')
.controller('SetupMirrorServerModalController', SetupMirrorServerModalController);
function SetupMirrorServerModalController(
- $scope,
$controller,
$q,
$rootScope,
+ $scope,
+ ahaGuide,
cardInfoTypes,
createAndBuildNewContainer,
- createBuildFromContextVersionId,
errs,
eventTracking,
- fetchUser,
- helpCards,
+ fetchInstancesByPod,
isTabNameValid,
keypather,
loading,
loadingPromises,
- ModalService,
promisify,
- OpenItems,
- TAB_VISIBILITY,
- updateDockerfileFromState,
+ // everything below comes from the modal open
+ build,
close,
instanceName,
+ masterBranch,
+ OpenItems,
repo,
- build,
- masterBranch
+ TAB_VISIBILITY
) {
var SMC = this; // Server Modal Controller (shared with EditServerModalController)
- SMC.helpCards = helpCards;
+ SMC.isAddingFirstRepo = ahaGuide.isAddingFirstRepo;
+ SMC.showUrlToolbar = SMC.isAddingFirstRepo();
var parentController = $controller('ServerModalController as SMC', { $scope: $scope });
angular.extend(SMC, {
@@ -43,6 +42,8 @@ function SetupMirrorServerModalController(
'getElasticHostname': parentController.getElasticHostname.bind(SMC),
'getNumberOfOpenTabs': parentController.getNumberOfOpenTabs.bind(SMC),
'getUpdatePromise': parentController.getUpdatePromise.bind(SMC),
+ 'handleInstanceUpdate': parentController.handleInstanceUpdate.bind(SMC),
+ 'hasOpenPorts': parentController.hasOpenPorts.bind(SMC),
'insertHostName': parentController.insertHostName.bind(SMC),
'isDirty': parentController.isDirty.bind(SMC),
'openDockerfile': parentController.openDockerfile.bind(SMC),
@@ -113,6 +114,11 @@ function SetupMirrorServerModalController(
repoSelected: true
});
+ fetchInstancesByPod()
+ .then(function (instances) {
+ SMC.data.instances = instances;
+ });
+
SMC.state.mainRepoContainerFile.name = repo.attrs.name;
SMC.state.promises.contextVersion = $q.when(SMC.state.contextVersion);
@@ -124,6 +130,10 @@ function SetupMirrorServerModalController(
SMC.openDockerfile(SMC.state, SMC.openItems)
.finally(function () {
loading(SMC.name, false);
+ })
+ .catch(function(err) {
+ errs.handler(err);
+ close();
});
$scope.$on('resetStateContextVersion', function ($event, contextVersion, showSpinner) {
@@ -182,6 +192,7 @@ function SetupMirrorServerModalController(
if (instance) {
SMC.instance = instance;
SMC.state.instance = instance;
+ SMC.state.instance.on('update', SMC.handleInstanceUpdate);
// Reset the opts, in the same way as `EditServerModalController`
SMC.state.opts = {
env: keypather.get(instance, 'attrs.env') || [],
diff --git a/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalView.jade b/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalView.jade
index 039dd2c6e..23f7b92de 100644
--- a/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalView.jade
+++ b/client/directives/environment/modals/modalSetupServer/setupMirrorServerModalView.jade
@@ -1,13 +1,12 @@
.modal-backdrop.in
.grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
- ng-if = "$root.featureFlags.aha1"
- ng-include = "'ahaGuideView'"
- ng-init = "\
- state.showStep = 1;\
- state.showSubStep = 6;\
- state.fromMirroring = true;\
- "
+ aha-guide
+ step-index = 1
+ sub-step-index = 6
+ sub-step = "filesMirror"
+ ng-if = "SMC.isAddingFirstRepo()"
)
+
form.modal-dialog.modal-edit(
name = "SMC.serverForm"
ng-include = "'serverModalView'"
diff --git a/client/directives/environment/modals/modalSetupServer/setupServerModalController.js b/client/directives/environment/modals/modalSetupServer/setupServerModalController.js
index cc6e68d4c..94264d480 100644
--- a/client/directives/environment/modals/modalSetupServer/setupServerModalController.js
+++ b/client/directives/environment/modals/modalSetupServer/setupServerModalController.js
@@ -9,13 +9,15 @@ function SetupServerModalController(
$filter,
$q,
$rootScope,
+ ahaGuide,
cardInfoTypes,
createAndBuildNewContainer,
createBuildFromContextVersionId,
+ dockerfileType,
errs,
eventTracking,
fetchDockerfileFromSource,
- helpCards,
+ fetchInstancesByPod,
isTabNameValid,
keypather,
loading,
@@ -31,7 +33,8 @@ function SetupServerModalController(
masterBranch
) {
var SMC = this; // Server Modal Controller (shared with EditServerModalController)
- SMC.helpCards = helpCards;
+ SMC.isAddingFirstRepo = ahaGuide.isAddingFirstRepo;
+ SMC.showUrlToolbar = SMC.isAddingFirstRepo();
var parentController = $controller('ServerModalController as SMC', { $scope: $scope });
angular.extend(SMC, {
@@ -43,6 +46,8 @@ function SetupServerModalController(
'getElasticHostname': parentController.getElasticHostname.bind(SMC),
'getNumberOfOpenTabs': parentController.getNumberOfOpenTabs.bind(SMC),
'getUpdatePromise': parentController.getUpdatePromise.bind(SMC),
+ 'handleInstanceUpdate': parentController.handleInstanceUpdate.bind(SMC),
+ 'hasOpenPorts': parentController.hasOpenPorts.bind(SMC),
'insertHostName': parentController.insertHostName.bind(SMC),
'isDirty': parentController.isDirty.bind(SMC),
'openDockerfile': parentController.openDockerfile.bind(SMC),
@@ -110,14 +115,26 @@ function SetupServerModalController(
// If a repo is passed into this controller, select that repo
angular.extend(SMC.state, {
- repo: repo,
- build: build,
- contextVersion: build.contextVersion,
acv: build.contextVersion.getMainAppCodeVersion(),
+ advanced: dockerfileType,
branch: masterBranch,
- repoSelected: true,
- advanced: false
+ build: build,
+ contextVersion: build.contextVersion,
+ repo: repo,
+ repoSelected: true
});
+
+ fetchInstancesByPod()
+ .then(function (instances) {
+ SMC.data.instances = instances;
+ });
+
+ // if the blank docker file is chosen, we need to load it because it is already available
+ if (dockerfileType === 'blankDockerfile') {
+ SMC.openDockerfile({contextVersion: build.contextVersion}, SMC.openItems);
+ SMC.changeTab('buildfiles');
+ }
+
SMC.state.mainRepoContainerFile.name = repo.attrs.name;
SMC.state.promises.contextVersion = $q.when(SMC.state.contextVersion);
@@ -235,7 +252,7 @@ function SetupServerModalController(
var createPromise = loadingPromises.finished(SMC.name)
.then(function () {
loadingPromises.clear(SMC.name);
- if (!SMC.state.advanced) {
+ if (!SMC.state.advanced || SMC.state.advanced === 'blankDockerfile') {
return updateDockerfileFromState(SMC.state, false, true);
}
return true;
@@ -256,6 +273,7 @@ function SetupServerModalController(
if (instance) {
SMC.instance = instance;
SMC.state.instance = instance;
+ SMC.state.instance.on('update', SMC.handleInstanceUpdate);
// Reset the opts, in the same way as `EditServerModalController`
SMC.state.opts = {
env: keypather.get(instance, 'attrs.env') || [],
@@ -329,6 +347,9 @@ function SetupServerModalController(
};
SMC.isPrimaryButtonDisabled = function (serverFormInvalid) {
+ if (SMC.state.advanced === 'blankDockerfile' || SMC.state.advanced === 'isMirroringDockerfile') {
+ return false;
+ }
return (
(SMC.state.step === 2 && SMC.repositoryForm && SMC.repositoryForm.$invalid) ||
$filter('selectedStackInvalid')(SMC.state.selectedStack)
diff --git a/client/directives/environment/modals/modalSetupServer/setupServerModalView.jade b/client/directives/environment/modals/modalSetupServer/setupServerModalView.jade
index d0c532e74..7ac7f7f4a 100644
--- a/client/directives/environment/modals/modalSetupServer/setupServerModalView.jade
+++ b/client/directives/environment/modals/modalSetupServer/setupServerModalView.jade
@@ -1,11 +1,17 @@
.modal-backdrop.in
.grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
- ng-if = "$root.featureFlags.aha1"
- ng-include = "'ahaGuideView'"
- ng-init = "\
- state.showStep = 1;\
- state.showSubStep = 4;\
- "
+ aha-guide
+ ng-if = "SMC.state.advanced !== 'blankDockerfile' && SMC.isAddingFirstRepo()"
+ step-index = 1
+ sub-step = "repository"
+ sub-step-index = 4
+ )
+ .grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
+ aha-guide
+ ng-if = "SMC.state.advanced === 'blankDockerfile' && SMC.isAddingFirstRepo()"
+ step-index = 1
+ sub-step = "buildfiles"
+ sub-step-index = 6
)
form.modal-dialog.modal-edit(
name = "SMC.serverForm"
diff --git a/client/directives/environment/modals/nameNonRepoContainer/nameNonRepoContainerView.jade b/client/directives/environment/modals/nameNonRepoContainer/nameNonRepoContainerView.jade
index 470f60b1c..5df5fa1c3 100644
--- a/client/directives/environment/modals/nameNonRepoContainer/nameNonRepoContainerView.jade
+++ b/client/directives/environment/modals/nameNonRepoContainer/nameNonRepoContainerView.jade
@@ -1,7 +1,7 @@
.modal-backdrop
.modal-dialog.modal-sm.modals-rename
header.modal-header
- h1.modal-heading.text-overflow Create Container
+ h1.modal-heading.text-overflow Create Template
svg.iconnables.icons-close(
ng-click = "MC.actions.cancel()"
)
@@ -13,7 +13,7 @@
name = "nameForm"
)
label.label.clearfix
- .label-col Container Name
+ .label-col Template Name
.input-col
div(
ng-attr-data-length = "{{19 - nameForm.newName.$viewValue.length}}"
@@ -38,7 +38,7 @@
ul.list.list-bulleted.list-validation
li.list-item(
ng-class = "{'ng-invalid': nameForm.$error.unique}"
- ) Choose a unique name in your Sandbox
+ ) Choose a unique name for this template
li.list-item(
ng-class = "{'ng-invalid': nameForm.$error.pattern || nameForm.$error.noDoubleDash}"
) Use letters, numbers, and single hyphens (-)
@@ -58,4 +58,4 @@
ng-include = "'spinner'"
ng-if = "MC.saving"
)
- span Create Container
+ span Create Template
diff --git a/client/directives/environment/modals/popovers/viewPopoverFileOptions.jade b/client/directives/environment/modals/popovers/viewPopoverFileOptions.jade
index 8143e6cc2..d84be8544 100644
--- a/client/directives/environment/modals/popovers/viewPopoverFileOptions.jade
+++ b/client/directives/environment/modals/popovers/viewPopoverFileOptions.jade
@@ -1,10 +1,10 @@
.popover.menu.bottom(
- ng-class = "{in: active}"
+ ng-class = "{'in': active}"
ng-style = "popoverStyle.getStyle()"
style = "transform-origin: 90% 0"
)
.arrow.white(
- style = "left: auto; right: 3px"
+ style = "left: auto; right: 2px"
)
.popover-content
ul.popover-list
diff --git a/client/directives/environment/modals/popovers/viewPopoverFilesUpload.jade b/client/directives/environment/modals/popovers/viewPopoverFilesUpload.jade
index 13744709a..aa6658361 100644
--- a/client/directives/environment/modals/popovers/viewPopoverFilesUpload.jade
+++ b/client/directives/environment/modals/popovers/viewPopoverFilesUpload.jade
@@ -49,7 +49,7 @@
ng-model = "data.commands"
spellcheck = "false"
)
- small.small Add scripts to be run before your container is started.
+ small.small Add scripts to run before your container is started.
.popover-footer.clearfix
button.btn.btn-sm.green(
diff --git a/client/directives/environment/modals/popovers/viewPopoverRenameContainer.jade b/client/directives/environment/modals/popovers/viewPopoverRenameContainer.jade
index 212fbd529..5b0031f90 100644
--- a/client/directives/environment/modals/popovers/viewPopoverRenameContainer.jade
+++ b/client/directives/environment/modals/popovers/viewPopoverRenameContainer.jade
@@ -4,7 +4,7 @@
ng-class = "{'in': active}"
)
.popover-content
- h3.popover-title Rename Container
+ h3.popover-title Rename Template
//- wrapper for validation
div(
@@ -26,7 +26,7 @@
)
ul.list.list-bulleted.list-validation
- li.list-item Choose a unique name in your Sandbox
+ li.list-item Choose a unique name for this template
li.list-item(
ng-class = "{'ng-invalid': rename.$error.pattern}"
) Use letters, numbers, and hyphens (-)
@@ -44,7 +44,7 @@
.popover-footer.clearfix
button.btn.btn-sm.green(
ng-disabled = "!rename.newName.$viewValue.length || rename.$invalid"
- ) Rename Container
+ ) Rename Template
button.btn.btn-sm.gray.btn-cancel(
ng-click = "actions.cancel()"
) Cancel
\ No newline at end of file
diff --git a/client/directives/environment/modals/serverModalController.js b/client/directives/environment/modals/serverModalController.js
index 02f54013e..8a4b49fc3 100644
--- a/client/directives/environment/modals/serverModalController.js
+++ b/client/directives/environment/modals/serverModalController.js
@@ -9,11 +9,10 @@ function ServerModalController(
$rootScope,
$scope,
createBuildFromContextVersionId,
+ configUserContentDomain,
errs,
eventTracking,
fetchDockerfileForContextVersion,
- hasKeypaths,
- helpCards,
keypather,
ModalService,
loading,
@@ -95,7 +94,7 @@ function ServerModalController(
toRedeploy = !toRebuild && rebuildOrRedeploy === 'update';
loadingPromises.clear(SMC.name);
- if (!SMC.openItems.isClean()) {
+ if (!SMC.openItems.isClean() || SMC.state.advanced === 'blankDockerfile') {
return SMC.openItems.updateAllFiles();
}
})
@@ -262,6 +261,10 @@ function ServerModalController(
}
};
+ this.hasOpenPorts = function() {
+ return !!keypather.get(this, 'instance.attrs.container.ports');
+ };
+
this.onEnvChange = function (newEnvArray, oldEnvArray) {
var SMC = this;
if (!newEnvArray) { return; }
@@ -273,11 +276,15 @@ function ServerModalController(
this.resetStateContextVersion = function (contextVersion, shouldParseDockerfile) {
var SMC = this;
- if (keypather.get(contextVersion, 'attrs.buildDockerfilePath')) {
- SMC.state.advanced = 'isMirroringDockerfile';
- } else {
- SMC.state.advanced = !!keypather.get(contextVersion, 'attrs.advanced');
+
+ if (SMC.state.advanced !== 'blankDockerfile') {
+ if (keypather.get(contextVersion, 'attrs.buildDockerfilePath')) {
+ SMC.state.advanced = 'isMirroringDockerfile';
+ } else {
+ SMC.state.advanced = !!keypather.get(contextVersion, 'attrs.advanced');
+ }
}
+
SMC.state.promises.contextVersion = loadingPromises.start(
SMC.name,
promisify(contextVersion, 'deepCopy')()
@@ -337,7 +344,6 @@ function ServerModalController(
$rootScope.$broadcast('close-popovers');
return SMC.rebuildAndOrRedeploy()
.then(function () {
- helpCards.refreshActiveCard();
$rootScope.$broadcast('alert', {
type: 'success',
text: 'Changes Saved'
@@ -346,6 +352,16 @@ function ServerModalController(
});
};
+ this.handleInstanceUpdate = function () {
+ var buildStatus = this.instance.status();
+ $rootScope.$broadcast('buildStatusUpdated', {
+ status: buildStatus
+ });
+ if (buildStatus === 'running') {
+ this.page = 'run';
+ }
+ };
+
this.switchToMirrorMode = function (state, openItems, dockerfile) {
var SMC = this;
return loadingPromises.add(SMC.name, promisify(state.contextVersion, 'update')({
@@ -362,7 +378,7 @@ function ServerModalController(
var SMC = this;
var errorMessage = '';
errorMessage += '# There was an error retrieving the Dockerfile from your repo';
- errorMessage += '# This error occured when disabling mirrorring your Dockerfile';
+ errorMessage += '# This error occured when disabling mirroring your Dockerfile';
var dockerfileBody = keypather.get(state, 'dockerfile.attrs.body') || errorMessage;
return loadingPromises.add(SMC.name, promisify(state.contextVersion, 'update')({
advanced: true,
@@ -479,8 +495,7 @@ function ServerModalController(
var repo = SMC.state.repo;
var repoName = repo.attrs.name;
var repoOwner = repo.attrs.owner.login.toLowerCase();
- var domain = SMC.state.repo.opts.userContentDomain;
- return repoName + '-staging-' + repoOwner + '.' + domain;
+ return repoName + '-staging-' + repoOwner + '.' + configUserContentDomain;
}
return '';
};
@@ -499,14 +514,15 @@ function ServerModalController(
};
/**
- * Updates the this.instance with all the states, emits the Changes Saved alert, and refreshes the
- * help cards. If a failure occurs, the cv is reset, and the error propagates.
+ * Updates the this.instance with all the states, emits the Changes Saved alert.
+ * If a failure occurs, the cv is reset, and the error propagates.
* @returns {Promise} Resolves when the instance update has been started, and the cv has been
* reset. The error is uncaught, so a catch should be added to this
*/
this.getUpdatePromise = this.saveInstanceAndRefreshCards;
this.changeTab = function (tabname) {
+ $rootScope.$broadcast('updatedTab', tabname);
var SMC = this;
if (keypather.get(SMC, 'serverForm.$invalid')) {
if (keypather.get(SMC, 'serverForm.$error.required.length')) {
diff --git a/client/directives/environment/modals/setupTemplate/setupTemplateModalController.js b/client/directives/environment/modals/setupTemplate/setupTemplateModalController.js
index caebf20a0..076b8b7f4 100644
--- a/client/directives/environment/modals/setupTemplate/setupTemplateModalController.js
+++ b/client/directives/environment/modals/setupTemplate/setupTemplateModalController.js
@@ -15,7 +15,6 @@ function SetupTemplateModalController(
fetchInstances,
getNewForkName,
promisify,
- helpCards,
ModalService,
close,
isolation
@@ -26,7 +25,6 @@ function SetupTemplateModalController(
STMC.templateServers = servers;
})
.catch(errs.handler);
- STMC.helpCard = helpCards.getActiveCard();
STMC.close = close;
STMC.addServerFromTemplate = function (sourceInstance) {
var instancesPromise = null;
diff --git a/client/directives/environment/newUserPrompt.jade b/client/directives/environment/newUserPrompt.jade
index f62b73258..db6159008 100644
--- a/client/directives/environment/newUserPrompt.jade
+++ b/client/directives/environment/newUserPrompt.jade
@@ -5,7 +5,7 @@ svg.iconnables.icons-close(
xlink:href = "#icons-close"
)
h1.grid-content.h1.justify-center.text-center Welcome to Runnable!
-p.p.text-center You made it to the configuration page, where you set up your app. We’ve got guides for common stacks to help you get started.
+p.p.text-center You made it to the template page, where you set up your app. We’ve got guides for common stacks to help you get started.
.grid-block
a.grid-content.shrink.btn.btn-xs.purple(
href = "https://runnable.zendesk.com/hc/en-us/articles/208383313-Node-js-"
diff --git a/client/directives/environment/tooltips/viewTooltipTools.jade b/client/directives/environment/tooltips/viewTooltipTools.jade
index a611c309a..995b0582c 100644
--- a/client/directives/environment/tooltips/viewTooltipTools.jade
+++ b/client/directives/environment/tooltips/viewTooltipTools.jade
@@ -29,4 +29,4 @@
xlink:href = "#icons-keys-files"
)
| Files & SSH Keys
- small.p.small Your configuration is saved when you enable editing and will be restored if you disable editing in the future.
+ small.p.small Your template is saved when you enable editing and will be restored if you disable editing in the future.
diff --git a/client/directives/help/viewHelpPopover.jade b/client/directives/help/viewHelpPopover.jade
deleted file mode 100644
index 05011b5a6..000000000
--- a/client/directives/help/viewHelpPopover.jade
+++ /dev/null
@@ -1,68 +0,0 @@
-.popover.help(
- ng-class = "{'in': active}"
- ng-style = "popoverStyle.getStyle()"
-)
- .help-lists-wrapper
- ul.triggered-help-list
- li.grid-block.triggered-help-item.clearfix(
- ng-repeat = "helpItem in data.triggered"
- )
- button.btn.btn-icon.btn-icon-xs(
- ng-click = "actions.ignoreHelp(helpItem)"
- )
- svg.iconnables
- use(
- xlink:href = "#icons-close"
- )
- p.p.grid-content(
- ng-bind-html= "helpItem.label"
- )
- button.btn.btn-xs.blue.grid-content.shrink(
- ng-click = "actions.getHelp(helpItem)"
- ) Show Me
- .general-help-container
- .strong General Help
- ul.general-help-list
- li.general-help-item(
- ng-repeat = "helpItem in data.general"
- ng-hide = "!showMore && $index > 5"
- ng-click = "actions.getHelp(helpItem)"
- ng-bind-html= "helpItem.label"
- )
- li.general-help-item
- a.link(
- target = "_blank"
- href = "http://www.youtube.com/watch?v=_uwPKIH990E"
- ) View our Getting Started video
- svg.iconnables.icons-link-external
- use(
- xlink:href = "#icons-link-external"
- )
- li.general-help-item
- a.link(
- target = "_blank"
- href = "https://runnable.zendesk.com/hc/en-us/articles/205184275-How-can-containers-in-my-Runnable-Sandbox-communicate-with-each-other-"
- ) Connect two containers together
- svg.iconnables.icons-link-external
- use(
- xlink:href = "#icons-link-external"
- )
-
- button.btn(
- ng-click = "POC.closePopover()"
- )
- svg.iconnables(
- ng-if = '!data.triggered.length'
- )
- use(
- xlink:href = "#icons-close"
- )
-
- | {{data.triggered.length ? 'Less Help' : 'Close'}}
-
- svg.iconnables(
- ng-if = 'data.triggered.length'
- )
- use(
- xlink:href = "#icons-arrow-down"
- )
diff --git a/client/directives/instances/instance/branchMenuPopover/branchMenuPopoverView.jade b/client/directives/instances/instance/branchMenuPopover/branchMenuPopoverView.jade
index f40d6c0af..621bd4f78 100644
--- a/client/directives/instances/instance/branchMenuPopover/branchMenuPopoverView.jade
+++ b/client/directives/instances/instance/branchMenuPopover/branchMenuPopoverView.jade
@@ -1,11 +1,27 @@
.popover.menu.right.popover-branch-menu(
ng-class = "{'in': active}"
- ng-style = "popoverStyle.getStyle()"
+ ng-style = "popoverStyle.getStyle(CIS.instanceBranches)"
)
- .arrow.white
+ .grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
+ ng-if = "$root.featureFlags.aha && CIS.instanceBranches.length && CIS.isAddingFirstBranch()"
+ aha-guide
+ step-index = 2
+ sub-step = "selectBranch"
+ )
+ .grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
+ ng-if = "$root.featureFlags.aha && CIS.instanceBranches && !CIS.instanceBranches.length && CIS.isAddingFirstBranch()"
+ aha-guide
+ step-index = 2
+ sub-step = "noBranches"
+ )
+
+ .arrow.white(
+ ng-style = "popoverStyle.getArrowStyle(CIS.instanceBranches)"
+ )
.grid-block.vertical.popover-content.empty(
ng-if = "$root.featureFlags.autoIsolationSetup"
)
+
svg.svg.grid-block
use(
xlink:href = "#icons-branch-burst"
@@ -16,10 +32,10 @@
) Set Up Branches
animated-panel-container.popover-views(
- ng-if = "!$root.featureFlags.autoIsolationSetup"
+ ng-if = "!$root.featureFlags.autoIsolationSetup && !CIS.isPopoverOpen()"
)
+ //- this should be the default panel when auto-isolation is implemented
animated-panel(
- default = "true"
name = "branchMenu"
)
.popover-view
@@ -62,12 +78,15 @@
)
| Include Containers…
animated-panel(
+ default = "true"
name = "addBranch"
)
.popover-view.fade(
ng-class = "{'in': isActivePanel()}"
)
- .popover-header
+ .popover-header(
+ ng-if = "$root.featureFlags.autoIsolation"
+ )
svg.btn.btn-sm.iconnables.icons-arrow-backward(
ng-class = "{'in': isActivePanel()}"
ng-click = "goToPanel('branchMenu', 'back');"
@@ -76,48 +95,74 @@
xlink:href = "#icons-arrow-down"
)
| Add Branch
- .popover-content(
- ng-init = "state.branchesLoaded = null"
- )
- .text-center.text-gray.small.padding-md(
- ng-if = "branch.length === 0"
- ) There are no branches to add.
-
+ .popover-content
.spinner-wrapper.spinner-sm.spinner-gray.spinner-center.in(
- ng-click = "state.branchesLoaded = true"
- ng-if = "!state.branchesLoaded"
+ ng-if = "$root.isLoading.fetchingBranches"
ng-include = "'spinner'"
)
.padding-xxs(
- ng-if = "state.branchesLoaded"
+ ng-if = "CIS.instanceBranches"
)
+ .grid-block.shrink.align-center.well.gray.padding-xxs(
+ ng-if = "!$root.featureFlags.autoIsolation"
+ )
+ .grid-content
+ .small Automatically add branches as they’re updated on GitHub.
+ button.btn.btn-xs.btn-permissions(
+ internal-modal-helper = "inviteAdminModalView"
+ ng-if = "$root.featureFlags.webhooks"
+ ng-include = "'permissionsButtonView'"
+ )
+ label.grid-content.shrink.toggle-wrapper
+ input.toggle-input(
+ ng-click = "CIS.setAutofork()"
+ ng-disabled = "$root.featureFlags.webhooks"
+ ng-checked = "!CIS.poppedInstance.attrs.shouldNotAutofork"
+ type = "checkbox"
+ )
+ .toggle-group.toggle-sm
input.input.input-xs.input-search(
- placeholder = "Filter"
+ ng-disabled = "$root.isLoading['buildingForkedBranch']"
+ ng-model = "CIS.branchQuery"
+ placeholder = "Filter by name"
required
type = "search"
+ ng-if = "CIS.instanceBranches.length"
)
ul.list.popover-list(
- ng-if = "state.branchesLoaded"
+ ng-if = "CIS.instanceBranches.length"
)
- //- show when loading paginated list
- //- li.list-item.padding-md
- .spinner-wrapper.spinner-sm.spinner-gray.spinner-center.in(
+ li.grid-block.align-center.list-item.popover-list-item(
+ ng-class = "{\
+ 'disabled': $root.isLoading['buildingForkedBranch'] && !$root.isLoading[branch.attrs.name],\
+ 'active': $root.isLoading['buildingForkedBranch'] && $root.isLoading[branch.attrs.name]\
+ }"
+ ng-repeat = "branch in CIS.getFilteredBranches()"
+ ng-click = "CIS.forkBranchFromInstance(branch, POC.closePopover);"
+ )
+ svg.grid-content.shrink.iconnables.icons-branch
+ use(
+ xlink:href = "#icons-branch-alt"
+ )
+ .grid-content.text-overflow(
+ title = "{{ branch.attrs.name }}"
+ ) {{ branch.attrs.name }}
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add(
+ ng-if = "!$root.isLoading[branch.attrs.name]"
+ ) Add
+ .grid-content.shrink.spinner-wrapper.spinner-sm.spinner-green(
+ ng-if = "$root.isLoading[branch.attrs.name]"
ng-include = "'spinner'"
)
- li.list-item.popover-list-item SAN-4377-Cant-add-files
- button.btn.btn-xs.btn-icon.btn-add
- svg.iconnables.icons-add
- use(
- xlink:href = "#icons-add"
- )
- li.list-item.popover-list-item SAN-4342-auto-isolation-setup
- button.btn.btn-xs.btn-icon.btn-add
- svg.iconnables.icons-add
- use(
- xlink:href = "#icons-add"
- )
- li.list-item.grid-block.justify-justified.list-pagination(
- )
- //- ng-if = "paginated"
- button.btn.btn-xs.gray.grid-content Last 50
- button.btn.btn-xs.gray.grid-content Next 50
+
+ .text-center.text-gray.small.padding-lg(
+ ng-if = "CIS.instanceBranches && !CIS.instanceBranches.length && CIS.totalInstanceBranches"
+ ) There are no branches to add.
+
+ .text-center.text-gray.small.padding-lg(
+ ng-if = "CIS.instanceBranches && !CIS.instanceBranches.length && !CIS.totalInstanceBranches"
+ ) The repository has no branches.
+
+ .text-center.text-gray.small.padding-lg(
+ ng-if = "CIS.instanceBranches && CIS.instanceBranches.length && CIS.totalInstanceBranches && !CIS.getFilteredBranches().length"
+ ) No branches match this filter.
diff --git a/client/directives/instances/instance/branchMenuPopover/includesModalView.jade b/client/directives/instances/instance/branchMenuPopover/includesModalView.jade
index 9100d0fbc..dafc6ae3e 100644
--- a/client/directives/instances/instance/branchMenuPopover/includesModalView.jade
+++ b/client/directives/instances/instance/branchMenuPopover/includesModalView.jade
@@ -1,14 +1,14 @@
.modal-backdrop.in
.modal-dialog.modal-sm.modal-includes
header.modal-header
- h1.modal-heading Select Containers
+ h1.modal-heading Select Templates
svg.iconnables.icons-close
use(
xlink:href = "#icons-close"
)
section.modal-body
- .grid-block.vertical.shrink.text-center.well.gray.small.padding-sm Select containers from your sandbox to be included with each branch. Changes will apply to all branches of repository-name.
+ .grid-block.vertical.shrink.text-center.well.gray.small.padding-sm Selected templates will be used to create containers for each branch. Changes will apply to all branches of repository-name.
.grid-block.vertical.shrink(
ng-include = "'branchSetupListView'"
)
diff --git a/client/directives/instances/instance/branchMenuPopover/introAddBranch.jade b/client/directives/instances/instance/branchMenuPopover/introAddBranch.jade
new file mode 100644
index 000000000..746fc1b11
--- /dev/null
+++ b/client/directives/instances/instance/branchMenuPopover/introAddBranch.jade
@@ -0,0 +1,35 @@
+.popover.menu.right.popover-branch-menu(
+ ng-class = "{'in': active}"
+ ng-style = "popoverStyle.getStyle()"
+)
+ .grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
+ ng-if = "$root.featureFlags.aha && !$root.isLoading.fetchingBranches && CIS.isAddingFirstBranch()"
+ aha-guide
+ step-index = 2
+ sub-step = "addBranch"
+ )
+
+ .grid-block.shrink.align-center.justify-center.padding-sm.show-autofork(
+ ng-if = "$root.featureFlags.aha && !$root.isLoading.fetchingBranches && CIS.showAutofork"
+ ng-include = "'ahaGuideView'"
+ ng-init = "showAutofork = true"
+ )
+
+ .arrow.white
+
+ animated-panel-container.popover-views(
+ ng-if = "!$root.featureFlags.autoIsolationSetup && $root.isLoading.fetchingBranches"
+ )
+ animated-panel(
+ default = "true"
+ name = "addBranch"
+ )
+ .popover-view.fade(
+ class = "in"
+ )
+ .popover-content(
+ )
+ .spinner-wrapper.spinner-sm.spinner-gray.spinner-center.in(
+ ng-if = "$root.isLoading.fetchingBranches"
+ ng-include = "'spinner'"
+ )
diff --git a/client/directives/instances/instance/branchMenuPopover/templateMenuPopoverView.jade b/client/directives/instances/instance/branchMenuPopover/templateMenuPopoverView.jade
new file mode 100644
index 000000000..aed80d6ef
--- /dev/null
+++ b/client/directives/instances/instance/branchMenuPopover/templateMenuPopoverView.jade
@@ -0,0 +1,200 @@
+.popover.menu.right.popover-template-menu(
+ ng-class = "{'in': active}"
+ ng-init = "\
+ state.tab = 'repo';\
+ state.loading = null;\
+ "
+ ng-style = "popoverStyle.getStyle()"
+)
+ .arrow.gray(
+ style = "top: 39px;"
+ )
+ .grid-block.popover-header
+ button.grid-block.align-center.btn.btn-radio(
+ ng-class = "{'active': state.tab === 'repo'}"
+ ng-click = "state.tab = 'repo'"
+ ng-disabled = "state.tab !== 'repo'&& state.loading"
+ )
+ .grid-block.vertical.shrink Repository
+ .small From your GitHub org
+ button.grid-block.align-center.btn.btn-radio(
+ ng-class = "{'active': state.tab === 'nonRepo'}"
+ ng-click = "state.tab = 'nonRepo'"
+ ng-disabled = "state.tab !== 'nonRepo'&& state.loading"
+ )
+ .grid-block.vertical.shrink Non-Repository
+ .small For a DB or service
+ .popover-content(
+ ng-if = "state.tab === 'repo'"
+ ng-init = "state.branchesLoaded = null"
+ )
+ .spinner-wrapper.spinner-sm.spinner-gray.spinner-center(
+ ng-click = "state.branchesLoaded = true"
+ ng-if = "!state.branchesLoaded"
+ ng-include = "'spinner'"
+ )
+ .padding-xxs(
+ ng-if = "state.branchesLoaded"
+ )
+ input.input.input-xs.input-search(
+ ng-disabled = "state.loading"
+ ng-if = "branch.length !== 0"
+ placeholder = "Filter by name"
+ required
+ type = "search"
+ )
+ .text-center.text-gray.small.padding-lg(
+ ng-if = "branch.length === 0"
+ ) There are no branches to add.
+ ul.list.popover-list(
+ ng-if = "state.branchesLoaded"
+ )
+ li.grid-block.align-center.list-item.popover-list-item.multi-line(
+ ng-class = "{'active': state.loading}"
+ ng-click = "state.loading = !state.loading"
+ )
+ svg.grid-content.shrink.iconnables.icons-repository
+ use(
+ xlink:href = "#icons-repository"
+ )
+ .grid-block.vertical
+ .grid-content.text-overflow(
+ title = "button-clicker"
+ ) button-clicker
+ .grid-block(
+ ng-if = "$root.featureFlags.inviteFlows"
+ )
+ .btn-user.text-overflow.no-touching(
+ ng-class = "{'active': state.active}"
+ ng-include = "'userButtonView'"
+ )
+ span.small(
+ ng-if = "$root.featureFlags.inviteFlows"
+ ) — 3 days ago
+
+ //- else
+ small.small(
+ ng-if = "!$root.featureFlags.inviteFlows"
+ ) Updated 3 days ago
+
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add(
+ ng-if = "!state.loading"
+ ) Select
+ .grid-content.shrink.spinner-wrapper.spinner-sm.spinner-green(
+ ng-if = "state.loading"
+ ng-include = "'spinner'"
+ )
+ li.grid-block.align-center.list-item.popover-list-item.multi-line(
+ ng-class = "{'disabled': state.loading}"
+ )
+ svg.grid-content.shrink.iconnables.icons-repository
+ use(
+ xlink:href = "#icons-repository"
+ )
+ .grid-block.vertical
+ .grid-content.text-overflow(
+ title = "api"
+ ) api
+ .grid-block(
+ ng-if = "$root.featureFlags.inviteFlows"
+ )
+ .btn-user.text-overflow.no-touching(
+ ng-class = "{'active': state.active}"
+ ng-include = "'userButtonView'"
+ )
+ span.small(
+ ng-if = "$root.featureFlags.inviteFlows"
+ ) — 3 days ago
+
+ //- else
+ small.small(
+ ng-if = "!$root.featureFlags.inviteFlows"
+ ) Updated 3 days ago
+
+ button.grid-block.shrink.btn.btn-xs.btn-icon.btn-add Select
+ li.grid-block.align-center.list-item.popover-list-item.multi-line(
+ ng-class = "{'disabled': state.loading}"
+ )
+ svg.grid-content.shrink.iconnables.icons-repository
+ use(
+ xlink:href = "#icons-repository"
+ )
+ .grid-block.vertical
+ .grid-content.text-overflow(
+ title = "runnable.com"
+ ) runnable.com
+ .grid-block(
+ ng-if = "$root.featureFlags.inviteFlows"
+ )
+ .btn-user.text-overflow.no-touching(
+ ng-class = "{'active': state.active}"
+ ng-include = "'userButtonView'"
+ )
+ span.small(
+ ng-if = "$root.featureFlags.inviteFlows"
+ ) — 3 days ago
+
+ //- else
+ small.small(
+ ng-if = "!$root.featureFlags.inviteFlows"
+ ) Updated 3 days ago
+
+ button.grid-block.shrink.btn.btn-xs.btn-icon.btn-add Select
+ .popover-content(
+ ng-if = "state.tab === 'nonRepo'"
+ ng-init = "state.servicesLoaded = null"
+ )
+ .spinner-wrapper.spinner-sm.spinner-gray.spinner-center(
+ ng-click = "state.servicesLoaded = true"
+ ng-if = "!state.servicesLoaded"
+ ng-include = "'spinner'"
+ )
+ .padding-xxs(
+ ng-if = "state.servicesLoaded"
+ )
+ input.input.input-xs.input-search(
+ ng-disabled = "state.loading"
+ placeholder = "Filter by name"
+ required
+ type = "search"
+ )
+ ul.list.popover-list(
+ ng-if = "state.servicesLoaded"
+ )
+ li.grid-block.align-center.list-item.popover-list-item.multi-line(
+ ng-class = "{'active': state.loading}"
+ ng-click = "state.loading = !state.loading"
+ )
+ img.grid-content.shrink.img(
+ height = "24"
+ ng-src = "/build/images/logos/logo-icon-cassandra.png"
+ width = "24"
+ )
+ .grid-content Cassandra
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add(
+ ng-if = "!state.loading"
+ ) Select
+ .grid-content.shrink.spinner-wrapper.spinner-sm.spinner-green(
+ ng-if = "state.loading"
+ ng-include = "'spinner'"
+ )
+ li.grid-block.align-center.list-item.popover-list-item.multi-line(
+ ng-class = "{'disabled': state.loading}"
+ )
+ img.grid-content.shrink.img(
+ height = "24"
+ ng-src = "/build/images/logos/logo-icon-consul-server.png"
+ width = "24"
+ )
+ .grid-content Consul-Server
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add Select
+ li.grid-block.align-center.list-item.popover-list-item.multi-line(
+ ng-class = "{'disabled': state.loading}"
+ )
+ img.grid-content.shrink.img(
+ height = "24"
+ ng-src = "/build/images/logos/logo-icon-elasticsearch.png"
+ width = "24"
+ )
+ .grid-content ElasticSearch
+ button.grid-content.shrink.btn.btn-xs.btn-icon.btn-add Select
diff --git a/client/directives/instances/instance/branchSetupModal/branchSetupListView.jade b/client/directives/instances/instance/branchSetupModal/branchSetupListView.jade
index 472bc5869..259223ec6 100644
--- a/client/directives/instances/instance/branchSetupModal/branchSetupListView.jade
+++ b/client/directives/instances/instance/branchSetupModal/branchSetupListView.jade
@@ -2,7 +2,7 @@
.empty.well.gray.padding-md(
ng-if = "containers.length === 0"
)
- .small.empty.text-center.text-gray Your sandbox doesn’t have any other containers yet, but you can continue and add containers later.
+ .small.empty.text-center.text-gray You don’t have any other templates yet, but you can continue and add more templates later.
.grid-block.vertical.shrink.list.list-bordered
.list-item.padding-xs
diff --git a/client/directives/instances/instance/branchSetupModal/branchSetupModalView.jade b/client/directives/instances/instance/branchSetupModal/branchSetupModalView.jade
index 45e14f9f9..eddf8cdfa 100644
--- a/client/directives/instances/instance/branchSetupModal/branchSetupModalView.jade
+++ b/client/directives/instances/instance/branchSetupModal/branchSetupModalView.jade
@@ -45,13 +45,13 @@
.empty.well.gray.padding-md(
ng-if = "branches.length === 0"
)
- .small.empty.text-center.text-gray We couldn’t find any branches for this container, but you can continue and add branches later.
+ .small.empty.text-center.text-gray We couldn’t find any branches, but you can continue and add branches later.
//- hide this on initial load, but show when paginating
h4.grid-block.shrink.align-center.h4.text-gray.small.padding-xs
.grid-content Select branches to add:
input.grid-content.shrink.input.input-xs.input-search(
- placeholder = "Filter"
+ placeholder = "Filter by name"
required
type = "search"
)
@@ -106,7 +106,7 @@
)
h1.modal-heading.fade(
ng-class = "{'in': isActivePanel()}"
- ) Select Containers
+ ) Select Templates
svg.iconnables.icons-close.fade(
ng-class = "{'in': isActivePanel()}"
)
@@ -120,7 +120,7 @@
//- do not show this if there are no containers
.grid-block.vertical.shrink.text-center.well.gray.small.padding-sm(
ng-if = "containers.length > 0"
- ) Select containers from your sandbox to be included with each branch.
+ ) Selected templates will be used to create containers for each branch.
.grid-block.vertical.shrink(
ng-include = "'branchSetupListView'"
diff --git a/client/directives/instances/instance/instanceHeaderDirective.js b/client/directives/instances/instance/instanceHeaderDirective.js
index a0fa40773..b4535dec1 100644
--- a/client/directives/instances/instance/instanceHeaderDirective.js
+++ b/client/directives/instances/instance/instanceHeaderDirective.js
@@ -8,8 +8,10 @@ require('app')
*/
function instanceHeader(
$localStorage,
+ $rootScope,
$stateParams,
- fetchPullRequest
+ fetchPullRequest,
+ ahaGuide
) {
return {
restrict: 'A',
@@ -32,6 +34,10 @@ function instanceHeader(
}
});
});
+ $scope.toggleSidebar = function () {
+ $rootScope.$broadcast('showAhaSidebar');
+ };
+ $scope.isInGuide = ahaGuide.isInGuide;
}
};
}
diff --git a/client/directives/instances/instance/instanceHeaderView.jade b/client/directives/instances/instance/instanceHeaderView.jade
index ac64b11b8..0bbd0228c 100644
--- a/client/directives/instances/instance/instanceHeaderView.jade
+++ b/client/directives/instances/instance/instanceHeaderView.jade
@@ -47,10 +47,10 @@
) {{key}}:{{value[0].HostPort}} |
button.grid-block.shrink.btn.btn-sm.gray.btn-aha(
- ng-click = "$root.featureFlags.ahaSidebar = true"
- ng-if = "$root.featureFlags.aha && !$root.featureFlags.ahaSidebar"
+ ng-click = "toggleSidebar()"
+ ng-if = "$root.featureFlags.aha && isInGuide()"
tooltip = "Setup Guide"
- tooltip-options = "{\"class\":\"left\",\"right\":42,\"top\":0}"
+ tooltip-options = "{\"class\":\"left\",\"right\":44,\"top\":0}"
)
svg.iconnables
use(
@@ -84,3 +84,24 @@
open-items = "openItems"
save-open-items-button
)
+
+ .popover.bottom.in.popover-aha.popover-aha-url.in(
+ ng-if = "$root.featureFlags.aha && $root.featureFlags.ahaBranchUrlStep"
+ )
+ .arrow.white(
+ style = "left: auto; right: 59px;"
+ )
+ .popover-content
+ .grid-block.shrink.align-center.justify-center.padding-sm.aha-guide
+ .grid-block.shrink.aha-meter.js-animate.aha-meter-100
+ svg.iconnables
+ use(
+ xlink:href = "#icons-check"
+ )
+ .grid-block.vertical.aha-text
+ p.p.small.text-gray-light Step 3: Add a Branch
+ p.p Nice work! Now you can see the web output of your branch by visiting its URL.
+ .grid-block.justify-right.popover-footer
+ button.grid-block.shrink.btn.btn-sm.green(
+ ng-click = "EC.showAddServicePopover = false"
+ ) Got It
diff --git a/client/directives/modals/directiveModal.js b/client/directives/modals/directiveModal.js
index 9ca2a5dd3..1e46ba86d 100755
--- a/client/directives/modals/directiveModal.js
+++ b/client/directives/modals/directiveModal.js
@@ -9,7 +9,8 @@ function modal() {
return {
restrict: 'A',
scope: {
- data: '=?modalData', // Contains modal specific data
+ controller: '=?modalController', // Contains modal specific data
+ controllerAs: '@?modalControllerAs', // the property name used to access controller
actions: '=?modalActions', // Contains modal specific actions
template: '@modalTemplate',
currentModel: '=?modalCurrentModel', // The object that contains the data to display
@@ -19,8 +20,9 @@ function modal() {
link: function ($scope, element, attrs) {
function openModal() {
$scope.$emit('open-modal', {
- data: $scope.data,
actions: $scope.actions,
+ controller: $scope.controller,
+ controllerAs: $scope.controllerAs,
template: $scope.template,
currentModel: $scope.currentModel,
stateModel: $scope.stateModel
diff --git a/client/directives/modals/directiveModalManager.js b/client/directives/modals/directiveModalManager.js
index 54f7d1ecc..4b1823a30 100644
--- a/client/directives/modals/directiveModalManager.js
+++ b/client/directives/modals/directiveModalManager.js
@@ -58,7 +58,7 @@ function modalManager(
}
$scope.currentModalScope = currentModalScope = $scope.$new(true);
- currentModalScope.data = options.data;
+ currentModalScope[options.controllerAs] = options.controller;
currentModalScope.actions = options.actions;
currentModalScope.template = options.template;
currentModalScope.openFlag = options.openFlag;
diff --git a/client/directives/modals/gracePeriodModal/forms/pausedSandboxView.jade b/client/directives/modals/gracePeriodModal/forms/pausedSandboxView.jade
index dcd894b9f..48b30dd8b 100644
--- a/client/directives/modals/gracePeriodModal/forms/pausedSandboxView.jade
+++ b/client/directives/modals/gracePeriodModal/forms/pausedSandboxView.jade
@@ -12,13 +12,13 @@
span(
title = "paws’d"
) paused
- | your containers due to inactivity. Give us the go ahead and we’ll get you back up and running.
+ | your environments due to inactivity. Give us the go ahead and we’ll get you back up and running.
footer.grid-block.vertical.modal-footer
button.grid-content.btn.btn-md.green.icons-intercom(
ng-click = "WBC.openIntercom()"
) Chat Now
a.grid-content.link.text-gray.text-center(
- href = "mailto:support@runnable.com?subject=I’m back! Please get my sandbox back up and running."
+ href = "mailto:support@runnable.com?subject=I’m back! Please get my environments back up and running."
) Email Support
.grid-block.justify-center.modal-outer-footer(
grace-period-footer
diff --git a/client/directives/modals/gracePeriodModal/forms/paymentDueView.jade b/client/directives/modals/gracePeriodModal/forms/paymentDueView.jade
index 670588c9e..e45cf9f39 100644
--- a/client/directives/modals/gracePeriodModal/forms/paymentDueView.jade
+++ b/client/directives/modals/gracePeriodModal/forms/paymentDueView.jade
@@ -15,7 +15,7 @@
ng-if = "EAC.activeAccount.isInGrace()"
)
strong.strong Note:
- | Your containers will be paused in {{EAC.activeAccount.graceHoursRemaining()}} hours if we cannot process a payment method.
+ | Your environments will be paused in {{EAC.activeAccount.graceHoursRemaining()}} hours if we cannot process a payment method.
hr.hr
.grid-block.vertical.form-payment.fade(
ng-class = "{'in': isActivePanel()}"
diff --git a/client/directives/modals/gracePeriodModal/forms/trialEndView.jade b/client/directives/modals/gracePeriodModal/forms/trialEndView.jade
index 2172c89a1..9d19b91ac 100644
--- a/client/directives/modals/gracePeriodModal/forms/trialEndView.jade
+++ b/client/directives/modals/gracePeriodModal/forms/trialEndView.jade
@@ -17,7 +17,7 @@
| .
small.grid-content.small.text-center.text-gray
strong.strong Note:
- | Your containers will be paused in {{EAC.activeAccount.graceHoursRemaining()}} hours if we cannot process a payment method.
+ | Your environments will be paused in {{EAC.activeAccount.graceHoursRemaining()}} hours if we cannot process a payment method.
hr.hr
.grid-block.vertical.form-payment.fade(
ng-class = "{'in': isActivePanel()}"
diff --git a/client/directives/modals/inviteAdminModal/inviteAdminModalController.js b/client/directives/modals/inviteAdminModal/inviteAdminModalController.js
index ad5538bd1..d6c609011 100644
--- a/client/directives/modals/inviteAdminModal/inviteAdminModalController.js
+++ b/client/directives/modals/inviteAdminModal/inviteAdminModalController.js
@@ -2,7 +2,7 @@
require('app')
.controller('InviteAdminModalController', InviteAdminModalController);
-var DEFAULT_MESSAGE = 'Join my Sandbox on Runnable, where we can run the code in CodeNow\'s repositories on demand.\n\nI need your admin permissions to enable some features. Thanks!';
+var DEFAULT_MESSAGE = 'Join me on Runnable, where we can run the code in CodeNow\'s repositories on demand.\n\nI need your admin permissions to enable some features. Thanks!';
function InviteAdminModalController(
$state,
diff --git a/client/directives/modals/modalChooseOrganization/chooseOrganizationModalController.js b/client/directives/modals/modalChooseOrganization/chooseOrganizationModalController.js
index 235beb7c2..fabc0b918 100644
--- a/client/directives/modals/modalChooseOrganization/chooseOrganizationModalController.js
+++ b/client/directives/modals/modalChooseOrganization/chooseOrganizationModalController.js
@@ -7,8 +7,10 @@ function ChooseOrganizationModalController(
$rootScope,
$scope,
$state,
+ ahaGuide,
createNewSandboxForUserService,
errs,
+ eventTracking,
featureFlags,
fetchWhitelistForDockCreated,
keypather,
@@ -37,6 +39,7 @@ function ChooseOrganizationModalController(
};
$scope.actions = {
+ selectedOrg: eventTracking.selectedOrg.bind(eventTracking),
selectAccount: function (selectedOrgName) {
$state.go('base.instances', {
userName: selectedOrgName
@@ -84,6 +87,7 @@ function ChooseOrganizationModalController(
return selectedOrgName.toLowerCase() === org.oauthName().toLowerCase();
});
};
+ COMC.isChoosingOrg = ahaGuide.isChoosingOrg;
// Polling stuff
COMC.cancelPolling = function () {
diff --git a/client/directives/modals/modalChooseOrganization/chooseOrganizationModalView.jade b/client/directives/modals/modalChooseOrganization/chooseOrganizationModalView.jade
index e828f4709..668cb157d 100644
--- a/client/directives/modals/modalChooseOrganization/chooseOrganizationModalView.jade
+++ b/client/directives/modals/modalChooseOrganization/chooseOrganizationModalView.jade
@@ -8,18 +8,14 @@
)
.grid-block.shrink.modal-dialog.modal-orgs(
ng-class = "{\
- 'modal-lg': data.allAccounts.length > 1,\
- 'modal-sm': data.allAccounts.length <= 1\
+ 'modal-lg': COS.allAccounts.length > 1,\
+ 'modal-sm': COS.allAccounts.length <= 1\
}"
)
.grid-block.shrink.align-center.justify-center.padding-md.aha-guide(
- ng-if = "$root.featureFlags.aha"
- ng-include = "'ahaGuideView'"
- ng-init = "\
- state.showStep = 0;\
- state.showSubStep = 0;\
- state.hideMenu = true;\
- "
+ aha-guide
+ ng-if = "$root.featureFlags.aha && COS.isChoosingOrg()"
+ sub-step = "orgSelection"
)
animated-panel-container
animated-panel.modal-body.grid-block.vertical.padding-sm(
@@ -30,7 +26,7 @@
p.p.padding-xs.text-center.fade(
ng-class = "{'in': isActivePanel()}"
ng-if = "!$root.featureFlags.aha"
- ) Choose an organization for your Sandbox. If you don’t see your organization, check if you’ve granted access
+ ) Select the organization you want to use with Runnable. If you don’t see your organization, check if you’ve granted access
a.link(
href = "https://github.com/settings/connections/applications/d42d6634d4070c9d9bf9"
target = "_blank"
@@ -39,7 +35,7 @@
.grid-block.shrink.justify-center.align-center.padding-xs.well.gray.aha-tips.fade(
ng-class = "{'in': isActivePanel()}"
- ng-if = "$root.featureFlags.aha && data.allAccounts.length"
+ ng-if = "$root.featureFlags.aha && COS.allAccounts.length"
)
svg.grid-content.shrink.iconnables
use(
@@ -54,7 +50,7 @@
//- empty state
.empty.well.gray.padding-lg(
- ng-if = "!data.allAccounts.length"
+ ng-if = "!COS.allAccounts.length"
)
h3.h3.empty.text-gray.text-center We couldn’t find any organizations.
small.small.empty.text-center Check if you’ve granted access to your organization
@@ -65,15 +61,15 @@
| . If you don’t have permission to grant access, you’ll have to ask your admin to give the go ahead.
form.grid-block.list.fade(
- name = "data.orgSelectorForm"
+ name = "COS.orgSelectorForm"
ng-class = "{'in': isActivePanel()}"
- ng-if = "data.allAccounts.length"
+ ng-if = "COS.allAccounts.length"
)
//- add .active class if this org is selected
//- add [disabled] property when loading NOT class!
label.grid-block.align-center.list-item.btn.white(
- ng-class = "{'active': org.oauthName() === data.selectedOrgName}"
- ng-repeat = "org in data.allAccounts"
+ ng-class = "{'active': org.oauthName() === COS.selectedOrgName}"
+ ng-repeat = "org in COS.allAccounts"
title = "{{org.oauthName()}}"
)
img.grid-block.shrink(
@@ -83,7 +79,8 @@
)
span.grid-block.text-left.text-overflow {{org.oauthName()}}
input.checkbox.hidden(
- ng-model = "data.selectedOrgName"
+ ng-change = "actions.selectedOrg(org.oauthName())"
+ ng-model = "COS.selectedOrgName"
value = "{{org.oauthName()}}"
type = "radio"
)
@@ -96,16 +93,14 @@
//- hide the footer if no orgs are found
footer.grid-block.vertical.modal-footer.fade(
ng-class = "{'in': isActivePanel()}"
- ng-if = "data.allAccounts.length"
+ ng-if = "COS.allAccounts.length"
)
//- disabled until an org is selected
- button.grid-block.align-center.justify-center.btn.btn-md.green(
- ng-click = "\
- actions.createOrCheckDock(data.selectedOrgName, goToPanel);\
- state.showSubStep = 1;\
- "
- ng-disabled = "!data.selectedOrgName"
- ) Create Sandbox
+ button.btn.btn-md.green(
+ data-event-name = "Org Confirmed"
+ ng-click = "actions.createOrCheckDock(COS.selectedOrgName, goToPanel)"
+ ng-disabled = "!COS.selectedOrgName"
+ ) Confirm Organization
animated-panel.modal-body.grid-block.vertical(
name = "dockLoading"
@@ -114,14 +109,27 @@
ng-class = "{'in': isActivePanel()}"
)
//- dock spinning up
- p.p.text-gray.padding-xs.text-center We’re spinning up a sandbox for your org. It’ll take about
+ p.p.text-gray.padding-xs.text-center(
+ ng-if = "!$root.featureFlags.contingencyPlan"
+ ) We’re spinning up infrastructure for your org. It’ll take about
strong.strong 10 minutes
| . We’ll email you and update this page when it’s ready.
- .grid-block.align-center.justify-center.padding-sm
+ .grid-block.align-center.justify-center.padding-sm(
+ ng-if = "!$root.featureFlags.contingencyPlan"
+ )
.spinner-wrapper.spinner-md.spinner-gray(
ng-include = "'spinner'"
)
//- ng-if = "isActivePanel()"
+
+ p.p.text-gray.text-center.strong(
+ ng-if = "$root.featureFlags.contingencyPlan"
+ ) We’re running slower than normal due to high demand.
+ p.p.text-gray.text-center.padding-xs(
+ ng-if = "$root.featureFlags.contingencyPlan"
+ ) We’ll email you at
+ span {{ COS.user.attrs.email }}
+ | as soon we’re done spinning up your infrastructure. Thanks for your patience.
animated-panel.modal-body.grid-block.vertical(
name = "dockLoaded"
)
@@ -129,15 +137,16 @@
ng-class = "{'in': isActivePanel()}"
)
//- dock spun up
- p.p.text-gray.padding-xs.text-center Your sandbox is ready for you now.
+ p.p.text-gray.padding-xs.text-center Thanks for waiting, we‘re ready for you now.
//- show this button when done waiting
footer.grid-block.vertical.modal-footer.fade(
ng-class = "{'in': isActivePanel()}"
)
- button.grid-block.align-center.justify-center.btn.btn-md.green(
- ng-click = "actions.selectAccount(data.selectedOrgName)"
- ) Go to your Sandbox!
+ button.btn.btn-md.green(
+ data-event-name = "Nav to Runnable (after infrastructure wait)"
+ ng-click = "actions.selectAccount(COS.selectedOrgName)"
+ ) Go to Runnable
.grid-block.justify-center.modal-outer-footer(
grace-period-footer
hide-choose-org = "true"
diff --git a/client/directives/modals/modalDeleteSandbox/viewModalDeleteSandbox.jade b/client/directives/modals/modalDeleteSandbox/viewModalDeleteSandbox.jade
deleted file mode 100644
index 58589d2e0..000000000
--- a/client/directives/modals/modalDeleteSandbox/viewModalDeleteSandbox.jade
+++ /dev/null
@@ -1,8 +0,0 @@
-.modal-dialog.modal-sm.modal-alert
- section.modal-body
- p.p.strong Are you sure you want to delete your private Sandbox?
- footer.modal-footer.clearfix
- button.btn.btn-sm.gray.float-left(
- ng-click = "defaultActions.close()"
- ) Cancel
- button.btn.btn-sm.red.float-right Delete Private Sandbox
\ No newline at end of file
diff --git a/client/directives/modals/modalGeneric/viewModalDeleteBox.jade b/client/directives/modals/modalGeneric/viewModalDeleteBox.jade
index c172213b1..ea169cddb 100755
--- a/client/directives/modals/modalGeneric/viewModalDeleteBox.jade
+++ b/client/directives/modals/modalGeneric/viewModalDeleteBox.jade
@@ -2,7 +2,7 @@
ng-click = "$event.stopPropagation()"
)
header.modal-header
- h1.modal-heading Delete Container
+ h1.modal-heading Delete Template
svg.iconnables.icons-close(
ng-click = "defaultActions.cancel()"
)
@@ -22,4 +22,4 @@
actions.deleteInstance(data.deleteLinked);\
defaultActions.cancel();\
"
- ) Delete Container
\ No newline at end of file
+ ) Delete Template
diff --git a/client/directives/modals/modalNewContainer/newContainerModalController.js b/client/directives/modals/modalNewContainer/newContainerModalController.js
index 221cd81e5..9df7bf714 100644
--- a/client/directives/modals/modalNewContainer/newContainerModalController.js
+++ b/client/directives/modals/modalNewContainer/newContainerModalController.js
@@ -6,6 +6,7 @@ require('app')
function NewContainerModalController(
$q,
$timeout,
+ ahaGuide,
createNewBuildAndFetchBranch,
createNonRepoInstance,
errs,
@@ -14,73 +15,71 @@ function NewContainerModalController(
fetchOwnerRepos,
fetchRepoDockerfiles,
getNewForkName,
- helpCards,
keypather,
loading,
ModalService,
close,
currentOrg
) {
- var NCMC = this;
- var helpCard = helpCards.getActiveCard();
- angular.extend(NCMC, {
+ var MC = this;
+ angular.extend(MC, {
name: 'newContainerModal',
- servicesActive: keypather.get(helpCard, 'id') === 'missingDependency',
state: {
tabName: 'repos',
dockerfile: null,
configurationMethod: null,
namesForAllInstances: []
- }
+ },
+ ahaGuide: ahaGuide
});
// Start loading repos and templates
- loading.reset(NCMC.name + 'Repos');
- loading.reset(NCMC.name + 'Templates');
- loading.reset(NCMC.name + 'SingleRepo');
+ loading.reset(MC.name + 'Repos');
+ loading.reset(MC.name + 'Templates');
+ loading.reset(MC.name + 'SingleRepo');
// Fetch all repos from Github
- loading(NCMC.name + 'Repos', true);
+ loading(MC.name + 'Repos', true);
$q.all({
instances: fetchInstancesByPod(),
repoList: fetchOwnerRepos(currentOrg.github.oauthName())
})
.then(function (data) {
- NCMC.instances = data.instances;
- NCMC.state.namesForAllInstances = NCMC.instances.map(function (instance) {
+ MC.instances = data.instances;
+ MC.state.namesForAllInstances = MC.instances.map(function (instance) {
return instance.attrs.name;
});
- NCMC.githubRepos = data.repoList;
- NCMC.githubRepos.models.forEach(function (repo) {
- repo.isAdded = NCMC.isRepoAdded(repo, data.instances);
+ MC.githubRepos = data.repoList;
+ MC.githubRepos.models.forEach(function (repo) {
+ repo.isAdded = MC.isRepoAdded(repo, data.instances);
});
})
.catch(errs.handler)
.finally(function () {
- loading(NCMC.name + 'Repos', false);
+ loading(MC.name + 'Repos', false);
});
- NCMC.fetchTemplateServers = function () {
- loading(NCMC.name + 'Templates', true);
+ MC.fetchTemplateServers = function () {
+ loading(MC.name + 'Templates', true);
// Fetch all non-repo containres
return fetchInstances({ githubUsername: 'HelloRunnable' })
.then(function (servers) {
- NCMC.templateServers = servers;
- loading(NCMC.name + 'Templates', false);
+ MC.templateServers = servers;
+ loading(MC.name + 'Templates', false);
return servers;
});
};
- NCMC.changeTab = function (tabName) {
+ MC.changeTab = function (tabName) {
if (!['repos', 'services'].includes(tabName)) {
return;
}
- NCMC.state.tabName = tabName;
+ MC.state.tabName = tabName;
// Reset repo and template
- NCMC.state.templateSource = null;
- NCMC.state.repo = null;
- if (NCMC.state.tabName === 'services' && !NCMC.templateServers) {
- NCMC.fetchTemplateServers();
+ MC.state.templateSource = null;
+ MC.state.repo = null;
+ if (MC.state.tabName === 'services' && !MC.templateServers) {
+ MC.fetchTemplateServers();
}
};
@@ -88,7 +87,7 @@ function NewContainerModalController(
return repo.attrs.name.replace(/[^a-zA-Z0-9-]/g, '-');
}
- NCMC.isRepoAdded = function (repo, instances) {
+ MC.isRepoAdded = function (repo, instances) {
// Since the newServers may have faked repos (just containing names), just check the name
return !!instances.find(function (instance) {
var repoName = instance.getRepoName();
@@ -100,21 +99,21 @@ function NewContainerModalController(
});
};
- NCMC.close = function () {
- if (NCMC.state.closed) { return; }
- NCMC.state.closed = true;
+ MC.close = function () {
+ if (MC.state.closed) { return; }
+ MC.state.closed = true;
return close();
};
- NCMC.setTemplate = function (sourceInstance, goToPanelCb) {
- NCMC.state.templateSource = sourceInstance;
+ MC.setTemplate = function (sourceInstance, goToPanelCb) {
+ MC.state.templateSource = sourceInstance;
var instanceToForkName = sourceInstance.attrs.name;
- loading(NCMC.name + 'SingleRepo', true);
+ loading(MC.name + 'SingleRepo', true);
return fetchInstances()
.then(function (instances) {
- loading(NCMC.name + 'SingleRepo', false);
+ loading(MC.name + 'SingleRepo', false);
var serverName = getNewForkName(instanceToForkName, instances, true);
- NCMC.state.instanceName = serverName;
+ MC.state.instanceName = serverName;
/**
* Warning: Hack Ahead
*
@@ -132,9 +131,9 @@ function NewContainerModalController(
.catch(errs.handler);
};
- NCMC.addServerFromTemplate = function (sourceInstance) {
+ MC.addServerFromTemplate = function (sourceInstance) {
var instanceToForkName = sourceInstance.attrs.name;
- NCMC.close();
+ MC.close();
return fetchInstances()
.then(function (instances) {
var serverName = getNewForkName(instanceToForkName, instances, true);
@@ -153,61 +152,68 @@ function NewContainerModalController(
.catch(errs.handler);
};
- NCMC.setRepo = function (repo, goToPanelCb) {
- if (repo.attrs.full_name === keypather.get(NCMC, 'state.repo.attrs.full_name')) {
+ MC.setRepo = function (repo, goToPanelCb) {
+ if (repo.attrs.full_name === keypather.get(MC, 'state.repo.attrs.full_name')) {
return goToPanelCb('dockerfileMirroring');
}
repo.loading = true;
- NCMC.state.repo = repo;
- loading(NCMC.name + 'SingleRepo', true);
+ MC.state.repo = repo;
+ loading(MC.name + 'SingleRepo', true);
var fullName = keypather.get(repo, 'attrs.full_name');
var defaultBranch = keypather.get(repo, 'attrs.default_branch');
- NCMC.state.configurationMethod = null;
- NCMC.state.instanceName = fullName.split('/')[1] || '';
- NCMC.state.instanceName = NCMC.state.instanceName.replace(/_/g, '-');
+ MC.state.configurationMethod = null;
+ MC.state.instanceName = fullName.split('/')[1] || '';
+ MC.state.instanceName = MC.state.instanceName.replace(/_/g, '-');
return fetchRepoDockerfiles(fullName, defaultBranch)
.then(function (dockerfiles) {
- if (dockerfiles.length === 0) {
- NCMC.state.configurationMethod = 'new';
- }
- loading(NCMC.name + 'SingleRepo', false);
+ loading(MC.name + 'SingleRepo', false);
repo.loading = false;
repo.dockerfiles = dockerfiles;
- NCMC.state.dockerfile = null;
+ MC.state.dockerfile = null;
return goToPanelCb('dockerfileMirroring');
});
};
- NCMC.createBuildAndGoToNewRepoModal = function (instanceName, repo, dockerfile, configurationMethod) {
- loading(NCMC.name + 'SingleRepo', true);
- return createNewBuildAndFetchBranch(currentOrg.github, repo, keypather.get(dockerfile, 'path'))
+ MC.createBuildAndGoToNewRepoModal = function (instanceName, repo, dockerfile, configurationMethod) {
+ var dockerfilePath;
+ loading(MC.name + 'SingleRepo', true);
+
+ if (configurationMethod === 'dockerfile') {
+ dockerfilePath = keypather.get(dockerfile, 'path');
+ } else {
+ dockerfilePath = '';
+ }
+ return createNewBuildAndFetchBranch(currentOrg.github, repo, dockerfilePath, configurationMethod)
.then(function (repoBuildAndBranch) {
repoBuildAndBranch.instanceName = instanceName;
if (configurationMethod === 'dockerfile' && dockerfile) {
- NCMC.newMirrorRepositoryContainer(repoBuildAndBranch);
+ MC.newMirrorRepositoryContainer(repoBuildAndBranch);
+ } else if (configurationMethod === 'blankDockerfile'){
+ MC.newRepositoryContainer(repoBuildAndBranch, configurationMethod);
} else {
- NCMC.newRepositoryContainer(repoBuildAndBranch);
+ MC.newRepositoryContainer(repoBuildAndBranch, false);
}
})
.finally(function () {
- loading(NCMC.name + 'SingleRepo', false);
+ loading(MC.name + 'SingleRepo', false);
});
};
- NCMC.createBuildFromTemplate = function (instanceName, sourceInstance) {
- NCMC.close();
+ MC.createBuildFromTemplate = function (instanceName, sourceInstance) {
+ MC.close();
return createNonRepoInstance(instanceName, sourceInstance)
.catch(errs.handler);
};
- NCMC.newRepositoryContainer = function (inputs) {
- if (NCMC.state.closed) { return; }
- NCMC.close();
+ MC.newRepositoryContainer = function (inputs, configurationMethod) {
+ if (MC.state.closed) { return; }
+ MC.close();
ModalService.showModal({
controller: 'SetupServerModalController',
controllerAs: 'SMC',
templateUrl: 'setupServerModalView',
inputs: angular.extend({
+ dockerfileType: configurationMethod,
instanceName: null,
repo: null,
build: null,
@@ -216,9 +222,9 @@ function NewContainerModalController(
});
};
- NCMC.newMirrorRepositoryContainer = function (inputs) {
- if (NCMC.state.closed) { return; }
- NCMC.close();
+ MC.newMirrorRepositoryContainer = function (inputs) {
+ if (MC.state.closed) { return; }
+ MC.close();
ModalService.showModal({
controller: 'SetupMirrorServerModalController',
controllerAs: 'SMC',
diff --git a/client/directives/modals/modalNewContainer/newContainerModalView.jade b/client/directives/modals/modalNewContainer/newContainerModalView.jade
index 0b6471925..25c91e622 100644
--- a/client/directives/modals/modalNewContainer/newContainerModalView.jade
+++ b/client/directives/modals/modalNewContainer/newContainerModalView.jade
@@ -1,11 +1,10 @@
.modal-backdrop.in
.grid-block.shrink.align-center.justify-center.padding-sm.aha-guide(
- ng-if = "$root.featureFlags.aha1"
- ng-include = "'ahaGuideView'"
- ng-init = "\
- state.showStep = 1;\
- state.showSubStep = 1;\
- "
+ aha-guide
+ ng-class = "{'p-slide js-animate': AGC.state.subStepIndex > 0}"
+ ng-if = "MC.ahaGuide.isAddingFirstRepo()"
+ sub-step = "containerSelection"
+ sub-step-index = 1
)
.modal-dialog.modal-lg
animated-panel-container.modal-servers
@@ -14,36 +13,37 @@
name = "containerSelection"
)
header.modal-header.grid-block.justify-center(
- ng-class = "{'lg': !$root.featureFlags.aha1}"
+ ng-class = "{'lg': !MC.ahaGuide.isAddingFirstRepo() || ( MC.instances.models && MC.instances.models.length !== 0 )}"
ng-click = "MC.changeTab('nameContainer')"
)
- .grid-block.shrink.btn(
+ .grid-block.align-center.shrink.btn.btn-radio(
ng-class = "{'active': MC.state.tabName === 'repos'}"
ng-click = "MC.changeTab('repos')"
- ng-if = "!$root.featureFlags.aha1"
+ ng-if = "!MC.ahaGuide.isAddingFirstRepo() || ( MC.instances.models && MC.instances.models.length !== 0 )"
)
svg.iconnables.icons-repository.grid-block.shrink
use(
xlink:href = "#icons-new-repository-server"
)
- .btn-text.grid-block Create from a repository
+ .btn-text.grid-block.vertical.text-left Repository Template
+ small.small From your GitHub org
+
//- disable this button when loading a repository
- .grid-block.shrink.btn(
+ .grid-block.align-center.shrink.btn.btn-radio(
ng-disabled = "$root.isLoading[MC.name + 'SingleRepo']"
ng-class = "{\
'active': MC.state.tabName === 'services', \
- 'btn-hint': MC.servicesActive, \
'disabled': $root.isLoading[MC.name + 'SingleRepo'] \
}"
ng-click = "!$root.isLoading[MC.name + 'SingleRepo'] && MC.changeTab('services')"
- ng-if = "!$root.featureFlags.aha1"
+ ng-if = "!MC.ahaGuide.isAddingFirstRepo() || ( MC.instances.models && MC.instances.models.length !== 0 )"
)
svg.iconnables.icons-template.grid-block.shrink
use(
xlink:href = "#icons-server-new"
)
- .btn-text.grid-block.vertical.text-left Create from a template
- small.small For services and databases
+ .btn-text.grid-block.vertical.text-left Non-Repository Template
+ small.small For a database or service
svg.iconnables.icons-close(
ng-click = "MC.close()"
)
@@ -73,8 +73,8 @@
xlink:href = "#icons-arrow-down"
)
h1.modal-heading(
- ng-if = "!$root.featureFlags.aha1"
- ) Configuration Method
+ ng-if = "!MC.ahaGuide.isAddingFirstRepo()"
+ ) Setup Method
svg.iconnables.icons-close(
ng-click = "MC.close()"
)
@@ -102,7 +102,7 @@
ng-include = "'spinner'"
ng-if = "$root.isLoading[MC.name + 'SingleRepo']"
)
- span() Next Step: Naming
+ span Next Step: Naming
animated-panel.grid-block.vertical.modals-rename(
name = "nameContainer"
@@ -110,14 +110,15 @@
)
header.modal-header
svg.iconnables.icons-arrow-backward(
+ ng-class = "{'disabled': $root.isLoading[MC.name + 'SingleRepo']}"
ng-click = "!$root.isLoading[MC.name + 'SingleRepo'] && goToPanel(MC.state.templateSource ? 'containerSelection' : 'dockerfileMirroring', 'back')"
)
use(
xlink:href = "#icons-arrow-down"
)
h1.modal-heading.text-overflow(
- ng-if = "!$root.featureFlags.aha1"
- ) Container Name
+ ng-if = "!MC.ahaGuide.isAddingFirstRepo()"
+ ) Template Name
svg.iconnables.icons-close(
ng-click = "MC.close()"
)
@@ -155,7 +156,7 @@
ul.list.list-bulleted.list-validation
li.list-item(
ng-class = "{'ng-invalid': MC.nameForm.$error.unique}"
- ) Choose a unique name in your Sandbox
+ ) Choose a unique name for your template
li.list-item(
ng-class = "{'ng-invalid': MC.nameForm.$error.pattern || MC.nameForm.$error.noDoubleDash}"
) Use letters, numbers, and single hyphens (-)
@@ -174,15 +175,15 @@
MC.createBuildFromTemplate(MC.state.instanceName, MC.state.templateSource) \
"
)
- //- should say "Next Step: Configure" if a repository container
- //- should say "Create Container" if its a non-repository container
- .spinner-wrapper.spinner-white.spinner-sm.in(
- ng-include = "'spinner'"
+ //- should say "Next Step: Setup" if a repository container
+ //- should say "Create Template" if its a non-repository container
+ .spinner-wrapper.spinner-white.spinner-sm.float-left(
ng-if = "$root.isLoading[MC.name + 'SingleRepo']"
+ ng-include = "'spinner'"
)
span(
ng-if = "MC.state.repo"
- ) Next Step: Configure
+ ) Next Step: Setup
span(
ng-if = "MC.state.templateSource"
- ) Create Container
+ ) Create Template
diff --git a/client/directives/modals/modalNewContainer/tooltips/viewCountainerTooltip.jade b/client/directives/modals/modalNewContainer/tooltips/viewCountainerTooltip.jade
index 1d91a3e5b..7edc089ce 100644
--- a/client/directives/modals/modalNewContainer/tooltips/viewCountainerTooltip.jade
+++ b/client/directives/modals/modalNewContainer/tooltips/viewCountainerTooltip.jade
@@ -5,4 +5,4 @@
.arrow
.small.text-center This repo already exists
br
- | in your sandbox
+ | in your environment
diff --git a/client/directives/modals/modalRepoDetail/repositoryDetailsModalController.js b/client/directives/modals/modalRepoDetail/repositoryDetailsModalController.js
index 14ffd4100..8207441a2 100644
--- a/client/directives/modals/modalRepoDetail/repositoryDetailsModalController.js
+++ b/client/directives/modals/modalRepoDetail/repositoryDetailsModalController.js
@@ -49,12 +49,22 @@ function RepositoryDetailsModalController(
});
};
+ RDMC.hasCommitBeenUpdated = function () {
+ var newCommitSha = keypather.get(RDMC, 'data.commit.attrs.sha');
+ var oldCommitSha = keypather.get(RDMC, 'appCodeVersion.attrs.commit');
+ return newCommitSha && newCommitSha !== oldCommitSha;
+ };
+
+ RDMC.hasLockedBeenUpdated = function () {
+ return RDMC.data.locked !== RDMC.instance.attrs.locked;
+ };
+
RDMC.updateInstance = function () {
var updateInstance = function () {
return $q.when()
.then(function () {
loading('main', true);
- if (RDMC.data.locked === RDMC.instance.attrs.locked) {
+ if (!RDMC.hasLockedBeenUpdated()) {
return;
}
return promisify(instance, 'update')({
@@ -62,7 +72,9 @@ function RepositoryDetailsModalController(
});
})
.then(function () {
- return updateInstanceWithNewAcvData(RDMC.instance, RDMC.appCodeVersion, RDMC.data);
+ if (RDMC.hasCommitBeenUpdated()) {
+ return updateInstanceWithNewAcvData(RDMC.instance, RDMC.appCodeVersion, RDMC.data);
+ }
})
.finally(function () {
loading('main', false);
diff --git a/client/directives/modals/modalRepoDetail/repositoryDetailsModalView.jade b/client/directives/modals/modalRepoDetail/repositoryDetailsModalView.jade
index 12f779c7b..b367d7cbc 100644
--- a/client/directives/modals/modalRepoDetail/repositoryDetailsModalView.jade
+++ b/client/directives/modals/modalRepoDetail/repositoryDetailsModalView.jade
@@ -28,4 +28,5 @@
) Cancel
button.btn.btn-md.green.float-right(
ng-click = "RDMC.updateInstance()"
- ) Save & Rebuild
+ ng-disabled = "!RDMC.hasCommitBeenUpdated() && !RDMC.hasLockedBeenUpdated()"
+ ) {{ RDMC.hasCommitBeenUpdated() ? 'Save and Build' : 'Save' }}
diff --git a/client/directives/modals/settingsModal/forms/billingForm/billingHistoryForm/billingHistoryForm.jade b/client/directives/modals/settingsModal/forms/billingForm/billingHistoryForm/billingHistoryForm.jade
index c410c466c..e14ee270c 100644
--- a/client/directives/modals/settingsModal/forms/billingForm/billingHistoryForm/billingHistoryForm.jade
+++ b/client/directives/modals/settingsModal/forms/billingForm/billingHistoryForm/billingHistoryForm.jade
@@ -10,9 +10,9 @@
.cell.text-overflow.small Paid by {{invoice.paidBy.githubUser.name || invoice.paidBy.githubUser.login}}
.cell.monospace.text-right {{getBillingDate(invoice)}}
-div(
+.well.gray.ignore-margin.text-center.padding-sm.small(
ng-if = "invoices.length === 0"
-) You have no billing history right now.
+) You have no billing history.
//- if there's something older to load
//-.label
diff --git a/client/directives/modals/settingsModal/forms/billingForm/changePaymentForm/changePaymentForm.jade b/client/directives/modals/settingsModal/forms/billingForm/changePaymentForm/changePaymentForm.jade
index 92ba4da14..6451dcc69 100644
--- a/client/directives/modals/settingsModal/forms/billingForm/changePaymentForm/changePaymentForm.jade
+++ b/client/directives/modals/settingsModal/forms/billingForm/changePaymentForm/changePaymentForm.jade
@@ -104,7 +104,7 @@ form.padding-md(
ng-disabled="$root.isLoading.savePayment"
)
- .grid-block.well.padding-xxs.small.justify-center.text-center(
+ .grid-content.well.padding-xxs.small.justify-center.text-center(
payment-summary
show-next = 'false'
)
diff --git a/client/directives/modals/settingsModal/forms/billingForm/components/paymentSummary/paymentSummaryView.jade b/client/directives/modals/settingsModal/forms/billingForm/components/paymentSummary/paymentSummaryView.jade
index 157b50903..d59d046db 100644
--- a/client/directives/modals/settingsModal/forms/billingForm/components/paymentSummary/paymentSummaryView.jade
+++ b/client/directives/modals/settingsModal/forms/billingForm/components/paymentSummary/paymentSummaryView.jade
@@ -4,6 +4,7 @@ span(
strong.strong(
ng-if = "currentOrg.poppa.isInTrial()"
) You will not be charged until your trial ends.
+ |
span(
ng-if = "currentOrg.poppa.isGraceExpired() || currentOrg.poppa.isInGrace()"
diff --git a/client/directives/modals/settingsModal/forms/billingForm/components/planSummary/planSummaryView.jade b/client/directives/modals/settingsModal/forms/billingForm/components/planSummary/planSummaryView.jade
index 7f7e71902..d0fc96d53 100644
--- a/client/directives/modals/settingsModal/forms/billingForm/components/planSummary/planSummaryView.jade
+++ b/client/directives/modals/settingsModal/forms/billingForm/components/planSummary/planSummaryView.jade
@@ -2,7 +2,7 @@
ng-if = 'plan'
)
p.strong {{plan.name}} Plan
- small.small Up to {{plan.maxConfigurations}} configurations
+ small.small Up to {{plan.maxConfigurations}} templates
.grid-block.shrink.p.align-baseline(
ng-if = 'plan'
)
diff --git a/client/directives/modals/settingsModal/forms/billingForm/confirmationForm/confirmationForm.jade b/client/directives/modals/settingsModal/forms/billingForm/confirmationForm/confirmationForm.jade
index d5a33a958..c65266b9c 100644
--- a/client/directives/modals/settingsModal/forms/billingForm/confirmationForm/confirmationForm.jade
+++ b/client/directives/modals/settingsModal/forms/billingForm/confirmationForm/confirmationForm.jade
@@ -17,7 +17,7 @@
footer.modal-footer.clearfix
button.btn.btn-md.btn-block.green(
ng-if = "currentOrg.poppa.isInActivePeriod()"
- ) Go to your sandbox!
+ ) Go to your Environment
button.btn.btn-md.btn-block.white(
ng-click = "goToPanel('billingForm', 'back');"
ng-if = "currentOrg.poppa.isInTrial()"
diff --git a/client/directives/modals/settingsModal/forms/billingForm/planStatus/planStatusForm.jade b/client/directives/modals/settingsModal/forms/billingForm/planStatus/planStatusForm.jade
index 0649eb315..6493c2f5d 100644
--- a/client/directives/modals/settingsModal/forms/billingForm/planStatus/planStatusForm.jade
+++ b/client/directives/modals/settingsModal/forms/billingForm/planStatus/planStatusForm.jade
@@ -1,7 +1,7 @@
//- changing plans
.padding-md
.clearfix
- .label-col.full-width.text-center Configurations Used
+ .label-col.full-width.text-center Templates Used
.meter(
ng-class = "getMeterClass()"
)
@@ -26,7 +26,7 @@
.tick
.tick
- .grid-block.align-center
+ .grid-block.align-center.plans-wrapper
.grid-block.vertical.align-center.card.card-plan.disabled.padding-sm.text-center(
ng-class = "{'active': PSFC.plan.id === 'runnable-starter'}"
ng-mouseenter = "preview = 'runnable-starter'"
@@ -47,7 +47,7 @@
| per month
.grid-content.shrink.small Up to
strong.strong 2
- | configurations.
+ | templates.
.grid-block.vertical.align-center.card.card-plan.disabled.padding-sm.text-center(
ng-class = "{'active': PSFC.plan.id === 'runnable-standard'}"
@@ -69,7 +69,7 @@
| per month
.grid-content.shrink.small Up to
strong.strong 7
- | configurations.
+ | templates.
.grid-block.vertical.align-center.card.card-plan.disabled.padding-sm.text-center(
ng-class = "{'active': PSFC.plan.id === 'runnable-plus'}"
@@ -91,7 +91,7 @@
| per month
.grid-content.shrink.small Up to
strong.strong 15
- | configurations.
+ | templates.
label.grid-block.align-center.padding-xs.well.well-plan.well-summary.disabled(
ng-if = "PSFC.discount"
@@ -100,7 +100,7 @@
discount = "PSFC.discount"
)
- p.grid-content.p.text-gray.text-center.padding-sm Your plan is automatically determined based on number of configurations at the end of each billing cycle.
+ p.grid-content.p.text-gray.text-center.padding-sm All plans require at least 3 users. Your plan is automatically determined based on number of templates at the end of each billing cycle.
.grid-block.justify-center
button.grid-block.shrink.btn.btn-md.green(
diff --git a/client/directives/modals/settingsModal/forms/billingForm/trialForm/trialForm.jade b/client/directives/modals/settingsModal/forms/billingForm/trialForm/trialForm.jade
index 9715ab510..c07dc0a39 100644
--- a/client/directives/modals/settingsModal/forms/billingForm/trialForm/trialForm.jade
+++ b/client/directives/modals/settingsModal/forms/billingForm/trialForm/trialForm.jade
@@ -21,11 +21,11 @@
ng-if = "currentOrg.poppa.trialDaysRemaining() > 3"
) You have
strong.strong {{currentOrg.poppa.trialDaysRemaining()}} days
- | left in your trial with unlimited configurations.
+ | left in your trial with unlimited templates.
p.grid-content.small.text-gray(
ng-if = "currentOrg.poppa.trialDaysRemaining() <= 3"
- ) You only have {{currentOrg.poppa.trialDaysRemaining()}} days left in your trial! Add your payment info to ensure your team has uninterrupted access to their sandbox.
+ ) You only have {{currentOrg.poppa.trialDaysRemaining()}} days left in your trial! Add your payment info to ensure your team has uninterrupted access to Runnable.
.grid-block.btn-wrapper(
diff --git a/client/directives/modals/settingsModal/forms/gitHubForm/gitHubForm.jade b/client/directives/modals/settingsModal/forms/gitHubForm/gitHubForm.jade
new file mode 100644
index 000000000..fb5d798e3
--- /dev/null
+++ b/client/directives/modals/settingsModal/forms/gitHubForm/gitHubForm.jade
@@ -0,0 +1,9 @@
+//- If loading:
+//- .modal-form
+ .spinner-wrapper.spinner-md.spinner-gray.in(
+ ng-include = "'spinner'"
+ )
+
+.modal-form.empty.grid-block.vertical.align-center.form-github(
+ github-integration
+)
diff --git a/client/directives/modals/settingsModal/forms/teamManagementForm/teamManagementFormView.jade b/client/directives/modals/settingsModal/forms/teamManagementForm/teamManagementFormView.jade
index f1e7c0107..764e95717 100644
--- a/client/directives/modals/settingsModal/forms/teamManagementForm/teamManagementFormView.jade
+++ b/client/directives/modals/settingsModal/forms/teamManagementForm/teamManagementFormView.jade
@@ -27,7 +27,7 @@
.p.text-gray.text-center.padding-xs(
ng-if = "state.fromTrialEnd"
- ) We’ll only create or update containers for the selected users.
+ ) We’ll only create and update containers for the selected users.
ol.list.list-bordered.list-teammates
li.list-item(
diff --git a/client/directives/modals/settingsModal/forms/teamManagementForm/teammateOptionsPopoverView.jade b/client/directives/modals/settingsModal/forms/teamManagementForm/teammateOptionsPopoverView.jade
index 19d19b1cf..0f27db6ec 100644
--- a/client/directives/modals/settingsModal/forms/teamManagementForm/teammateOptionsPopoverView.jade
+++ b/client/directives/modals/settingsModal/forms/teamManagementForm/teammateOptionsPopoverView.jade
@@ -1,10 +1,10 @@
.popover.menu.bottom(
- ng-class = "{in: active}"
+ ng-class = "{'in': active}"
ng-style = "popoverStyle.getStyle()"
style = "transform-origin: 90% 0"
)
.arrow.white(
- style = "left: auto; right: 0"
+ style = "left: auto; right: 1px"
)
.popover-content
ul.popover-list
diff --git a/client/directives/modals/settingsModal/settingsModalView.jade b/client/directives/modals/settingsModal/settingsModalView.jade
index 36b7113bb..85b414f77 100644
--- a/client/directives/modals/settingsModal/settingsModalView.jade
+++ b/client/directives/modals/settingsModal/settingsModalView.jade
@@ -29,20 +29,26 @@
.btn-text.grid-content Billing
button.btn.btn-radio.grid-block.vertical(
ng-class = "{'active': SEMC.currentTab === 'teamManagement'}"
- ng-click = "\
- SEMC.currentTab = 'teamManagement';\
- "
+ ng-click = "SEMC.currentTab = 'teamManagement'"
)
svg.iconnables.grid-content
use(
xlink:href = "#icons-team"
)
.btn-text.grid-content Teammates
+ button.btn.btn-radio.grid-block.vertical(
+ ng-class = "{'active': SEMC.currentTab === 'githubIntegration'}"
+ ng-click = "SEMC.currentTab = 'githubIntegration'"
+ ng-if = "$root.featureFlags.gitHubIntegration"
+ )
+ svg.iconnables.grid-content
+ use(
+ xlink:href = "#icons-octicons-github-gray"
+ )
+ .btn-text.grid-content PR Bot
button.btn.btn-radio.grid-block.vertical(
ng-class = "{'active': SEMC.currentTab === 'slackIntegration'}"
- ng-click = "\
- SEMC.currentTab = 'slackIntegration';\
- "
+ ng-click = "SEMC.currentTab = 'slackIntegration'"
)
img.img.iconnables.grid-content(
height = "24"
@@ -62,6 +68,11 @@
ng-if = "SEMC.currentTab === 'teamManagement'"
)
+ div(
+ ng-if = "SEMC.currentTab === 'githubIntegration'"
+ ng-include = "'gitHubForm'"
+ )
+
slack-integration-form(
ng-if = "SEMC.currentTab === 'slackIntegration'"
)
diff --git a/client/directives/navBar/viewNav.jade b/client/directives/navBar/viewNav.jade
index 1dbf2171b..fb52867a3 100644
--- a/client/directives/navBar/viewNav.jade
+++ b/client/directives/navBar/viewNav.jade
@@ -4,9 +4,9 @@
data = "dataApp.data"
)
-//- aha menu
+//- aha menu --- This should be triggered via an event!
.popover.right.in.popover-aha(
- ng-if = "$root.featureFlags.aha2 && !$root.featureFlags.aha1ExitedEarly"
+ ng-if = "$root.featureFlags.aha && CA.showAhaNavPopover"
ng-include = "'ahaPopoverView'"
)
@@ -18,10 +18,10 @@ a.a(
use(
xlink:href = "#icons-gear-dark"
)
- | Configure
+ | Templates
a.a.disabled(
- ng-if = "(dataApp.state.includes('base.config') && CA.instancesByPod && !CA.instancesByPod.models.length) || $root.featureFlags.aha1 || $root.featureFlags.aha1ExitedEarly"
+ ng-if = "(dataApp.state.includes('base.config') && CA.instancesByPod && !CA.instancesByPod.models.length) && !$root.featureFlags.containersViewTemplateControls"
tooltip = "You don’t have any running containers yet!"
tooltip-options = "{\"class\":\"right\",\"left\":75,\"top\":17}"
)
@@ -32,10 +32,14 @@ a.a.disabled(
| Containers
a.a(
- ng-if = "(dataApp.state.includes('base.instances') || !CA.instancesByPod || CA.instancesByPod.models.length) && !$root.featureFlags.aha1 && !$root.featureFlags.aha1ExitedEarly"
+ ng-if = "(dataApp.state.includes('base.instances') || !CA.instancesByPod || CA.instancesByPod.models.length) || $root.featureFlags.containersViewTemplateControls"
ui-sref = "base.instances({ userName: CA.activeAccount.oauthName() })"
ui-sref-active = "active"
)
+ .aha-overlay-div(
+ ng-if = "$root.featureFlags.aha && CA.ahaGuide.isAddingFirstRepo() && CA.instancesByPod.models.length && !CA.ahaGuide.hasConfirmedSetup()"
+ ng-click = "CA.showAhaConfirmation($event)"
+ )
svg.iconnables.icons-server-dark
use(
xlink:href = "#icons-server-dark"
diff --git a/client/directives/ngclick.js b/client/directives/ngclick.js
index 3a1415d24..67582e8f6 100644
--- a/client/directives/ngclick.js
+++ b/client/directives/ngclick.js
@@ -22,6 +22,7 @@ function ngClick(
});
eventTracking.trackClicked({
attrs: cleanedAttrs,
+ eventName: attrs.eventName,
text: text
});
}
diff --git a/client/directives/popovers/popOverController.js b/client/directives/popovers/popOverController.js
index 3e4f5be83..30d0985c8 100644
--- a/client/directives/popovers/popOverController.js
+++ b/client/directives/popovers/popOverController.js
@@ -15,6 +15,7 @@ function PopOverController(
var POC = this;
POC.unbindDocumentClick = angular.noop;
POC.unbindPopoverOpened = angular.noop;
+ POC.unbindSpecificPopoverOpened = angular.noop;
POC.isPopoverActive = function () {
return $scope.active;
@@ -25,6 +26,11 @@ function PopOverController(
$scope.active = false;
POC.unbindDocumentClick();
POC.unbindPopoverOpened();
+ POC.unbindSpecificPopoverOpened();
+ $rootScope.$broadcast('popover-closed', {
+ template: $scope.template,
+ data: $scope.data
+ });
// We need a closure because they could technically re-open the popover and we want to manage THIS scope and THIS element.
(function (popoverElementScope, popoverElement) {
//Give the transition some time to finish!
@@ -39,6 +45,10 @@ function PopOverController(
}(POC.popoverElementScope, POC.popoverElement));
};
POC.openPopover = function () {
+ $rootScope.$broadcast('popover-opened', {
+ template: $scope.template,
+ data: $scope.data
+ });
$scope.popoverOptions = $scope.popoverOptions || {};
if (!exists($scope.popoverOptions.top) && !exists($scope.popoverOptions.bottom)) {
@@ -48,20 +58,30 @@ function PopOverController(
$scope.popoverOptions.left = 0;
}
- $rootScope.$broadcast('close-popovers');
+ if (!$scope.noBroadcast) {
+ $rootScope.$broadcast('close-popovers');
+ }
+
$timeout(function () {
// If the click has no target we should close the popover.
// If the click has a target and that target is on the page but not on our popover we should close the popover.
// Otherwise we should keep the popover alive.
POC.unbindDocumentClick = $scope.$on('app-document-click', function (event, target) {
- if (!target || (target && $document[0].contains(target) && !POC.popoverElement[0].contains(target))) {
+ if (!$scope.userCannotClose && (!target || (target && $document[0].contains(target) && !POC.popoverElement[0].contains(target)))) {
POC.closePopover();
}
});
}, 0);
- POC.unbindPopoverOpened = $scope.$on('close-popovers', function () {
- POC.closePopover();
+ POC.unbindPopoverOpened = $scope.$on('close-popovers', function (event, closeAllPopoversOverride) {
+ if (!$scope.userCannotClose || closeAllPopoversOverride) {
+ POC.closePopover();
+ }
+ });
+ POC.unbindSpecificPopoverOpened = $scope.$on('close-open-state-popover', function (event, popoverName) {
+ if ($scope.data && $scope.data.popoverName === popoverName) {
+ POC.closePopover();
+ }
});
var template = $templateCache.get($scope.template);
diff --git a/client/directives/popovers/popOverDirective.js b/client/directives/popovers/popOverDirective.js
index fda8b35ab..480760a63 100755
--- a/client/directives/popovers/popOverDirective.js
+++ b/client/directives/popovers/popOverDirective.js
@@ -9,14 +9,15 @@ require('app')
var scopeVars = {
- data: '=? popOverData',
- popoverOptions: '=? popOverOptions',
- noBroadcast: '=? popOverNoBroadcast',
actions: '=? popOverActions',
active: '=? popOverActive',
- template: '= popOverTemplate',
controller: '=? popOverController',
- controllerAs: '@? popOverControllerAs'
+ controllerAs: '@? popOverControllerAs',
+ data: '=? popOverData',
+ noBroadcast: '=? popOverNoBroadcast',
+ popoverOptions: '=? popOverOptions',
+ template: '= popOverTemplate',
+ userCannotClose: '=? popOverUncloseable'
};
function popOver(
@@ -53,6 +54,7 @@ function popOver(
return $log.error('Pop over needs a template');
}
}
+ $scope.element = element;
$scope.popoverOptions = $scope.popoverOptions || {};
$scope.active = $scope.active || false;
$scope.popoverStyle = {
@@ -60,7 +62,9 @@ function popOver(
if (!$scope.active) {
return previousStyle;
}
+
var offset = {};
+ var topMargin = 8;
var scrollTop = $document.find('body')[0].scrollTop || $document.find('html')[0].scrollTop;
if (keypather.get($scope, 'popoverOptions.mouse')) {
@@ -99,11 +103,42 @@ function popOver(
if (keypather.get($scope, 'popoverOptions.verticallyCentered')) {
style.bottom = null;
- style.top = Math.round((-POC.popoverElement[0].offsetHeight / 2 + offset.top + (offset.bottom - offset.top) / 2)) + 'px';
+ var targetedTopVal = Math.round((-POC.popoverElement[0].offsetHeight / 2 + offset.top + (offset.bottom - offset.top) / 2));
+ if (
+ $scope.popoverOptions.pinToViewPort && // If true, make sure popover is not displayed outside the viewport
+ POC.popoverElement[0].offsetHeight + targetedTopVal > $document.find('body')[0].offsetHeight
+ ) {
+ targetedTopVal = $document.find('body')[0].offsetHeight - POC.popoverElement[0].offsetHeight - 8;
+ }
+ if (targetedTopVal < 0) {
+ targetedTopVal = topMargin;
+ }
+
+ style.top = targetedTopVal + 'px';
}
previousStyle = style;
return style;
+ },
+
+ getArrowStyle: function() {
+ var style = {};
+ var elementPosition = $scope.element[0].getBoundingClientRect();
+ var elementCenter = (elementPosition.bottom + elementPosition.top) / 2;
+
+ var popoverElementPosition = POC.popoverElement[0].getBoundingClientRect();
+
+ var topInt = parseInt($scope.popoverStyle.getStyle().top.replace('px', ''));
+ var isAtBottom = window.innerHeight - elementPosition.top < 180;
+
+ var diff = Math.abs(popoverElementPosition.top - elementCenter);
+
+ if (topInt > 8 && !isAtBottom || diff > POC.popoverElement[0].getBoundingClientRect().height) {
+ return style;
+ } else {
+ style.top = diff + 'px';
+ return style;
+ }
}
};
@@ -129,8 +164,10 @@ function popOver(
bottom: event.pageY
}
};
+
POC.openPopover($scope.options);
}
+
var trigger = attrs.popOverTrigger || 'click';
switch (trigger) {
case 'rightClick':
diff --git a/client/directives/popovers/popoverMoreContainers/viewMoreContainersPopover.jade b/client/directives/popovers/popoverMoreContainers/viewMoreContainersPopover.jade
index 2675a4408..f48f69000 100644
--- a/client/directives/popovers/popoverMoreContainers/viewMoreContainersPopover.jade
+++ b/client/directives/popovers/popoverMoreContainers/viewMoreContainersPopover.jade
@@ -2,10 +2,10 @@
ng-class = "{in: active}"
ng-style = "popoverStyle.getStyle()"
)
- .popover-header api Containers
+ .popover-header api
input.input.input-xs.input-search(
ng-model = "data.repoFilter"
- placeholder = "Filter by branch name"
+ placeholder = "Filter by name"
required
type = "search"
select-on = "showFilter"
diff --git a/client/directives/repositorySelector/views/viewPopoverFilesRepositoryOptions.jade b/client/directives/repositorySelector/views/viewPopoverFilesRepositoryOptions.jade
index c90fcd2bd..eaab64423 100644
--- a/client/directives/repositorySelector/views/viewPopoverFilesRepositoryOptions.jade
+++ b/client/directives/repositorySelector/views/viewPopoverFilesRepositoryOptions.jade
@@ -69,7 +69,7 @@
ng-model = "repoSelector.data.commands"
spellcheck = "false"
)
- small.small Add scripts to be run before your container is started.
+ small.small Add scripts to run before your container is started.
.popover-footer.clearfix.fade(
ng-class = "{'in': isActivePanel()}"
diff --git a/client/directives/repositorySelector/views/viewPopoverFilesRepositorySelect.jade b/client/directives/repositorySelector/views/viewPopoverFilesRepositorySelect.jade
index 6e9d042c3..a68136a3d 100644
--- a/client/directives/repositorySelector/views/viewPopoverFilesRepositorySelect.jade
+++ b/client/directives/repositorySelector/views/viewPopoverFilesRepositorySelect.jade
@@ -36,7 +36,7 @@
ul.list.list-servers(
ng-if = "repoSelector.data.githubRepos.models"
)
- li.list-item.multi-line(
+ li.grid-block.align-center.list-item.multi-line(
ng-class = "{\
'active': repo.loading,\
'no-touching': repoSelector.data.loading\
@@ -46,34 +46,37 @@
repo in repoSelector.data.githubRepos.models | \
repos: repoSelector.data.repoFilter | \
allBut: data.appCodeVersions | \
- orderBy: '-attrs.updated_at'\
+ orderBy: '-attrs.pushed_at'\
"
- ) {{ repo.attrs.name}}
+ )
+ .grid-content.text-overflow(
+ title = "{{ repo.attrs.name}}"
+ ) {{ repo.attrs.name}}
- //- if invite flows...
- .row.row-author(
- ng-if = "$root.featureFlags.inviteFlows"
- )
- .btn-user.text-overflow.no-touching(
- ng-class = "{'active': state.active}"
- ng-include = "'userButtonView'"
- )
- span.small(
+ //- if invite flows...
+ .row.row-author(
ng-if = "$root.featureFlags.inviteFlows"
- ) —{{repo.attrs.updated_at | timeFrom}}
+ )
+ .btn-user.text-overflow.no-touching(
+ ng-class = "{'active': state.active}"
+ ng-include = "'userButtonView'"
+ )
+ span.small(
+ ng-if = "$root.featureFlags.inviteFlows"
+ ) —{{repo.attrs.pushed_at | timeFrom}}
- //- else
- small.small(
- ng-if = "!$root.featureFlags.inviteFlows"
- ) Updated {{ repo.attrs.updated_at | timeFrom }}
+ //- else
+ small.small(
+ ng-if = "!$root.featureFlags.inviteFlows"
+ ) Updated {{ repo.attrs.pushed_at | timeFrom }}
- svg.iconnables.icons-arrow-down(
+ svg.grid-content.shrink.iconnables.icons-arrow-down(
ng-if = "!repo.loading"
)
use(
xlink:href = "#icons-arrow-down"
)
- .spinner-wrapper.spinner-sm.spinner-purple.in(
+ .grid-content.shrink.spinner-wrapper.spinner-sm.spinner-purple.in(
ng-if = "repo.loading"
ng-include = "'spinner'"
)
diff --git a/client/services/ahaGuideService.js b/client/services/ahaGuideService.js
new file mode 100644
index 000000000..1bc90be98
--- /dev/null
+++ b/client/services/ahaGuideService.js
@@ -0,0 +1,343 @@
+'use strict';
+
+require('app')
+ .factory('ahaGuide', ahaGuide);
+
+var STEPS = {
+ CHOOSE_ORGANIZATION: 1,
+ ADD_FIRST_REPO: 2,
+ ADD_FIRST_BRANCH: 3,
+ SETUP_RUNNABOT: 4,
+ COMPLETED: -1
+};
+
+function ahaGuide(
+ $rootScope,
+ currentOrg,
+ fetchInstancesByPod,
+ isRunnabotPartOfOrg,
+ keypather,
+ patchOrgMetadata
+) {
+ var instances = [];
+ var hasRunnabot = false;
+ function refreshInstances() {
+ return fetchInstancesByPod()
+ .then(function (fetchedInstances) {
+ instances = fetchedInstances;
+ });
+ }
+ function refreshHasRunnabot() {
+ if (hasRunnabot) { return true; }
+ return isRunnabotPartOfOrg(keypather.get(currentOrg, 'github.attrs.login'))
+ .then(function (runnabot) {
+ if (runnabot && isInGuide()) {
+ endGuide()
+ .then(function() {
+ $rootScope.$broadcast('showAutoLaunchPopover');
+ });
+ }
+ hasRunnabot = runnabot;
+ return hasRunnabot;
+ });
+ }
+
+ refreshInstances();
+ refreshHasRunnabot();
+
+ var stepList = {};
+ stepList[STEPS.CHOOSE_ORGANIZATION] = {
+ title: 'Step 1: Choose your Organization',
+ subSteps: {
+ orgSelection: {
+ caption: 'Select the organization you want to use with Runnable.',
+ className: 'aha-meter-33'
+ },
+ dockLoading: {
+ caption: 'Bear with us!',
+ className: 'aha-meter-66'
+ },
+ dockLoaded: {
+ caption: 'Continue to start configuring your project.',
+ className: 'aha-meter-100'
+ }
+ },
+ panelSteps: {
+ orgSelection: 0,
+ dockLoading: 1,
+ dockLoaded: 2
+ },
+ defaultSubstep: 'orgSelection'
+ };
+
+ stepList[STEPS.ADD_FIRST_REPO] = {
+ title: 'Step 2: Configure your Application',
+ subSteps: {
+ addRepository: {
+ className: 'aha-meter-11',
+ step: 0,
+ value: 10
+ },
+ containerSelection: {
+ className: 'aha-meter-22',
+ step: 1,
+ value: 20
+ },
+ dockerfileMirroring: {
+ className: 'aha-meter-33',
+ step: 2,
+ value: 30
+ },
+ nameContainer: {
+ className: 'aha-meter-44',
+ step: 3,
+ value: 40
+ },
+ repository: {
+ className: 'aha-meter-55',
+ step: 4,
+ value: 50
+ },
+ commands: {
+ className: 'aha-meter-66',
+ step: 5,
+ value: 60
+ },
+ buildfiles: {
+ className: 'aha-meter-77',
+ step: 6,
+ value: 70
+ },
+ default: {
+ className: 'aha-meter-77',
+ step: 6,
+ value: 70
+ },
+ env: {
+ className: 'aha-meter-77',
+ step: 6,
+ value: 70
+ },
+ files: {
+ className: 'aha-meter-77',
+ step: 6,
+ value: 70
+ },
+ filesMirror: {
+ className: 'aha-meter-77',
+ step: 6,
+ value: 70
+ },
+ ports: {
+ className: 'aha-meter-77',
+ step: 6,
+ value: 70
+ },
+ translation: {
+ className: 'aha-meter-77',
+ step: 6,
+ value: 70
+ },
+ logs: {
+ className: 'aha-meter-88',
+ step: 7,
+ value: 80
+ },
+ exitedEarly: {
+ className: 'aha-meter-88',
+ step: 7,
+ value: 80
+ },
+ success: {
+ className: 'aha-meter-100',
+ step: 8,
+ value: 90
+ },
+ complete: {
+ className: 'aha-meter-100',
+ step: 9,
+ value: 100
+ }
+ },
+ buildStatus: {
+ building: 'We‘re building! Build time varies depending on your build commands.',
+ starting: 'We‘re building! Build time varies depending on your build commands.',
+ running: 'Looking good! Check out your URL, and click ‘Done’ if it looks good to you too.',
+ stopped: 'Your template isn‘t running yet! Check the logs to debug any issues. If you‘re stumped, ask our engineers!',
+ cmdFailed: 'Your template isn‘t running yet! Check the logs to debug any issues. If you‘re stumped, ask our engineers!',
+ crashed: 'Your template isn‘t running yet! Check the logs to debug any issues. If you‘re stumped, ask our engineers!',
+ buildFailed: 'Your template isn‘t running yet! Check the logs to debug any issues. If you‘re stumped, ask our engineers!'
+ },
+ configSubsteps: ['default', 'env', 'files', 'ports', 'translation'],
+ defaultSubstep: 'addRepository'
+ };
+
+ stepList[STEPS.ADD_FIRST_BRANCH] = {
+ title: 'Step 3: Add a Branch',
+ subSteps: {
+ addBranch: {
+ caption: 'Almost done! Click the + button next to a repo name to add a branch.',
+ className: 'aha-meter-33',
+ value: 33
+ },
+ selectBranch: {
+ className: 'aha-meter-66',
+ value: 66
+ },
+ noBranches: {
+ className: 'aha-meter-100',
+ value: 100
+ },
+ deletedTemplate: {
+ caption: 'You\'ve deleted your repository template. Create another one to continue.',
+ className: 'aha-meter-20',
+ value: -1
+ }
+ },
+ panelSteps: { },
+ defaultSubstep: 'addBranch'
+ };
+
+ stepList[STEPS.SETUP_RUNNABOT] = {
+ subSteps: {
+ setupRunnabot: {
+ caption: 'Get the most out of Runnabot by adding branches automatically',
+ className: 'aha-meter-50'
+ }
+ }
+ };
+
+ var cachedSubstep = {};
+
+/**
+ * Furthest Substep getter/setter
+ *
+ * When setting the substep, the new subStep must have a value greater than the previous step to
+ * be updated
+ *
+ * @param step {Number} Which step to reference when looking at the substep
+ * @param newSubstep {String} new substep to go to
+ * @returns {String} substep currently on
+ */
+ function furthestSubstep(step, newSubstep) {
+ if (arguments.length > 1) {
+ if (!cachedSubstep[step]) {
+ cachedSubstep[step] = newSubstep;
+ } else {
+ var newStepValue = keypather.get(stepList[step], 'subSteps.' + newSubstep + '.value');
+ var oldSubstepValue = keypather.get(stepList[step], 'subSteps.' + cachedSubstep[step] + '.value');
+ if (newStepValue === -1 || newStepValue > oldSubstepValue) {
+ // automatically allow switch when an error state
+ cachedSubstep[step] = newSubstep;
+ }
+ }
+ }
+ return cachedSubstep[step] || stepList[step].defaultSubstep;
+ }
+
+ var cachedStep;
+ $rootScope.$watch(function () {
+ cachedStep = null;
+ });
+ $rootScope.$on('$stateChangeSuccess', function () {
+ refreshInstances();
+ refreshHasRunnabot();
+ });
+ function getCurrentStep() {
+ if (!cachedStep) {
+ if ($rootScope.featureFlags.aha && !keypather.get(currentOrg, 'poppa.id')) {
+ cachedStep = STEPS.CHOOSE_ORGANIZATION;
+ } else if (!isInGuide()) {
+ cachedStep = STEPS.COMPLETED;
+ } else if (!hasConfirmedSetup()) {
+ cachedStep = STEPS.ADD_FIRST_REPO;
+ } else {
+ // loop over instances and see if any has ever had a branch launched
+ var hasBranchLaunched = false;
+ if (keypather.get(instances, 'models.length')) {
+ instances.models.some(function (instance) {
+ hasBranchLaunched = instance.attrs.hasAddedBranches || keypather.get(instance, 'children.models.length');
+ return hasBranchLaunched;
+ });
+ }
+ if (!hasBranchLaunched && !ahaGuide.skippedBranchMilestone) {
+ cachedStep = STEPS.ADD_FIRST_BRANCH;
+ } else if (!hasRunnabot) {
+ cachedStep = STEPS.SETUP_RUNNABOT;
+ } else {
+ cachedStep = STEPS.COMPLETED;
+ }
+ }
+ }
+ return cachedStep;
+ }
+
+ function isInGuide () {
+ return keypather.get(currentOrg, 'poppa.attrs.metadata.hasAha');
+ }
+
+ function hasConfirmedSetup () {
+ return keypather.get(currentOrg, 'poppa.attrs.metadata.hasConfirmedSetup');
+ }
+
+ function updateCurrentOrg (updatedOrg) {
+ if (keypather.has(updatedOrg, 'metadata.hasAha') && keypather.has(updatedOrg, 'metadata.hasConfirmedSetup')) {
+ currentOrg.poppa.attrs.metadata = updatedOrg.metadata;
+ }
+ }
+
+ function skipBranchMilestone () {
+ ahaGuide.skippedBranchMilestone = true;
+ $rootScope.$broadcast('showAhaSidebar');
+ }
+
+ function endGuide () {
+ $rootScope.$broadcast('close-popovers');
+ return patchOrgMetadata(currentOrg.poppa.id(), {
+ metadata: {
+ hasAha: false
+ }
+ })
+ .then(function (updatedOrg) {
+ updateCurrentOrg(updatedOrg);
+ });
+ }
+
+ function resetGuide() {
+ return patchOrgMetadata(currentOrg.poppa.id(), {
+ metadata: {
+ hasAha: true,
+ hasConfirmedSetup: false
+ }
+ })
+ .then(function (updatedOrg) {
+ updateCurrentOrg(updatedOrg);
+ });
+ }
+
+ return {
+ endGuide: endGuide,
+ resetGuide: resetGuide,
+ getCurrentStep: getCurrentStep,
+ hasConfirmedSetup: hasConfirmedSetup,
+ hasRunnabot: refreshHasRunnabot,
+ isInGuide: isInGuide,
+ stepList: stepList,
+ steps: STEPS,
+ updateCurrentOrg: updateCurrentOrg,
+ furthestSubstep: furthestSubstep,
+ skipBranchMilestone: skipBranchMilestone,
+ isChoosingOrg: function() {
+ return getCurrentStep() === STEPS.CHOOSE_ORGANIZATION;
+ },
+ isAddingFirstRepo: function () {
+ return getCurrentStep() === STEPS.ADD_FIRST_REPO;
+ },
+ isAddingFirstBranch: function() {
+ return getCurrentStep() === STEPS.ADD_FIRST_BRANCH;
+ },
+ isSettingUpRunnabot: function() {
+ return getCurrentStep() === STEPS.SETUP_RUNNABOT && !hasRunnabot;
+ }
+ };
+}
diff --git a/client/services/configs/serviceIntercomAppId.js b/client/services/configs/serviceIntercomAppId.js
new file mode 100644
index 000000000..234b58cf7
--- /dev/null
+++ b/client/services/configs/serviceIntercomAppId.js
@@ -0,0 +1,4 @@
+'use strict';
+
+require('app')
+ .value('intercomAppId', require('config/environment').intercomAppId);
diff --git a/client/services/configs/siftApiConfigService.js b/client/services/configs/siftApiConfigService.js
new file mode 100755
index 000000000..9e015a6b0
--- /dev/null
+++ b/client/services/configs/siftApiConfigService.js
@@ -0,0 +1,4 @@
+'use strict';
+
+require('app')
+ .value('siftApiConfig', require('config/api').siftApiKey);
diff --git a/client/services/createAndBuildNewContainerService.js b/client/services/createAndBuildNewContainerService.js
index af03c678a..db346b010 100644
--- a/client/services/createAndBuildNewContainerService.js
+++ b/client/services/createAndBuildNewContainerService.js
@@ -20,7 +20,7 @@ function createAndBuildNewContainer(
fetchInstancesByPod,
fetchPlan,
fetchUser,
- helpCards
+ keypather
) {
return function (createPromiseForState, containerName, options) {
options = options || {};
@@ -35,7 +35,7 @@ function createAndBuildNewContainer(
plan: fetchPlan()
})
.then(function (response) {
- oldPlanId = response.plan.next.id;
+ oldPlanId = keypather.get(response, 'plan.next.id');
var instanceOptions = {
name: containerName,
owner: {
@@ -51,7 +51,6 @@ function createAndBuildNewContainer(
return $q.when(createPromiseForState);
})
.then(function (newServerModel) {
- helpCards.hideActiveCard();
if (options.isolation) {
newServerModel.opts.isIsolationGroupMaster = false;
newServerModel.opts.isolated = options.isolation.id();
@@ -78,12 +77,13 @@ function createAndBuildNewContainer(
});
})
.then(function (instance) {
- helpCards.refreshAllCards();
return instance;
})
.catch(function (err) {
// Remove it from the servers list
- instance.dealloc();
+ if (instance) {
+ instance.dealloc();
+ }
return $q.reject(err);
});
};
diff --git a/client/services/createNewSandboxForUserService.js b/client/services/createNewSandboxForUserService.js
index dfba27d2a..a66333e30 100644
--- a/client/services/createNewSandboxForUserService.js
+++ b/client/services/createNewSandboxForUserService.js
@@ -4,12 +4,14 @@ require('app')
.factory('createNewSandboxForUserService', createNewSandboxForUserService);
function createNewSandboxForUserService(
+ eventTracking,
fetchUser,
promisify
) {
return function (orgName) {
return fetchUser()
.then(function (user) {
+ eventTracking.waitingForInfrastructure(orgName);
return promisify(user, 'createUserWhitelist')({ name: orgName });
});
};
diff --git a/client/services/featureFlagService.js b/client/services/featureFlagService.js
index 9ef1f8daa..242959269 100644
--- a/client/services/featureFlagService.js
+++ b/client/services/featureFlagService.js
@@ -7,28 +7,27 @@ function featureFlags(
$localStorage
) {
var defaultFeatureFlags = {
- aha: false,
- aha0: false, // step 1: create sandbox
- aha1: false, // step 2: working repo config
- aha1ExitedEarly: false, // step 2: if the user left the flow before getting a running config
- aha2: false, // step 3: add branch
- aha3: false, // step 4: runnabot
- ahaOverview: false, // toggle sidebar
- ahaSidebar: false, // toggle sidebar
+ addBranches: true,
+ aha: true,
+ ahaBranchUrlStep: false,
allowIsolatedUpdate: false,
autoIsolation: false,
autoIsolationSetup: false,
backup: false,
- blankDockerfile: false, // allows users to skip the verification flow
+ blankDockerfile: true, // allows users to skip the verification flow
billing: true,
cardStatus: false,
connections: false,
- configTerminal: false, // flag for terminal in config view
+ configTerminal: true, // flag for terminal in config view
+ containersViewTemplateControls: false,
+ containersViewEmptyState: false,
+ contingencyPlan: false,
dockerfileMirroringMultiple: false,
editAnyInstance: false,
emptyFolder: false, // shows empty folder markup
fullScreen: false, // toggles full screen
fullScreenToggle: false, // toggles the button that toggles full screen
+ gitHubIntegration: true,
hostnameNotifications: false,
hostnameTool: false,
imAfraidOfTheDark: false, // toggles theme
@@ -39,8 +38,8 @@ function featureFlags(
multilineStartCmd: false,
multipleRepositoryContainers: false, // for adding multiple containers with the same repository
navListFilter: false,
- nextPayment: false, // show the next payment date under payment summary
newUserPrompt: false, // modal for new users
+ nextPayment: false, // show the next payment date under payment summary
noBuildLogs: true,
optionsInModal: false, // allows delete in modal
renameContainer: false,
@@ -52,7 +51,7 @@ function featureFlags(
trial: false, // sets account to trial mode
undoDelete: false, // undo delete configuration
webhooks: false,
- webToolbar: false, // webview toolbar
+ webToolbar: true, // webview toolbar
whitelistIpFiltering: false
};
diff --git a/client/services/patchOrgMetadata.js b/client/services/patchOrgMetadata.js
new file mode 100644
index 000000000..3e54076bf
--- /dev/null
+++ b/client/services/patchOrgMetadata.js
@@ -0,0 +1,22 @@
+'use strict';
+
+require('app')
+ .factory('patchOrgMetadata', patchOrgMetadata);
+
+function patchOrgMetadata(
+ $http,
+ configAPIHost,
+ errs
+) {
+ return function (orgId, params) {
+ return $http({
+ method: 'patch',
+ url: configAPIHost + '/auth/whitelist/' + orgId,
+ data: params
+ })
+ .then(function(response) {
+ return response.data;
+ })
+ .catch(errs.handler);
+ };
+}
diff --git a/client/services/runnabotService.js b/client/services/runnabotService.js
new file mode 100644
index 000000000..2c504e3a7
--- /dev/null
+++ b/client/services/runnabotService.js
@@ -0,0 +1,22 @@
+'use strict';
+
+require('app')
+ .factory('isRunnabotPartOfOrg', isRunnabotPartOfOrg);
+
+function isRunnabotPartOfOrg(
+ $http,
+ configAPIHost
+) {
+ return function (orgName) {
+ return $http({
+ method: 'get',
+ url: configAPIHost + '/github/orgs/' + orgName + '/memberships/runnabot'
+ })
+ .then(function (data) {
+ return data.status < 400; // Github returns 404 when the user isn't part of the org
+ })
+ .catch(function () {
+ return false;
+ });
+ };
+}
\ No newline at end of file
diff --git a/client/services/serviceCreateNewBuild.js b/client/services/serviceCreateNewBuild.js
index 167b18423..94efd9a73 100644
--- a/client/services/serviceCreateNewBuild.js
+++ b/client/services/serviceCreateNewBuild.js
@@ -13,6 +13,7 @@ function createNewBuild(
return function (activeAccount, opts) {
opts = opts || {};
var dockerfilePath = opts.dockerfilePath;
+ var configurationMethod = opts.configurationMethod;
var thisUser, version;
function createContext(user) {
return promisify(user, 'createContext')({
@@ -32,6 +33,11 @@ function createNewBuild(
buildDockerfilePath: dockerfilePath
});
}
+ if (configurationMethod === 'blankDockerfile') {
+ return promisify(version, 'update')({
+ advanced: true,
+ });
+ }
return version;
});
}
@@ -68,7 +74,7 @@ function createNewBuildAndFetchBranch(
fetchStackData,
promisify
) {
- return function (activeAccount, repo, dockerfilePath) {
+ return function (activeAccount, repo, dockerfilePath, configurationMethod) {
var inputs = {
repo: repo,
masterBranch: null,
@@ -76,7 +82,10 @@ function createNewBuildAndFetchBranch(
};
return fetchStackData(repo)
.then(function () {
- return createNewBuild(activeAccount, { dockerfilePath: dockerfilePath });
+ return createNewBuild(activeAccount, {
+ configurationMethod: configurationMethod,
+ dockerfilePath: dockerfilePath
+ });
})
.then(function (buildWithVersion) {
inputs.build = buildWithVersion;
diff --git a/client/services/serviceEventTracking.js b/client/services/serviceEventTracking.js
index 90507ea67..3c9583dd2 100644
--- a/client/services/serviceEventTracking.js
+++ b/client/services/serviceEventTracking.js
@@ -9,9 +9,11 @@
require('app')
.service('eventTracking', EventTracking);
var User = require('@runnable/api-client/lib/models/user');
+var UUID = require('node-uuid');
var _keypather;
var _$location;
var INTERCOM_APP_ID;
+var SIFT_API_KEY;
/**
* EventTracking
@@ -26,19 +28,20 @@ function EventTracking(
$window,
assign,
keypather,
- configEnvironment
+ intercomAppId,
+ siftApiConfig
) {
- if (configEnvironment === 'production') {
- INTERCOM_APP_ID = 'wqzm3rju'; // production ID
- } else {
- INTERCOM_APP_ID = 'xs5g95pd'; // test ID
- }
+ INTERCOM_APP_ID = intercomAppId;
+ var self = this;
+ SIFT_API_KEY = siftApiConfig;
+
_keypather = keypather;
_$location = $location;
- this._Intercom = $window.Intercom;
- this._user = null;
- this.$window = $window;
+ self._Intercom = $window.Intercom;
+ self.analytics = $window.analytics;
+ self._user = null;
+ self.$window = $window;
/**
* Extend per-event data with specific properties
@@ -46,8 +49,8 @@ function EventTracking(
* @param {Object} data - data for given event to be extended
* @return Object - extended event object
*/
- this.extendEventData = function (data) {
- if (!this._user) {
+ self.extendEventData = function (data) {
+ if (!self._user) {
$log.error('eventTracking.boot() must be invoked before reporting events');
}
// username owner if server page
@@ -57,8 +60,8 @@ function EventTracking(
state: $state.$current.name,
href: $window.location.href
};
- if (angular.isFunction(keypather.get(this._user, 'oauthName'))) {
- baseData.userName = this._user.oauthName();
+ if (angular.isFunction(keypather.get(self._user, 'oauthName'))) {
+ baseData.userName = self._user.oauthName();
}
if ($stateParams.userName) {
baseData.instanceOwner = $stateParams.userName;
@@ -73,9 +76,31 @@ function EventTracking(
* Stub Intercom when SDK not present
* (development/staging environments)
*/
- if (!this._Intercom || $browser.cookies().isModerating) {
+ if (!self._Intercom || $browser.cookies().isModerating) {
// stub intercom if not present
- this._Intercom = angular.noop;
+ self._Intercom = angular.noop;
+ }
+
+ /**
+ * Stub Segment when SDK not present
+ * (development/staging environments)
+ */
+ if (!self.analytics) {
+ // stub segment (analytics) if not present
+ self.analytics = {
+ ready: angular.noop,
+ track: angular.noop,
+ identify: angular.noop,
+ alias: angular.noop,
+ page: angular.noop,
+ group: angular.noop,
+ trackLink: angular.noop,
+ trackForm: angular.noop,
+ user: angular.noop,
+ debug: angular.noop,
+ on: angular.noop,
+ timeout: angular.noop
+ };
}
/**
@@ -83,7 +108,7 @@ function EventTracking(
* @param {String} mixpanel SDK API method name
* @params [1..n] optional arguments passed to mixpanel SDK
*/
- this._mixpanel = function () {
+ self._mixpanel = function () {
if (!angular.isFunction(keypather.get($window, 'mixpanel.'+arguments[0]))) {
// $log.info('Mixpanel JS SDK stubbed');
// $log.info(arguments);
@@ -100,14 +125,15 @@ function EventTracking(
}
/**
- * Intercom and Mixpanel user identification
+ * Intercom, Mixpanel, and Segment user identification
* @throws Error
* @param {Object} user - User Model instance
* @return this
*/
EventTracking.prototype.boot = function (user, opts) {
+ var self = this;
opts = opts || {};
- if (this._user) { return this; }
+ if (self._user) { return self; }
if (!(user instanceof User)) {
throw new Error('arguments[0] must be instance of User');
}
@@ -115,14 +141,26 @@ EventTracking.prototype.boot = function (user, opts) {
if (user.attrs._beingModerated) {
user = new User(user.attrs._beingModerated, { noStore: true });
} else {
- if (this.$window.fbq) {
- this.$window.fbq('track', 'ViewContent', {
+ var session = window.sessionStorage.getItem('sessionId');
+ if (!session) {
+ session = UUID.v4();
+ window.sessionStorage.setItem('sessionId', session);
+ }
+
+ var _sift = window._sift = window._sift || [];
+ _sift.push(['_setAccount', SIFT_API_KEY]);
+ _sift.push(['_setUserId', user.name]);
+ _sift.push(['_setSessionId', session]);
+ _sift.push(['_trackPageview']);
+
+ self.analytics.ready(function () {
+ self.analytics.track('ViewContent', {
action: 'LoggedIn'
});
- }
+ });
}
- this._user = user;
+ self._user = user;
var data = {
name: user.oauthName(),
email: user.attrs.email,
@@ -139,12 +177,12 @@ EventTracking.prototype.boot = function (user, opts) {
// Mixpanel uses a string GUID to track anon users
// If we're still tracking the user via GUID, we need to alias
// Otherwise, we can just identify ourselves
- if (angular.isString(this._mixpanel('get_distinct_id'))) {
- this._mixpanel('alias', user.oauthId());
+ if (angular.isString(self._mixpanel('get_distinct_id'))) {
+ self._mixpanel('alias', user.oauthId());
} else {
- this._mixpanel('identify', user.oauthId());
+ self._mixpanel('identify', user.oauthId());
}
- this._Intercom('boot', data);
+ self._Intercom('boot', data);
var userJSON = user.toJSON();
var firstName = '';
var lastName = '';
@@ -153,19 +191,39 @@ EventTracking.prototype.boot = function (user, opts) {
firstName = displayName.split(/ (.+)/)[0];
lastName = displayName.split(/ (.+)/)[1];
}
- this._mixpanel('people.set', {
+ self._mixpanel('people.set', {
'$first_name': firstName,
'$last_name': lastName,
'$created': _keypather.get(userJSON, 'created'),
'$email': _keypather.get(userJSON, 'email')
});
- return this;
+
+ // Segment
+ self.analytics.ready(function () {
+ self.analytics.identify(data.name, {
+ firstName: firstName,
+ lastName: lastName,
+ username: data.name,
+ email: _keypather.get(userJSON, 'email'),
+ createdAt: _keypather.get(userJSON, 'created'),
+ avatar: _keypather.get(userJSON, 'gravatar')
+ });
+ self.analytics.alias(user.oauthId());
+ self.analytics.alias(_keypather.get(userJSON, '_id'));
+ if (opts.orgName) {
+ self.analytics.group(data.company.id, {
+ name: data.company.name
+ });
+ }
+ });
+ return self;
};
/**
* Record user event toggling of selected commit in repository
* Reports to:
* - mixpanel
+ * - segment
* @param {Object} data - key/value pairs of event data
* - keys
* - triggeredBuild: Boolean
@@ -173,13 +231,17 @@ EventTracking.prototype.boot = function (user, opts) {
* @return this
*/
EventTracking.prototype.toggledCommit = function (data) {
+ var self = this;
var eventName = 'toggled-commit';
- var eventData = this.extendEventData({
+ var eventData = self.extendEventData({
triggeredBuild: !!data.triggeredBuild,
selectedCommit: data.acv
});
- this._mixpanel('track', eventName, eventData);
- return this;
+ self._mixpanel('track', eventName, eventData);
+ self.analytics.ready(function () {
+ self.analytics.track(eventName, eventData);
+ });
+ return self;
};
/**
@@ -187,32 +249,42 @@ EventTracking.prototype.toggledCommit = function (data) {
* Reports to:
* - intercom
* - mixpanel
+ * - segment
* @param {Boolean} cache - build triggered without cache
* @return this
*/
EventTracking.prototype.triggeredBuild = function (cache) {
+ var self = this;
var eventName = 'triggered-build';
- var eventData = this.extendEventData({
+ var eventData = self.extendEventData({
cache: cache
});
- this._Intercom('trackEvent', eventName, eventData);
- this._mixpanel('track', eventName, eventData);
- return this;
+ self._Intercom('trackEvent', eventName, eventData);
+ self._mixpanel('track', eventName, eventData);
+ self.analytics.ready(function () {
+ self.analytics.track(eventName, eventData);
+ });
+ return self;
};
/**
* Record user visit to states
* Reports to:
* - mixpanel
+ * - segment
* @return this
*/
EventTracking.prototype.visitedState = function () {
+ var self = this;
var eventName = 'visited-state';
- var eventData = this.extendEventData({
+ var eventData = self.extendEventData({
referral: _$location.search().ref || 'direct'
});
- this._mixpanel('track', eventName, eventData);
- return this;
+ self._mixpanel('track', eventName, eventData);
+ self.analytics.ready(function () {
+ self.analytics.track(eventName, eventData);
+ });
+ return self;
};
/**
@@ -221,8 +293,9 @@ EventTracking.prototype.visitedState = function () {
* @return this
*/
EventTracking.prototype.update = function () {
- this._Intercom('update');
- return this;
+ var self = this;
+ self._Intercom('update');
+ return self;
};
/**
@@ -231,8 +304,13 @@ EventTracking.prototype.update = function () {
* @returns {EventTracking}
*/
EventTracking.prototype.trackClicked = function (data) {
- this._mixpanel('track', 'clicked - ' + _keypather.get(data, 'text'), data);
- return this;
+ var self = this;
+
+ self._mixpanel('track', 'Click', data);
+ self.analytics.ready(function () {
+ self.analytics.track('Click', data);
+ });
+ return self;
};
/**
@@ -242,19 +320,21 @@ EventTracking.prototype.trackClicked = function (data) {
* @returns {EventTracking}
*/
EventTracking.prototype.createdRepoContainer = function (org, repo) {
- if (this._mixpanel) {
- this._mixpanel('track', 'createRepoContainer', {
+ var self = this;
+ if (self._mixpanel) {
+ self._mixpanel('track', 'createRepoContainer', {
org: org,
repo: repo
});
}
- if (this.$window.fbq) {
- this.$window.fbq('track', 'ViewContent', {
+ self.analytics.ready(function () {
+ self.analytics.track('ViewContent', {
action: 'CreateContainer',
- type: 'Repo'
+ type: 'Repo',
+ containerName: repo
});
- }
+ });
};
/**
@@ -263,16 +343,143 @@ EventTracking.prototype.createdRepoContainer = function (org, repo) {
* @returns {EventTracking}
*/
EventTracking.prototype.createdNonRepoContainer = function (containerName) {
- if (this._mixpanel) {
- this._mixpanel('track', 'createNonRepoContainer', {
+ var self = this;
+ if (self._mixpanel) {
+ self._mixpanel('track', 'createNonRepoContainer', {
containerName: containerName
});
}
- if (this.$window.fbq) {
- this.$window.fbq('track', 'ViewContent', {
+ self.analytics.ready(function () {
+ self.analytics.track('ViewContent', {
action: 'CreateContainer',
- type: 'NonRepo'
+ type: 'NonRepo',
+ containerName: containerName
});
- }
+ });
+};
+
+/**
+ * Track user visit to /orgSelect page
+ * Reports to:
+ * - mixpanel
+ * - segment
+ * @return this
+ */
+EventTracking.prototype.visitedOrgSelectPage = function () {
+ var self = this;
+ var eventName = 'Visited org-select page';
+
+ self._mixpanel('track', eventName);
+ self.analytics.ready(function () {
+ self.analytics.track(eventName);
+ });
+ return self;
+};
+
+/**
+ * Track user clicks on an org on the orgSelect page
+ * Reports to:
+ * - mixpanel
+ * - segment
+ * @return this
+ */
+EventTracking.prototype.selectedOrg = function (org) {
+ var self = this;
+ var eventName = 'Org Selected';
+
+ self._mixpanel('track', eventName, {
+ org: org
+ });
+ self.analytics.ready(function () {
+ self.analytics.track(eventName, {org: org});
+ });
+ return self;
+};
+
+
+/**
+ * Track org click on /orgSelect page
+ * Reports to:
+ * - segment
+ * @return this
+ */
+EventTracking.prototype.waitingForInfrastructure = function (orgName) {
+ var self = this;
+ var eventName = 'Waiting for infrastrucuture';
+
+ self.analytics.ready(function () {
+ self.analytics.track(eventName, {org: orgName});
+ });
+ return self;
+};
+
+/**
+ * Milestone 2: Select repository
+ * Reports to:
+ * - mixpanel
+ * @return this
+ */
+EventTracking.prototype.milestone2SelectTemplate = function () {
+ var self = this;
+ var eventName = 'Milestone 2: Select template';
+
+ self._mixpanel('track', eventName);
+ return self;
+};
+
+/**
+ * Milestone 2: Verify repository tab
+ * Reports to:
+ * - mixpanel
+ * @return this
+ */
+EventTracking.prototype.milestone2VerifyRepositoryTab = function () {
+ var self = this;
+ var eventName = 'Milestone 2: Verify repository tab';
+
+ self._mixpanel('track', eventName);
+ return self;
+};
+
+/**
+ * Milestone 2: Verify commands tab
+ * Reports to:
+ * - mixpanel
+ * @return this
+ */
+EventTracking.prototype.milestone2VerifyCommandsTab = function () {
+ var self = this;
+ var eventName = 'Milestone 2: Verify commands tab';
+
+ self._mixpanel('track', eventName);
+ return self;
+};
+
+/**
+ * Milestone 2: Building
+ * Reports to:
+ * - mixpanel
+ * @return this
+ */
+EventTracking.prototype.milestone2Building = function () {
+ var self = this;
+ var eventName = 'Milestone 2: Building';
+
+ self._mixpanel('track', eventName);
+ return self;
+};
+
+/**
+ * Milestone 2: Container popover
+ * Reports to:
+ * - mixpanel
+ * @return this
+ */
+EventTracking.prototype.milestone2BuildSuccess = function () {
+ var self = this;
+ var eventName = 'Milestone 2: Build success message (in modal)';
+
+ self._mixpanel('track', eventName);
+ return self;
};
diff --git a/client/services/serviceFetch.js b/client/services/serviceFetch.js
index 335172e9c..7c153d47a 100644
--- a/client/services/serviceFetch.js
+++ b/client/services/serviceFetch.js
@@ -26,6 +26,7 @@ require('app')
.factory('fetchDebugContainer', fetchDebugContainer)
.factory('fetchStackData', fetchStackData)
// Github API
+ .factory('fetchGithubUserIsAdminOfOrg', fetchGithubUserIsAdminOfOrg)
.factory('fetchGitHubUser', fetchGitHubUser)
.factory('fetchGitHubMembers', fetchGitHubMembers)
.factory('fetchGitHubAdminsByRepo', fetchGitHubAdminsByRepo)
@@ -193,6 +194,7 @@ function fetchInstance(
var fetchByPodCache = {};
function fetchInstancesByPod(
+ $q,
$state,
fetchInstances,
fetchUser,
@@ -200,6 +202,9 @@ function fetchInstancesByPod(
) {
return function (username) {
username = username || $state.params.userName;
+ if (!username) {
+ return $q.when([]);
+ }
if (!fetchByPodCache[username]) {
var userPromise = fetchUser();
fetchByPodCache[username] = fetchInstances({
@@ -697,6 +702,27 @@ function fetchGitHubUser(
});
}
+function fetchGithubUserIsAdminOfOrg(
+ $http,
+ configAPIHost,
+ keypather,
+ memoize
+) {
+ return memoize(function (orgName) {
+ return $http({
+ method: 'get',
+ url: configAPIHost + '/github/user/memberships/orgs/' + orgName
+ })
+ .catch(function () {
+ return false;
+ })
+ .then(function (response) {
+ return keypather.get(response, 'data.state') === 'active' &&
+ keypather.get(response, 'data.role') === 'admin';
+ });
+ });
+}
+
/**
* Given an org name and a repo name, fetch all github users who have admin access to a repo. This
* returns a promise containing a map of all of the users, indexed by their github login.
diff --git a/client/services/serviceFetchDockerfile.js b/client/services/serviceFetchDockerfile.js
index 1792ae9c0..1022f6474 100644
--- a/client/services/serviceFetchDockerfile.js
+++ b/client/services/serviceFetchDockerfile.js
@@ -56,6 +56,7 @@ function doesDockerfileExist() {
}
function fetchDockerfileForContextVersion (
+ $q,
base64,
doesDockerfileExist,
fetchCommitsForFile,
@@ -71,18 +72,18 @@ function fetchDockerfileForContextVersion (
if (buildDockerfilePath && repoFullName) {
var branchName = keypather.get(acv, 'attrs.branch');
// Get everything before the last '/' and add a '/' at the end
- var result = /^(\/?[^\/]*)\/([^\/]*)$/.exec(buildDockerfilePath);
- if (result.length < 3) {
- throw new Error('BuilddockerfilePath is invalid');
+ var result = /^((\/?[^\/]*)*)\/([^\/]*)$/.exec(buildDockerfilePath);
+ if (keypather.get(result, 'length') < 3) {
+ return $q.reject(new Error('Dockerfile path is invalid'));
}
- var path = result && result[1] || '';
+ var name = result[result.length - 1];
+ var path = result[1];
// Get everything after the last '/'
- var name = result && result[2] || '';
return fetchRepoDockerfile(repoFullName, branchName, buildDockerfilePath)
.then(doesDockerfileExist)
.then(function (dockerfile) {
if (!dockerfile) {
- return null;
+ return $q.reject(new Error('No Dockerfile in this repo'));
}
return fetchCommitsForFile(repoFullName, branchName, buildDockerfilePath)
.then(function (commits) {
diff --git a/client/services/serviceHandleErr.js b/client/services/serviceHandleErr.js
index def9fa892..a4ba0e8eb 100644
--- a/client/services/serviceHandleErr.js
+++ b/client/services/serviceHandleErr.js
@@ -24,6 +24,10 @@ function errs (
$window.location = configAPIHost + '/auth/github?redirect=' + $window.location.protocol + '//' + $window.location.host + '/?auth';
return false;
}
+ if (err.message === 'collection requires a client') {
+ // Fuck this error
+ return false;
+ }
if (~noDisplayCodes.indexOf(keypather.get(err, 'data.statusCode'))) { return false; }
return true;
diff --git a/client/services/serviceHelpCards.js b/client/services/serviceHelpCards.js
deleted file mode 100644
index 3fadb0902..000000000
--- a/client/services/serviceHelpCards.js
+++ /dev/null
@@ -1,312 +0,0 @@
-'use strict';
-var EventEmitter = require('events').EventEmitter;
-
-require('app')
- .factory('helpCards', helpCardsFactory);
-
-function helpCardsFactory(
- $interpolate,
- $q,
- keypather,
- fetchSettings,
- errs,
- promisify,
- $rootScope,
- jsonHash
-) {
-
-//POSSIBLE TARGETS:
-//repository
-//exposedPorts
-//environmentVariables
-//commands
-//containerFiles
-//findAndReplace
-//newContainer
-//buildCommand
- var helpCards = {
- 'general': [
- {
- label: 'Connect to an external service',
- targets: [
- 'environmentVariables',
- 'findAndReplace'
- ],
- helpTop: 'Use Environment Variables or Find and Replace to connect to a service.',
- helpPopover: {
- 'environmentVariables': 'Add or update an environment variable to reference your external service.',
- 'findAndReplace': 'Create a new string rule to connect to your external service.'
- }
- },
- {
- label: 'Connect to an OAuth service',
- targets: [
- 'environmentVariables',
- 'findAndReplace'
- ],
- helpTop: 'Use Environment Variables or Find and Replace to update your OAuth credentials.',
- helpPopover: {
- 'environmentVariables': 'Add or update the environment variables for your OAuth credentials.',
- 'findAndReplace': 'Add a string rule to update your OAuth credentials in your code.'
- }
- },
- {
- label: 'Add a library',
- targets: [
- 'commands',
- ],
- helpTop: 'Use Commands and Packages to add a library.',
- },
- {
- label: 'Seed a database',
- targets: ['containerFiles'],
- helpTop: 'Use Files & SSH Keys to upload seed data and import it using scripts.',
- helpPopover: {
- 'containerFiles': 'Click Upload File to select and upload your seed file. Then enter the scripts you need to import the data.'
- }
- }
- ],
- 'triggered': [
- // when we detect that one existing container depends on service for which there is no existing container
- {
- id: 'missingDependency',
- label: '{{instance.getDisplayName()}} may need a {{dependency}} container.',
- targets: [
- 'newContainer'
- ],
- helpTop: 'Click on the New Container button to add a {{dependency}} container.',
- helpPopover: {
- 'newContainer': 'Click Non-repository to add a {{dependency}} container.'
- }
- },
- // when we detect that one existing container depends on another existing contianer
- {
- id: 'missingAssociation',
- label: 'You may need to connect {{instance.getDisplayName()}} to {{association}}.',
- targets: [
- 'environmentVariables',
- 'findAndReplace'
- ],
- helpTop: 'Use Environment Variables or Find and Replace to connect {{instance.getDisplayName()}} to {{association}}.',
- helpPopover: {
- 'environmentVariables': 'Connect to {{association}} by using its URL in an environment variable.',
- 'findAndReplace': 'Connect to {{association}} by adding a string rule with its URL.'
- }
- },
- // when the user adds a non-repo container, but we can't detect which containers depend on it
- {
- id: 'missingMapping',
- label: 'You may need to connect some repository containers to {{mapping}}.',
- targets: [
- 'environmentVariables',
- 'findAndReplace'
- ],
- helpTop: 'Use Environment Variables or Find and Replace to connect one or more of your repository containers to {{mapping}}.',
- helpPopover: {
- environmentVariables: 'Connect to {{mapping}} by using its URL in an environment variable.',
- findAndReplace: 'Connect to {{mapping}} by adding a string rule with its URL.'
- },
- highlightRepoContainers: true
- }
- ]
- };
-
-
-
- var HelpCard = function (config) {
- var self = this;
- Object.keys(config).forEach(function (key) {
- self[key] = config[key];
- });
-
- var cardClone = {
- id: this.id,
- type: this.type,
- data: {}
- };
- if (this.data && this.data.instance && this.data.instance.attrs) {
- cardClone.data = { instance: this.data.instance.attrs.shortHash };
- }
-
- if (this.data) {
- Object.keys(this.data).forEach(function (key) {
- if (key !== 'instance') {
- cardClone.data[key] = self.data[key];
- }
- });
- }
- this.hash = jsonHash.digest(cardClone);
- };
-
- HelpCard.prototype = Object.create(EventEmitter.prototype);
-
- helpCards.general = helpCards.general.map(function (cardConfig) {
- cardConfig.type = 'general';
- var card = new HelpCard(cardConfig);
- var targetHash = {};
- card.targets.forEach(function (target) {
- if (keypather.get($rootScope, 'featureFlags.' + target) !== false) {
- targetHash[target] = true;
- }
- });
- card.targets = targetHash;
- return card;
- });
-
- var triggeredHash = {};
- helpCards.triggered.forEach(function (cardConfig) {
- cardConfig.type = 'triggered';
- var card = new HelpCard(cardConfig);
- var targetHash = {};
- card.targets.forEach(function (target) {
- if (keypather.get($rootScope, 'featureFlags.' + target) !== false) {
- targetHash[target] = true;
- }
- });
- card.targets = targetHash;
- triggeredHash[card.id] = card;
- });
-
- helpCards.triggered = triggeredHash;
-
-
- var currentCardHash = {};
- var activeCard = null;
- var helpCardManager = {
- cards: {
- general: helpCards.general,
- triggered: []
- },
- getActiveCard: function () {
- return activeCard;
- },
- setActiveCard: function (newCard) {
- if (activeCard && activeCard !== newCard) {
- activeCard.emit('deactivate');
- }
-
- if (newCard) {
- newCard.emit('activate');
- $rootScope.$broadcast('helpCardScroll:enable');
- } else {
- $rootScope.$broadcast('helpCardScroll:disable');
- }
-
- activeCard = newCard;
- },
- clearAllCards: function () {
- this.cards.triggered = [];
- currentCardHash = {};
- activeCard = null;
- },
- hideActiveCard: function () {
- if (this.getActiveCard()) {
- var helpCard = this.getActiveCard();
- currentCardHash[helpCard.hash] = null;
- this.setActiveCard(null);
- var index = this.cards.triggered.indexOf(helpCard);
- this.cards.triggered.splice(index, 1);
- }
- },
- refreshActiveCard: function () {
- if (this.getActiveCard()) {
- this.getActiveCard().emit('refresh');
- this.setActiveCard(null);
- }
- },
- refreshAllCards: function () {
- this.cards.triggered.forEach(function (card) {
- if (!card.removed) {
- card.emit('refresh');
- }
- });
- currentCardHash = {};
- this.cards.triggered = [];
- this.setActiveCard(null);
- },
- cardIsActiveOnThisContainer: function (container) {
- activeCard = this.getActiveCard();
-
- return activeCard &&
- (
- activeCard.type === 'general' ||
- angular.equals(container, keypather.get(activeCard, 'data.instance')) ||
- ( activeCard.highlightRepoContainers && container.contextVersion.getMainAppCodeVersion() )
- );
- },
- removeByInstance: function (instance) {
- this.cards.triggered
- .filter(function (card) {
- return keypather.get(card, 'data.instance.attrs.shortHash') === instance.attrs.shortHash;
- })
- .forEach(function (card) {
- if (!card.removed) {
- card.emit('remove');
- }
- });
- },
- triggerCard: function (cardId, data) {
- var self = this;
- return fetchSettings().then(function (settings) {
- var ignoredHelpCards = settings.attrs.ignoredHelpCards || [];
-
- var cardConfig = helpCards.triggered[cardId];
- if (!cardConfig) {
- throw new Error('Attempt to create a help card with invalid ID.');
- }
- cardConfig = angular.copy(cardConfig);
-
-
- cardConfig.label = $interpolate(cardConfig.label)(data);
- cardConfig.helpTop = $interpolate(cardConfig.helpTop)(data);
- Object.keys(cardConfig.helpPopover).forEach(function (key) {
- cardConfig.helpPopover[key] = $interpolate(cardConfig.helpPopover[key])(data);
- });
-
- cardConfig.data = data;
-
- var helpCard = new HelpCard(cardConfig);
-
- if (!currentCardHash[helpCard.hash] && ignoredHelpCards.indexOf(helpCard.hash) === -1) {
- self.cards.triggered.unshift(helpCard);
- currentCardHash[helpCard.hash] = helpCard;
- helpCard.on('remove', function () {
- if (self.getActiveCard() === helpCard) {
- self.setActiveCard(null);
- }
- helpCard.removed = true;
- var index = self.cards.triggered.indexOf(helpCard);
- self.cards.triggered.splice(index, 1);
- currentCardHash[helpCard.hash] = null;
- });
- helpCard.on('refresh', function () {
- if (!helpCard.removed) {
- helpCard.emit('remove');
- }
- });
- }
- return $q.when(currentCardHash[helpCard.hash]);
- })
- .catch(errs.handler);
- },
- ignoreCard: function (card) {
- var index = this.cards.triggered.indexOf(card);
- this.cards.triggered.splice(index, 1);
- if (this.getActiveCard() === card) {
- this.setActiveCard(null);
- }
- fetchSettings().then(function (settings) {
- var ignoredHelpCards = settings.attrs.ignoredHelpCards || [];
- ignoredHelpCards.push(card.hash);
-
- return promisify(settings, 'update')({
- json: {
- ignoredHelpCards: ignoredHelpCards
- }
- });
- })
- .catch(errs.handler);
- }
- };
- return helpCardManager;
-}
diff --git a/client/services/serviceValidateEnvVars.js b/client/services/serviceValidateEnvVars.js
index c116b5bb7..807eb9b8b 100644
--- a/client/services/serviceValidateEnvVars.js
+++ b/client/services/serviceValidateEnvVars.js
@@ -27,7 +27,7 @@ function validateEnvVars() {
return;
}
// Check for syntactic validity
- if (!/^([A-z]+[A-z0-9_]*)=.*$/.test(line)) {
+ if (!/^([A-z]+[A-z0-9_]*)=\S+$/.test(line)) {
response.valid = false;
response.errors.push(index);
return;
diff --git a/client/services/tabVisibilityService.js b/client/services/tabVisibilityService.js
index 1a06e4a36..c1e561c85 100644
--- a/client/services/tabVisibilityService.js
+++ b/client/services/tabVisibilityService.js
@@ -21,7 +21,6 @@ require('app')
advanced: true,
basic: true,
mirror: true,
- featureFlagName: 'whitelist',
nonRepo: true,
step: 3
},
@@ -47,8 +46,8 @@ require('app')
step: 3
},
buildfiles: {
- basic: true,
advanced: true,
+ basic: true,
mirror: true,
nonRepo: true,
step: 3
diff --git a/client/templates/instances/viewInstances.jade b/client/templates/instances/viewInstances.jade
index 5e1620072..6002f91c9 100644
--- a/client/templates/instances/viewInstances.jade
+++ b/client/templates/instances/viewInstances.jade
@@ -1,7 +1,7 @@
//- instance list
.grid-block.shrink.list-instances(
ng-class = "{\
- 'deprecated': !$root.featureFlags.autoIsolation,\
+ 'deprecated': !$root.featureFlags.addBranches,\
'in': !CIS.$storage.instanceListIsClosed\
}"
ng-if = "CIS.instancesByPod"
@@ -20,6 +20,5 @@
)
.grid-block.vertical.instance-wrapper(
- ng-class = "{'empty': $root.featureFlags.aha && $root.featureFlags.aha2}"
ui-view
)
diff --git a/client/templates/instances/viewInstancesList.jade b/client/templates/instances/viewInstancesList.jade
index d20ae562a..d7a786939 100644
--- a/client/templates/instances/viewInstancesList.jade
+++ b/client/templates/instances/viewInstancesList.jade
@@ -8,15 +8,32 @@ label.grid-block.vertical.label-search
)
p.p.text-center.text-gray-light.padding-sm(
- ng-if = "CIS.getFilteredInstanceList().length < 1"
-) No containers match filter.
+ ng-if = "!CIS.filterMatchedAnything()"
+) No containers match this filter.
//- master cluster
.list-clusters.master-cluster(
- ng-if = "$root.featureFlags.autoIsolation"
+ ng-if = "$root.featureFlags.addBranches && CIS.getFilteredInstanceList().length"
)
- .list-item-cluster
+ .grid-block.align-center.list-item-cluster.list-clusters-heading
+ span.grid-content.text-overflow Templates
+ //- div instead of button so safari doesn’t get weird with alignment
+ .grid-block.align-center.shrink.btn.btn-xxs.white(
+ ng-class = "{'active': state.active}"
+ ng-if = "$root.featureFlags.containersViewTemplateControls"
+ pop-over
+ pop-over-options = "{\"top\":-30,\"left\":114}"
+ pop-over-template = "templateMenuPopoverView"
+ ) Create Template
+ svg.iconnables.icons-arrow-forward
+ use(
+ xlink:href = "#icons-arrow-down"
+ )
+
+ .list-item-cluster(
+ ng-if = "!$root.featureFlags.containersViewEmptyState"
+ )
.grid-block.list-containers.vertical.text-overflow.open
//- master repository containers
.grid-block(
@@ -24,18 +41,25 @@ p.p.text-center.text-gray-light.padding-sm(
instance = "masterInstance"
instance-navigation
master-instance = "masterInstance"
- ng-repeat = "masterInstance in CIS.instancesByPod.models | instanceHasRepo:true | orderBy: ['attrs.name'] track by masterInstance.attrs.name"
+ ng-repeat = "masterInstance in CIS.getFilteredInstanceList() | instanceHasRepo:true | orderBy: ['attrs.name'] track by masterInstance.attrs.name"
)
//- master non-repository containers
.grid-block(
active-account = "CIS.activeAccount"
instance = "masterInstance"
instance-navigation
- ng-repeat = "masterInstance in CIS.instancesByPod.models | instanceHasRepo:false | orderBy: ['attrs.name'] as nonRepoInstances track by masterInstance.attrs.name"
+ ng-repeat = "masterInstance in CIS.getFilteredInstanceList() | instanceHasRepo:false | orderBy: ['attrs.name'] as nonRepoInstances track by masterInstance.attrs.name"
)
+.well.text-center(
+ ng-if = "$root.featureFlags.containersViewEmptyState"
+) 😐
+ br
+ .small You don’t have any templates. Click the button above to create one.
+
//- branch clusters
.list-clusters(
+ ng-if = "!$root.featureFlags.containersViewEmptyState"
ng-repeat = "masterInstance in CIS.instancesByPod | instanceHasRepo:true | orderBy: ['attrs.name'] track by masterInstance.attrs.name"
ng-show = "CIS.shouldShowParent(masterInstance)"
)
@@ -43,28 +67,63 @@ p.p.text-center.text-gray-light.padding-sm(
//- cluster list heading
.grid-block.align-center.list-item-cluster.list-clusters-heading
//- repository name
- span.grid-block.text-overflow(
+ span.grid-content.text-overflow(
title = "{{masterInstance.getName()}}"
) {{masterInstance.getName()}}
- //- '+' button for adding branches and configuring clusters
- button.grid-block.shrink.btn.btn-xs.btn-icon.gray(
- ng-class = "{'active': state.active}"
- ng-if = "$root.featureFlags.autoIsolation"
+ .grid-block.align-center.shrink.btn.btn-xxs.white(
+ ng-if = "$root.featureFlags.addBranches"
+ ng-click = "CIS.popInstanceOpen(masterInstance)"
pop-over
- pop-over-options = "{\"verticallyCentered\":true,\"left\":24}"
+ pop-over-controller = "CIS"
+ pop-over-options = "{\"verticallyCentered\":true,\"left\":87,\"pinToViewPort\":true}"
pop-over-template = "branchMenuPopoverView"
- tooltip = "Add Branch"
- tooltip-options = "{\"class\":\"bottom center text-center\",\"left\":-36,\"top\":24}"
- )
- svg.iconnables
+ pop-over-data = "'branchSelect'"
+ ) Add Branch
+ //- '+' button for adding branches and configuring clusters
+ svg.iconnables.icons-arrow-forward
use(
- xlink:href = "#icons-add"
+ xlink:href = "#icons-arrow-down"
)
+ .stepOneUncloseablePopover(
+ ng-if = "$root.featureFlags.aha &&\
+ $index === 0 &&\
+ CIS.shouldShowPopover &&\
+ !CIS.$storage.instanceListIsClosed &&\
+ CIS.shouldShowParent(masterInstance) &&\
+ (CIS.isAddingFirstBranch() && !masterInstance.attrs.hasAddedBranches)\
+ "
+ pop-over
+ pop-over-active = "CIS.shouldShowPopover"
+ pop-over-controller = "CIS"
+ pop-over-options = "{\"verticallyCentered\":true,\"left\":6}"
+ pop-over-template = "introAddBranch"
+ pop-over-trigger = "activeAttr"
+ pop-over-uncloseable = "CIS.isAddingFirstBranch()"
+ pop-over-data = "'ahaTemplate'"
+ )
+
+ .autoForkPopover(
+ ng-if = "$root.featureFlags.aha &&\
+ $index === 0 &&\
+ !CIS.$storage.instanceListIsClosed &&\
+ CIS.shouldShowParent(masterInstance) &&\
+ !CIS.isAddingFirstBranch() &&\
+ (CIS.showAutofork && masterInstance.attrs.shouldNotAutofork)\
+ "
+ pop-over
+ pop-over-active = "CIS.showAutofork"
+ pop-over-controller = "CIS"
+ pop-over-options = "{\"verticallyCentered\":true,\"left\":6}"
+ pop-over-template = "introAddBranch"
+ pop-over-trigger = "activeAttr"
+ pop-over-data = "'ahaTemplate'"
+ )
+
//- repo config button (pre auto-isolation)
svg.grid-block.shrink.iconnables.icons-gear(
ng-click = "CIS.editInstance(masterInstance)"
- ng-if = "!$root.featureFlags.autoIsolation"
- title = "Configure"
+ ng-if = "!$root.featureFlags.addBranches"
+ title = "Configure Template"
)
use(
xlink:href = "#icons-gear"
@@ -76,7 +135,7 @@ p.p.text-center.text-gray-light.padding-sm(
instance = "masterInstance"
instance-navigation
master-instance = "masterInstance"
- ng-if = "!$root.featureFlags.autoIsolation && CIS.filterMasterInstance(masterInstance)"
+ ng-if = "!$root.featureFlags.addBranches && CIS.filterMasterInstance(masterInstance)"
)
//- wraps auto-isolated clusters
@@ -99,7 +158,7 @@ p.p.text-center.text-gray-light.padding-sm(
//- non-repo containers (pre auto-isolation)
.list-clusters(
- ng-if = "!$root.featureFlags.autoIsolation"
+ ng-if = "!$root.featureFlags.addBranches"
ng-show = "nonRepoInstances.length"
)
.list-item-cluster(
diff --git a/client/templates/svg/svgDefs.jade b/client/templates/svg/svgDefs.jade
index c26a9f3b8..c07ac9a3f 100755
--- a/client/templates/svg/svgDefs.jade
+++ b/client/templates/svg/svgDefs.jade
@@ -13,6 +13,9 @@ svg(xmlns='http://www.w3.org/2000/svg')
path(d='M10,8.006l-0.032,6A0.982,0.982,0,0,1,9.005,15H8.995a0.982,0.982,0,0,1-.962-0.994L8,8.006A0.982,0.982,0,0,1,8.962,7H9.038A0.982,0.982,0,0,1,10,8.006Z', transform='translate(0 -1.123)')
symbol#icons-alert-alt(viewBox='0 0 18 15.877')
path(d='M17.853,15.306L13.9,8.456,9.943,1.606a1.088,1.088,0,0,0-1.885,0L4.1,8.456l-3.955,6.85a1.088,1.088,0,0,0,.943,1.633H16.91A1.088,1.088,0,0,0,17.853,15.306ZM10,8.006l-0.032,6A0.982,0.982,0,0,1,9.005,15H8.995a0.982,0.982,0,0,1-.962-0.994L8,8.006A0.982,0.982,0,0,1,8.962,7H9.038A0.982,0.982,0,0,1,10,8.006Z', transform='translate(0 -1.061)')
+ symbol#icons-alert-alt-round(viewBox='0 0 18 18')
+ circle(cx='9', cy='9', r='9', fill='none')
+ path(d='M15.885,13.9L12.809,8.577,9.733,3.249a0.846,0.846,0,0,0-1.466,0L5.191,8.577,2.115,13.9a0.846,0.846,0,0,0,.733,1.27h12.3A0.846,0.846,0,0,0,15.885,13.9ZM9.778,8.227L9.753,12.893A0.763,0.763,0,0,1,9,13.667H9a0.763,0.763,0,0,1-.749-0.773L8.222,8.227a0.764,0.764,0,0,1,.749-0.782H9.029A0.764,0.764,0,0,1,9.778,8.227Z', transform='translate(0)')
symbol#icons-alert-round(viewBox='0 0 30 30')
path(d='M15,5c5.5,0,10,4.5,10,10s-4.5,10-10,10S5,20.5,5,15S9.5,5,15,5 M15,3C8.4,3,3,8.4,3,15s5.4,12,12,12s12-5.4,12-12S21.6,3,15,3L15,3z')
path(d='M15,18.3c-0.6,0-1-0.4-1-1V9.5c0-0.6,0.4-1,1-1s1,0.4,1,1v7.8C16,17.8,15.6,18.3,15,18.3z')
@@ -159,8 +162,6 @@ svg(xmlns='http://www.w3.org/2000/svg')
path(d='M8.4,9.1c0.1,0,0.3,0,0.4,0.1c0.2,0.2,0.2,0.5,0,0.7l-4,4H8c0.3,0,0.5,0.2,0.5,0.5S8.3,15,8,15H3.5h0c0,0,0,0,0,0h0c0,0,0,0,0,0l0,0c0,0,0,0,0,0l0,0c-0.1,0-0.2,0-0.3-0.1c0,0,0,0,0,0v0c0,0,0,0-0.1-0.1C3,14.7,3,14.6,3,14.5c0,0,0,0,0,0V10c0-0.3,0.2-0.5,0.5-0.5S4,9.7,4,10v3.3l4-4C8.1,9.2,8.2,9.1,8.4,9.1z')
symbol#icons-fat-check(viewBox='0 0 30 30')
path(d='M24.3,9.2c-0.6-0.6-1.5-0.6-2.1,0l-8.5,8.5l-4.3-4.3c-0.6-0.6-1.5-0.6-2.1,0c-0.6,0.6-0.6,1.5,0,2.1l5.4,5.4c0.3,0.3,0.6,0.4,1.1,0.4c0.4,0,0.8-0.2,1.1-0.4l9.6-9.6C24.8,10.8,24.8,9.8,24.3,9.2z')
- symbol#icons-github(viewBox='0 0 30 30')
- path(d='M22.4,7.8c2,2,3,4.5,3.1,7.4c0,2.4-0.7,4.4-2,6.2c-1.3,1.8-3,3-5.1,3.8c-0.3,0-0.4,0-0.6-0.1c-0.1-0.1-0.2-0.2-0.2-0.4l0-2.9c0-0.5-0.1-0.9-0.2-1.2c-0.1-0.3-0.3-0.6-0.5-0.7c1.2-0.1,2.3-0.5,3.3-1.2c1-0.7,1.5-2,1.5-4c0-0.6-0.1-1.1-0.3-1.6c-0.2-0.5-0.4-0.9-0.8-1.3c0.1-0.1,0.2-0.5,0.2-0.9c0.1-0.5,0-1.1-0.3-1.8c0,0-0.2,0-0.7,0c-0.5,0.1-1.2,0.4-2.2,1.1C16.8,10,15.9,9.8,15,9.8c-0.9,0-1.8,0.1-2.6,0.3c-1-0.6-1.7-1-2.2-1.1c-0.5-0.1-0.7-0.1-0.7,0C9.2,9.8,9.1,10.5,9.2,11c0.1,0.5,0.1,0.8,0.2,0.9c-0.3,0.4-0.6,0.8-0.8,1.3c-0.2,0.5-0.3,1-0.3,1.6c0.1,2,0.6,3.3,1.5,4c1,0.7,2.1,1.1,3.3,1.2c-0.2,0.1-0.3,0.3-0.4,0.6c-0.1,0.2-0.2,0.5-0.3,0.9c-0.3,0.2-0.8,0.3-1.4,0.3c-0.6,0-1.2-0.4-1.7-1.1c0,0-0.1-0.2-0.4-0.5c-0.3-0.3-0.7-0.5-1.2-0.6c-0.1,0-0.2,0-0.4,0.1c-0.2,0.1-0.1,0.3,0.3,0.6c0,0,0.1,0.1,0.4,0.3c0.3,0.2,0.5,0.6,0.8,1.2c0,0.1,0.2,0.4,0.7,0.9c0.5,0.5,1.4,0.6,2.9,0.4l0,1.9c0,0.2-0.1,0.3-0.2,0.4c-0.1,0.1-0.3,0.2-0.6,0.1c-2.1-0.7-3.8-2-5.1-3.8c-1.3-1.8-2-3.8-2-6.2c0.1-3,1.1-5.5,3.1-7.4c2-2,4.5-3,7.4-3.1C18,4.8,20.5,5.8,22.4,7.8z')
symbol#icons-help(viewBox='0 0 16.4 16.8')
path(d='M0,14.6c0-1.3,0.9-2.2,2.2-2.2c1.3,0,2.1,0.9,2.1,2.2c0,1.3-0.8,2.2-2.1,2.2C0.9,16.8,0,15.8,0,14.6z M0.8,11.2L0.2,0.3h3.8L3.5,11.2H0.8z')
path(d='M9.9,11.3l0-0.6c-0.1-1.2,0.3-2.5,1.4-3.8c0.8-0.9,1.4-1.7,1.4-2.5c0-0.8-0.6-1.4-1.8-1.4c-0.8,0-1.8,0.3-2.4,0.7L7.8,1c0.9-0.5,2.3-1,4-1c3.2,0,4.6,1.8,4.6,3.8c0,1.8-1.1,3-2,4.1c-0.9,1-1.3,1.9-1.2,3v0.4H9.9z M9.3,14.6c0-1.3,0.9-2.2,2.1-2.2c1.3,0,2.1,0.9,2.2,2.2c0,1.3-0.9,2.2-2.2,2.2C10.2,16.8,9.3,15.8,9.3,14.6z')
@@ -222,19 +223,20 @@ svg(xmlns='http://www.w3.org/2000/svg')
path(d='M3.059,11.928c0.479-0.479,0.522-1.071-0.436-2.029s-1.55-0.915-2.029-0.436c-1,1.052-0.436,2.9-0.436,2.9S2.033,12.954,3.059,11.928z')
path(d='M12.523,0C10.605,0,9.009,0.668,5.8,2.565c-2.433-0.818-3.983-0.344-5.298,0.97l1.857,1.857c-1.385,1.385-1.15,1.679,0.972,3.8c1.945,1.945,2.249,2.249,3.663,0.835l1.994,1.994c1.358-1.358,1.814-2.947,0.891-5.528C11.734,3.311,12.523,2.102,12.523,0z')
symbol#icons-life-preserver(viewBox='0 0 18 18')
- path(d='M16,9a7,7,0,1,0-7,7A7,7,0,0,0,16,9ZM4.8,9A4.2,4.2,0,1,1,9,13.2,4.2,4.2,0,0,1,4.8,9Z', transform='translate(-1.5 -1.5)', fill='#ffffff', stroke='#c4c4c4', stroke-miterlimit='10')
- path(d='M4.316,3.134H5.685a0.673,0.673,0,0,1,.673.673V6.191a0.675,0.675,0,0,1-.675.675H4.316a0.673,0.673,0,0,1-.673-0.673V3.807a0.673,0.673,0,0,1,.673-0.673Z', transform='translate(10.572 3.5) rotate(135)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
- path(d='M12.515,3.134h1.369a0.673,0.673,0,0,1,.673.673V6.191a0.675,0.675,0,0,1-.675.675H12.515a0.673,0.673,0,0,1-.673-0.673V3.807A0.673,0.673,0,0,1,12.515,3.134Z', transform='translate(5.902 -9.369) rotate(45)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
- path(d='M4.316,11.334H5.685a0.673,0.673,0,0,1,.673.673v2.384a0.675,0.675,0,0,1-.675.675H4.316a0.673,0.673,0,0,1-.673-0.673V12.007a0.673,0.673,0,0,1,.673-0.673Z', transform='translate(-2.297 24.569) rotate(-135)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
- path(d='M12.515,11.334h1.369a0.673,0.673,0,0,1,.673.673v2.384a0.675,0.675,0,0,1-.675.675H12.515a0.673,0.673,0,0,1-.673-0.673V12.007A0.673,0.673,0,0,1,12.515,11.334Z', transform='translate(-6.967 11.7) rotate(-45)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
+ path(d='M16,9a7,7,0,1,0-7,7A7,7,0,0,0,16,9ZM4.8,9A4.2,4.2,0,1,1,9,13.2,4.2,4.2,0,0,1,4.8,9Z', transform='translate(0 0)', fill='#fff', stroke='#c4c4c4', stroke-miterlimit='10')
+ path(d='M4.316,3.134H5.685a0.673,0.673,0,0,1,.673.673V6.191a0.675,0.675,0,0,1-.675.675H4.316a0.673,0.673,0,0,1-.673-0.673V3.807a0.673,0.673,0,0,1,.673-0.673Z', transform='translate(12.072 5) rotate(135)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
+ path(d='M12.515,3.134h1.369a0.673,0.673,0,0,1,.673.673V6.191a0.675,0.675,0,0,1-.675.675H12.515a0.673,0.673,0,0,1-.673-0.673V3.807a0.673,0.673,0,0,1,.673-0.673Z', transform='translate(7.402 -7.869) rotate(45)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
+ path(d='M4.316,11.334H5.685a0.673,0.673,0,0,1,.673.673v2.384a0.675,0.675,0,0,1-.675.675H4.316a0.673,0.673,0,0,1-.673-0.673V12.007a0.673,0.673,0,0,1,.673-0.673Z', transform='translate(-0.797 26.07) rotate(-135)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
+ path(d='M12.515,11.334h1.369a0.673,0.673,0,0,1,.673.673v2.384a0.675,0.675,0,0,1-.675.675H12.515a0.673,0.673,0,0,1-.673-0.673V12.007A0.673,0.673,0,0,1,12.515,11.334Z', transform='translate(-5.468 13.2) rotate(-45)', fill='#ef7883', stroke='#c14444', stroke-miterlimit='10')
+ rect(width='18', height='18', fill='none')
symbol#icons-lightning(viewBox='0 0 10.692 17.006')
path(d='M9.643,7.053C9.557,6.886,9.386,6.782,9.199,6.782l-2.144,0l2.604-6.084c0.065-0.155,0.05-0.332-0.043-0.472C9.524,0.084,9.367,0,9.199,0H2.355c-0.237,0-0.442,0.167-0.49,0.399L0.01,9.405c-0.03,0.147,0.007,0.3,0.102,0.417C0.208,9.938,0.35,10.006,0.5,10.006h1.731l-0.585,6.417c-0.039,0.229,0.086,0.456,0.302,0.545c0.062,0.025,0.127,0.038,0.191,0.038c0.158,0,0.312-0.075,0.407-0.21l7.059-9.224C9.714,7.419,9.729,7.219,9.643,7.053z')
symbol#icons-link(viewBox='0 0 18 18')
path(d='M3.8,17.8L3.8,17.8c-0.7,0-1.4-0.3-1.8-0.8l-1.2-1.2C0.3,15.4,0,14.7,0,14c0-0.7,0.3-1.4,0.8-1.9l3.9-3.9c0.3-0.3,0.9-0.3,1.2,0c0.3,0.3,0.3,0.9,0,1.2l-3.9,3.9c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l1.2,1.2c0.2,0.2,0.4,0.3,0.7,0.3l0,0c0.3,0,0.5-0.1,0.7-0.3L8.4,12c0.3-0.3,0.9-0.3,1.2,0c0.3,0.3,0.3,0.9,0,1.2l-3.9,3.9C5.2,17.6,4.5,17.8,3.8,17.8z')
path(d='M9.1,9.8c-0.2,0-0.4-0.1-0.6-0.2c-0.3-0.3-0.3-0.9,0-1.2l3.9-3.9c0.4-0.4,0.4-1,0-1.3l-1.2-1.2c-0.4-0.4-1-0.4-1.3,0L5.9,5.9c-0.3,0.3-0.9,0.3-1.2,0C4.4,5.5,4.4,5,4.7,4.7l3.9-3.9c1-1,2.7-1,3.7,0l1.2,1.2c1,1,1,2.7,0,3.7L9.6,9.6C9.5,9.7,9.3,9.8,9.1,9.8z')
symbol#icons-link-external(viewBox='0 0 18 18')
- path(d='M8.5,7C8.4,7,8.2,7,8.1,6.9C8,6.7,8,6.3,8.1,6.1L13.3,1H10C9.7,1,9.5,0.8,9.5,0.5S9.7,0,10,0h4.5h0c0,0,0,0,0,0h0c0,0,0,0,0,0l0,0c0,0,0,0,0,0l0,0c0.1,0,0.2,0,0.3,0.1c0,0,0,0,0,0v0c0,0,0,0,0.1,0.1C15,0.3,15,0.4,15,0.5c0,0,0,0,0,0V5c0,0.3-0.2,0.5-0.5,0.5S14,5.3,14,5V1.7L8.9,6.9C8.8,7,8.6,7,8.5,7z')
- path(d='M12.3,6.2L12,6.5V12c0,1.1-0.9,2-2,2H3c-1.1,0-2-0.9-2-2V5c0-1.1,0.9-2,2-2h5.5l0.3-0.3C8.5,2.5,8.2,2.3,8,2H3C1.3,2,0,3.3,0,5v7c0,1.7,1.3,3,3,3h7c1.7,0,3-1.3,3-3V7C12.7,6.8,12.5,6.5,12.3,6.2z')
+ path(d='M16.5,1.965A0.5,0.5,0,0,0,16.4,1.7a0.56,0.56,0,0,0-.07-0.074h0a0.5,0.5,0,0,0-.32-0.121H11.5a0.5,0.5,0,0,0,0,1h3.293L9.646,7.646a0.5,0.5,0,1,0,.707.707L15.5,3.207V6.5a0.5,0.5,0,0,0,1,0V2C16.5,1.991,16.5,1.978,16.5,1.965Z')
+ path(d='M13.817,7.718L13.5,8.035V13.5a2,2,0,0,1-2,2h-7a2,2,0,0,1-2-2v-7a2,2,0,0,1,2-2H9.965l0.317-.317A2.5,2.5,0,0,1,9.527,3.5H4.5a3,3,0,0,0-3,3v7a3,3,0,0,0,3,3h7a3,3,0,0,0,3-3V8.473A2.5,2.5,0,0,1,13.817,7.718Z')
symbol#icons-lock(viewBox='0 0 15.725 17')
path(d='M2.249,8a1.136,1.136,0,0,0-1.1,1.141V15.9a1.1,1.1,0,0,0,1.1,1.1H15.774a1.1,1.1,0,0,0,1.1-1.1V9.141A1.136,1.136,0,0,0,15.774,8H2.249Z', transform='translate(-1.149)', style='fill:#d8a956')
path(d='M15.774,9.125l-0.025.016,0.025,6.734-13.5.025L2.249,9.125H15.774m0-1.125H2.249a1.136,1.136,0,0,0-1.1,1.141V15.9a1.1,1.1,0,0,0,1.1,1.1H15.774a1.1,1.1,0,0,0,1.1-1.1V9.141A1.136,1.136,0,0,0,15.774,8h0Z', transform='translate(-1.149)', style='fill:#ad8850')
@@ -289,14 +291,12 @@ svg(xmlns='http://www.w3.org/2000/svg')
symbol#icons-redirect(viewBox='0 0 16 35.173')
path(d='M16,2V0C7.163,0,0,7.163,0,16c0,6.937,4.421,12.826,10.595,15.042l-4.764,2.224c-0.5,0.233-0.717,0.828-0.483,1.329c0.144,0.31,0.429,0.511,0.743,0.563c0.193,0.032,0.397,0.009,0.587-0.08l6.859-3.202c0.493-0.23,0.711-0.811,0.492-1.308l-3.046-6.93c-0.224-0.505-0.813-0.734-1.318-0.513c-0.505,0.223-0.735,0.812-0.513,1.318l2.064,4.695C5.848,27.179,2,22.037,2,16C2,8.28,8.28,2,16,2z')
symbol#icons-repository(viewBox='0 0 18 18')
- path(fill='#E6E6E6', d='M3.371,16.534c-1.213,0-2.905-0.66-2.905-1.734V13c0-1.442,2.23-1.484,2.484-1.484h10.628c0.4,0,0.419-0.001,0.604-0.012c0.128-0.007,0.92-0.041,0.92-0.041l0.078-0.034c0.126-0.053,0.243-0.114,0.353-0.185V14c0,0.941-0.323,2.534-1.534,2.534H3.371z')
- path(fill='#808080', d='M15.068,11.93V14c0,0.831-0.284,2.068-1.068,2.068H3.371c-1.098,0-2.439-0.585-2.439-1.268V13c0-1.007,1.936-1.018,2.018-1.018H13.58c0.419,0,0.437-0.001,0.632-0.012c0.127-0.007,0.337-0.019,0.825-0.038L15.068,11.93M16,9.697c-0.069,0.66-0.484,1.085-1,1.303c-1.188,0.047-0.759,0.049-1.42,0.049H2.951C1.531,11.049,0,11.581,0,13v1.8C0,16.219,1.952,17,3.371,17H14c1.419,0,2-1.581,2-3V9.697L16,9.697z')
- path(fill='#B3B3B3', d='M0.466,3c0.004-1.278,1.255-2.534,2.524-2.534h10.134c1.316,0.005,2.385,1.109,2.38,2.462L15.478,9.86c-0.11,0.366-0.365,0.567-0.588,0.678c-0.439,0.018-0.636,0.028-0.758,0.035c-0.17,0.01-0.187,0.011-0.553,0.011H2.951c-1.009,0-1.878,0.239-2.484,0.67V3z')
- path(fill='#808080', d='M2.99,0.932l0.01,0h10.121c1.061,0.004,1.921,0.898,1.917,1.993l-0.027,6.858c-0.033,0.084-0.101,0.198-0.25,0.293c-0.364,0.015-0.54,0.025-0.652,0.031c-0.164,0.009-0.178,0.009-0.529,0.009H2.951c-0.753,0-1.44,0.125-2.018,0.36V3.003C0.936,1.888,2.067,0.932,2.99,0.932 M2.99,0C1.521,0,0.006,1.392,0,3v9h0.347c0.529-0.672,1.59-0.951,2.604-0.951H13.58c0.662,0,0.233-0.003,1.42-0.049c0.451-0.191,0.81-0.551,0.943-1.076l0.028-6.994c0.006-1.612-1.268-2.923-2.846-2.93H3C2.997,0,2.994,0,2.99,0L2.99,0z')
- path(fill='#999999', d='M0.466,3C0.47,1.876,1.438,0.77,2.534,0.519v10.082c-0.842,0.061-1.552,0.288-2.067,0.654V3z')
- path(fill='#808080', d='M2.068,1.209v8.969c-0.411,0.059-0.792,0.16-1.135,0.299V3.003C0.935,2.251,1.45,1.572,2.068,1.209 M2.99,0C1.521,0,0.006,1.392,0,3v9h0.347c0.529-0.672,1.59-0.951,2.604-0.951H3V0C2.997,0,2.994,0,2.99,0L2.99,0z')
- polygon(fill='#EF9CA4', points='5.985,15.289 4.506,16.769 4.527,12.5 7.498,12.5 7.477,16.78')
- path(fill='#F25058', d='M6.995,13l-0.013,2.579l-0.29-0.29l-0.707-0.707l-0.707,0.707l-0.266,0.266L5.024,13H6.995 M8,12H4.029L4,17.982l1.985-1.985l1.985,1.985L8,12L8,12z')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:gray;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#ef9ca4;stroke:#f25058;stroke-linejoin:round')
+ path(d='M5.5,11.5V0.5H14A2.5,2.5,0,0,1,16.5,3v8.5H5.5Z', style='fill:#bbb;stroke:#888;stroke-miterlimit:10')
+ path(d='M1.5,13.5V3A2.5,2.5,0,0,1,4,.5H5.5v13h-4Z', style='fill:#a1a1a1;stroke:#888;stroke-miterlimit:10')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:#888;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#ef9ca4;stroke:#f25058;stroke-linejoin:round')
symbol#icons-repository-alt(viewBox='0 0 12 14.546')
path(d='M12,0.909v10.909c-0.011,0.256-0.11,0.469-0.297,0.639c-0.188,0.17-0.422,0.261-0.703,0.27H6v1.818l-1.5-1.364L3,14.546v-1.818H1c-0.281-0.01-0.516-0.1-0.703-0.27C0.109,12.287,0.01,12.074,0,11.819V0.909C0.01,0.654,0.109,0.441,0.297,0.27S0.719,0.01,1,0h10c0.281,0.01,0.516,0.1,0.703,0.27S11.989,0.654,12,0.909z M11,10.001H1v1.818h2v-0.909h3v0.909h5V10.001zM11,0.909H2v8.182H11V0.909z M4,1.818H3v0.909h1V1.818z M4,3.637H3v0.909h1V3.637z M4,5.455H3v0.909h1V5.455z M4,8.182H3V7.273h1V8.182z')
symbol#icons-search(viewBox='0 0 30 30')
@@ -520,58 +520,44 @@ svg(xmlns='http://www.w3.org/2000/svg')
path(fill='#3CCB5A', d='M12.5,9c1.93,0,3.5,1.57,3.5,3.5S14.43,16,12.5,16S9,14.43,9,12.5S10.57,9,12.5,9 M12.5,8C10.015,8,8,10.015,8,12.5s2.015,4.5,4.5,4.5s4.5-2.015,4.5-4.5S14.985,8,12.5,8L12.5,8z')
polygon(fill='#3CCB5A', points='15,12 13,12 13,10 12,10 12,12 10,12 10,13 12,13 12,15 13,15 13,13 15,13 ')
symbol#icons-new-repository-server(viewBox='0 0 18 18')
- path(fill='#B3B3B3', d='M0.466,11.534V3c0.005-1.325,1.147-2.534,2.397-2.534h10.261c1.316,0.005,2.385,1.109,2.38,2.462l-0.027,7.053c-0.204,0.874-1.039,1.553-2.021,1.553H0.466z')
- path(fill='#808080', d='M2.863,0.932l0.01,0h10.249c1.061,0.004,1.921,0.898,1.917,1.993l-0.028,6.943c-0.196,0.711-0.823,1.199-1.554,1.199H0.932V3.003C0.936,1.939,1.874,0.932,2.863,0.932 M2.863,0C1.394,0,0.006,1.392,0,3v9h13.457c1.227,0,2.232-0.867,2.486-2.017l0.028-7.053c0.006-1.612-1.268-2.923-2.846-2.93H2.873C2.87,0,2.866,0,2.863,0L2.863,0z')
- path(fill='#E6E6E6', d='M3.371,15.534c-1.213,0-2.905-0.66-2.905-1.734V13c0-1.442,2.23-1.484,2.484-1.484h10.628c0.4,0,0.419-0.001,0.604-0.012c0.128-0.007,0.92-0.041,0.92-0.041l0.078-0.034c0.126-0.053,0.243-0.114,0.353-0.185V13c0,0.941-0.323,2.534-1.534,2.534H3.371z')
- path(fill='#808080', d='M15.068,11.93V13c0,0.831-0.284,2.068-1.068,2.068H3.371c-1.098,0-2.439-0.585-2.439-1.268V13c0-1.007,1.936-1.018,2.018-1.018H13.58c0.419,0,0.437-0.001,0.632-0.012c0.127-0.007,0.337-0.019,0.825-0.038L15.068,11.93M16,9.697c-0.069,0.66-0.484,1.085-1,1.303c-1.188,0.047-0.759,0.049-1.42,0.049H2.951C1.531,11.049,0,11.581,0,13v0.8C0,15.219,1.952,16,3.371,16H14c1.419,0,2-1.581,2-3V9.697L16,9.697z')
- polygon(fill='#EF9CA4', points='5.001,15.29 3.506,16.774 3.527,12.5 6.5,12.5 6.5,16.791 ')
- path(fill='#F25058', d='M6,13v2.583L5.708,15.29l-0.704-0.706l-0.708,0.703l-0.284,0.282L4.024,13H6 M7,12H3.029L3,17.982l2-1.985L7,18V12L7,12z')
- circle(fill='#FFFFFF', cx='12.5', cy='12.5', r='5.5')
- path(fill='#EBFFEE', d='M12.5,16.5c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4S14.706,16.5,12.5,16.5z')
- path(fill='#3CCB5A', d='M12.5,9c1.93,0,3.5,1.57,3.5,3.5S14.43,16,12.5,16S9,14.43,9,12.5S10.57,9,12.5,9 M12.5,8C10.015,8,8,10.015,8,12.5s2.015,4.5,4.5,4.5s4.5-2.015,4.5-4.5S14.985,8,12.5,8L12.5,8z')
- polygon(fill='#3CCB5A', points='15,12 13,12 13,10 12,10 12,12 10,12 10,13 12,13 12,15 13,15 13,13 15,13 ')
- path(fill='#999999', d='M0.446,3c0.004-1.094,1.022-2.244,2.107-2.501v11.066c-0.607,0.029-1.464,0.134-2.107,0.466V3z')
- path(fill='#808080', d='M2.107,1.162v9.98c-0.451,0.041-0.857,0.117-1.215,0.227l0-8.366C0.895,2.313,1.444,1.555,2.107,1.162M2.992,0C1.522,0,0.006,1.525,0,3v10.344c0-1.283,2.45-1.344,2.922-1.344C2.972,11.999,3,12,3,12V0C2.997,0,2.995,0,2.992,0L2.992,0z')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:gray;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#ef9ca4;stroke:#f25058;stroke-linejoin:round')
+ path(d='M5.5,11.5V0.5H14A2.5,2.5,0,0,1,16.5,3v8.5H5.5Z', style='fill:#bbb;stroke:#888;stroke-miterlimit:10')
+ path(d='M1.5,13.5V3A2.5,2.5,0,0,1,4,.5H5.5v13h-4Z', style='fill:#a1a1a1;stroke:#888;stroke-miterlimit:10')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:#888;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#ef9ca4;stroke:#f25058;stroke-linejoin:round')
+ circle(cx='13.5', cy='13.5', r='5.5', style='fill:#fff')
+ circle(cx='13.5', cy='13.5', r='4', style='fill:#ebffee;stroke:#3ccb5a;stroke-miterlimit:10')
+ line(x1='11', y1='13.5', x2='16', y2='13.5', style='fill:none;stroke:#3ccb5a;stroke-miterlimit:10')
+ line(x1='13.5', y1='16', x2='13.5', y2='11', style='fill:none;stroke:#3ccb5a;stroke-miterlimit:10')
symbol#icons-repository-additional(viewBox='0 0 18 18')
- path(fill='#B3B3B3', d='M0.6,11.6l0-8.7c0-1.3,1-2.4,2.2-2.4l10.3,0.1c1.3,0,2.4,1.1,2.4,2.5l0,7.1c-0.2,0.9-1,1.6-2,1.6H0.6z')
- path(fill='#808080', d='M2.9,0l0,0.9L13.1,1C14.2,1,15,1.9,15,3l0,6.9c-0.2,0.7-0.8,1.2-1.6,1.2H1.1l0-8.2c0-1.1,0.8-2,1.7-2V0M2.9,0C1.4,0,0.2,1.3,0.2,2.9l0,9.1h13.3c1.2,0,2.2-0.9,2.5-2L16,3c0-1.6-1.3-2.9-2.8-2.9L2.9,0C2.9,0,2.9,0,2.9,0L2.9,0z')
- path(fill='#E6E6E6', d='M3.4,16.6c-1.2,0-2.9-0.7-2.9-1.7v-1.8c0-1.4,2.2-1.5,2.5-1.5h10.6c0.4,0,0.4,0,0.6,0c0.1,0,0.9,0,0.9,0l0.1,0c0.1-0.1,0.2-0.1,0.4-0.2v2.8c0,0.9-0.3,2.5-1.5,2.5H3.4z')
- path(fill='#808080', d='M15.1,12v2.1c0,0.8-0.3,2.1-1.1,2.1H3.4c-1.1,0-2.4-0.6-2.4-1.3v-1.8c0-1,1.9-1,2-1h10.6c0.4,0,0.4,0,0.6,0C14.3,12,14.5,12,15.1,12L15.1,12 M16,9.7c-0.1,0.7-0.5,1.1-1,1.3c-1.2,0-0.8,0-1.4,0H3c-1.4,0-3,0.5-3,2v1.8c0,1.4,2,2.2,3.4,2.2H14c1.4,0,2-1.6,2-3V9.7L16,9.7z')
- path(fill='#A68AC4', d='M6.3,15.7c-0.1-0.1-0.2-0.1-0.4-0.1s-0.3,0-0.4,0.1l-1.1,1.1l0-4.3h3l0,4.3L6.3,15.7z')
- path(fill='#834FAB', d='M7,13.1l0,2.6l-0.3-0.3C6.5,15.1,6.2,15,6,15s-0.5,0.1-0.7,0.3L5,15.6l0-2.6H7 M8,12.1H4l0,6l2-2l2,2L8,12.1L8,12.1z')
- path(fill='#999999', d='M0.6,11.5l0-8.6c0-1.2,0.8-2.2,1.7-2.4v11H0.6z')
- path(fill='#808080', d='M1.9,1.2V11H1.1l0-8.1C1.1,2.2,1.5,1.6,1.9,1.2 M2.9,0C1.4,0,0.2,1.3,0.2,2.9l0,9.1h2.7L2.9,0C2.9,0,2.9,0,2.9,0L2.9,0z')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:gray;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#ef9ca4;stroke:#f25058;stroke-linejoin:round')
+ path(d='M5.5,11.5V0.5H14A2.5,2.5,0,0,1,16.5,3v8.5H5.5Z', style='fill:#bbb;stroke:#888;stroke-miterlimit:10')
+ path(d='M1.5,13.5V3A2.5,2.5,0,0,1,4,.5H5.5v13h-4Z', style='fill:#a1a1a1;stroke:#888;stroke-miterlimit:10')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:#888;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#a68ac4;stroke:#834fab;stroke-linejoin:round')
symbol#icons-repository-delete(viewBox='0 0 18 18')
- path(fill='#B3B3B3', d='M0.6,11.6l0-8.7c0-1.3,1-2.4,2.2-2.4h10.3c1.3,0,2.4,1.1,2.4,2.5l0,7.1c-0.2,0.9-1,1.6-2,1.6H0.6z')
- path(fill='#808080', d='M2.9,1L2.9,1l10.3,0C14.2,1,15,1.9,15,3l0,6.9c-0.2,0.7-0.8,1.2-1.6,1.2H1.1l0-8.2C1.1,1.8,1.9,1,2.9,1M2.9,0.1c-1.5,0-2.7,1.2-2.7,2.9l0,9.1h13.3c1.2,0,2.2-0.9,2.5-2L16,3c0-1.6-1.3-2.9-2.8-2.9L2.9,0.1C2.9,0.1,2.9,0.1,2.9,0.1L2.9,0.1z')
- path(fill='#E6E6E6', d='M3.4,15.6c-1.2,0-2.9-0.7-2.9-1.7v-0.8c0-1.4,2.2-1.5,2.5-1.5h10.6c0.4,0,0.4,0,0.6,0c0.1,0,0.9,0,0.9,0l0.1,0c0.1-0.1,0.2-0.1,0.4-0.2v1.8c0,0.9-0.3,2.5-1.5,2.5H3.4z')
- path(fill='#808080', d='M15.1,12v1.1c0,0.8-0.3,2.1-1.1,2.1H3.4c-1.1,0-2.4-0.6-2.4-1.3v-0.8c0-1,1.9-1,2-1h10.6c0.4,0,0.4,0,0.6,0C14.3,12,14.5,12,15.1,12L15.1,12 M16,9.7c-0.1,0.7-0.5,1.1-1,1.3c-1.2,0-0.8,0-1.4,0H3c-1.4,0-3,0.5-3,2v0.8c0,1.4,2,2.2,3.4,2.2H14c1.4,0,2-1.6,2-3V9.7L16,9.7z')
- path(fill='#999999', d='M0.6,10.5l0-7.9c0-1.1,0.8-2,1.8-2.2v10H0.6z')
- path(fill='#808080', d='M2,1.1v8.9H1.1l0-7.4C1.1,2,1.5,1.4,2,1.1 M2.9,0C1.4,0,0.2,1.2,0.2,2.7l0,8.3h2.7L2.9,0C2.9,0,2.9,0,2.9,0L2.9,0z')
- path(fill='#A68AC4', d='M5.4,15.7c-0.1-0.1-0.2-0.1-0.4-0.1c-0.1,0-0.3,0-0.4,0.1l-1.1,1.1l0-4.3h3v4.3L5.4,15.7z')
- path(fill='#834FAB', d='M6,13.1v2.6l-0.3-0.3C5.5,15.1,5.3,15,5,15c-0.3,0-0.5,0.1-0.7,0.3L4,15.6l0-2.6H6 M7,12.1H3l0,6l2-2l2,2V12.1L7,12.1z')
- circle(fill='#FFFFFF', cx='12.5', cy='12.6', r='5.5')
- path(fill='#FFF0F1', d='M12.5,16.6c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4S14.7,16.6,12.5,16.6z')
- path(fill='#F25058', d='M12.5,9.1c1.9,0,3.5,1.6,3.5,3.5s-1.6,3.5-3.5,3.5S9,14.5,9,12.6S10.6,9.1,12.5,9.1 M12.5,8.1c-2.5,0-4.5,2-4.5,4.5s2,4.5,4.5,4.5s4.5-2,4.5-4.5S15,8.1,12.5,8.1L12.5,8.1z')
- rect(x='10', y='12.1', fill='#F25058', width='5', height='1')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:gray;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#ef9ca4;stroke:#f25058;stroke-linejoin:round')
+ path(d='M5.5,11.5V0.5H14A2.5,2.5,0,0,1,16.5,3v8.5H5.5Z', style='fill:#bbb;stroke:#888;stroke-miterlimit:10')
+ path(d='M1.5,13.5V3A2.5,2.5,0,0,1,4,.5H5.5v13h-4Z', style='fill:#a1a1a1;stroke:#888;stroke-miterlimit:10')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:#888;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#a68ac4;stroke:#834fab;stroke-linejoin:round')
+ circle(cx='13.5', cy='13.5', r='5.5', style='fill:#fff')
+ circle(cx='13.5', cy='13.5', r='4', style='fill:#fff0f1;stroke:#f25058;stroke-miterlimit:10')
+ line(x1='11', y1='13.5', x2='16', y2='13.5', style='fill:none;stroke:#f25058;stroke-miterlimit:10')
symbol#icons-repository-new(viewBox='0 0 18 18')
- path(fill='#B3B3B3', d='M0.6,11.6l0-8.7c0-1.3,1-2.4,2.2-2.4h10.3c1.3,0,2.4,1.1,2.4,2.5l0,7.1c-0.2,0.9-1,1.6-2,1.6H0.6z')
- path(fill='#808080', d='M2.9,1L2.9,1l10.3,0C14.2,1,15,1.9,15,3l0,6.9c-0.2,0.7-0.8,1.2-1.6,1.2H1.1l0-8.2C1.1,1.8,1.9,1,2.9,1M2.9,0.1c-1.5,0-2.7,1.2-2.7,2.9l0,9.1h13.3c1.2,0,2.2-0.9,2.5-2L16,3c0-1.6-1.3-2.9-2.8-2.9L2.9,0.1C2.9,0.1,2.9,0.1,2.9,0.1L2.9,0.1z')
- path(fill='#E6E6E6', d='M3.4,15.6c-1.2,0-2.9-0.7-2.9-1.7v-0.8c0-1.4,2.2-1.5,2.5-1.5h10.6c0.4,0,0.4,0,0.6,0c0.1,0,0.9,0,0.9,0l0.1,0c0.1-0.1,0.2-0.1,0.4-0.2v1.8c0,0.9-0.3,2.5-1.5,2.5H3.4z')
- path(fill='#808080', d='M15.1,12v1.1c0,0.8-0.3,2.1-1.1,2.1H3.4c-1.1,0-2.4-0.6-2.4-1.3v-0.8c0-1,1.9-1,2-1h10.6c0.4,0,0.4,0,0.6,0C14.3,12,14.5,12,15.1,12L15.1,12 M16,9.7c-0.1,0.7-0.5,1.1-1,1.3c-1.2,0-0.8,0-1.4,0H3c-1.4,0-3,0.5-3,2v0.8c0,1.4,2,2.2,3.4,2.2H14c1.4,0,2-1.6,2-3V9.7L16,9.7z')
- path(fill='#A68AC4', d='M5.4,15.7c-0.1-0.1-0.2-0.1-0.4-0.1c-0.1,0-0.3,0-0.4,0.1l-1.1,1.1l0-4.3h3v4.3L5.4,15.7z')
- path(fill='#834FAB', d='M6,13.1v2.6l-0.3-0.3C5.5,15.1,5.3,15,5,15c-0.3,0-0.5,0.1-0.7,0.3L4,15.6l0-2.6H6 M7,12.1H3l0,6l2-2l2,2V12.1L7,12.1z')
- path(fill='#999999', d='M0.6,10.5l0-7.9c0-1.1,0.8-2,1.8-2.2v10H0.6z')
- path(fill='#808080', d='M2,1.1v8.9H1.1l0-7.4C1.1,2,1.5,1.4,2,1.1 M2.9,0C1.4,0,0.2,1.2,0.2,2.7l0,8.3h2.7L2.9,0C2.9,0,2.9,0,2.9,0L2.9,0z')
- circle(fill='#FFFFFF', cx='12.5', cy='12.6', r='5.5')
- path(fill='#EBFFEE', d='M12.5,16.6c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4S14.7,16.6,12.5,16.6z')
- path(fill='#3CCB5A', d='M12.5,9.1c1.9,0,3.5,1.6,3.5,3.5s-1.6,3.5-3.5,3.5S9,14.5,9,12.6S10.6,9.1,12.5,9.1 M12.5,8.1c-2.5,0-4.5,2-4.5,4.5s2,4.5,4.5,4.5s4.5-2,4.5-4.5S15,8.1,12.5,8.1L12.5,8.1z')
- polygon(fill='#3CCB5A', points='15,12.1 13,12.1 13,10.1 12,10.1 12,12.1 10,12.1 10,13.1 12,13.1 12,15.1 13,15.1 13,13.1 15,13.1 ')
- symbol#icons-runnabot(viewBox='0 0 18 18')
- circle(cx='9', cy='9', r='9', fill='none')
- path(d='M11.519,4.624H6.481A2.871,2.871,0,0,0,3.61,7.494V9.512a2.871,2.871,0,0,0,2.871,2.871H8.75c0.862,0.969,2.621,2.777,2.38,1.1a5.374,5.374,0,0,1-.07-1.1h0.46A2.871,2.871,0,0,0,14.39,9.512V7.494A2.871,2.871,0,0,0,11.519,4.624Z')
- circle(cx='6.87', cy='8.503', r='0.937', fill='#fff')
- circle(cx='11.13', cy='8.503', r='0.937', fill='#fff')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:gray;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#ef9ca4;stroke:#f25058;stroke-linejoin:round')
+ path(d='M5.5,11.5V0.5H14A2.5,2.5,0,0,1,16.5,3v8.5H5.5Z', style='fill:#bbb;stroke:#888;stroke-miterlimit:10')
+ path(d='M1.5,13.5V3A2.5,2.5,0,0,1,4,.5H5.5v13h-4Z', style='fill:#a1a1a1;stroke:#888;stroke-miterlimit:10')
+ path(d='M4,16.5a2.5,2.5,0,0,1,0-5H14a2.505,2.505,0,0,0,2.45-2H16.5V14A2.5,2.5,0,0,1,14,16.5H4Z', style='fill:#e6e6e6;stroke:#888;stroke-miterlimit:10')
+ polyline(points='8.5 12 8.5 17.25 7 16.25 5.5 17.25 5.5 12', style='fill:#a68ac4;stroke:#834fab;stroke-linejoin:round')
+ circle(cx='13.5', cy='13.5', r='5.5', style='fill:#fff')
+ circle(cx='13.5', cy='13.5', r='4', style='fill:#ebffee;stroke:#3ccb5a;stroke-miterlimit:10')
+ line(x1='11', y1='13.5', x2='16', y2='13.5', style='fill:none;stroke:#3ccb5a;stroke-miterlimit:10')
+ line(x1='13.5', y1='16', x2='13.5', y2='11', style='fill:none;stroke:#3ccb5a;stroke-miterlimit:10')
symbol#icons-server-delete(viewBox='0 0 18 18')
path(fill='#E6E6E6', d='M8,15.185c-0.129,0-0.258-0.03-0.374-0.088l-6.664-3.332C0.677,11.622,0.5,11.336,0.5,11.018v-6.35c0-0.318,0.177-0.604,0.462-0.747l6.665-3.332C7.742,0.531,7.871,0.5,8,0.5s0.258,0.031,0.374,0.088l6.665,3.332C15.323,4.063,15.5,4.35,15.5,4.667v6.35c0,0.313-0.182,0.606-0.462,0.747l-6.665,3.332C8.258,15.154,8.129,15.185,8,15.185z')
path(fill='#999999', d='M8,1c0.052,0,0.104,0.012,0.15,0.035l6.665,3.332C14.929,4.425,15,4.54,15,4.668v6.35c0,0.128-0.071,0.243-0.185,0.3L8.15,14.649C8.104,14.673,8.052,14.685,8,14.685c-0.052,0-0.104-0.012-0.15-0.035l-6.665-3.332C1.071,11.26,1,11.145,1,11.017v-6.35c0-0.128,0.071-0.243,0.185-0.3L7.85,1.035C7.896,1.012,7.948,1,8,1 M8,0C7.795,0,7.591,0.047,7.403,0.141L0.738,3.473C0.286,3.7,0,4.162,0,4.668v6.35c0,0.506,0.286,0.968,0.738,1.194l6.665,3.332C7.591,15.638,7.795,15.685,8,15.685s0.409-0.047,0.597-0.141l6.665-3.332C15.714,11.985,16,11.523,16,11.017v-6.35c0-0.506-0.286-0.968-0.738-1.194L8.597,0.141C8.409,0.047,8.205,0,8,0L8,0z')
@@ -606,6 +592,10 @@ svg(xmlns='http://www.w3.org/2000/svg')
symbol#icons-octicons-branch(viewBox='0 0 18 18')
circle(cx='9', cy='9', r='9', fill='none')
path(d='M11.747,5.129a1.481,1.481,0,0,1,1.5,1.5,1.415,1.415,0,0,1-.205.756,1.549,1.549,0,0,1-.545.533V8.129a3.011,3.011,0,0,1-.937,2.062,3.011,3.011,0,0,1-2.063.938,1.624,1.624,0,0,0-.7.135,1.218,1.218,0,0,0-.445.346,1.5,1.5,0,1,1-2.6,1.02,1.415,1.415,0,0,1,.205-0.756A1.549,1.549,0,0,1,6.5,11.34V6.43A1.549,1.549,0,0,1,5.952,5.9a1.415,1.415,0,0,1-.205-0.756,1.5,1.5,0,1,1,3,0,1.415,1.415,0,0,1-.205.756A1.549,1.549,0,0,1,8,6.43V9.981a3.087,3.087,0,0,1,1.5-.34,1.613,1.613,0,0,0,1.5-1.5V7.93A1.549,1.549,0,0,1,10.452,7.4a1.415,1.415,0,0,1-.205-0.756,1.481,1.481,0,0,1,1.5-1.5V5.129ZM6.719,4.614a0.738,0.738,0,1,0,1.055,0A0.736,0.736,0,0,0,6.719,4.614Zm1.055,8.555a0.738,0.738,0,1,0-1.055,0A0.736,0.736,0,0,0,7.774,13.168Zm4.5-6a0.738,0.738,0,1,0-1.055,0A0.736,0.736,0,0,0,12.274,7.168Z')
+ symbol#icons-octicons-github(viewBox='0 0 18 18')
+ path(d='M15.372,2.628a9.007,9.007,0,0,1,.888,11.68,9.062,9.062,0,0,1-4.412,3.234,0.515,0.515,0,0,1-.475-0.1,0.486,0.486,0,0,1-.141-0.343l0.018-2.461a2.9,2.9,0,0,0-.193-1.046,1.664,1.664,0,0,0-.422-0.624,5.256,5.256,0,0,0,2.8-1.011q1.239-.905,1.31-3.436a3.844,3.844,0,0,0-.255-1.336,3.427,3.427,0,0,0-.677-1.072,2.44,2.44,0,0,0,.176-0.809,3.7,3.7,0,0,0-.264-1.582,1.289,1.289,0,0,0-.6.026,5.553,5.553,0,0,0-1.881.905,8.62,8.62,0,0,0-4.5,0A5.553,5.553,0,0,0,4.87,3.753a1.289,1.289,0,0,0-.6-0.026,3.7,3.7,0,0,0-.264,1.582,2.44,2.44,0,0,0,.176.809,3.429,3.429,0,0,0-.677,1.072,3.844,3.844,0,0,0-.255,1.336q0.07,2.531,1.3,3.436a5.232,5.232,0,0,0,2.812,1.011,1.45,1.45,0,0,0-.36.475,2.56,2.56,0,0,0-.22.738,2.487,2.487,0,0,1-1.2.22,1.815,1.815,0,0,1-1.424-.976,2.414,2.414,0,0,0-.484-0.562,1.325,1.325,0,0,0-.888-0.352q-0.527.018-.4,0.229a0.993,0.993,0,0,0,.413.352,1.937,1.937,0,0,1,.562.615,4.326,4.326,0,0,1,.352.65,1.648,1.648,0,0,0,.738.879,3.375,3.375,0,0,0,2.285.193L6.768,17.1a0.486,0.486,0,0,1-.141.343,0.515,0.515,0,0,1-.475.1A9.064,9.064,0,0,1,1.74,14.308,9,9,0,0,1,15.372,2.628Z')
+ symbol#icons-octicons-github-gray(viewBox='0 0 18 18')
+ path(fill='#555', d='M15.372,2.628a9.007,9.007,0,0,1,.888,11.68,9.062,9.062,0,0,1-4.412,3.234,0.515,0.515,0,0,1-.475-0.1,0.486,0.486,0,0,1-.141-0.343l0.018-2.461a2.9,2.9,0,0,0-.193-1.046,1.664,1.664,0,0,0-.422-0.624,5.256,5.256,0,0,0,2.8-1.011q1.239-.905,1.31-3.436a3.844,3.844,0,0,0-.255-1.336,3.427,3.427,0,0,0-.677-1.072,2.44,2.44,0,0,0,.176-0.809,3.7,3.7,0,0,0-.264-1.582,1.289,1.289,0,0,0-.6.026,5.553,5.553,0,0,0-1.881.905,8.62,8.62,0,0,0-4.5,0A5.553,5.553,0,0,0,4.87,3.753a1.289,1.289,0,0,0-.6-0.026,3.7,3.7,0,0,0-.264,1.582,2.44,2.44,0,0,0,.176.809,3.429,3.429,0,0,0-.677,1.072,3.844,3.844,0,0,0-.255,1.336q0.07,2.531,1.3,3.436a5.232,5.232,0,0,0,2.812,1.011,1.45,1.45,0,0,0-.36.475,2.56,2.56,0,0,0-.22.738,2.487,2.487,0,0,1-1.2.22,1.815,1.815,0,0,1-1.424-.976,2.414,2.414,0,0,0-.484-0.562,1.325,1.325,0,0,0-.888-0.352q-0.527.018-.4,0.229a0.993,0.993,0,0,0,.413.352,1.937,1.937,0,0,1,.562.615,4.326,4.326,0,0,1,.352.65,1.648,1.648,0,0,0,.738.879,3.375,3.375,0,0,0,2.285.193L6.768,17.1a0.486,0.486,0,0,1-.141.343,0.515,0.515,0,0,1-.475.1A9.064,9.064,0,0,1,1.74,14.308,9,9,0,0,1,15.372,2.628Z')
symbol#icons-octicons-repo(viewBox='0 0 18 18')
circle(cx='9', cy='9', r='9', fill='none')
path(d='M13.293,4.446v7.806a0.63,0.63,0,0,1-.213.457,0.761,0.761,0,0,1-.5.193H9v1.3l-1.073-.976L6.854,14.2V12.9H5.422a0.761,0.761,0,0,1-.5-0.193,0.629,0.629,0,0,1-.212-0.457V4.446a0.629,0.629,0,0,1,.212-0.457,0.761,0.761,0,0,1,.5-0.193h7.156a0.761,0.761,0,0,1,.5.193A0.63,0.63,0,0,1,13.293,4.446Zm-0.716,6.505H5.422v1.3H6.854V11.6H9v0.651h3.578v-1.3Zm0-6.505H6.138V10.3h6.44V4.446ZM7.569,5.1H6.854V5.748H7.569V5.1Zm0,1.3H6.854V7.048H7.569V6.4Zm0,1.3H6.854V8.349H7.569V7.7Zm0,1.951H6.854V9H7.569V9.651h0Z')
diff --git a/client/templates/viewBranchSelection.jade b/client/templates/viewBranchSelection.jade
deleted file mode 100644
index 18df07073..000000000
--- a/client/templates/viewBranchSelection.jade
+++ /dev/null
@@ -1,28 +0,0 @@
-main.home.server-selection
- img.logo.float-left(
- height = "45"
- src = "/build/images/runnable-logo-gray.svg"
- width = "240"
- )
-
- h3.h3.header-thin Choose a container to run…
- a.block-quote(
- href = "#"
- target = "_blank"
- ) {{ message }}
- //- spinner
- .spinner-wrapper.spinner-md.in(
- ng-if = "loading"
- ng-include = "'spinner'"
- )
- ol.list.list-bordered(
- ng-show = "!loading"
- )
- li.list-item(
- ng-class = "{active: data.listExpand}"
- ng-repeat = "instance in instances.models"
- )
- .list-item-row(
- ng-click = "selectInstance(instance)"
- )
- h4.h4.header-thin {{ instance.attrs.name }}
diff --git a/client/templates/viewInstance.jade b/client/templates/viewInstance.jade
index 4222e2ec3..998c2054c 100644
--- a/client/templates/viewInstance.jade
+++ b/client/templates/viewInstance.jade
@@ -5,35 +5,9 @@
)
.grid-block.vertical.instance(
- ng-if = "!isLoading.main"
+ ng-if = "!isLoading.main && !$root.featureFlags.containersViewEmptyState"
)
-
- .grid-block.shrink.vertical.instance-header(
- ng-if = "$root.featureFlags.aha2"
- )
- button.grid-block.shrink.btn.btn-sm.gray.btn-aha(
- ng-click = "$root.featureFlags.ahaSidebar = true"
- ng-if = "$root.featureFlags.aha && !$root.featureFlags.ahaSidebar"
- tooltip = "Setup Guide"
- tooltip-options = "{\"class\":\"left\",\"right\":42,\"top\":0}"
- )
- svg.iconnables
- use(
- xlink:href = "#icons-help"
- )
-
- .grid-block.align-center.justify-center(
- ng-if = "$root.featureFlags.aha2"
- )
- .modal-dialog.modal-sm
- .grid-block.align-center.aha-guide.padding-md(
- ng-include = "'ahaGuideView'"
- ng-init = "state.showStep = 2"
- )
-
- .grid-block.vertical(
- ng-if = "!$root.featureFlags.aha2"
- )
+ .grid-block.vertical
//- show if server build is being swapped out
- orange when build is updating or has failed
- green if build is successfully built
@@ -84,6 +58,8 @@
)
.grid-block.vertical.aha-sidebar.padding-sm.js-animate(
- ng-include = "'ahaSidebarView'"
- ng-if = "$root.featureFlags.aha && $root.featureFlags.ahaSidebar"
+ aha-sidebar
+ toggle-sidebar = "CI.toggleSidebar"
+ show-overview = "false"
+ ng-if = "$root.featureFlags.aha && CI.isInGuide() && CI.showSidebar"
)
diff --git a/client/templates/viewOrgSelect.jade b/client/templates/viewOrgSelect.jade
index d1bb2a251..75282a982 100644
--- a/client/templates/viewOrgSelect.jade
+++ b/client/templates/viewOrgSelect.jade
@@ -1,7 +1,8 @@
div(
modal
modal-actions = "actions"
- modal-data = "COS"
+ modal-controller = "COS"
+ modal-controller-as = "COS"
modal-open-flag = "true"
modal-template = "chooseOrganizationModalView"
-)
\ No newline at end of file
+)
diff --git a/layout.jade b/layout.jade
index 1138b2ac8..04cca5047 100644
--- a/layout.jade
+++ b/layout.jade
@@ -47,9 +47,13 @@ html(
if env === 'production'
script.
!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t