Commit 0a082b3e authored by Phil Hughes's avatar Phil Hughes

Merge branch 'extract-components-from-operations-dashboard' into 'master'

Extract Components to Reuse in Other Dashboards

See merge request gitlab-org/gitlab-ee!10348
parents 3fb07dcd 1ef003e3
<script>
import { mapState, mapActions } from 'vuex';
import { GlLoadingIcon, GlDashboardSkeleton } from '@gitlab/ui';
import ProjectSearch from 'ee/vue_shared/dashboards/components/project_search.vue';
import DashboardProject from './project.vue';
import ProjectSearch from './project_search.vue';
export default {
components: {
......
......@@ -7,10 +7,11 @@ import Icon from '~/vue_shared/components/icon.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import Commit from '~/vue_shared/components/commit.vue';
import Alerts from 'ee/vue_shared/dashboards/components/alerts.vue';
import TimeAgo from 'ee/vue_shared/dashboards/components/time_ago.vue';
import ProjectPipeline from 'ee/vue_shared/dashboards/components/project_pipeline.vue';
import { STATUS_FAILED, STATUS_RUNNING } from 'ee/vue_shared/dashboards/constants';
import ProjectHeader from './project_header.vue';
import Alerts from './alerts.vue';
import ProjectPipeline from './project_pipeline.vue';
import { STATUS_FAILED, STATUS_RUNNING } from '../../constants';
export default {
components: {
......@@ -19,6 +20,7 @@ export default {
Commit,
Alerts,
ProjectPipeline,
TimeAgo,
GlTooltip,
Icon,
},
......@@ -128,20 +130,11 @@ export default {
</div>
<div class="col-sm-5 pl-0 text-right align-self-center d-none d-sm-block">
<div v-if="shouldShowTimeAgo" class="text-secondary">
<icon
name="clock"
class="dashboard-card-time-ago-icon align-text-bottom js-dashboard-project-clock-icon"
/>
<time ref="timeAgo" class="js-dashboard-project-time-ago">
{{ timeFormated(finishedTime) }}
</time>
<gl-tooltip :target="() => $refs.timeAgo">
<div class="bold">{{ $options.tooltips.timeAgo }}</div>
<div>{{ finishedTimeTitle }}</div>
</gl-tooltip>
</div>
<time-ago
v-if="shouldShowTimeAgo"
:time="finishedTime"
:tooltip-text="$options.tooltips.timeAgo"
/>
<alerts :count="project.alert_count" />
</div>
......
<script>
import { __, n__, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
Icon,
},
props: {
count: {
type: Number,
required: false,
default: 0,
},
},
computed: {
alertClasses() {
return {
'text-tertiary': this.count <= 0,
'text-warning': this.count > 0,
};
},
alertCount() {
return sprintf(__('%{count} %{alerts}'), {
count: this.count,
alerts: this.pluralizedAlerts,
});
},
pluralizedAlerts() {
return n__('Alert', 'Alerts', this.count);
},
},
};
</script>
<template>
<div class="dashboard-card-alert row">
<div class="col-12">
<icon
:class="alertClasses"
class="align-text-bottom js-dashboard-alerts-icon"
name="warning"
/>
<span class="js-alert-count text-secondary prepend-left-4"> {{ alertCount }} </span>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import inputFocus from '../../mixins';
import inputFocus from '../mixins';
export default {
components: {
......
......@@ -4,7 +4,7 @@ import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
import { GlLink, GlTooltip } from '@gitlab/ui';
import { STATUS_FAILED } from '../../constants';
import { STATUS_FAILED } from '../constants';
export default {
components: {
......
......@@ -5,8 +5,8 @@ import { __, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import ProjectAvatar from '~/vue_shared/components/project_avatar/default.vue';
import { GlLoadingIcon } from '@gitlab/ui';
import TokenizedInput from '../tokenized_input/input.vue';
import inputFocus from '../../mixins';
import TokenizedInput from './input.vue';
import inputFocus from '../mixins';
const inputSearchDelay = 300;
......
<script>
import { GlTooltip } from '@gitlab/ui';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
GlTooltip,
Icon,
},
mixins: [timeagoMixin],
props: {
time: {
type: String,
required: true,
},
tooltipText: {
type: String,
required: true,
},
},
computed: {
timeTitle() {
return this.tooltipTitle(this.time);
},
formattedTime() {
return this.timeFormated(this.time);
},
},
};
</script>
<template>
<div class="text-secondary">
<icon
name="clock"
class="dashboard-card-time-ago-icon align-text-bottom js-dashboard-project-clock-icon"
/>
<time ref="timeAgo" class="js-dashboard-project-time-ago">
{{ formattedTime }}
</time>
<gl-tooltip :target="() => $refs.timeAgo">
<div class="bold">{{ tooltipText }}</div>
<div>{{ timeTitle }}</div>
</gl-tooltip>
</div>
</template>
export const STATUS_FAILED = 'failed';
export const STATUS_RUNNING = 'running';
export default {
data() {
return {
isInputFocused: false,
};
},
methods: {
onFocus() {
this.isInputFocused = true;
this.$emit('focus');
},
onBlur() {
this.isInputFocused = false;
this.$emit('blur');
},
},
};
import Vue from 'vue';
import store from 'ee/operations/store/index';
import Dashboard from 'ee/operations/components/dashboard/dashboard.vue';
import ProjectSearch from 'ee/operations/components/dashboard/project_search.vue';
import ProjectSearch from 'ee/vue_shared/dashboards/components/project_search.vue';
import DashboardProject from 'ee/operations/components/dashboard/project.vue';
import { getChildInstances, clearState } from '../../helpers';
import { mockProjectData, mockText } from '../../mock_data';
......
import Vue from 'vue';
import store from 'ee/operations/store/index';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import ProjectSearch from 'ee/operations/components/dashboard/project_search.vue';
import TokenizedInput from 'ee/operations/components/tokenized_input/input.vue';
import ProjectSearch from 'ee/vue_shared/dashboards/components/project_search.vue';
import TokenizedInput from 'ee/vue_shared/dashboards/components/input.vue';
import { mockText, mockProjectData } from '../../mock_data';
import { getChildInstances, mouseEvent, clearState } from '../../helpers';
......
......@@ -3,7 +3,7 @@ import Vuex from 'vuex';
import Commit from '~/vue_shared/components/commit.vue';
import Project from 'ee/operations/components/dashboard/project.vue';
import ProjectHeader from 'ee/operations/components/dashboard/project_header.vue';
import Alerts from 'ee/operations/components/dashboard/alerts.vue';
import Alerts from 'ee/vue_shared/dashboards/components/alerts.vue';
import store from 'ee/operations/store';
import { mockOneProject } from '../../mock_data';
......@@ -79,18 +79,5 @@ describe('project component', () => {
expect(commit.props('tag')).toBe(wrapper.props().project.last_pipeline.ref.tag);
});
});
describe('deploy finished at', () => {
it('renders clock icon', () => {
expect(wrapper.contains('.js-dashboard-project-clock-icon')).toBe(true);
});
it('renders time ago of finished time', () => {
const timeago = '1 day ago';
const container = wrapper.element.querySelector('.js-dashboard-project-time-ago');
expect(container.innerText.trim()).toBe(timeago);
});
});
});
});
import Vue from 'vue';
import store from 'ee/operations/store/index';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import TokenizedInput from 'ee/operations/components/tokenized_input/input.vue';
import TokenizedInput from 'ee/vue_shared/dashboards/components/input.vue';
import { clearState } from '../../helpers';
import { mockProjectData } from '../../mock_data';
......
import { TEST_HOST } from 'spec/test_constants';
const AVATAR_URL = `${TEST_HOST}/dummy.jpg`;
import mockPipelineData from 'ee_spec/vue_shared/dashboards/mock_data';
export const mockText = {
ADD_PROJECTS: 'Add projects',
......@@ -18,71 +16,6 @@ export const mockText = {
SEARCH_DESCRIPTION_SUFFIX: 'in projects',
};
export function mockPipelineData(
status = 'success',
id = 1,
finishedTimeStamp = new Date(Date.now() - 86400000).toISOString(),
isTag = false,
) {
return {
id,
user: {
id: 1,
name: 'Test',
username: 'test',
state: 'active',
avatar_url: AVATAR_URL,
web_url: '/test',
status_tooltip_html: null,
path: '/test',
},
active: false,
path: '/test/test-project/pipelines/1',
details: {
status: {
icon: `status_${status}`,
text: status,
label: status,
group: status,
tooltip: status,
has_details: true,
details_path: '/test/test-project/pipelines/1',
illustration: null,
},
finished_at: finishedTimeStamp,
},
ref: {
name: 'master',
path: 'test/test-project/commits/master',
tag: isTag,
branch: true,
merge_request: false,
},
commit: {
id: 'e778416d94deaf75bdabcc8fdd6b7d21f482bcca',
short_id: 'e778416d',
title: "Add new file to the branch I'm working on",
message: "Add new file to the branch I'm working on",
author: {
id: 1,
name: 'Test',
username: 'test',
state: 'active',
avatar_url: AVATAR_URL,
status_tooltip_html: null,
path: '/test',
},
commit_url: '/test/test-project/commit/e778416d94deaf75bdabcc8fdd6b7d21f482bcca',
commit_path: '/test/test-project/commit/e778416d94deaf75bdabcc8fdd6b7d21f482bcca',
},
project: {
full_name: 'Test / test-project',
full_path: '/test/test-project',
name: 'test-project',
},
};
}
export function mockProjectData(
projectCount = 1,
currentPipelineStatus = 'success',
......
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Alerts from 'ee/operations/components/dashboard/alerts.vue';
import Alerts from 'ee/vue_shared/dashboards/components/alerts.vue';
const localVue = createLocalVue();
......
import { mount, createLocalVue } from '@vue/test-utils';
import ProjectPipeline from 'ee/operations/components/dashboard/project_pipeline.vue';
import { mockPipelineData } from '../../mock_data';
import ProjectPipeline from 'ee/vue_shared/dashboards/components/project_pipeline.vue';
import mockPipelineData from '../mock_data';
const localVue = createLocalVue();
......
import { shallowMount, createLocalVue } from '@vue/test-utils';
import TimeAgo from 'ee/vue_shared/dashboards/components/time_ago.vue';
const localVue = createLocalVue();
describe('time ago component', () => {
const TimeAgoComponent = localVue.extend(TimeAgo);
let wrapper;
beforeEach(() => {
wrapper = shallowMount(TimeAgoComponent, {
sync: false,
localVue,
propsData: {
time: new Date(Date.now() - 86400000).toISOString(),
tooltipText: 'Finished',
},
});
});
describe('render', () => {
it('renders clock icon', () => {
expect(wrapper.contains('.js-dashboard-project-clock-icon')).toBe(true);
});
it('renders time ago of finished time', () => {
const timeago = '1 day ago';
const container = wrapper.element.querySelector('.js-dashboard-project-time-ago');
expect(container.innerText.trim()).toBe(timeago);
});
});
});
import { TEST_HOST } from 'spec/test_constants';
const AVATAR_URL = `${TEST_HOST}/dummy.jpg`;
export default function mockPipelineData(
status = 'success',
id = 1,
finishedTimeStamp = new Date(Date.now() - 86400000).toISOString(),
isTag = false,
) {
return {
id,
user: {
id: 1,
name: 'Test',
username: 'test',
state: 'active',
avatar_url: AVATAR_URL,
web_url: '/test',
status_tooltip_html: null,
path: '/test',
},
active: false,
path: '/test/test-project/pipelines/1',
details: {
status: {
icon: `status_${status}`,
text: status,
label: status,
group: status,
tooltip: status,
has_details: true,
details_path: '/test/test-project/pipelines/1',
illustration: null,
},
finished_at: finishedTimeStamp,
},
ref: {
name: 'master',
path: 'test/test-project/commits/master',
tag: isTag,
branch: true,
merge_request: false,
},
commit: {
id: 'e778416d94deaf75bdabcc8fdd6b7d21f482bcca',
short_id: 'e778416d',
title: "Add new file to the branch I'm working on",
message: "Add new file to the branch I'm working on",
author: {
id: 1,
name: 'Test',
username: 'test',
state: 'active',
avatar_url: AVATAR_URL,
status_tooltip_html: null,
path: '/test',
},
commit_url: '/test/test-project/commit/e778416d94deaf75bdabcc8fdd6b7d21f482bcca',
commit_path: '/test/test-project/commit/e778416d94deaf75bdabcc8fdd6b7d21f482bcca',
},
project: {
full_name: 'Test / test-project',
full_path: '/test/test-project',
name: 'test-project',
},
};
}
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