Commit 6f0c22cc authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents 1f1caf53 8c89668d
...@@ -30,6 +30,9 @@ export default { ...@@ -30,6 +30,9 @@ export default {
showLoading() { showLoading() {
return !this.currentTree || this.currentTree.loading; return !this.currentTree || this.currentTree.loading;
}, },
actualTreeList() {
return this.currentTree.tree.filter(entry => !entry.moved);
},
}, },
mounted() { mounted() {
this.updateViewer(this.viewerType); this.updateViewer(this.viewerType);
...@@ -54,9 +57,9 @@ export default { ...@@ -54,9 +57,9 @@ export default {
<slot name="header"></slot> <slot name="header"></slot>
</header> </header>
<div class="ide-tree-body h-100"> <div class="ide-tree-body h-100">
<template v-if="currentTree.tree.length"> <template v-if="actualTreeList.length">
<file-row <file-row
v-for="file in currentTree.tree" v-for="file in actualTreeList"
:key="file.key" :key="file.key"
:file="file" :file="file"
:level="0" :level="0"
......
...@@ -8,6 +8,7 @@ import * as types from './mutation_types'; ...@@ -8,6 +8,7 @@ import * as types from './mutation_types';
import { decorateFiles } from '../lib/files'; import { decorateFiles } from '../lib/files';
import { stageKeys } from '../constants'; import { stageKeys } from '../constants';
import service from '../services'; import service from '../services';
import router from '../ide_router';
export const redirectToUrl = (self, url) => visitUrl(url); export const redirectToUrl = (self, url) => visitUrl(url);
...@@ -234,10 +235,15 @@ export const renameEntry = ( ...@@ -234,10 +235,15 @@ export const renameEntry = (
parentPath: newParentPath, parentPath: newParentPath,
}); });
}); });
} } else {
const newPath = parentPath ? `${parentPath}/${name}` : name;
const newEntry = state.entries[newPath];
commit(types.TOGGLE_FILE_CHANGED, { file: newEntry, changed: true });
if (!entryPath && !entry.tempFile) { if (entry.opened) {
dispatch('deleteEntry', path); router.push(`/project${newEntry.url}`);
commit(types.TOGGLE_FILE_OPEN, entry.path);
}
} }
dispatch('triggerFilesChange'); dispatch('triggerFilesChange');
......
...@@ -73,7 +73,9 @@ export const getFileData = ( ...@@ -73,7 +73,9 @@ export const getFileData = (
.getFileData(joinPaths(gon.relative_url_root || '', url.replace('/-/', '/'))) .getFileData(joinPaths(gon.relative_url_root || '', url.replace('/-/', '/')))
.then(({ data, headers }) => { .then(({ data, headers }) => {
const normalizedHeaders = normalizeHeaders(headers); const normalizedHeaders = normalizeHeaders(headers);
setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE'])); let title = normalizedHeaders['PAGE-TITLE'];
title = file.prevPath ? title.replace(file.prevPath, file.path) : title;
setPageTitle(decodeURI(title));
if (data) commit(types.SET_FILE_DATA, { data, file }); if (data) commit(types.SET_FILE_DATA, { data, file });
if (openFile) commit(types.TOGGLE_FILE_OPEN, path); if (openFile) commit(types.TOGGLE_FILE_OPEN, path);
......
...@@ -216,15 +216,16 @@ export default { ...@@ -216,15 +216,16 @@ export default {
Vue.set(state.entries, newPath, { Vue.set(state.entries, newPath, {
...oldEntry, ...oldEntry,
id: newPath, id: newPath,
key: `${newPath}-${oldEntry.type}-${oldEntry.id}`, key: `${newPath}-${oldEntry.type}-${oldEntry.path}`,
path: newPath, path: newPath,
name: entryPath ? oldEntry.name : name, name: entryPath ? oldEntry.name : name,
tempFile: true, tempFile: true,
prevPath: oldEntry.tempFile ? null : oldEntry.path, prevPath: oldEntry.tempFile ? null : oldEntry.path,
url: oldEntry.url.replace(new RegExp(`${oldEntry.path}/?$`), newPath), url: oldEntry.url.replace(new RegExp(`${oldEntry.path}/?$`), newPath),
tree: [], tree: [],
parentPath,
raw: '', raw: '',
opened: false,
parentPath,
}); });
oldEntry.moved = true; oldEntry.moved = true;
...@@ -241,10 +242,6 @@ export default { ...@@ -241,10 +242,6 @@ export default {
state.changedFiles = state.changedFiles.concat(newEntry); state.changedFiles = state.changedFiles.concat(newEntry);
} }
if (state.entries[newPath].opened) {
state.openFiles.push(state.entries[newPath]);
}
if (oldEntry.tempFile) { if (oldEntry.tempFile) {
const filterMethod = f => f.path !== oldEntry.path; const filterMethod = f => f.path !== oldEntry.path;
......
...@@ -147,9 +147,9 @@ export const createCommitPayload = ({ ...@@ -147,9 +147,9 @@ export const createCommitPayload = ({
commit_message: state.commitMessage || getters.preBuiltCommitMessage, commit_message: state.commitMessage || getters.preBuiltCommitMessage,
actions: getCommitFiles(rootState.stagedFiles).map(f => ({ actions: getCommitFiles(rootState.stagedFiles).map(f => ({
action: commitActionForFile(f), action: commitActionForFile(f),
file_path: f.path, file_path: f.moved ? f.movedPath : f.path,
previous_path: f.prevPath === '' ? undefined : f.prevPath, previous_path: f.prevPath === '' ? undefined : f.prevPath,
content: f.content || undefined, content: f.prevPath ? null : f.content || undefined,
encoding: f.base64 ? 'base64' : 'text', encoding: f.base64 ? 'base64' : 'text',
last_commit_id: newBranch || f.deleted || f.prevPath ? undefined : f.lastCommitSha, last_commit_id: newBranch || f.deleted || f.prevPath ? undefined : f.lastCommitSha,
})), })),
......
...@@ -3,7 +3,7 @@ import { commitItemIconMap } from './constants'; ...@@ -3,7 +3,7 @@ import { commitItemIconMap } from './constants';
export const getCommitIconMap = file => { export const getCommitIconMap = file => {
if (file.deleted) { if (file.deleted) {
return commitItemIconMap.deleted; return commitItemIconMap.deleted;
} else if (file.tempFile) { } else if (file.tempFile && !file.prevPath) {
return commitItemIconMap.addition; return commitItemIconMap.addition;
} }
......
...@@ -234,7 +234,7 @@ export default { ...@@ -234,7 +234,7 @@ export default {
</script> </script>
<template> <template>
<div v-if="!showEmptyState" class="prometheus-graphs"> <div class="prometheus-graphs">
<div class="gl-p-3 border-bottom bg-gray-light d-flex justify-content-between"> <div class="gl-p-3 border-bottom bg-gray-light d-flex justify-content-between">
<div <div
v-if="environmentsEndpoint" v-if="environmentsEndpoint"
...@@ -253,11 +253,12 @@ export default { ...@@ -253,11 +253,12 @@ export default {
:key="environment.id" :key="environment.id"
:active="environment.name === currentEnvironmentName" :active="environment.name === currentEnvironmentName"
active-class="is-active" active-class="is-active"
:href="environment.metrics_path"
>{{ environment.name }}</gl-dropdown-item >{{ environment.name }}</gl-dropdown-item
> >
</gl-dropdown> </gl-dropdown>
</div> </div>
<div class="d-flex align-items-center prepend-left-8"> <div v-if="!showEmptyState" class="d-flex align-items-center prepend-left-8">
<strong>{{ s__('Metrics|Show last') }}</strong> <strong>{{ s__('Metrics|Show last') }}</strong>
<gl-dropdown <gl-dropdown
class="prepend-left-10 js-time-window-dropdown" class="prepend-left-10 js-time-window-dropdown"
...@@ -276,7 +277,7 @@ export default { ...@@ -276,7 +277,7 @@ export default {
</div> </div>
</div> </div>
<div class="d-flex"> <div class="d-flex">
<div v-if="isEE && canAddMetrics"> <div v-if="isEE && canAddMetrics && !showEmptyState">
<gl-button <gl-button
v-gl-modal-directive="$options.addMetric.modalId" v-gl-modal-directive="$options.addMetric.modalId"
class="js-add-metric-button text-success border-success" class="js-add-metric-button text-success border-success"
...@@ -317,40 +318,42 @@ export default { ...@@ -317,40 +318,42 @@ export default {
</gl-button> </gl-button>
</div> </div>
</div> </div>
<graph-group <div v-if="!showEmptyState">
v-for="(groupData, index) in groupsWithData" <graph-group
:key="index" v-for="(groupData, index) in groupsWithData"
:name="groupData.group" :key="index"
:show-panels="showPanels" :name="groupData.group"
> :show-panels="showPanels"
<monitor-area-chart
v-for="(graphData, graphIndex) in chartsWithData(groupData.metrics)"
:key="graphIndex"
:graph-data="graphData"
:deployment-data="deploymentData"
:thresholds="getGraphAlertValues(graphData.queries)"
:container-width="elWidth"
group-id="monitor-area-chart"
> >
<alert-widget <monitor-area-chart
v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData" v-for="(graphData, graphIndex) in chartsWithData(groupData.metrics)"
:alerts-endpoint="alertsEndpoint" :key="graphIndex"
:relevant-queries="graphData.queries" :graph-data="graphData"
:alerts-to-manage="getGraphAlerts(graphData.queries)" :deployment-data="deploymentData"
@setAlerts="setAlerts" :thresholds="getGraphAlertValues(graphData.queries)"
/> :container-width="elWidth"
</monitor-area-chart> group-id="monitor-area-chart"
</graph-group> >
<alert-widget
v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData"
:alerts-endpoint="alertsEndpoint"
:relevant-queries="graphData.queries"
:alerts-to-manage="getGraphAlerts(graphData.queries)"
@setAlerts="setAlerts"
/>
</monitor-area-chart>
</graph-group>
</div>
<empty-state
v-else
:selected-state="emptyState"
:documentation-path="documentationPath"
:settings-path="settingsPath"
:clusters-path="clustersPath"
:empty-getting-started-svg-path="emptyGettingStartedSvgPath"
:empty-loading-svg-path="emptyLoadingSvgPath"
:empty-no-data-svg-path="emptyNoDataSvgPath"
:empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
/>
</div> </div>
<empty-state
v-else
:selected-state="emptyState"
:documentation-path="documentationPath"
:settings-path="settingsPath"
:clusters-path="clustersPath"
:empty-getting-started-svg-path="emptyGettingStartedSvgPath"
:empty-loading-svg-path="emptyLoadingSvgPath"
:empty-no-data-svg-path="emptyNoDataSvgPath"
:empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
/>
</template> </template>
---
title: Re-name files in Web IDE in a more natural way
merge_request: 29948
author:
type: changed
---
title: Fix broken environment selector and always display it on monitoring dashboard
merge_request: 29705
author:
type: fixed
--- ---
last_updated: 2019-06-04 last_updated: 2019-06-25
type: concepts, reference, howto type: concepts, reference, howto
--- ---
...@@ -138,9 +138,9 @@ verify your domain's ownership with a TXT record: ...@@ -138,9 +138,9 @@ verify your domain's ownership with a TXT record:
> - **Do not** add any special chars after the default Pages > - **Do not** add any special chars after the default Pages
domain. E.g., **do not** point your `subdomain.domain.com` to domain. E.g., **do not** point your `subdomain.domain.com` to
`namespace.gitlab.io.` or `namespace.gitlab.io/`. `namespace.gitlab.io.` or `namespace.gitlab.io/`.
> - GitLab Pages IP on GitLab.com [was changed](https://about.gitlab.com/2017/03/06/we-are-changing-the-ip-of-gitlab-pages-on-gitlab-com/) in 2017 > - GitLab Pages IP on GitLab.com [was changed](https://about.gitlab.com/2017/03/06/we-are-changing-the-ip-of-gitlab-pages-on-gitlab-com/) in 2017.
> - GitLab Pages IP on GitLab.com [has been changed](https://about.gitlab.com/2018/07/19/gcp-move-update/#gitlab-pages-and-custom-domains) > - GitLab Pages IP on GitLab.com [has been changed](https://about.gitlab.com/2018/07/19/gcp-move-update/#gitlab-pages-and-custom-domains)
from `52.167.214.135` to `35.185.44.232` in 2018 from `52.167.214.135` to `35.185.44.232` in 2018.
### Add your custom domain to GitLab Pages settings ### Add your custom domain to GitLab Pages settings
...@@ -199,7 +199,7 @@ Certificates are NOT required to add to your custom ...@@ -199,7 +199,7 @@ Certificates are NOT required to add to your custom
highly recommendable. highly recommendable.
Let's start with an introduction to the importance of HTTPS. Let's start with an introduction to the importance of HTTPS.
Alternatively, jump ahead to [adding certificates to your project](#adding-certificates-to-your-project). Alternatively, jump ahead to [adding certificates to your project](#adding-certificates-to-pages).
### Why should I care about HTTPS? ### Why should I care about HTTPS?
...@@ -255,12 +255,12 @@ which also offers a [free CDN service](https://blog.cloudflare.com/cloudflares-f ...@@ -255,12 +255,12 @@ which also offers a [free CDN service](https://blog.cloudflare.com/cloudflares-f
Their certs are valid up to 15 years. See the tutorial on Their certs are valid up to 15 years. See the tutorial on
[how to add a CloudFlare Certificate to your GitLab Pages website](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/). [how to add a CloudFlare Certificate to your GitLab Pages website](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/).
### Adding certificates to your project ### Adding certificates to Pages
Regardless the CA you choose, the steps to add your certificate to Regardless the CA you choose, the steps to add your certificate to
your Pages project are the same. your Pages project are the same.
### What do you need #### Requirements
1. A PEM certificate 1. A PEM certificate
1. An intermediate certificate 1. An intermediate certificate
...@@ -270,7 +270,7 @@ your Pages project are the same. ...@@ -270,7 +270,7 @@ your Pages project are the same.
These fields are found under your **Project**'s **Settings** > **Pages** > **New Domain**. These fields are found under your **Project**'s **Settings** > **Pages** > **New Domain**.
### What's what? #### Certificate types
- A PEM certificate is the certificate generated by the CA, - A PEM certificate is the certificate generated by the CA,
which needs to be added to the field **Certificate (PEM)**. which needs to be added to the field **Certificate (PEM)**.
...@@ -283,21 +283,32 @@ These fields are found under your **Project**'s **Settings** > **Pages** > **New ...@@ -283,21 +283,32 @@ These fields are found under your **Project**'s **Settings** > **Pages** > **New
- A private key is an encrypted key which validates - A private key is an encrypted key which validates
your PEM against your domain. your PEM against your domain.
### Now what? #### Add the certificate to your project
Now that you hopefully understand why you need all Once you've met the requirements:
of this, it's simple:
- Your PEM certificate needs to be added to the first field - Your PEM certificate needs to be added to the first field.
- If your certificate is missing its intermediate, copy - If your certificate is missing its intermediate, copy
and paste the root certificate (usually available from your CA website) and paste the root certificate (usually available from your CA website)
and paste it in the [same field as your PEM certificate](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/), and paste it in the [same field as your PEM certificate](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/),
just jumping a line between them. just jumping a line between them.
- Copy your private key and paste it in the last field - Copy your private key and paste it in the last field.
>**Note:** NOTE: **Note:**
**Do not** open certificates or encryption keys in **Do not** open certificates or encryption keys in
regular text editors. Always use code editors (such as regular text editors. Always use code editors (such as
Sublime Text, Atom, Dreamweaver, Brackets, etc). Sublime Text, Atom, Dreamweaver, Brackets, etc).
_Read on about [Creating and Tweaking GitLab CI/CD for GitLab Pages](getting_started_part_four.md)_ ## Force HTTPS for GitLab Pages websites
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/28857) in GitLab 10.7.
To make your website's visitors even more secure, you can choose to
force HTTPS for GitLab Pages. By doing so, all attempts to visit your
website via HTTP will be automatically redirected to HTTPS via 301.
It works with both GitLab's default domain and with your custom
domain (as long as you've set a valid certificate for it).
To enable this setting, navigate to your project's **Settings > Pages**
and tick the checkbox **Force HTTPS (requires valid certificates)**.
...@@ -102,6 +102,10 @@ describe 'Group issues page' do ...@@ -102,6 +102,10 @@ describe 'Group issues page' do
end end
context 'manual ordering' do context 'manual ordering' do
before do
stub_feature_flags(manual_sorting: true)
end
let!(:issue1) { create(:issue, project: project, title: 'Issue #1') } let!(:issue1) { create(:issue, project: project, title: 'Issue #1') }
let!(:issue2) { create(:issue, project: project, title: 'Issue #2') } let!(:issue2) { create(:issue, project: project, title: 'Issue #2') }
let!(:issue3) { create(:issue, project: project, title: 'Issue #3') } let!(:issue3) { create(:issue, project: project, title: 'Issue #3') }
...@@ -138,10 +142,12 @@ describe 'Group issues page' do ...@@ -138,10 +142,12 @@ describe 'Group issues page' do
to_index: 2, to_index: 2,
list_to_index: 0) list_to_index: 0)
wait_for_requests
page.within('.manual-ordering') do page.within('.manual-ordering') do
expect(find('.issue:nth-child(1) .title')).to have_content('Issue #2') expect(find('.issue:nth-child(1) .title')).to have_content('Issue #2')
expect(find('.issue:nth-child(2) .title')).to have_content('Issue #1') expect(find('.issue:nth-child(2) .title')).to have_content('Issue #3')
expect(find('.issue:nth-child(3) .title')).to have_content('Issue #3') expect(find('.issue:nth-child(3) .title')).to have_content('Issue #1')
end end
end end
end end
......
...@@ -9,11 +9,11 @@ describe 'Environment > Metrics' do ...@@ -9,11 +9,11 @@ describe 'Environment > Metrics' do
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
let(:current_time) { Time.now.utc } let(:current_time) { Time.now.utc }
let!(:staging) { create(:environment, name: 'staging', project: project) }
before do before do
project.add_developer(user) project.add_developer(user)
create(:deployment, environment: environment, deployable: build) stub_any_prometheus_request
stub_all_prometheus_requests(environment.slug)
sign_in(user) sign_in(user)
visit_environment(environment) visit_environment(environment)
...@@ -23,15 +23,50 @@ describe 'Environment > Metrics' do ...@@ -23,15 +23,50 @@ describe 'Environment > Metrics' do
Timecop.freeze(current_time) { example.run } Timecop.freeze(current_time) { example.run }
end end
shared_examples 'has environment selector' do
it 'has a working environment selector', :js do
click_link('See metrics')
expect(page).to have_metrics_path(environment)
expect(page).to have_css('div.js-environments-dropdown')
within('div.js-environments-dropdown') do
# Click on the dropdown
click_on(environment.name)
# Select the staging environment
click_on(staging.name)
end
expect(page).to have_metrics_path(staging)
wait_for_requests
end
end
context 'without deployments' do
it_behaves_like 'has environment selector'
end
context 'with deployments and related deployable present' do context 'with deployments and related deployable present' do
before do
create(:deployment, environment: environment, deployable: build)
end
it 'shows metrics' do it 'shows metrics' do
click_link('See metrics') click_link('See metrics')
expect(page).to have_css('div#prometheus-graphs') expect(page).to have_css('div#prometheus-graphs')
end end
it_behaves_like 'has environment selector'
end end
def visit_environment(environment) def visit_environment(environment)
visit project_environment_path(environment.project, environment) visit project_environment_path(environment.project, environment)
end end
def have_metrics_path(environment)
have_current_path(metrics_project_environment_path(project, id: environment.id))
end
end end
import { commitItemIconMap } from '~/ide/constants';
import { getCommitIconMap } from '~/ide/utils';
import { decorateData } from '~/ide/stores/utils';
describe('WebIDE utils', () => {
const createFile = (name = 'name', id = name, type = '', parent = null) =>
decorateData({
id,
type,
icon: 'icon',
url: 'url',
name,
path: parent ? `${parent.path}/${name}` : name,
parentPath: parent ? parent.path : '',
lastCommit: {},
});
describe('getCommitIconMap', () => {
let entry;
beforeEach(() => {
entry = createFile('Entry item');
});
it('renders "deleted" icon for deleted entries', () => {
entry.deleted = true;
expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.deleted);
});
it('renders "addition" icon for temp entries', () => {
entry.tempFile = true;
expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.addition);
});
it('renders "modified" icon for newly-renamed entries', () => {
entry.prevPath = 'foo/bar';
entry.tempFile = false;
expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.modified);
});
it('renders "modified" icon even for temp entries if they are newly-renamed', () => {
entry.prevPath = 'foo/bar';
entry.tempFile = true;
expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.modified);
});
});
});
...@@ -58,6 +58,20 @@ describe('IDE tree list', () => { ...@@ -58,6 +58,20 @@ describe('IDE tree list', () => {
it('renders list of files', () => { it('renders list of files', () => {
expect(vm.$el.textContent).toContain('fileName'); expect(vm.$el.textContent).toContain('fileName');
}); });
it('does not render moved entries', done => {
const tree = [file('moved entry'), file('normal entry')];
tree[0].moved = true;
store.state.trees['abcproject/master'].tree = tree;
const container = vm.$el.querySelector('.ide-tree-body');
vm.$nextTick(() => {
expect(container.children.length).toBe(1);
expect(vm.$el.textContent).not.toContain('moved entry');
expect(vm.$el.textContent).toContain('normal entry');
done();
});
});
}); });
describe('empty-branch state', () => { describe('empty-branch state', () => {
......
...@@ -275,6 +275,43 @@ describe('IDE store file actions', () => { ...@@ -275,6 +275,43 @@ describe('IDE store file actions', () => {
}); });
}); });
describe('Re-named success', () => {
beforeEach(() => {
localFile = file(`newCreate-${Math.random()}`);
localFile.url = `project/getFileDataURL`;
localFile.prevPath = 'old-dull-file';
localFile.path = 'new-shiny-file';
store.state.entries[localFile.path] = localFile;
mock.onGet(`${RELATIVE_URL_ROOT}/project/getFileDataURL`).replyOnce(
200,
{
blame_path: 'blame_path',
commits_path: 'commits_path',
permalink: 'permalink',
raw_path: 'raw_path',
binary: false,
html: '123',
render_error: '',
},
{
'page-title': 'testing old-dull-file',
},
);
});
it('sets document title considering `prevPath` on a file', done => {
store
.dispatch('getFileData', { path: localFile.path })
.then(() => {
expect(document.title).toBe('testing new-shiny-file');
done();
})
.catch(done.fail);
});
});
describe('error', () => { describe('error', () => {
beforeEach(() => { beforeEach(() => {
mock.onGet(`project/getFileDataURL`).networkError(); mock.onGet(`project/getFileDataURL`).networkError();
......
...@@ -536,8 +536,15 @@ describe('Multi-file store actions', () => { ...@@ -536,8 +536,15 @@ describe('Multi-file store actions', () => {
type: types.RENAME_ENTRY, type: types.RENAME_ENTRY,
payload: { path: 'test', name: 'new-name', entryPath: null, parentPath: 'parent-path' }, payload: { path: 'test', name: 'new-name', entryPath: null, parentPath: 'parent-path' },
}, },
{
type: types.TOGGLE_FILE_CHANGED,
payload: {
file: store.state.entries['parent-path/new-name'],
changed: true,
},
},
], ],
[{ type: 'deleteEntry', payload: 'test' }, { type: 'triggerFilesChange' }], [{ type: 'triggerFilesChange' }],
done, done,
); );
}); });
...@@ -584,7 +591,6 @@ describe('Multi-file store actions', () => { ...@@ -584,7 +591,6 @@ describe('Multi-file store actions', () => {
parentPath: 'parent-path/new-name', parentPath: 'parent-path/new-name',
}, },
}, },
{ type: 'deleteEntry', payload: 'test' },
{ type: 'triggerFilesChange' }, { type: 'triggerFilesChange' },
], ],
done, done,
......
...@@ -309,7 +309,7 @@ describe('Multi-file store mutations', () => { ...@@ -309,7 +309,7 @@ describe('Multi-file store mutations', () => {
...localState.entries.oldPath, ...localState.entries.oldPath,
id: 'newPath', id: 'newPath',
name: 'newPath', name: 'newPath',
key: 'newPath-blob-name', key: 'newPath-blob-oldPath',
path: 'newPath', path: 'newPath',
tempFile: true, tempFile: true,
prevPath: 'oldPath', prevPath: 'oldPath',
...@@ -318,6 +318,7 @@ describe('Multi-file store mutations', () => { ...@@ -318,6 +318,7 @@ describe('Multi-file store mutations', () => {
url: `${gl.TEST_HOST}/newPath`, url: `${gl.TEST_HOST}/newPath`,
moved: jasmine.anything(), moved: jasmine.anything(),
movedPath: jasmine.anything(), movedPath: jasmine.anything(),
opened: false,
}); });
}); });
...@@ -349,13 +350,5 @@ describe('Multi-file store mutations', () => { ...@@ -349,13 +350,5 @@ describe('Multi-file store mutations', () => {
expect(localState.entries.parentPath.tree.length).toBe(1); expect(localState.entries.parentPath.tree.length).toBe(1);
}); });
it('adds to openFiles if previously opened', () => {
localState.entries.oldPath.opened = true;
mutations.RENAME_ENTRY(localState, { path: 'oldPath', name: 'newPath' });
expect(localState.openFiles).toEqual([localState.entries.newPath]);
});
}); });
}); });
...@@ -62,16 +62,34 @@ describe('Dashboard', () => { ...@@ -62,16 +62,34 @@ describe('Dashboard', () => {
}); });
describe('no metrics are available yet', () => { describe('no metrics are available yet', () => {
it('shows a getting started empty state when no metrics are present', () => { beforeEach(() => {
component = new DashboardComponent({ component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'), el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData }, propsData: { ...propsData },
store, store,
}); });
});
it('shows a getting started empty state when no metrics are present', () => {
expect(component.$el.querySelector('.prometheus-graphs')).toBe(null); expect(component.$el.querySelector('.prometheus-graphs')).toBe(null);
expect(component.emptyState).toEqual('gettingStarted'); expect(component.emptyState).toEqual('gettingStarted');
}); });
it('shows the environment selector', () => {
expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy();
});
});
describe('no data found', () => {
it('shows the environment selector dropdown', () => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData, showEmptyState: true },
store,
});
expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy();
});
}); });
describe('requests information to the server', () => { describe('requests information to the server', () => {
...@@ -150,14 +168,24 @@ describe('Dashboard', () => { ...@@ -150,14 +168,24 @@ describe('Dashboard', () => {
singleGroupResponse, singleGroupResponse,
); );
setTimeout(() => { Vue.nextTick()
const dropdownMenuEnvironments = component.$el.querySelectorAll( .then(() => {
'.js-environments-dropdown .dropdown-item', const dropdownMenuEnvironments = component.$el.querySelectorAll(
); '.js-environments-dropdown .dropdown-item',
);
expect(dropdownMenuEnvironments.length).toEqual(component.environments.length); expect(component.environments.length).toEqual(environmentData.length);
done(); expect(dropdownMenuEnvironments.length).toEqual(component.environments.length);
});
Array.from(dropdownMenuEnvironments).forEach((value, index) => {
if (environmentData[index].metrics_path) {
expect(value).toHaveAttr('href', environmentData[index].metrics_path);
}
});
done();
})
.catch(done.fail);
}); });
it('hides the environments dropdown list when there is no environments', done => { it('hides the environments dropdown list when there is no environments', done => {
...@@ -212,7 +240,7 @@ describe('Dashboard', () => { ...@@ -212,7 +240,7 @@ describe('Dashboard', () => {
Vue.nextTick() Vue.nextTick()
.then(() => { .then(() => {
const dropdownItems = component.$el.querySelectorAll( const dropdownItems = component.$el.querySelectorAll(
'.js-environments-dropdown .dropdown-item[active="true"]', '.js-environments-dropdown .dropdown-item.is-active',
); );
expect(dropdownItems.length).toEqual(1); expect(dropdownItems.length).toEqual(1);
......
...@@ -70,6 +70,10 @@ module PrometheusHelpers ...@@ -70,6 +70,10 @@ module PrometheusHelpers
WebMock.stub_request(:get, url).to_raise(exception_type) WebMock.stub_request(:get, url).to_raise(exception_type)
end end
def stub_any_prometheus_request
WebMock.stub_request(:any, /prometheus.example.com/)
end
def stub_all_prometheus_requests(environment_slug, body: nil, status: 200) def stub_all_prometheus_requests(environment_slug, body: nil, status: 200)
stub_prometheus_request( stub_prometheus_request(
prometheus_query_with_time_url(prometheus_memory_query(environment_slug), Time.now.utc), prometheus_query_with_time_url(prometheus_memory_query(environment_slug), Time.now.utc),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment