Skip to content
代码片段 群组 项目
提交 e4bddbf3 编辑于 作者: Jose Ivan Vargas's avatar Jose Ivan Vargas
浏览文件

Merge branch '424966-frontend-add-the-readme-tab-with-the-current-content' into 'master'

No related branches found
No related tags found
无相关合并请求
显示
230 个添加28 个删除
<script>
import SafeHtml from '~/vue_shared/directives/safe_html';
import { GlTab, GlTabs } from '@gitlab/ui';
import { __ } from '~/locale';
import CiResourceReadme from './ci_resource_readme.vue';
export default {
directives: { SafeHtml },
components: {
CiResourceReadme,
GlTab,
GlTabs,
},
props: {
readmeHtml: {
required: true,
resourceId: {
type: String,
required: true,
},
},
i18n: {
tabs: {
readme: __('Readme'),
},
},
};
</script>
<template>
<div v-safe-html="readmeHtml"></div>
<gl-tabs>
<gl-tab :title="$options.i18n.tabs.readme" lazy>
<ci-resource-readme :resource-id="resourceId" />
</gl-tab>
</gl-tabs>
</template>
<style></style>
......@@ -72,7 +72,7 @@ export default {
};
</script>
<template>
<div class="gl-border-b">
<div>
<ci-resource-header-skeleton-loader v-if="isLoadingSharedData" class="gl-py-5" />
<div v-else class="gl-display-flex gl-py-5">
<gl-avatar-link :href="resource.webPath">
......
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import { createAlert } from '~/alert';
import { __ } from '~/locale';
import SafeHtml from '~/vue_shared/directives/safe_html';
import getCiCatalogResourceReadme from '../../graphql/queries/get_ci_catalog_resource_readme.query.graphql';
export default {
components: {
GlLoadingIcon,
},
directives: { SafeHtml },
props: {
resourceId: {
type: String,
required: true,
},
},
data() {
return {
readmeHtml: null,
};
},
apollo: {
readmeHtml: {
query: getCiCatalogResourceReadme,
variables() {
return {
id: this.resourceId,
};
},
update(data) {
return data?.ciCatalogResource?.readmeHtml || null;
},
error() {
createAlert({ message: this.$options.i18n.loadingError });
},
},
},
computed: {
isLoading() {
return this.$apollo.queries.readmeHtml.loading;
},
},
i18n: {
loadingError: __("There was a problem loading this project's readme content."),
},
};
</script>
<template>
<div>
<gl-loading-icon v-if="isLoading" class="gl-mt-5" size="lg" />
<div v-else v-safe-html="readmeHtml"></div>
</div>
</template>
<script>
import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import { GlEmptyState } from '@gitlab/ui';
import { s__ } from '~/locale';
import { createAlert } from '~/alert';
import { convertToGraphQLId } from '~/graphql_shared/utils';
......@@ -14,7 +14,6 @@ export default {
CiResourceDetails,
CiResourceHeader,
GlEmptyState,
GlLoadingIcon,
},
inject: ['ciCatalogPath'],
data() {
......@@ -104,8 +103,7 @@ export default {
:pipeline-status="pipelineStatus"
:resource="resourceSharedData"
/>
<gl-loading-icon v-if="isLoadingDetails" size="lg" class="gl-mt-5" />
<ci-resource-details v-else :readme-html="resourceAdditionalDetails.readmeHtml" />
<ci-resource-details :resource-id="graphQLId" />
</div>
</div>
</template>
query getCiCatalogResourceDetails($id: CiCatalogResourceID!) {
ciCatalogResource(id: $id) {
id
readmeHtml
openIssuesCount
openMergeRequestsCount
versions(first: 1) {
......
query getCiCatalogResourceReadme($id: CiCatalogResourceID!) {
ciCatalogResource(id: $id) {
id
readmeHtml
}
}
import { GlTabs, GlTab } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import CiResourceDetails from 'ee/ci/catalog/components/details/ci_resource_details.vue';
import CiResourceReadme from 'ee/ci/catalog/components/details/ci_resource_readme.vue';
describe('CiResourceDetails', () => {
let wrapper;
const defaultProps = { readmeHtml: '<h1>Hello world</h1>' };
const defaultProps = {
resourceId: 'gid://gitlab/Ci::Catalog::Resource/1',
};
const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMount(CiResourceDetails, {
......@@ -12,16 +16,37 @@ describe('CiResourceDetails', () => {
...defaultProps,
...props,
},
stubs: {
GlTabs,
},
});
};
const findAllTabs = () => wrapper.findAllComponents(GlTab);
const findCiResourceReadme = () => wrapper.findComponent(CiResourceReadme);
beforeEach(() => {
createComponent();
});
describe('tabs', () => {
it('renders the right number of tabs', () => {
expect(findAllTabs()).toHaveLength(1);
});
it('renders the readme tab as default', () => {
expect(findCiResourceReadme().exists()).toBe(true);
});
describe('when mounted', () => {
beforeEach(() => {
createComponent();
it('passes lazy attribute to all tabs', () => {
findAllTabs().wrappers.forEach((tab) => {
expect(tab.attributes().lazy).not.toBeUndefined();
});
});
it('renders the received HTML', () => {
expect(wrapper.html()).toContain(defaultProps.readmeHtml);
describe('readme tab', () => {
it('passes the right props to the readme component', () => {
expect(findCiResourceReadme().props().resourceId).toBe(defaultProps.resourceId);
});
});
});
});
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import CiResourceReadme from 'ee/ci/catalog/components/details/ci_resource_readme.vue';
import getCiCatalogResourceReadme from 'ee/ci/catalog/graphql/queries/get_ci_catalog_resource_readme.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
jest.mock('~/alert');
Vue.use(VueApollo);
const readmeHtml = '<h1>This is a readme file</h1>';
const resourceId = 'gid://gitlab/Ci::Catalog::Resource/1';
describe('CiResourceReadme', () => {
let wrapper;
let mockReadmeResponse;
const readmeMockData = {
data: {
ciCatalogResource: {
id: resourceId,
readmeHtml,
},
},
};
const defaultProps = { resourceId };
const createComponent = ({ props = {} } = {}) => {
const handlers = [[getCiCatalogResourceReadme, mockReadmeResponse]];
wrapper = shallowMountExtended(CiResourceReadme, {
propsData: {
...defaultProps,
...props,
},
apolloProvider: createMockApollo(handlers),
});
};
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
beforeEach(() => {
mockReadmeResponse = jest.fn();
});
describe('when loading', () => {
beforeEach(() => {
mockReadmeResponse.mockResolvedValue(readmeMockData);
createComponent();
});
it('renders only a loading icon', () => {
expect(findLoadingIcon().exists()).toBe(true);
expect(wrapper.html()).not.toContain(readmeHtml);
});
});
describe('when mounted', () => {
beforeEach(async () => {
mockReadmeResponse.mockResolvedValue(readmeMockData);
createComponent();
await waitForPromises();
});
it('renders only the received HTML', () => {
expect(findLoadingIcon().exists()).toBe(false);
expect(wrapper.html()).toContain(readmeHtml);
});
it('does not render an error', () => {
expect(createAlert).not.toHaveBeenCalled();
});
});
describe('when there is an error loading the readme', () => {
beforeEach(async () => {
mockReadmeResponse.mockRejectedValue({ errors: [] });
createComponent();
await waitForPromises();
});
it('calls the createAlert function to show an error', () => {
expect(createAlert).toHaveBeenCalled();
expect(createAlert).toHaveBeenCalledWith({
message: "There was a problem loading this project's readme content.",
});
});
});
});
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import VueRouter from 'vue-router';
import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import { GlEmptyState } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { cacheConfig } from 'ee/ci/catalog/graphql/settings';
import { CI_CATALOG_RESOURCE_TYPE, cacheConfig } from 'ee/ci/catalog/graphql/settings';
import getCiCatalogResourceSharedData from 'ee/ci/catalog/graphql/queries/get_ci_catalog_resource_shared_data.query.graphql';
import getCiCatalogResourceDetails from 'ee/ci/catalog/graphql/queries/get_ci_catalog_resource_details.query.graphql';
......@@ -17,6 +17,7 @@ import CiResourceHeaderSkeletonLoader from 'ee/ci/catalog/components/details/ci_
import { createRouter } from 'ee/ci/catalog/router/index';
import { CI_RESOURCE_DETAILS_PAGE_NAME } from 'ee/ci/catalog/router/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { catalogSharedDataMock, catalogAdditionalDetailsMock } from '../../mock';
Vue.use(VueApollo);
......@@ -41,7 +42,6 @@ describe('CiResourceDetailsPage', () => {
const findDetailsComponent = () => wrapper.findComponent(CiResourceDetails);
const findHeaderComponent = () => wrapper.findComponent(CiResourceHeader);
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findHeaderSkeletonLoader = () => wrapper.findComponent(CiResourceHeaderSkeletonLoader);
const createComponent = ({ props = {} } = {}) => {
......@@ -89,8 +89,7 @@ describe('CiResourceDetailsPage', () => {
createComponent();
});
it('renders only the details loading state', () => {
expect(findLoadingIcon().exists()).toBe(true);
it('renders the header skeleton loader', () => {
expect(findHeaderSkeletonLoader().exists()).toBe(false);
});
......@@ -111,11 +110,11 @@ describe('CiResourceDetailsPage', () => {
createComponent();
});
it('renders all loading states', () => {
expect(findLoadingIcon().exists()).toBe(true);
it('does not render the header skeleton', () => {
expect(findHeaderSkeletonLoader().exists()).toBe(false);
});
it('passes down the loading state to the header component', () => {
it('passes all loading state to the header component as true', () => {
expect(findHeaderComponent().props()).toMatchObject({
isLoadingDetails: true,
isLoadingSharedData: true,
......@@ -150,8 +149,8 @@ describe('CiResourceDetailsPage', () => {
await waitForPromises();
});
it('does not render a loading icon', () => {
expect(findLoadingIcon().exists()).toBe(false);
it('does not render the header skeleton loader', () => {
expect(findHeaderSkeletonLoader().exists()).toBe(false);
});
describe('Catalog header', () => {
......@@ -179,7 +178,7 @@ describe('CiResourceDetailsPage', () => {
it('passes expected props', () => {
expect(findDetailsComponent().props()).toEqual({
readmeHtml: defaultAdditionalData.readmeHtml,
resourceId: convertToGraphQLId(CI_CATALOG_RESOURCE_TYPE, defaultAdditionalData.id),
});
});
});
......
......@@ -74,6 +74,7 @@ describe('CiResourcesPage', () => {
await createComponent();
});
it('renders the empty state', () => {
expect(findLoadingState().exists()).toBe(false);
expect(findEmptyState().exists()).toBe(true);
......
......@@ -38757,6 +38757,9 @@ msgstr ""
msgid "Read their documentation."
msgstr ""
 
msgid "Readme"
msgstr ""
msgid "Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project."
msgstr ""
 
......@@ -48003,6 +48006,9 @@ msgstr ""
msgid "There was a problem handling the pipeline data."
msgstr ""
 
msgid "There was a problem loading this project's readme content."
msgstr ""
msgid "There was a problem sending the confirmation email"
msgstr ""
 
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册