Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/cycle_analytics')
-rw-r--r--app/assets/javascripts/cycle_analytics/components/base.vue192
-rw-r--r--app/assets/javascripts/cycle_analytics/components/filter_bar.vue144
-rw-r--r--app/assets/javascripts/cycle_analytics/components/formatted_stage_count.vue32
-rw-r--r--app/assets/javascripts/cycle_analytics/components/metric_tile.vue51
-rw-r--r--app/assets/javascripts/cycle_analytics/components/path_navigation.vue113
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_table.vue305
-rw-r--r--app/assets/javascripts/cycle_analytics/components/total_time.vue61
-rw-r--r--app/assets/javascripts/cycle_analytics/components/value_stream_filters.vue109
-rw-r--r--app/assets/javascripts/cycle_analytics/constants.js47
-rw-r--r--app/assets/javascripts/cycle_analytics/index.js50
-rw-r--r--app/assets/javascripts/cycle_analytics/store/actions.js209
-rw-r--r--app/assets/javascripts/cycle_analytics/store/getters.js57
-rw-r--r--app/assets/javascripts/cycle_analytics/store/index.js25
-rw-r--r--app/assets/javascripts/cycle_analytics/store/mutation_types.js28
-rw-r--r--app/assets/javascripts/cycle_analytics/store/mutations.js112
-rw-r--r--app/assets/javascripts/cycle_analytics/store/state.js31
-rw-r--r--app/assets/javascripts/cycle_analytics/utils.js117
17 files changed, 0 insertions, 1683 deletions
diff --git a/app/assets/javascripts/cycle_analytics/components/base.vue b/app/assets/javascripts/cycle_analytics/components/base.vue
deleted file mode 100644
index f06544f50c6..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/base.vue
+++ /dev/null
@@ -1,192 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { mapActions, mapState, mapGetters } from 'vuex';
-import { getCookie, setCookie } from '~/lib/utils/common_utils';
-import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue';
-import { VSA_METRICS_GROUPS } from '~/analytics/shared/constants';
-import { toYmd } from '~/analytics/shared/utils';
-import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
-import StageTable from '~/cycle_analytics/components/stage_table.vue';
-import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filters.vue';
-import UrlSync from '~/vue_shared/components/url_sync.vue';
-import { __ } from '~/locale';
-import { SUMMARY_METRICS_REQUEST, METRICS_REQUESTS } from '../constants';
-
-const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
-
-export default {
- name: 'CycleAnalytics',
- components: {
- GlLoadingIcon,
- PathNavigation,
- StageTable,
- ValueStreamFilters,
- ValueStreamMetrics,
- UrlSync,
- },
- props: {
- noDataSvgPath: {
- type: String,
- required: true,
- },
- noAccessSvgPath: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- isOverviewDialogDismissed: getCookie(OVERVIEW_DIALOG_COOKIE),
- };
- },
- computed: {
- ...mapState([
- 'isLoading',
- 'isLoadingStage',
- 'isEmptyStage',
- 'selectedStage',
- 'selectedStageEvents',
- 'selectedStageError',
- 'stageCounts',
- 'endpoints',
- 'features',
- 'createdBefore',
- 'createdAfter',
- 'pagination',
- 'hasNoAccessError',
- ]),
- ...mapGetters(['pathNavigationData', 'filterParams']),
- isLoaded() {
- return !this.isLoading && !this.isLoadingStage;
- },
- displayStageEvents() {
- const { selectedStageEvents, isLoadingStage, isEmptyStage } = this;
- return selectedStageEvents.length && !isLoadingStage && !isEmptyStage;
- },
- displayNotEnoughData() {
- return !this.isLoadingStage && this.isEmptyStage;
- },
- displayNoAccess() {
- return !this.isLoadingStage && this.hasNoAccessError;
- },
- displayPathNavigation() {
- return this.isLoading || (this.selectedStage && this.pathNavigationData.length);
- },
- emptyStageTitle() {
- if (this.displayNoAccess) {
- return __('You need permission.');
- }
- return this.selectedStageError
- ? this.selectedStageError
- : __("We don't have enough data to show this stage.");
- },
- emptyStageText() {
- if (this.displayNoAccess) {
- return __('Want to see the data? Please ask an administrator for access.');
- }
- return !this.selectedStageError && this.selectedStage?.emptyStageText
- ? this.selectedStage?.emptyStageText
- : '';
- },
- selectedStageCount() {
- if (this.selectedStage) {
- const {
- stageCounts,
- selectedStage: { id },
- } = this;
- return stageCounts[id];
- }
- return 0;
- },
- metricsRequests() {
- return this.features?.cycleAnalyticsForGroups ? METRICS_REQUESTS : SUMMARY_METRICS_REQUEST;
- },
- query() {
- return {
- created_after: toYmd(this.createdAfter),
- created_before: toYmd(this.createdBefore),
- stage_id: this.selectedStage?.id || null,
- sort: this.pagination?.sort || null,
- direction: this.pagination?.direction || null,
- page: this.pagination?.page || null,
- };
- },
- },
- methods: {
- ...mapActions([
- 'fetchStageData',
- 'setSelectedStage',
- 'setDateRange',
- 'updateStageTablePagination',
- ]),
- onSetDateRange({ startDate, endDate }) {
- this.setDateRange({
- createdAfter: new Date(startDate),
- createdBefore: new Date(endDate),
- });
- },
- onSelectStage(stage) {
- this.setSelectedStage(stage);
- this.updateStageTablePagination({ ...this.pagination, page: 1 });
- },
- dismissOverviewDialog() {
- this.isOverviewDialogDismissed = true;
- setCookie(OVERVIEW_DIALOG_COOKIE, '1');
- },
- onHandleUpdatePagination(data) {
- this.updateStageTablePagination(data);
- },
- },
- dayRangeOptions: [7, 30, 90],
- i18n: {
- dropdownText: __('Last %{days} days'),
- pageTitle: __('Value Stream Analytics'),
- recentActivity: __('Recent Project Activity'),
- },
- VSA_METRICS_GROUPS,
-};
-</script>
-<template>
- <div>
- <h3>{{ $options.i18n.pageTitle }}</h3>
- <value-stream-filters
- :group-id="endpoints.groupId"
- :group-path="endpoints.groupPath"
- :has-project-filter="false"
- :start-date="createdAfter"
- :end-date="createdBefore"
- @setDateRange="onSetDateRange"
- />
- <div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row">
- <path-navigation
- v-if="displayPathNavigation"
- data-testid="vsa-path-navigation"
- class="gl-w-full gl-mt-4"
- :loading="isLoading || isLoadingStage"
- :stages="pathNavigationData"
- :selected-stage="selectedStage"
- @selected="onSelectStage"
- />
- </div>
- <value-stream-metrics
- :request-path="endpoints.fullPath"
- :request-params="filterParams"
- :requests="metricsRequests"
- :group-by="$options.VSA_METRICS_GROUPS"
- />
- <gl-loading-icon v-if="isLoading" size="lg" />
- <stage-table
- v-else
- :is-loading="isLoading || isLoadingStage"
- :stage-events="selectedStageEvents"
- :selected-stage="selectedStage"
- :stage-count="selectedStageCount"
- :empty-state-title="emptyStageTitle"
- :empty-state-message="emptyStageText"
- :no-data-svg-path="noDataSvgPath"
- :pagination="pagination"
- @handleUpdatePagination="onHandleUpdatePagination"
- />
- <url-sync v-if="isLoaded" :query="query" />
- </div>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/filter_bar.vue b/app/assets/javascripts/cycle_analytics/components/filter_bar.vue
deleted file mode 100644
index 0ad325a8523..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/filter_bar.vue
+++ /dev/null
@@ -1,144 +0,0 @@
-<script>
-import { mapActions, mapState } from 'vuex';
-import {
- OPERATOR_IS_ONLY,
- DEFAULT_NONE_ANY,
- TOKEN_TITLE_ASSIGNEE,
- TOKEN_TITLE_AUTHOR,
- TOKEN_TITLE_LABEL,
- TOKEN_TITLE_MILESTONE,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
-import {
- prepareTokens,
- processFilters,
- filterToQueryObject,
-} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
-import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
-import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
-import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
-import UrlSync from '~/vue_shared/components/url_sync.vue';
-
-export default {
- name: 'FilterBar',
- components: {
- FilteredSearchBar,
- UrlSync,
- },
- props: {
- groupPath: {
- type: String,
- required: true,
- },
- },
- computed: {
- ...mapState('filters', {
- selectedMilestone: (state) => state.milestones.selected,
- selectedAuthor: (state) => state.authors.selected,
- selectedLabelList: (state) => state.labels.selectedList,
- selectedAssigneeList: (state) => state.assignees.selectedList,
- milestonesData: (state) => state.milestones.data,
- labelsData: (state) => state.labels.data,
- authorsData: (state) => state.authors.data,
- assigneesData: (state) => state.assignees.data,
- }),
- tokens() {
- return [
- {
- icon: 'clock',
- title: TOKEN_TITLE_MILESTONE,
- type: 'milestone',
- token: MilestoneToken,
- initialMilestones: this.milestonesData,
- unique: true,
- symbol: '%',
- operators: OPERATOR_IS_ONLY,
- fetchMilestones: this.fetchMilestones,
- },
- {
- icon: 'labels',
- title: TOKEN_TITLE_LABEL,
- type: 'labels',
- token: LabelToken,
- defaultLabels: DEFAULT_NONE_ANY,
- initialLabels: this.labelsData,
- unique: false,
- symbol: '~',
- operators: OPERATOR_IS_ONLY,
- fetchLabels: this.fetchLabels,
- },
- {
- icon: 'pencil',
- title: TOKEN_TITLE_AUTHOR,
- type: 'author',
- token: AuthorToken,
- initialAuthors: this.authorsData,
- unique: true,
- operators: OPERATOR_IS_ONLY,
- fetchAuthors: this.fetchAuthors,
- },
- {
- icon: 'user',
- title: TOKEN_TITLE_ASSIGNEE,
- type: 'assignees',
- token: AuthorToken,
- initialAuthors: this.assigneesData,
- unique: false,
- operators: OPERATOR_IS_ONLY,
- fetchAuthors: this.fetchAssignees,
- },
- ];
- },
- query() {
- return filterToQueryObject({
- milestone_title: this.selectedMilestone,
- author_username: this.selectedAuthor,
- label_name: this.selectedLabelList,
- assignee_username: this.selectedAssigneeList,
- });
- },
- },
- methods: {
- ...mapActions('filters', [
- 'setFilters',
- 'fetchMilestones',
- 'fetchLabels',
- 'fetchAuthors',
- 'fetchAssignees',
- ]),
- initialFilterValue() {
- return prepareTokens({
- milestone: this.selectedMilestone,
- author: this.selectedAuthor,
- assignees: this.selectedAssigneeList,
- labels: this.selectedLabelList,
- });
- },
- handleFilter(filters) {
- const { labels, milestone, author, assignees } = processFilters(filters);
-
- this.setFilters({
- selectedAuthor: author ? author[0] : null,
- selectedMilestone: milestone ? milestone[0] : null,
- selectedAssigneeList: assignees || [],
- selectedLabelList: labels || [],
- });
- },
- },
-};
-</script>
-
-<template>
- <div>
- <filtered-search-bar
- class="gl-flex-grow-1"
- :namespace="groupPath"
- recent-searches-storage-key="value-stream-analytics"
- :search-input-placeholder="__('Filter results')"
- :tokens="tokens"
- :initial-filter-value="initialFilterValue()"
- @onFilter="handleFilter"
- />
- <url-sync :query="query" />
- </div>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/formatted_stage_count.vue b/app/assets/javascripts/cycle_analytics/components/formatted_stage_count.vue
deleted file mode 100644
index b622b0441e2..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/formatted_stage_count.vue
+++ /dev/null
@@ -1,32 +0,0 @@
-<script>
-import { s__, n__, sprintf, formatNumber } from '~/locale';
-
-export default {
- props: {
- stageCount: {
- type: Number,
- required: false,
- default: null,
- },
- },
- computed: {
- formattedStageCount() {
- if (!this.stageCount) {
- return '-';
- } else if (this.stageCount > 1000) {
- return sprintf(s__('ValueStreamAnalytics|%{stageCount}+ items'), {
- stageCount: formatNumber(1000),
- });
- }
-
- return sprintf(n__('%{count} item', '%{count} items', this.stageCount), {
- count: formatNumber(this.stageCount),
- });
- },
- },
-};
-</script>
-
-<template>
- <span>{{ formattedStageCount }}</span>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/metric_tile.vue b/app/assets/javascripts/cycle_analytics/components/metric_tile.vue
deleted file mode 100644
index a5c20b237b3..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/metric_tile.vue
+++ /dev/null
@@ -1,51 +0,0 @@
-<script>
-import { GlSingleStat } from '@gitlab/ui/dist/charts';
-import { redirectTo } from '~/lib/utils/url_utility';
-import MetricPopover from '~/analytics/shared/components/metric_popover.vue';
-
-export default {
- name: 'MetricTile',
- components: {
- GlSingleStat,
- MetricPopover,
- },
- props: {
- metric: {
- type: Object,
- required: true,
- },
- },
- computed: {
- decimalPlaces() {
- const parsedFloat = parseFloat(this.metric.value);
- return Number.isNaN(parsedFloat) || Number.isInteger(parsedFloat) ? 0 : 1;
- },
- hasLinks() {
- return this.metric.links?.length && this.metric.links[0].url;
- },
- },
- methods: {
- clickHandler({ links }) {
- if (this.hasLinks) {
- redirectTo(links[0].url);
- }
- },
- },
-};
-</script>
-<template>
- <div v-bind="$attrs">
- <gl-single-stat
- :id="metric.identifier"
- :value="`${metric.value}`"
- :title="metric.label"
- :unit="metric.unit || ''"
- :should-animate="true"
- :animation-decimal-places="decimalPlaces"
- :class="{ 'gl-hover-cursor-pointer': hasLinks }"
- tabindex="0"
- @click="clickHandler(metric)"
- />
- <metric-popover :metric="metric" :target="metric.identifier" />
- </div>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/path_navigation.vue b/app/assets/javascripts/cycle_analytics/components/path_navigation.vue
deleted file mode 100644
index 72a7659aac0..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/path_navigation.vue
+++ /dev/null
@@ -1,113 +0,0 @@
-<script>
-import { GlPath, GlPopover, GlSkeletonLoader, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
-import Tracking from '~/tracking';
-import { OVERVIEW_STAGE_ID } from '../constants';
-import FormattedStageCount from './formatted_stage_count.vue';
-
-export default {
- name: 'PathNavigation',
- components: {
- GlPath,
- GlSkeletonLoader,
- GlPopover,
- FormattedStageCount,
- },
- directives: {
- SafeHtml,
- },
- mixins: [Tracking.mixin()],
- props: {
- loading: {
- type: Boolean,
- required: false,
- default: false,
- },
- stages: {
- type: Array,
- required: true,
- },
- selectedStage: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- },
- methods: {
- showPopover({ id }) {
- return id && id !== OVERVIEW_STAGE_ID;
- },
- onSelectStage($event) {
- this.$emit('selected', $event);
- this.track('click_path_navigation', {
- extra: {
- stage_id: $event.id,
- },
- });
- },
- },
- popoverOptions: {
- triggers: 'hover',
- placement: 'bottom',
- },
-};
-</script>
-<template>
- <gl-skeleton-loader v-if="loading" :width="235" :lines="2" />
- <gl-path v-else :key="selectedStage.id" :items="stages" @selected="onSelectStage">
- <template #default="{ pathItem, pathId }">
- <gl-popover
- v-if="showPopover(pathItem)"
- v-bind="$options.popoverOptions"
- :target="pathId"
- :css-classes="['stage-item-popover']"
- data-testid="stage-item-popover"
- >
- <template #title>{{ pathItem.title }}</template>
- <div class="gl-px-4">
- <div class="gl-display-flex gl-justify-content-space-between">
- <div class="gl-pr-4 gl-pb-4">
- {{ s__('ValueStreamEvent|Stage time (median)') }}
- </div>
- <div class="gl-pb-4 gl-font-weight-bold">{{ pathItem.metric }}</div>
- </div>
- </div>
- <div class="gl-px-4">
- <div class="gl-display-flex gl-justify-content-space-between">
- <div class="gl-pr-4 gl-pb-4">
- {{ s__('ValueStreamEvent|Items in stage') }}
- </div>
- <div class="gl-pb-4 gl-font-weight-bold">
- <formatted-stage-count :stage-count="pathItem.stageCount" />
- </div>
- </div>
- </div>
- <div class="gl-px-4 gl-pt-4 gl-border-t-1 gl-border-t-solid gl-border-gray-50">
- <div
- v-if="pathItem.startEventHtmlDescription"
- class="gl-display-flex gl-flex-direction-row"
- >
- <div class="gl-display-flex gl-flex-direction-column gl-pr-4 gl-pb-4 metric-label">
- {{ s__('ValueStreamEvent|Start') }}
- </div>
- <div
- v-safe-html="pathItem.startEventHtmlDescription"
- class="gl-display-flex gl-flex-direction-column gl-pb-4 stage-event-description"
- ></div>
- </div>
- <div
- v-if="pathItem.endEventHtmlDescription"
- class="gl-display-flex gl-flex-direction-row"
- >
- <div class="gl-display-flex gl-flex-direction-column gl-pr-4 metric-label">
- {{ s__('ValueStreamEvent|Stop') }}
- </div>
- <div
- v-safe-html="pathItem.endEventHtmlDescription"
- class="gl-display-flex gl-flex-direction-column stage-event-description"
- ></div>
- </div>
- </div>
- </gl-popover>
- </template>
- </gl-path>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_table.vue b/app/assets/javascripts/cycle_analytics/components/stage_table.vue
deleted file mode 100644
index f1fdffd4b72..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/stage_table.vue
+++ /dev/null
@@ -1,305 +0,0 @@
-<script>
-import {
- GlEmptyState,
- GlIcon,
- GlLink,
- GlLoadingIcon,
- GlPagination,
- GlTable,
- GlBadge,
-} from '@gitlab/ui';
-import FormattedStageCount from '~/cycle_analytics/components/formatted_stage_count.vue';
-import { __ } from '~/locale';
-import Tracking from '~/tracking';
-import {
- NOT_ENOUGH_DATA_ERROR,
- FIELD_KEY_TITLE,
- PAGINATION_SORT_FIELD_END_EVENT,
- PAGINATION_SORT_FIELD_DURATION,
- PAGINATION_SORT_DIRECTION_ASC,
- PAGINATION_SORT_DIRECTION_DESC,
-} from '../constants';
-import TotalTime from './total_time.vue';
-
-const DEFAULT_WORKFLOW_TITLE_PROPERTIES = {
- thClass: 'gl-w-half',
- key: FIELD_KEY_TITLE,
- sortable: false,
-};
-
-const WORKFLOW_COLUMN_TITLES = {
- issues: { ...DEFAULT_WORKFLOW_TITLE_PROPERTIES, label: __('Issues') },
- jobs: { ...DEFAULT_WORKFLOW_TITLE_PROPERTIES, label: __('Jobs') },
- deployments: { ...DEFAULT_WORKFLOW_TITLE_PROPERTIES, label: __('Deployments') },
- mergeRequests: { ...DEFAULT_WORKFLOW_TITLE_PROPERTIES, label: __('Merge requests') },
-};
-
-const fullProjectPath = ({ namespaceFullPath = '', projectPath }) =>
- namespaceFullPath.split('/').length > 1 ? `${namespaceFullPath}/${projectPath}` : projectPath;
-
-export default {
- name: 'StageTable',
- components: {
- GlEmptyState,
- GlIcon,
- GlLink,
- GlLoadingIcon,
- GlPagination,
- GlTable,
- GlBadge,
- TotalTime,
- FormattedStageCount,
- },
- mixins: [Tracking.mixin()],
- props: {
- selectedStage: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- isLoading: {
- type: Boolean,
- required: true,
- },
- stageEvents: {
- type: Array,
- required: true,
- },
- stageCount: {
- type: Number,
- required: false,
- default: null,
- },
- noDataSvgPath: {
- type: String,
- required: true,
- },
- emptyStateTitle: {
- type: String,
- required: false,
- default: null,
- },
- emptyStateMessage: {
- type: String,
- required: false,
- default: '',
- },
- pagination: {
- type: Object,
- required: false,
- default: null,
- },
- sortable: {
- type: Boolean,
- required: false,
- default: true,
- },
- includeProjectName: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- if (this.pagination) {
- const {
- pagination: { sort, direction },
- } = this;
- return {
- sort,
- direction,
- sortDesc: direction === PAGINATION_SORT_DIRECTION_DESC,
- };
- }
- return { sort: null, direction: null, sortDesc: null };
- },
- computed: {
- isEmptyStage() {
- return !this.selectedStage || !this.stageEvents.length;
- },
- emptyStateTitleText() {
- return this.emptyStateTitle || NOT_ENOUGH_DATA_ERROR;
- },
- isMergeRequestStage() {
- const [firstEvent] = this.stageEvents;
- return this.isMrLink(firstEvent.url);
- },
- workflowTitle() {
- if (this.isMergeRequestStage) {
- return WORKFLOW_COLUMN_TITLES.mergeRequests;
- }
- return WORKFLOW_COLUMN_TITLES.issues;
- },
- fields() {
- return [
- this.workflowTitle,
- {
- key: PAGINATION_SORT_FIELD_END_EVENT,
- label: __('Last event'),
- sortable: this.sortable,
- },
- {
- key: PAGINATION_SORT_FIELD_DURATION,
- label: __('Duration'),
- sortable: this.sortable,
- },
- ];
- },
- prevPage() {
- return Math.max(this.pagination.page - 1, 0);
- },
- nextPage() {
- return this.pagination.hasNextPage ? this.pagination.page + 1 : null;
- },
- },
- methods: {
- isMrLink(url = '') {
- return url.includes('/merge_request');
- },
- itemId({ iid, projectPath, namespaceFullPath = '' }, separator = '#') {
- const prefix = this.includeProjectName
- ? fullProjectPath({ namespaceFullPath, projectPath })
- : '';
- return `${prefix}${separator}${iid}`;
- },
- itemDisplayName(item) {
- const separator = this.isMrLink(item.url) ? '!' : '#';
- return this.itemId(item, separator);
- },
- itemTitle(item) {
- return item.title || item.name;
- },
- onSelectPage(page) {
- const { sort, direction } = this.pagination;
- this.track('click_button', { label: 'pagination' });
- this.$emit('handleUpdatePagination', { sort, direction, page });
- },
- onSort({ sortBy, sortDesc }) {
- const direction = sortDesc ? PAGINATION_SORT_DIRECTION_DESC : PAGINATION_SORT_DIRECTION_ASC;
- this.sort = sortBy;
- this.sortDesc = sortDesc;
- this.$emit('handleUpdatePagination', { sort: sortBy, direction });
- this.track('click_button', { label: `sort_${sortBy}_${direction}` });
- },
- },
-};
-</script>
-<template>
- <div data-testid="vsa-stage-table">
- <gl-loading-icon v-if="isLoading" class="gl-mt-4" size="lg" />
- <gl-empty-state
- v-else-if="isEmptyStage"
- :title="emptyStateTitleText"
- :description="emptyStateMessage"
- :svg-path="noDataSvgPath"
- />
- <gl-table
- v-else
- stacked="lg"
- show-empty
- :sort-by.sync="sort"
- :sort-direction.sync="direction"
- :sort-desc.sync="sortDesc"
- :fields="fields"
- :items="stageEvents"
- :empty-text="emptyStateMessage"
- @sort-changed="onSort"
- >
- <template v-if="stageCount" #head(title)="data">
- <span>{{ data.label }}</span
- ><gl-badge class="gl-ml-2" size="sm"
- ><formatted-stage-count :stage-count="stageCount"
- /></gl-badge>
- </template>
- <template #head(duration)="data">
- <span data-testid="vsa-stage-header-duration">{{ data.label }}</span>
- </template>
- <template #head(end_event)="data">
- <span data-testid="vsa-stage-header-last-event">{{ data.label }}</span>
- </template>
- <template #cell(title)="{ item }">
- <div data-testid="vsa-stage-event">
- <div v-if="item.id" data-testid="vsa-stage-content">
- <p class="gl-m-0">
- <gl-link
- data-testid="vsa-stage-event-link"
- class="gl-text-black-normal"
- :href="item.url"
- >{{ itemId(item.id, '#') }}</gl-link
- >
- <gl-icon :size="16" name="fork" />
- <gl-link
- v-if="item.branch"
- :href="item.branch.url"
- class="gl-text-black-normal ref-name"
- >{{ item.branch.name }}</gl-link
- >
- <span class="icon-branch gl-text-gray-400">
- <gl-icon name="commit" :size="14" />
- </span>
- <gl-link
- class="commit-sha"
- :href="item.commitUrl"
- data-testid="vsa-stage-event-build-sha"
- >{{ item.shortSha }}</gl-link
- >
- </p>
- <p class="gl-m-0">
- <span data-testid="vsa-stage-event-build-author-and-date">
- <gl-link class="gl-text-black-normal" :href="item.url">{{ item.date }}</gl-link>
- {{ s__('ByAuthor|by') }}
- <gl-link
- class="gl-text-black-normal issue-author-link"
- :href="item.author.webUrl"
- >{{ item.author.name }}</gl-link
- >
- </span>
- </p>
- </div>
- <div v-else data-testid="vsa-stage-content">
- <h5 class="gl-font-weight-bold gl-my-1" data-testid="vsa-stage-event-title">
- <gl-link class="gl-text-black-normal" :href="item.url">{{ itemTitle(item) }}</gl-link>
- </h5>
- <p class="gl-m-0">
- <gl-link
- data-testid="vsa-stage-event-link"
- class="gl-text-black-normal"
- :href="item.url"
- >{{ itemDisplayName(item) }}</gl-link
- >
- <span class="gl-font-lg">&middot;</span>
- <span data-testid="vsa-stage-event-date">
- {{ s__('OpenedNDaysAgo|Created') }}
- <gl-link class="gl-text-black-normal" :href="item.url">{{
- item.createdAt
- }}</gl-link>
- </span>
- <span data-testid="vsa-stage-event-author">
- {{ s__('ByAuthor|by') }}
- <gl-link class="gl-text-black-normal" :href="item.author.webUrl">{{
- item.author.name
- }}</gl-link>
- </span>
- </p>
- </div>
- </div>
- </template>
- <template #cell(duration)="{ item }">
- <total-time :time="item.totalTime" data-testid="vsa-stage-event-time" />
- </template>
- <template #cell(end_event)="{ item }">
- <span data-testid="vsa-stage-last-event">{{ item.endEventTimestamp }}</span>
- </template>
- </gl-table>
- <gl-pagination
- v-if="pagination && !isLoading && !isEmptyStage"
- :value="pagination.page"
- :prev-page="prevPage"
- :next-page="nextPage"
- align="center"
- class="gl-mt-3"
- data-testid="vsa-stage-pagination"
- @input="onSelectPage"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/total_time.vue b/app/assets/javascripts/cycle_analytics/components/total_time.vue
deleted file mode 100644
index 725952c3518..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/total_time.vue
+++ /dev/null
@@ -1,61 +0,0 @@
-<script>
-import { n__, s__ } from '~/locale';
-
-export default {
- props: {
- time: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- },
- computed: {
- hasData() {
- return Object.keys(this.time).length;
- },
- calculatedTime() {
- const {
- time: { days = null, mins = null, hours = null, seconds = null },
- } = this;
-
- if (days) {
- return {
- duration: days,
- units: n__('day', 'days', days),
- };
- }
-
- if (hours) {
- return {
- duration: hours,
- units: n__('Time|hr', 'Time|hrs', hours),
- };
- }
-
- if (mins && !days) {
- return {
- duration: mins,
- units: n__('Time|min', 'Time|mins', mins),
- };
- }
-
- if ((seconds && this.hasData === 1) || seconds === 0) {
- return {
- duration: seconds,
- units: s__('Time|s'),
- };
- }
-
- return { duration: null, units: null };
- },
- },
-};
-</script>
-<template>
- <span>
- <template v-if="hasData">
- {{ calculatedTime.duration }} <span>{{ calculatedTime.units }}</span>
- </template>
- <template v-else> -- </template>
- </span>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/value_stream_filters.vue b/app/assets/javascripts/cycle_analytics/components/value_stream_filters.vue
deleted file mode 100644
index 17decb6b448..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/value_stream_filters.vue
+++ /dev/null
@@ -1,109 +0,0 @@
-<script>
-import { GlTooltipDirective } from '@gitlab/ui';
-import DateRange from '~/analytics/shared/components/daterange.vue';
-import ProjectsDropdownFilter from '~/analytics/shared/components/projects_dropdown_filter.vue';
-import { DATE_RANGE_LIMIT, PROJECTS_PER_PAGE } from '~/analytics/shared/constants';
-import FilterBar from './filter_bar.vue';
-
-export default {
- name: 'ValueStreamFilters',
- components: {
- DateRange,
- ProjectsDropdownFilter,
- FilterBar,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- selectedProjects: {
- type: Array,
- required: false,
- default: () => [],
- },
- hasProjectFilter: {
- type: Boolean,
- required: false,
- default: true,
- },
- hasDateRangeFilter: {
- type: Boolean,
- required: false,
- default: true,
- },
- groupId: {
- type: Number,
- required: true,
- },
- groupPath: {
- type: String,
- required: true,
- },
- startDate: {
- type: Date,
- required: false,
- default: null,
- },
- endDate: {
- type: Date,
- required: false,
- default: null,
- },
- },
- computed: {
- projectsQueryParams() {
- return {
- first: PROJECTS_PER_PAGE,
- includeSubgroups: true,
- };
- },
- currentDate() {
- const now = new Date();
- return new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
- },
- },
- multiProjectSelect: true,
- maxDateRange: DATE_RANGE_LIMIT,
-};
-</script>
-<template>
- <div
- class="gl-mt-3 gl-py-2 gl-px-3 gl-bg-gray-10 gl-border-b-1 gl-border-b-solid gl-border-t-1 gl-border-t-solid gl-border-gray-100"
- >
- <filter-bar
- data-testid="vsa-filter-bar"
- class="filtered-search-box gl-display-flex gl-mb-2 gl-mr-3 gl-border-none"
- :group-path="groupPath"
- />
- <div
- v-if="hasDateRangeFilter || hasProjectFilter"
- class="gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-justify-content-space-between"
- >
- <div>
- <projects-dropdown-filter
- v-if="hasProjectFilter"
- :key="groupId"
- class="js-projects-dropdown-filter project-select gl-mb-2 gl-lg-mb-0"
- :group-id="groupId"
- :group-namespace="groupPath"
- :query-params="projectsQueryParams"
- :multi-select="$options.multiProjectSelect"
- :default-projects="selectedProjects"
- @selected="$emit('selectProject', $event)"
- />
- </div>
- <div class="gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row">
- <date-range
- v-if="hasDateRangeFilter"
- :start-date="startDate"
- :end-date="endDate"
- :max-date="currentDate"
- :max-date-range="$options.maxDateRange"
- :include-selected-date="true"
- class="js-daterange-picker"
- @change="$emit('setDateRange', $event)"
- />
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/cycle_analytics/constants.js b/app/assets/javascripts/cycle_analytics/constants.js
deleted file mode 100644
index 2758d686fb1..00000000000
--- a/app/assets/javascripts/cycle_analytics/constants.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import {
- getValueStreamMetrics,
- METRIC_TYPE_SUMMARY,
- METRIC_TYPE_TIME_SUMMARY,
-} from '~/api/analytics_api';
-import { __, s__ } from '~/locale';
-
-export const OVERVIEW_STAGE_ID = 'overview';
-
-export const DEFAULT_VALUE_STREAM = {
- id: 'default',
- slug: 'default',
- name: 'default',
-};
-
-export const NOT_ENOUGH_DATA_ERROR = s__(
- "ValueStreamAnalyticsStage|We don't have enough data to show this stage.",
-);
-
-export const PAGINATION_TYPE = 'keyset';
-export const PAGINATION_SORT_FIELD_END_EVENT = 'end_event';
-export const PAGINATION_SORT_FIELD_DURATION = 'duration';
-export const PAGINATION_SORT_DIRECTION_DESC = 'desc';
-export const PAGINATION_SORT_DIRECTION_ASC = 'asc';
-export const FIELD_KEY_TITLE = 'title';
-
-export const I18N_VSA_ERROR_STAGES = __(
- 'There was an error fetching value stream analytics stages.',
-);
-export const I18N_VSA_ERROR_STAGE_MEDIAN = __('There was an error fetching median data for stages');
-export const I18N_VSA_ERROR_SELECTED_STAGE = __(
- 'There was an error fetching data for the selected stage',
-);
-
-export const OVERVIEW_METRICS = {
- TIME_SUMMARY: 'TIME_SUMMARY',
- RECENT_ACTIVITY: 'RECENT_ACTIVITY',
-};
-
-export const SUMMARY_METRICS_REQUEST = [
- { endpoint: METRIC_TYPE_SUMMARY, name: __('recent activity'), request: getValueStreamMetrics },
-];
-
-export const METRICS_REQUESTS = [
- { endpoint: METRIC_TYPE_TIME_SUMMARY, name: __('time summary'), request: getValueStreamMetrics },
- ...SUMMARY_METRICS_REQUEST,
-];
diff --git a/app/assets/javascripts/cycle_analytics/index.js b/app/assets/javascripts/cycle_analytics/index.js
deleted file mode 100644
index 3da8696edeb..00000000000
--- a/app/assets/javascripts/cycle_analytics/index.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import Vue from 'vue';
-import {
- extractFilterQueryParameters,
- extractPaginationQueryParameters,
-} from '~/analytics/shared/utils';
-import Translate from '../vue_shared/translate';
-import CycleAnalytics from './components/base.vue';
-import createStore from './store';
-import { buildCycleAnalyticsInitialData } from './utils';
-
-Vue.use(Translate);
-
-export default () => {
- const store = createStore();
- const el = document.querySelector('#js-cycle-analytics');
- const { noAccessSvgPath, noDataSvgPath } = el.dataset;
- const initialData = buildCycleAnalyticsInitialData({ ...el.dataset, gon });
-
- const pagination = extractPaginationQueryParameters(window.location.search);
- const {
- selectedAuthor,
- selectedMilestone,
- selectedAssigneeList,
- selectedLabelList,
- } = extractFilterQueryParameters(window.location.search);
-
- store.dispatch('initializeVsa', {
- ...initialData,
- selectedAuthor,
- selectedMilestone,
- selectedAssigneeList,
- selectedLabelList,
- pagination,
- });
-
- // eslint-disable-next-line no-new
- new Vue({
- el,
- name: 'CycleAnalytics',
- apolloProvider: {},
- store,
- render: (createElement) =>
- createElement(CycleAnalytics, {
- props: {
- noDataSvgPath,
- noAccessSvgPath,
- },
- }),
- });
-};
diff --git a/app/assets/javascripts/cycle_analytics/store/actions.js b/app/assets/javascripts/cycle_analytics/store/actions.js
deleted file mode 100644
index 4a201e00582..00000000000
--- a/app/assets/javascripts/cycle_analytics/store/actions.js
+++ /dev/null
@@ -1,209 +0,0 @@
-import {
- getProjectValueStreamStages,
- getProjectValueStreams,
- getValueStreamStageMedian,
- getValueStreamStageRecords,
- getValueStreamStageCounts,
-} from '~/api/analytics_api';
-import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils';
-import { createAlert } from '~/flash';
-import { __ } from '~/locale';
-import { DEFAULT_VALUE_STREAM, I18N_VSA_ERROR_STAGE_MEDIAN } from '../constants';
-import * as types from './mutation_types';
-
-export const setSelectedValueStream = ({ commit, dispatch }, valueStream) => {
- commit(types.SET_SELECTED_VALUE_STREAM, valueStream);
- return dispatch('fetchValueStreamStages');
-};
-
-export const fetchValueStreamStages = ({ commit, state }) => {
- const {
- endpoints: { fullPath },
- selectedValueStream: { id },
- } = state;
- commit(types.REQUEST_VALUE_STREAM_STAGES);
-
- return getProjectValueStreamStages(fullPath, id)
- .then(({ data }) => commit(types.RECEIVE_VALUE_STREAM_STAGES_SUCCESS, data))
- .catch(({ response: { status } }) => {
- commit(types.RECEIVE_VALUE_STREAM_STAGES_ERROR, status);
- });
-};
-
-export const receiveValueStreamsSuccess = ({ commit, dispatch }, data = []) => {
- commit(types.RECEIVE_VALUE_STREAMS_SUCCESS, data);
- if (data.length) {
- const [firstStream] = data;
- return dispatch('setSelectedValueStream', firstStream);
- }
- return dispatch('setSelectedValueStream', DEFAULT_VALUE_STREAM);
-};
-
-export const fetchValueStreams = ({ commit, dispatch, state }) => {
- const {
- endpoints: { fullPath },
- } = state;
- commit(types.REQUEST_VALUE_STREAMS);
-
- return getProjectValueStreams(fullPath)
- .then(({ data }) => dispatch('receiveValueStreamsSuccess', data))
- .catch(({ response: { status } }) => {
- commit(types.RECEIVE_VALUE_STREAMS_ERROR, status);
- });
-};
-
-export const fetchStageData = ({
- getters: { requestParams, filterParams, paginationParams },
- commit,
-}) => {
- commit(types.REQUEST_STAGE_DATA);
-
- return getValueStreamStageRecords(requestParams, { ...filterParams, ...paginationParams })
- .then(({ data, headers }) => {
- // when there's a query timeout, the request succeeds but the error is encoded in the response data
- if (data?.error) {
- commit(types.RECEIVE_STAGE_DATA_ERROR, data.error);
- } else {
- commit(types.RECEIVE_STAGE_DATA_SUCCESS, data);
- const { page = null, nextPage = null } = parseIntPagination(normalizeHeaders(headers));
- commit(types.SET_PAGINATION, { ...paginationParams, page, hasNextPage: Boolean(nextPage) });
- }
- })
- .catch(() => commit(types.RECEIVE_STAGE_DATA_ERROR));
-};
-
-const getStageMedians = ({ stageId, vsaParams, filterParams = {} }) => {
- return getValueStreamStageMedian({ ...vsaParams, stageId }, filterParams).then(({ data }) => ({
- id: stageId,
- value: data?.value || null,
- }));
-};
-
-export const fetchStageMedians = ({
- state: { stages },
- getters: { requestParams: vsaParams, filterParams },
- commit,
-}) => {
- commit(types.REQUEST_STAGE_MEDIANS);
- return Promise.all(
- stages.map(({ id: stageId }) =>
- getStageMedians({
- vsaParams,
- stageId,
- filterParams,
- }),
- ),
- )
- .then((data) => commit(types.RECEIVE_STAGE_MEDIANS_SUCCESS, data))
- .catch((error) => {
- commit(types.RECEIVE_STAGE_MEDIANS_ERROR, error);
- createAlert({ message: I18N_VSA_ERROR_STAGE_MEDIAN });
- });
-};
-
-const getStageCounts = ({ stageId, vsaParams, filterParams = {} }) => {
- return getValueStreamStageCounts({ ...vsaParams, stageId }, filterParams).then(({ data }) => ({
- id: stageId,
- ...data,
- }));
-};
-
-export const fetchStageCountValues = ({
- state: { stages },
- getters: { requestParams: vsaParams, filterParams },
- commit,
-}) => {
- commit(types.REQUEST_STAGE_COUNTS);
- return Promise.all(
- stages.map(({ id: stageId }) =>
- getStageCounts({
- vsaParams,
- stageId,
- filterParams,
- }),
- ),
- )
- .then((data) => commit(types.RECEIVE_STAGE_COUNTS_SUCCESS, data))
- .catch((error) => {
- commit(types.RECEIVE_STAGE_COUNTS_ERROR, error);
- createAlert({
- message: __('There was an error fetching stage total counts'),
- });
- });
-};
-
-export const fetchValueStreamStageData = ({ dispatch }) =>
- Promise.all([
- dispatch('fetchStageData'),
- dispatch('fetchStageMedians'),
- dispatch('fetchStageCountValues'),
- ]);
-
-export const refetchStageData = async ({ dispatch, commit }) => {
- commit(types.SET_LOADING, true);
- await dispatch('fetchValueStreamStageData');
- commit(types.SET_LOADING, false);
-};
-
-export const setSelectedStage = ({ dispatch, commit }, selectedStage = null) => {
- commit(types.SET_SELECTED_STAGE, selectedStage);
- return dispatch('refetchStageData');
-};
-
-export const setFilters = ({ dispatch }) => dispatch('refetchStageData');
-
-export const setDateRange = ({ dispatch, commit }, { createdAfter, createdBefore }) => {
- commit(types.SET_DATE_RANGE, { createdAfter, createdBefore });
- return dispatch('refetchStageData');
-};
-
-export const setInitialStage = ({ dispatch, commit, state: { stages } }, stage) => {
- if (!stages.length && !stage) {
- commit(types.SET_NO_ACCESS_ERROR);
- return null;
- }
-
- const selectedStage = stage || stages[0];
- commit(types.SET_SELECTED_STAGE, selectedStage);
- return dispatch('fetchValueStreamStageData');
-};
-
-export const updateStageTablePagination = (
- { commit, dispatch, state: { selectedStage } },
- paginationParams,
-) => {
- commit(types.SET_PAGINATION, paginationParams);
- return dispatch('fetchStageData', selectedStage.id);
-};
-
-export const initializeVsa = async ({ commit, dispatch }, initialData = {}) => {
- commit(types.INITIALIZE_VSA, initialData);
-
- const {
- endpoints: { fullPath, groupPath, milestonesPath = '', labelsPath = '' },
- selectedAuthor,
- selectedMilestone,
- selectedAssigneeList,
- selectedLabelList,
- selectedStage = null,
- } = initialData;
-
- dispatch('filters/setEndpoints', {
- labelsEndpoint: labelsPath,
- milestonesEndpoint: milestonesPath,
- groupEndpoint: groupPath,
- projectEndpoint: fullPath,
- });
-
- dispatch('filters/initialize', {
- selectedAuthor,
- selectedMilestone,
- selectedAssigneeList,
- selectedLabelList,
- });
-
- commit(types.SET_LOADING, true);
- await dispatch('fetchValueStreams');
- await dispatch('setInitialStage', selectedStage);
- commit(types.SET_LOADING, false);
-};
diff --git a/app/assets/javascripts/cycle_analytics/store/getters.js b/app/assets/javascripts/cycle_analytics/store/getters.js
deleted file mode 100644
index 83068cabf0f..00000000000
--- a/app/assets/javascripts/cycle_analytics/store/getters.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import { dateFormats } from '~/analytics/shared/constants';
-import dateFormat from '~/lib/dateformat';
-import { filterToQueryObject } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
-import { PAGINATION_TYPE } from '../constants';
-import { transformStagesForPathNavigation, filterStagesByHiddenStatus } from '../utils';
-
-export const pathNavigationData = ({ stages, medians, stageCounts, selectedStage }) => {
- return transformStagesForPathNavigation({
- stages: filterStagesByHiddenStatus(stages, false),
- medians,
- stageCounts,
- selectedStage,
- });
-};
-
-export const requestParams = (state) => {
- const {
- endpoints: { fullPath },
- selectedValueStream: { id: valueStreamId },
- selectedStage: { id: stageId = null },
- } = state;
- return { requestPath: fullPath, valueStreamId, stageId };
-};
-
-export const paginationParams = ({ pagination: { page, sort, direction } }) => ({
- pagination: PAGINATION_TYPE,
- sort,
- direction,
- page,
-});
-
-const filterBarParams = ({ filters }) => {
- const {
- authors: { selected: selectedAuthor },
- milestones: { selected: selectedMilestone },
- assignees: { selectedList: selectedAssigneeList },
- labels: { selectedList: selectedLabelList },
- } = filters;
- return filterToQueryObject({
- milestone_title: selectedMilestone,
- author_username: selectedAuthor,
- label_name: selectedLabelList,
- assignee_username: selectedAssigneeList,
- });
-};
-
-const dateRangeParams = ({ createdAfter, createdBefore }) => ({
- created_after: createdAfter ? dateFormat(createdAfter, dateFormats.isoDate) : null,
- created_before: createdBefore ? dateFormat(createdBefore, dateFormats.isoDate) : null,
-});
-
-export const filterParams = (state) => {
- return {
- ...filterBarParams(state),
- ...dateRangeParams(state),
- };
-};
diff --git a/app/assets/javascripts/cycle_analytics/store/index.js b/app/assets/javascripts/cycle_analytics/store/index.js
deleted file mode 100644
index 76e3e835016..00000000000
--- a/app/assets/javascripts/cycle_analytics/store/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * While we are in the process implementing group level features at the project level
- * we will use a simplified vuex store for the project level, eventually this can be
- * replaced with the store at ee/app/assets/javascripts/analytics/cycle_analytics/store/index.js
- * once we have enough of the same features implemented across the project and group level
- */
-
-import Vue from 'vue';
-import Vuex from 'vuex';
-import filters from '~/vue_shared/components/filtered_search_bar/store/modules/filters';
-import * as actions from './actions';
-import * as getters from './getters';
-import mutations from './mutations';
-import state from './state';
-
-Vue.use(Vuex);
-
-export default () =>
- new Vuex.Store({
- actions,
- getters,
- mutations,
- state,
- modules: { filters },
- });
diff --git a/app/assets/javascripts/cycle_analytics/store/mutation_types.js b/app/assets/javascripts/cycle_analytics/store/mutation_types.js
deleted file mode 100644
index 9376d81f317..00000000000
--- a/app/assets/javascripts/cycle_analytics/store/mutation_types.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export const INITIALIZE_VSA = 'INITIALIZE_VSA';
-
-export const SET_LOADING = 'SET_LOADING';
-export const SET_SELECTED_VALUE_STREAM = 'SET_SELECTED_VALUE_STREAM';
-export const SET_SELECTED_STAGE = 'SET_SELECTED_STAGE';
-export const SET_DATE_RANGE = 'SET_DATE_RANGE';
-export const SET_PAGINATION = 'SET_PAGINATION';
-export const SET_NO_ACCESS_ERROR = 'SET_NO_ACCESS_ERROR';
-
-export const REQUEST_VALUE_STREAMS = 'REQUEST_VALUE_STREAMS';
-export const RECEIVE_VALUE_STREAMS_SUCCESS = 'RECEIVE_VALUE_STREAMS_SUCCESS';
-export const RECEIVE_VALUE_STREAMS_ERROR = 'RECEIVE_VALUE_STREAMS_ERROR';
-
-export const REQUEST_VALUE_STREAM_STAGES = 'REQUEST_VALUE_STREAM_STAGES';
-export const RECEIVE_VALUE_STREAM_STAGES_SUCCESS = 'RECEIVE_VALUE_STREAM_STAGES_SUCCESS';
-export const RECEIVE_VALUE_STREAM_STAGES_ERROR = 'RECEIVE_VALUE_STREAM_STAGES_ERROR';
-
-export const REQUEST_STAGE_DATA = 'REQUEST_STAGE_DATA';
-export const RECEIVE_STAGE_DATA_SUCCESS = 'RECEIVE_STAGE_DATA_SUCCESS';
-export const RECEIVE_STAGE_DATA_ERROR = 'RECEIVE_STAGE_DATA_ERROR';
-
-export const REQUEST_STAGE_MEDIANS = 'REQUEST_STAGE_MEDIANS';
-export const RECEIVE_STAGE_MEDIANS_SUCCESS = 'RECEIVE_STAGE_MEDIANS_SUCCESS';
-export const RECEIVE_STAGE_MEDIANS_ERROR = 'RECEIVE_STAGE_MEDIANS_ERROR';
-
-export const REQUEST_STAGE_COUNTS = 'REQUEST_STAGE_COUNTS';
-export const RECEIVE_STAGE_COUNTS_SUCCESS = 'RECEIVE_STAGE_COUNTS_SUCCESS';
-export const RECEIVE_STAGE_COUNTS_ERROR = 'RECEIVE_STAGE_COUNTS_ERROR';
diff --git a/app/assets/javascripts/cycle_analytics/store/mutations.js b/app/assets/javascripts/cycle_analytics/store/mutations.js
deleted file mode 100644
index 8567529caf2..00000000000
--- a/app/assets/javascripts/cycle_analytics/store/mutations.js
+++ /dev/null
@@ -1,112 +0,0 @@
-import Vue from 'vue';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import { PAGINATION_SORT_FIELD_END_EVENT, PAGINATION_SORT_DIRECTION_DESC } from '../constants';
-import { formatMedianValues } from '../utils';
-import * as types from './mutation_types';
-
-export default {
- [types.INITIALIZE_VSA](
- state,
- { endpoints, features, createdBefore, createdAfter, pagination = {} },
- ) {
- state.endpoints = endpoints;
- state.createdBefore = createdBefore;
- state.createdAfter = createdAfter;
- state.features = features;
-
- Vue.set(state, 'pagination', {
- page: pagination.page ?? state.pagination.page,
- sort: pagination.sort ?? state.pagination.sort,
- direction: pagination.direction ?? state.pagination.direction,
- });
- },
- [types.SET_LOADING](state, loadingState) {
- state.isLoading = loadingState;
- },
- [types.SET_SELECTED_VALUE_STREAM](state, selectedValueStream = {}) {
- state.selectedValueStream = convertObjectPropsToCamelCase(selectedValueStream, { deep: true });
- },
- [types.SET_SELECTED_STAGE](state, stage) {
- state.selectedStage = stage;
- },
- [types.SET_DATE_RANGE](state, { createdAfter, createdBefore }) {
- state.createdBefore = createdBefore;
- state.createdAfter = createdAfter;
- },
- [types.SET_PAGINATION](state, { page, hasNextPage, sort, direction }) {
- Vue.set(state, 'pagination', {
- page,
- hasNextPage,
- sort: sort || PAGINATION_SORT_FIELD_END_EVENT,
- direction: direction || PAGINATION_SORT_DIRECTION_DESC,
- });
- },
- [types.SET_NO_ACCESS_ERROR](state) {
- state.hasNoAccessError = true;
- },
- [types.REQUEST_VALUE_STREAMS](state) {
- state.valueStreams = [];
- },
- [types.RECEIVE_VALUE_STREAMS_SUCCESS](state, valueStreams = []) {
- state.valueStreams = valueStreams;
- },
- [types.RECEIVE_VALUE_STREAMS_ERROR](state) {
- state.valueStreams = [];
- },
- [types.REQUEST_VALUE_STREAM_STAGES](state) {
- state.stages = [];
- },
- [types.RECEIVE_VALUE_STREAM_STAGES_SUCCESS](state, { stages = [] }) {
- state.stages = stages.map((s) => convertObjectPropsToCamelCase(s, { deep: true }));
- },
- [types.RECEIVE_VALUE_STREAM_STAGES_ERROR](state) {
- state.stages = [];
- },
- [types.REQUEST_STAGE_DATA](state) {
- state.isLoadingStage = true;
- state.isEmptyStage = false;
- state.selectedStageEvents = [];
-
- state.hasNoAccessError = false;
- },
- [types.RECEIVE_STAGE_DATA_SUCCESS](state, events = []) {
- state.isLoadingStage = false;
- state.isEmptyStage = !events.length;
- state.selectedStageEvents = events.map((ev) =>
- convertObjectPropsToCamelCase(ev, { deep: true }),
- );
-
- state.hasNoAccessError = false;
- },
- [types.RECEIVE_STAGE_DATA_ERROR](state, error) {
- state.isLoadingStage = false;
- state.isEmptyStage = true;
- state.selectedStageEvents = [];
-
- state.selectedStageError = error;
- },
- [types.REQUEST_STAGE_MEDIANS](state) {
- state.medians = {};
- },
- [types.RECEIVE_STAGE_MEDIANS_SUCCESS](state, medians) {
- state.medians = formatMedianValues(medians);
- },
- [types.RECEIVE_STAGE_MEDIANS_ERROR](state) {
- state.medians = {};
- },
- [types.REQUEST_STAGE_COUNTS](state) {
- state.stageCounts = {};
- },
- [types.RECEIVE_STAGE_COUNTS_SUCCESS](state, stageCounts = []) {
- state.stageCounts = stageCounts.reduce(
- (acc, { id, count }) => ({
- ...acc,
- [id]: count,
- }),
- {},
- );
- },
- [types.RECEIVE_STAGE_COUNTS_ERROR](state) {
- state.stageCounts = {};
- },
-};
diff --git a/app/assets/javascripts/cycle_analytics/store/state.js b/app/assets/javascripts/cycle_analytics/store/state.js
deleted file mode 100644
index 8d662333afa..00000000000
--- a/app/assets/javascripts/cycle_analytics/store/state.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import {
- PAGINATION_SORT_FIELD_END_EVENT,
- PAGINATION_SORT_DIRECTION_DESC,
-} from '~/cycle_analytics/constants';
-
-export default () => ({
- id: null,
- features: {},
- endpoints: {},
- createdAfter: null,
- createdBefore: null,
- stages: [],
- analytics: [],
- valueStreams: [],
- selectedValueStream: {},
- selectedStage: {},
- selectedStageEvents: [],
- selectedStageError: '',
- medians: {},
- stageCounts: {},
- hasNoAccessError: false,
- isLoading: false,
- isLoadingStage: false,
- isEmptyStage: false,
- pagination: {
- page: null,
- hasNextPage: false,
- sort: PAGINATION_SORT_FIELD_END_EVENT,
- direction: PAGINATION_SORT_DIRECTION_DESC,
- },
-});
diff --git a/app/assets/javascripts/cycle_analytics/utils.js b/app/assets/javascripts/cycle_analytics/utils.js
deleted file mode 100644
index 428bb11b950..00000000000
--- a/app/assets/javascripts/cycle_analytics/utils.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import { parseSeconds } from '~/lib/utils/datetime_utility';
-import { formatTimeAsSummary } from '~/lib/utils/datetime/date_format_utility';
-
-/**
- * Takes the stages and median data, combined with the selected stage, to build an
- * array which is formatted to proivde the data required for the path navigation.
- *
- * @param {Array} stages - The stages available to the group / project
- * @param {Object} medians - The median values for the stages available to the group / project
- * @param {Object} stageCounts - The total item count for the stages available
- * @param {Object} selectedStage - The currently selected stage
- * @returns {Array} An array of stages formatted with data required for the path navigation
- */
-export const transformStagesForPathNavigation = ({
- stages,
- medians,
- stageCounts = {},
- selectedStage,
-}) => {
- const formattedStages = stages.map((stage) => {
- return {
- metric: medians[stage?.id],
- selected: stage?.id === selectedStage?.id, // Also could null === null cause an issue here?
- stageCount: stageCounts && stageCounts[stage?.id],
- icon: null,
- ...stage,
- };
- });
-
- return formattedStages;
-};
-
-/**
- * Takes a raw median value in seconds and converts it to a string representation
- * ie. converts 172800 => 2d (2 days)
- *
- * @param {Number} Median - The number of seconds for the median calculation
- * @returns {String} String representation ie 2w
- */
-export const medianTimeToParsedSeconds = (value) =>
- formatTimeAsSummary({
- ...parseSeconds(value, { daysPerWeek: 7, hoursPerDay: 24 }),
- seconds: value,
- });
-
-/**
- * Takes the raw median value arrays and converts them into a useful object
- * containing the string for display in the path navigation
- * ie. converts [{ id: 'test', value: 172800 }] => { 'test': '2d' }
- *
- * @param {Array} Medians - Array of stage median objects, each contains a `id`, `value` and `error`
- * @returns {Object} Returns key value pair with the stage name and its display median value
- */
-export const formatMedianValues = (medians = []) =>
- medians.reduce((acc, { id, value = 0 }) => {
- return {
- ...acc,
- [id]: value ? medianTimeToParsedSeconds(value) : '-',
- };
- }, {});
-
-export const filterStagesByHiddenStatus = (stages = [], isHidden = true) =>
- stages.filter(({ hidden = false }) => hidden === isHidden);
-
-/**
- * @typedef {Object} MetricData
- * @property {String} title - Title of the metric measured
- * @property {String} value - String representing the decimal point value, e.g '1.5'
- * @property {String} [unit] - String representing the decimal point value, e.g '1.5'
- *
- * @typedef {Object} TransformedMetricData
- * @property {String} label - Title of the metric measured
- * @property {String} value - String representing the decimal point value, e.g '1.5'
- * @property {String} identifier - Slugified string based on the 'title' or the provided 'identifier' attribute
- * @property {String} description - String to display for a description
- * @property {String} unit - String representing the decimal point value, e.g '1.5'
- */
-
-const extractFeatures = (gon) => ({
- cycleAnalyticsForGroups: Boolean(gon?.licensed_features?.cycleAnalyticsForGroups),
-});
-
-/**
- * Builds the initial data object for Value Stream Analytics with data loaded from the backend
- *
- * @param {Object} dataset - dataset object paseed to the frontend via data-* properties
- * @returns {Object} - The initial data to load the app with
- */
-export const buildCycleAnalyticsInitialData = ({
- fullPath,
- requestPath,
- projectId,
- groupId,
- groupPath,
- labelsPath,
- milestonesPath,
- stage,
- createdAfter,
- createdBefore,
- gon,
-} = {}) => {
- return {
- projectId: parseInt(projectId, 10),
- endpoints: {
- requestPath,
- fullPath,
- labelsPath,
- milestonesPath,
- groupId: parseInt(groupId, 10),
- groupPath,
- },
- createdAfter: new Date(createdAfter),
- createdBefore: new Date(createdBefore),
- selectedStage: stage ? JSON.parse(stage) : null,
- features: extractFeatures(gon),
- };
-};