diff options
Diffstat (limited to 'app/assets/javascripts/environments')
15 files changed, 258 insertions, 143 deletions
diff --git a/app/assets/javascripts/environments/components/delete_environment_modal.vue b/app/assets/javascripts/environments/components/delete_environment_modal.vue index 3173c2bd644..78e1b8d5cb2 100644 --- a/app/assets/javascripts/environments/components/delete_environment_modal.vue +++ b/app/assets/javascripts/environments/components/delete_environment_modal.vue @@ -1,6 +1,6 @@ <script> import { GlTooltipDirective, GlModal } from '@gitlab/ui'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import { __, s__, sprintf } from '~/locale'; import eventHub from '../event_hub'; import deleteEnvironmentMutation from '../graphql/mutations/delete_environment.mutation.graphql'; @@ -65,11 +65,11 @@ export default { .then(({ data }) => { const [message] = data?.deleteEvironment?.errors ?? []; if (message) { - createFlash({ message }); + createAlert({ message }); } }) .catch((error) => - createFlash({ + createAlert({ message: s__( 'Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again.', ), diff --git a/app/assets/javascripts/environments/components/deployment.vue b/app/assets/javascripts/environments/components/deployment.vue index 3475b38c8c9..b00a0777a03 100644 --- a/app/assets/javascripts/environments/components/deployment.vue +++ b/app/assets/javascripts/environments/components/deployment.vue @@ -10,7 +10,7 @@ import { import { __, s__ } from '~/locale'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import deploymentDetails from '../graphql/queries/deployment_details.query.graphql'; import DeploymentStatusBadge from './deployment_status_badge.vue'; import Commit from './commit.vue'; @@ -119,7 +119,7 @@ export default { return data?.project?.deployment?.tags; }, error(error) { - createFlash({ + createAlert({ message: this.$options.i18n.LOAD_ERROR_MESSAGE, captureError: true, error, diff --git a/app/assets/javascripts/environments/components/edit_environment.vue b/app/assets/javascripts/environments/components/edit_environment.vue index 96742a11ebb..901d0f5b34d 100644 --- a/app/assets/javascripts/environments/components/edit_environment.vue +++ b/app/assets/javascripts/environments/components/edit_environment.vue @@ -1,5 +1,5 @@ <script> -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { visitUrl } from '~/lib/utils/url_utility'; import EnvironmentForm from './environment_form.vue'; @@ -39,7 +39,7 @@ export default { .then(({ data: { path } }) => visitUrl(path)) .catch((error) => { const message = error.response.data.message[0]; - createFlash({ message }); + createAlert({ message }); this.loading = false; }); }, diff --git a/app/assets/javascripts/environments/components/empty_state.vue b/app/assets/javascripts/environments/components/empty_state.vue index 563fa6c96fb..e40c37b5095 100644 --- a/app/assets/javascripts/environments/components/empty_state.vue +++ b/app/assets/javascripts/environments/components/empty_state.vue @@ -1,9 +1,14 @@ <script> +import { GlEmptyState, GlLink } from '@gitlab/ui'; import { s__ } from '~/locale'; import { ENVIRONMENTS_SCOPE } from '../constants'; export default { - name: 'EnvironmentsEmptyState', + components: { + GlEmptyState, + GlLink, + }, + inject: ['newEnvironmentPath'], props: { helpPath: { type: String, @@ -13,10 +18,23 @@ export default { type: String, required: true, }, + hasTerm: { + type: Boolean, + required: false, + default: false, + }, }, computed: { title() { - return this.$options.i18n.title[this.scope]; + return this.hasTerm + ? this.$options.i18n.searchingTitle + : this.$options.i18n.title[this.scope]; + }, + content() { + return this.hasTerm ? this.$options.i18n.searchingContent : this.$options.i18n.content; + }, + buttonText() { + return this.hasTerm ? this.$options.i18n.newEnvironmentButtonLabel : ''; }, }, i18n: { @@ -27,20 +45,21 @@ export default { content: s__( 'Environments|Environments are places where code gets deployed, such as staging or production.', ), + searchingTitle: s__('Environments|No results found'), + searchingContent: s__('Environments|Edit your search and try again'), link: s__('Environments|How do I create an environment?'), + newEnvironmentButtonLabel: s__('Environments|New environment'), }, }; </script> <template> - <div class="empty-state"> - <div class="text-content"> - <h4 class="js-blank-state-title"> - {{ title }} - </h4> - <p> - {{ $options.i18n.content }} - <a :href="helpPath"> {{ $options.i18n.link }} </a> - </p> - </div> - </div> + <gl-empty-state :primary-button-text="buttonText" :primary-button-link="newEnvironmentPath"> + <template #title> + <h4>{{ title }}</h4> + </template> + <template #description> + <p>{{ content }}</p> + <gl-link v-if="!hasTerm" :href="helpPath">{{ $options.i18n.link }}</gl-link> + </template> + </gl-empty-state> </template> diff --git a/app/assets/javascripts/environments/components/enable_review_app_modal.vue b/app/assets/javascripts/environments/components/enable_review_app_modal.vue index 6343fe8702a..420ad3d9c42 100644 --- a/app/assets/javascripts/environments/components/enable_review_app_modal.vue +++ b/app/assets/javascripts/environments/components/enable_review_app_modal.vue @@ -1,18 +1,19 @@ <script> -import { GlLink, GlModal, GlSprintf } from '@gitlab/ui'; +import { GlLink, GlModal, GlSprintf, GlIcon, GlPopover } from '@gitlab/ui'; import { uniqueId } from 'lodash'; import { helpPagePath } from '~/helpers/help_page_helper'; -import { s__ } from '~/locale'; import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; +import { REVIEW_APP_MODAL_I18N as i18n } from '../constants'; export default { components: { GlLink, GlModal, GlSprintf, + GlIcon, + GlPopover, ModalCopyButton, }, - inject: ['defaultBranchName'], model: { prop: 'visible', event: 'change', @@ -28,25 +29,6 @@ export default { default: false, }, }, - instructionText: { - step1: s__( - 'EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}.', - ), - step2: s__('EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:'), - step3: s__( - `EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file.`, - ), - step4: s__( - `EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}.`, - ), - }, - modalInfo: { - closeText: s__('EnableReviewApp|Close'), - copyToClipboardText: s__('EnableReviewApp|Copy snippet text'), - title: s__('ReviewApp|Enable Review App'), - }, - visualReviewsDocs: helpPagePath('ci/review_apps/index.md', { anchor: 'visual-reviews' }), - connectClusterDocs: helpPagePath('user/clusters/agent/index'), data() { const modalInfoCopyId = uniqueId('enable-review-app-copy-string-'); @@ -57,81 +39,99 @@ export default { return `deploy_review: stage: deploy script: - - echo "Deploy a review app" + - echo "Add script here that deploys the code to your infrastructure" environment: name: review/$CI_COMMIT_REF_NAME url: https://$CI_ENVIRONMENT_SLUG.example.com - only: - - branches - except: - - ${this.defaultBranchName}`; + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event"`; + }, + }, + methods: { + commaOrPeriod(index, length) { + return index + 1 === length ? '.' : ','; }, }, + i18n, + configuringReviewAppsPath: helpPagePath('ci/review_apps/index.md', { + anchor: 'configuring-review-apps', + }), + reviewAppsExamplesPath: helpPagePath('ci/review_apps/index.md', { + anchor: 'review-apps-examples', + }), }; </script> <template> <gl-modal :visible="visible" :modal-id="modalId" - :title="$options.modalInfo.title" + :title="$options.i18n.title" static size="lg" - ok-only - ok-variant="light" - :ok-title="$options.modalInfo.closeText" + hide-footer @change="$emit('change', $event)" > + <p>{{ $options.i18n.intro }}</p> <p> - <gl-sprintf :message="$options.instructionText.step1"> - <template #step="{ content }"> - <strong>{{ content }}</strong> - </template> - <template #link="{ content }"> - <gl-link :href="$options.connectClusterDocs" target="_blank">{{ content }}</gl-link> - </template> - </gl-sprintf> + <strong>{{ $options.i18n.instructions.title }}</strong> </p> - <div> - <p> - <gl-sprintf :message="$options.instructionText.step2"> - <template #step="{ content }"> - <strong>{{ content }}</strong> - </template> - </gl-sprintf> - </p> - <div class="gl-display-flex align-items-start"> - <pre :id="modalInfoCopyId" class="gl-w-full" data-testid="enable-review-app-copy-string"> - {{ modalInfoCopyStr }} </pre - > - <modal-copy-button - :title="$options.modalInfo.copyToClipboardText" - :modal-id="modalId" - css-classes="border-0" - :target="`#${modalInfoCopyId}`" - /> - </div> + <div class="gl-mb-6"> + <ol class="gl-px-6"> + <li> + {{ $options.i18n.instructions.step1 }} + <gl-icon + ref="informationIcon" + name="information-o" + class="gl-text-blue-600 gl-hover-cursor-pointer" + /> + <gl-popover + :target="() => $refs.informationIcon.$el" + :title="$options.i18n.staticSitePopover.title" + triggers="hover focus" + > + {{ $options.i18n.staticSitePopover.body }} + </gl-popover> + </li> + <li>{{ $options.i18n.instructions.step2 }}</li> + <li> + {{ $options.i18n.instructions.step3 }} + <ul class="gl-px-4 gl-py-2"> + <li>{{ $options.i18n.instructions.step3a }}</li> + <li> + <gl-sprintf :message="$options.i18n.instructions.step3b"> + <template #code="{ content }" + ><code>{{ content }}</code></template + > + </gl-sprintf> + </li> + <li class="gl-list-style-none"> + <div class="gl-display-flex align-items-start"> + <pre + :id="modalInfoCopyId" + class="gl-w-full" + data-testid="enable-review-app-copy-string" + >{{ modalInfoCopyStr }}</pre + > + <modal-copy-button + :title="$options.i18n.copyToClipboardText" + :modal-id="modalId" + css-classes="border-0" + :target="`#${modalInfoCopyId}`" + /> + </div> + </li> + </ul> + </li> + <li>{{ $options.i18n.instructions.step4 }}</li> + </ol> + <gl-link :href="$options.configuringReviewAppsPath" target="_blank"> + {{ $options.i18n.learnMore }} + <gl-icon name="external-link" /> + </gl-link> + <gl-link :href="$options.reviewAppsExamplesPath" target="_blank" class="gl-ml-6"> + {{ $options.i18n.viewMoreExampleProjects }} + <gl-icon name="external-link" /> + </gl-link> </div> - <p> - <gl-sprintf :message="$options.instructionText.step3"> - <template #step="{ content }"> - <strong>{{ content }}</strong> - </template> - <template #link="{ content }"> - <gl-link :href="`blob/${defaultBranchName}/.gitlab-ci.yml`" target="_blank">{{ - content - }}</gl-link> - </template> - </gl-sprintf> - </p> - <p> - <gl-sprintf :message="$options.instructionText.step4"> - <template #step="{ content }"> - <strong>{{ content }}</strong> - </template> - <template #link="{ content }"> - <gl-link :href="$options.visualReviewsDocs" target="_blank">{{ content }}</gl-link> - </template> - </gl-sprintf> - </p> </gl-modal> </template> diff --git a/app/assets/javascripts/environments/components/environment_external_url.vue b/app/assets/javascripts/environments/components/environment_external_url.vue index b8def676e7d..04a390fbba7 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.vue +++ b/app/assets/javascripts/environments/components/environment_external_url.vue @@ -1,6 +1,8 @@ <script> import { GlTooltipDirective, GlButton } from '@gitlab/ui'; -import { s__ } from '~/locale'; +import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; +import { s__, __ } from '~/locale'; +import { isSafeURL } from '~/lib/utils/url_utility'; /** * Renders the external url link in environments table. @@ -8,6 +10,7 @@ import { s__ } from '~/locale'; export default { components: { GlButton, + ModalCopyButton, }, directives: { GlTooltip: GlTooltipDirective, @@ -21,11 +24,19 @@ export default { i18n: { title: s__('Environments|Open live environment'), open: s__('Environments|Open'), + copy: __('Copy URL'), + copyTitle: s__('Environments|Copy live environment URL'), + }, + computed: { + isSafeUrl() { + return isSafeURL(this.externalUrl); + }, }, }; </script> <template> <gl-button + v-if="isSafeUrl" v-gl-tooltip :title="$options.i18n.title" :aria-label="$options.i18n.title" @@ -37,4 +48,7 @@ export default { > {{ $options.i18n.open }} </gl-button> + <modal-copy-button v-else :title="$options.i18n.copyTitle" :text="externalUrl"> + {{ $options.i18n.copy }} + </modal-copy-button> </template> diff --git a/app/assets/javascripts/environments/components/environment_folder.vue b/app/assets/javascripts/environments/components/environment_folder.vue index 881f404340d..2f6c54e4707 100644 --- a/app/assets/javascripts/environments/components/environment_folder.vue +++ b/app/assets/javascripts/environments/components/environment_folder.vue @@ -24,6 +24,10 @@ export default { type: String, required: true, }, + search: { + type: String, + required: true, + }, }, data() { return { visible: false, interval: undefined }; @@ -32,7 +36,11 @@ export default { folder: { query: folderQuery, variables() { - return { environment: this.nestedEnvironment.latest, scope: this.scope }; + return { + environment: this.nestedEnvironment.latest, + scope: this.scope, + search: this.search, + }; }, }, interval: { diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue index f44182e822b..55e6a891e27 100644 --- a/app/assets/javascripts/environments/components/environments_app.vue +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -1,7 +1,9 @@ <script> -import { GlBadge, GlPagination, GlTab, GlTabs } from '@gitlab/ui'; +import { GlBadge, GlPagination, GlSearchBoxByType, GlTab, GlTabs } from '@gitlab/ui'; +import { debounce } from 'lodash'; import { s__, __, sprintf } from '~/locale'; import { updateHistory, setUrlParams, queryToObject } from '~/lib/utils/url_utility'; +import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import environmentAppQuery from '../graphql/queries/environment_app.query.graphql'; import pollIntervalQuery from '../graphql/queries/poll_interval.query.graphql'; import pageInfoQuery from '../graphql/queries/page_info.query.graphql'; @@ -31,6 +33,7 @@ export default { StopEnvironmentModal, GlBadge, GlPagination, + GlSearchBoxByType, GlTab, GlTabs, }, @@ -41,11 +44,10 @@ export default { return { scope: this.scope, page: this.page ?? 1, + search: this.search, }; }, - pollInterval() { - return this.interval; - }, + pollInterval: 3000, }, interval: { query: pollIntervalQuery, @@ -80,10 +82,11 @@ export default { next: __('Next'), prev: __('Prev'), goto: (page) => sprintf(__('Go to page %{page}'), { page }), + searchPlaceholder: s__('Environments|Search by environment name'), }, modalId: 'enable-review-app-info', data() { - const { page = '1', scope } = queryToObject(window.location.search); + const { page = '1', search = '', scope } = queryToObject(window.location.search); return { interval: undefined, isReviewAppModalVisible: false, @@ -97,6 +100,7 @@ export default { environmentToStop: {}, environmentToChangeCanary: {}, weight: 0, + search, }; }, computed: { @@ -112,6 +116,9 @@ export default { hasEnvironments() { return this.environments.length > 0 || this.folders.length > 0; }, + hasSearch() { + return Boolean(this.search); + }, availableCount() { return this.environmentApp?.availableCount; }, @@ -152,11 +159,19 @@ export default { return this.pageInfo?.perPage; }, }, + watch: { + interval(val) { + this.$apollo.queries.environmentApp.stopPolling(); + this.$apollo.queries.environmentApp.startPolling(val); + }, + }, mounted() { window.addEventListener('popstate', this.syncPageFromQueryParams); + window.addEventListener('popstate', this.syncSearchFromQueryParams); }, destroyed() { window.removeEventListener('popstate', this.syncPageFromQueryParams); + window.removeEventListener('popstate', this.syncSearchFromQueryParams); this.$apollo.queries.environmentApp.stopPolling(); }, methods: { @@ -173,23 +188,24 @@ export default { moveToPage(page) { this.page = page; updateHistory({ - url: setUrlParams({ page: this.page }), + url: setUrlParams({ page: this.page, scope: this.scope, search: this.search }), title: document.title, }); - this.resetPolling(); }, + setSearch: debounce(function setSearch(input) { + this.search = input; + this.moveToPage(1); + }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS), syncPageFromQueryParams() { const { page = '1' } = queryToObject(window.location.search); this.page = parseInt(page, 10); }, - resetPolling() { - this.$apollo.queries.environmentApp.stopPolling(); + syncSearchFromQueryParams() { + const { search = '' } = queryToObject(window.location.search); + this.search = search; + }, + refetchEnvironments() { this.$apollo.queries.environmentApp.refetch(); - this.$nextTick(() => { - if (this.interval) { - this.$apollo.queries.environmentApp.startPolling(this.interval); - } - }); }, }, ENVIRONMENTS_SCOPE, @@ -237,12 +253,19 @@ export default { </template> </gl-tab> </gl-tabs> + <gl-search-box-by-type + class="gl-mb-4" + :value="search" + :placeholder="$options.i18n.searchPlaceholder" + @input="setSearch" + /> <template v-if="hasEnvironments"> <environment-folder v-for="folder in folders" :key="folder.name" class="gl-mb-3" :scope="scope" + :search="search" :nested-environment="folder" /> <environment-item @@ -250,10 +273,15 @@ export default { :key="environment.name" class="gl-mb-3 gl-border-gray-100 gl-border-1 gl-border-b-solid" :environment="environment.latest" - @change="resetPolling" + @change="refetchEnvironments" /> </template> - <empty-state v-else :help-path="helpPagePath" :scope="scope" /> + <empty-state + v-else-if="!$apollo.queries.environmentApp.loading" + :help-path="helpPagePath" + :scope="scope" + :has-term="hasSearch" + /> <gl-pagination align="center" :total-items="totalItems" diff --git a/app/assets/javascripts/environments/components/environments_detail_header.vue b/app/assets/javascripts/environments/components/environments_detail_header.vue index bd67908a6b4..bb2f053b3fc 100644 --- a/app/assets/javascripts/environments/components/environments_detail_header.vue +++ b/app/assets/javascripts/environments/components/environments_detail_header.vue @@ -4,6 +4,8 @@ import csrf from '~/lib/utils/csrf'; import { __, s__ } from '~/locale'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import timeagoMixin from '~/vue_shared/mixins/timeago'; +import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; +import { isSafeURL } from '~/lib/utils/url_utility'; import DeleteEnvironmentModal from './delete_environment_modal.vue'; import StopEnvironmentModal from './stop_environment_modal.vue'; @@ -16,6 +18,7 @@ export default { TimeAgo, DeleteEnvironmentModal, StopEnvironmentModal, + ModalCopyButton, }, directives: { GlModalDirective, @@ -73,6 +76,8 @@ export default { deleteButtonText: s__('Environments|Delete'), externalButtonTitle: s__('Environments|Open live environment'), externalButtonText: __('View deployment'), + copyUrlText: __('Copy URL'), + copyUrlTitle: s__('Environments|Copy live environment URL'), cancelAutoStopButtonTitle: __('Prevent environment from auto-stopping'), }, computed: { @@ -82,6 +87,9 @@ export default { shouldShowExternalUrlButton() { return Boolean(this.environment.externalUrl); }, + isSafeUrl() { + return isSafeURL(this.environment.externalUrl); + }, shouldShowStopButton() { return this.canStopEnvironment && this.environment.isAvailable; }, @@ -123,16 +131,25 @@ export default { :href="terminalPath" icon="terminal" /> - <gl-button - v-if="shouldShowExternalUrlButton" - v-gl-tooltip.hover - data-testid="external-url-button" - :title="$options.i18n.externalButtonTitle" - :href="environment.externalUrl" - icon="external-link" - target="_blank" - >{{ $options.i18n.externalButtonText }}</gl-button - > + <template v-if="shouldShowExternalUrlButton"> + <gl-button + v-if="isSafeUrl" + v-gl-tooltip.hover + data-testid="external-url-button" + :title="$options.i18n.externalButtonTitle" + :href="environment.externalUrl" + icon="external-link" + target="_blank" + >{{ $options.i18n.externalButtonText }}</gl-button + > + <modal-copy-button + v-else + :title="$options.i18n.copyUrlTitle" + :text="environment.externalUrl" + > + {{ $options.i18n.copyUrlText }} + </modal-copy-button> + </template> <gl-button v-if="shouldShowExternalUrlButton" v-gl-tooltip.hover diff --git a/app/assets/javascripts/environments/components/new_environment.vue b/app/assets/javascripts/environments/components/new_environment.vue index 14da2668417..bb4d6ab3428 100644 --- a/app/assets/javascripts/environments/components/new_environment.vue +++ b/app/assets/javascripts/environments/components/new_environment.vue @@ -1,5 +1,5 @@ <script> -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { visitUrl } from '~/lib/utils/url_utility'; import EnvironmentForm from './environment_form.vue'; @@ -32,7 +32,7 @@ export default { .then(({ data: { path } }) => visitUrl(path)) .catch((error) => { const message = error.response.data.message[0]; - createFlash({ message }); + createAlert({ message }); this.loading = false; }); }, diff --git a/app/assets/javascripts/environments/constants.js b/app/assets/javascripts/environments/constants.js index 942491039d6..c4d02da9d21 100644 --- a/app/assets/javascripts/environments/constants.js +++ b/app/assets/javascripts/environments/constants.js @@ -1,4 +1,4 @@ -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; // These statuses are based on how the backend defines pod phases here // lib/gitlab/kubernetes/pod.rb @@ -48,3 +48,32 @@ export const ENVIRONMENT_COUNT_BY_SCOPE = { [ENVIRONMENTS_SCOPE.AVAILABLE]: 'availableCount', [ENVIRONMENTS_SCOPE.STOPPED]: 'stoppedCount', }; + +export const REVIEW_APP_MODAL_I18N = { + title: s__('ReviewApp|Enable Review App'), + intro: s__( + 'EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch.', + ), + instructions: { + title: s__('EnableReviewApp|To configure a dynamic review app, you must:'), + step1: s__( + 'EnableReviewApp|Have access to infrastructure that can host and deploy the review apps.', + ), + step2: s__('EnableReviewApp|Install and configure a runner to do the deployment.'), + step3: s__('EnableReviewApp|Add a job in your CI/CD configuration that:'), + step3a: s__('EnableReviewApp|Only runs for feature branches or merge requests.'), + step3b: s__( + 'EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:', + ), + step4: s__('EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps.'), + }, + staticSitePopover: { + title: s__('EnableReviewApp|Using a static site?'), + body: s__( + 'EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing.', + ), + }, + learnMore: __('Learn more'), + viewMoreExampleProjects: s__('EnableReviewApp|View more example projects'), + copyToClipboardText: s__('EnableReviewApp|Copy snippet'), +}; diff --git a/app/assets/javascripts/environments/graphql/queries/environment_app.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_app.query.graphql index c3ab9cf7fca..1a572208a1c 100644 --- a/app/assets/javascripts/environments/graphql/queries/environment_app.query.graphql +++ b/app/assets/javascripts/environments/graphql/queries/environment_app.query.graphql @@ -1,5 +1,5 @@ -query getEnvironmentApp($page: Int, $scope: String) { - environmentApp(page: $page, scope: $scope) @client { +query getEnvironmentApp($page: Int, $scope: String, $search: String) { + environmentApp(page: $page, scope: $scope, search: $search) @client { availableCount stoppedCount environments diff --git a/app/assets/javascripts/environments/graphql/queries/folder.query.graphql b/app/assets/javascripts/environments/graphql/queries/folder.query.graphql index e8c145ee916..c662acb8f93 100644 --- a/app/assets/javascripts/environments/graphql/queries/folder.query.graphql +++ b/app/assets/javascripts/environments/graphql/queries/folder.query.graphql @@ -1,5 +1,5 @@ -query getEnvironmentFolder($environment: NestedLocalEnvironment, $scope: String) { - folder(environment: $environment, scope: $scope) @client { +query getEnvironmentFolder($environment: NestedLocalEnvironment, $scope: String, $search: String) { + folder(environment: $environment, scope: $scope, search: $search) @client { availableCount environments stoppedCount diff --git a/app/assets/javascripts/environments/graphql/resolvers.js b/app/assets/javascripts/environments/graphql/resolvers.js index 722bb78bcf9..afd56d0cf0d 100644 --- a/app/assets/javascripts/environments/graphql/resolvers.js +++ b/app/assets/javascripts/environments/graphql/resolvers.js @@ -30,8 +30,8 @@ const mapEnvironment = (env) => ({ export const resolvers = (endpoint) => ({ Query: { - environmentApp(_context, { page, scope }, { cache }) { - return axios.get(endpoint, { params: { nested: true, page, scope } }).then((res) => { + environmentApp(_context, { page, scope, search }, { cache }) { + return axios.get(endpoint, { params: { nested: true, page, scope, search } }).then((res) => { const headers = normalizeHeaders(res.headers); const interval = headers['POLL-INTERVAL']; const pageInfo = { ...parseIntPagination(headers), __typename: 'LocalPageInfo' }; @@ -59,8 +59,8 @@ export const resolvers = (endpoint) => ({ }; }); }, - folder(_, { environment: { folderPath }, scope }) { - return axios.get(folderPath, { params: { scope, per_page: 3 } }).then((res) => ({ + folder(_, { environment: { folderPath }, scope, search }) { + return axios.get(folderPath, { params: { scope, search, per_page: 3 } }).then((res) => ({ availableCount: res.data.available_count, environments: res.data.environments.map(mapEnvironment), stoppedCount: res.data.stopped_count, diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js index 8957a3074ed..5e936ad8c96 100644 --- a/app/assets/javascripts/environments/mixins/environments_mixin.js +++ b/app/assets/javascripts/environments/mixins/environments_mixin.js @@ -3,7 +3,7 @@ */ import { isEqual, isFunction, omitBy } from 'lodash'; import Visibility from 'visibilityjs'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import Poll from '~/lib/utils/poll'; import { getParameterByName } from '~/lib/utils/url_utility'; import { s__, __ } from '~/locale'; @@ -94,7 +94,7 @@ export default { errorCallback() { this.isLoading = false; - createFlash({ + createAlert({ message: s__('Environments|An error occurred while fetching the environments.'), }); }, @@ -123,7 +123,7 @@ export default { }) .catch((err) => { this.isLoading = false; - createFlash({ + createAlert({ message: isFunction(errorMessage) ? errorMessage(err.response.data) : errorMessage, }); }); @@ -179,7 +179,7 @@ export default { window.location.href = url.join('/'); }) .catch(() => { - createFlash({ + createAlert({ message: errorMessage, }); }); |