Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
<CommunityLibraryStatusButton
v-if="communityLibraryStatus"
:status="communityLibraryStatus"
@click="showReviewSubmissionPanel = true"
/>
<KEmptyPlaceholder v-else />
</td>
Expand All @@ -210,6 +211,11 @@
flat
/>
</td>
<ReviewSubmissionSidePanel
v-if="showReviewSubmissionPanel"
:channel="channel"
@close="showReviewSubmissionPanel = false"
/>
</tr>

</template>
Expand All @@ -219,6 +225,7 @@

import { mapGetters, mapActions } from 'vuex';
import ClipboardChip from '../../components/ClipboardChip';
import ReviewSubmissionSidePanel from '../../components/sidePanels/ReviewSubmissionSidePanel';
import CommunityLibraryStatusButton from '../../components/CommunityLibraryStatusButton.vue';
import { RouteNames } from '../../constants';
import ChannelActionsDropdown from './ChannelActionsDropdown';
Expand All @@ -233,6 +240,7 @@
ClipboardChip,
Checkbox,
CommunityLibraryStatusButton,
ReviewSubmissionSidePanel,
},
mixins: [fileSizeMixin],
props: {
Expand All @@ -245,6 +253,11 @@
required: true,
},
},
data() {
return {
showReviewSubmissionPanel: false,
};
},
computed: {
...mapGetters('channel', ['getChannel']),
selected: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { mount } from '@vue/test-utils';
import CommunityLibraryStatusButton from '../../../components/CommunityLibraryStatusButton.vue';
import ReviewSubmissionSidePanel from '../../../components/sidePanels/ReviewSubmissionSidePanel';
import router from '../../../router';
import { factory } from '../../../store';
import { RouteNames } from '../../../constants';
Expand Down Expand Up @@ -176,4 +177,18 @@ describe('channelItem', () => {
expect(statusButton.props('status')).toBe(CommunityLibraryStatus.REJECTED);
});
});

it('Clicking on the status button opens the review submission side panel', async () => {
wrapper.setData({ testedChannel: submittedChannel });
await wrapper.vm.$nextTick();

const statusCell = wrapper.find('[data-test="community-library-status"]');
const statusButton = statusCell.findComponent(CommunityLibraryStatusButton);

expect(wrapper.findComponent(ReviewSubmissionSidePanel).exists()).toBe(false);

await statusButton.trigger('click');

expect(wrapper.findComponent(ReviewSubmissionSidePanel).exists()).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import { factory } from '../../../../store';

import SubmitToCommunityLibrarySidePanel from '../';
import Box from '../Box.vue';
import StatusChip from '../StatusChip.vue';

import { usePublishedData } from '../composables/usePublishedData';
import { useLatestCommunityLibrarySubmission } from '../composables/useLatestCommunityLibrarySubmission';
import { useVersionDetail } from '../composables/useVersionDetail';
import { useLatestCommunityLibrarySubmission } from 'shared/composables/useLatestCommunityLibrarySubmission';
import CommunityLibraryStatusChip from 'shared/views/communityLibrary/CommunityLibraryStatusChip.vue';
import { Categories, CommunityLibraryStatus } from 'shared/constants';
import { communityChannelsStrings } from 'shared/strings/communityChannelsStrings';
import { CommunityLibrarySubmission } from 'shared/data/resources';
import CountryField from 'shared/views/form/CountryField.vue';

jest.mock('../composables/usePublishedData');
jest.mock('../composables/useLatestCommunityLibrarySubmission');
jest.mock('../composables/useVersionDetail');
jest.mock('../composables/useLicenseAudit');
jest.mock('shared/composables/useLatestCommunityLibrarySubmission');
jest.mock('shared/data/resources', () => ({
CommunityLibrarySubmission: {
create: jest.fn(() => Promise.resolve()),
Expand All @@ -40,7 +40,7 @@ async function makeWrapper({ channel, publishedData, latestSubmission }) {
store.state.currentChannel.currentChannelId = channel.id;
store.commit('channel/ADD_CHANNEL', channel);

usePublishedData.mockReturnValue({
useVersionDetail.mockReturnValue({
isLoading,
isFinished,
data: computed(() => publishedData),
Expand Down Expand Up @@ -377,7 +377,7 @@ describe('SubmitToCommunityLibrarySidePanel', () => {
latestSubmission: null,
});

const statusChip = wrapper.findAllComponents(StatusChip);
const statusChip = wrapper.findAllComponents(CommunityLibraryStatusChip);
expect(statusChip.exists()).toBe(false);
});

Expand All @@ -389,7 +389,7 @@ describe('SubmitToCommunityLibrarySidePanel', () => {
latestSubmission: { channel_version: 1, status: submissionStatus },
});

const statusChip = wrapper.findComponent(StatusChip);
const statusChip = wrapper.findComponent(CommunityLibraryStatusChip);
expect(statusChip.props('status')).toBe(chipStatus);
});
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useFetch } from '../../../../composables/useFetch';
import { useFetch } from 'shared/composables/useFetch';
import { Channel } from 'shared/data/resources';

export function usePublishedData(channelId) {
export function useVersionDetail(channelId) {
return useFetch({ asyncFetchFunc: () => Channel.getVersionDetail(channelId) });
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
{{ infoText }}
</template>
</div>
<StatusChip
<CommunityLibraryStatusChip
v-if="latestSubmissionStatus"
:status="latestSubmissionStatus"
class="status-chip"
Expand Down Expand Up @@ -118,8 +118,8 @@
class="metadata-line"
>
<LoadingText
:loading="publishedDataIsLoading"
:finishedLoading="publishedDataIsFinished"
:loading="versionDetailIsLoading"
:finishedLoading="versionDetailIsFinished"
:omitted="!detectedLanguages"
>
{{ detectedLanguages }}
Expand All @@ -130,8 +130,8 @@
class="metadata-line"
>
<LoadingText
:loading="publishedDataIsLoading"
:finishedLoading="publishedDataIsFinished"
:loading="versionDetailIsLoading"
:finishedLoading="versionDetailIsFinished"
:omitted="!detectedCategories"
>
{{ detectedCategories }}
Expand Down Expand Up @@ -245,14 +245,14 @@

import Box from './Box';
import LoadingText from './LoadingText';
import StatusChip from './StatusChip';
import { useLatestCommunityLibrarySubmission } from './composables/useLatestCommunityLibrarySubmission';
import { useLicenseAudit } from './composables/useLicenseAudit';
import { usePublishedData } from './composables/usePublishedData';
import { useVersionDetail } from './composables/useVersionDetail';

import InvalidLicensesNotice from './licenseCheck/InvalidLicensesNotice.vue';
import CompatibleLicensesNotice from './licenseCheck/CompatibleLicensesNotice.vue';
import SpecialPermissionsList from './licenseCheck/SpecialPermissionsList.vue';
import CommunityLibraryStatusChip from 'shared/views/communityLibrary/CommunityLibraryStatusChip';
import { useLatestCommunityLibrarySubmission } from 'shared/composables/useLatestCommunityLibrarySubmission';
import { translateMetadataString } from 'shared/utils/metadataStringsTranslation';
import countriesUtil from 'shared/utils/countries';
import { communityChannelsStrings } from 'shared/strings/communityChannelsStrings';
Expand All @@ -269,7 +269,7 @@
SidePanelModal,
Box,
LoadingText,
StatusChip,
CommunityLibraryStatusChip,
CountryField,
InvalidLicensesNotice,
CompatibleLicensesNotice,
Expand Down Expand Up @@ -330,7 +330,7 @@
isFinished: latestSubmissionIsFinished,
data: latestSubmissionData,
fetchData: fetchLatestSubmission,
} = useLatestCommunityLibrarySubmission(props.channel.id);
} = useLatestCommunityLibrarySubmission({ channelId: props.channel.id });

function countryCodeToName(code) {
return countriesUtil.getName(code, 'en');
Expand Down Expand Up @@ -416,11 +416,11 @@
});

const {
isLoading: publishedDataIsLoading,
isFinished: publishedDataIsFinished,
isLoading: versionDetailIsLoading,
isFinished: versionDetailIsFinished,
data: versionDetail,
fetchData: fetchPublishedData,
} = usePublishedData(props.channel.id);
fetchData: fetchVersionDetail,
} = useVersionDetail(props.channel.id);

// Use the latest version available from either channel or versionDetail
const displayedVersion = computed(() => {
Expand Down Expand Up @@ -453,7 +453,7 @@
!hasInvalidLicenses.value,
licenseAuditIsFinished.value,
canBeEdited.value,
publishedDataIsFinished.value,
versionDetailIsFinished.value,
description.value.length >= 1,
];

Expand All @@ -467,7 +467,7 @@
// Watch for when publishing completes - fetch publishedData to get the new version's data
watch(isPublishing, async (newIsPublishing, oldIsPublishing) => {
if (oldIsPublishing === true && newIsPublishing === false) {
await fetchPublishedData();
await fetchVersionDetail();
await checkAndTriggerLicenseAudit();
}
});
Expand All @@ -476,7 +476,7 @@
await fetchLatestSubmission();

if (!isPublishing.value) {
await fetchPublishedData();
await fetchVersionDetail();
await checkAndTriggerLicenseAudit();
}
});
Expand Down Expand Up @@ -575,8 +575,8 @@
canBeEdited,
displayedVersion,
canBeSubmitted,
publishedDataIsLoading,
publishedDataIsFinished,
versionDetailIsLoading,
versionDetailIsFinished,
detectedLanguages,
detectedCategories,
licenseAuditIsLoading,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useLatestCommunityLibrarySubmission } from '../useLatestCommunityLibrarySubmission';
import { CommunityLibrarySubmission } from 'shared/data/resources';

const mockResponse = {
results: [],
};

jest.mock('shared/data/resources', () => {
return {
CommunityLibrarySubmission: {
fetchCollection: jest.fn(() => Promise.resolve(mockResponse)),
fetchCollectionAsAdmin: jest.fn(() => Promise.resolve(mockResponse)),
},
};
});

describe('useLatestCommunityLibrarySubmission', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('by default uses non-admin endpoint', async () => {
const { fetchData } = useLatestCommunityLibrarySubmission({ channelId: 'channel-id' });
await fetchData();

expect(CommunityLibrarySubmission.fetchCollection).toHaveBeenCalled();
expect(CommunityLibrarySubmission.fetchCollectionAsAdmin).not.toHaveBeenCalled();
});

it('uses admin endpoint when initialized with admin=true', async () => {
const { fetchData } = useLatestCommunityLibrarySubmission({
channelId: 'channel-id',
admin: true,
});
await fetchData();

expect(CommunityLibrarySubmission.fetchCollection).not.toHaveBeenCalled();
expect(CommunityLibrarySubmission.fetchCollectionAsAdmin).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export function useFetch({ asyncFetchFunc }) {
data.value = await asyncFetchFunc();
isLoading.value = false;
isFinished.value = true;
} catch (error) {
error.value = error;
throw error;
} catch (caughtError) {
error.value = caughtError;
throw caughtError;
} finally {
isLoading.value = false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useFetch } from './useFetch';
import { CommunityLibrarySubmission } from 'shared/data/resources';

export function useLatestCommunityLibrarySubmission({ channelId, admin = false }) {
const fetchSubmissionFunc = admin
? params => CommunityLibrarySubmission.fetchCollectionAsAdmin(params)
: params => CommunityLibrarySubmission.fetchCollection(params);

function fetchLatestSubmission() {
// Submissions are ordered by most recent first in the backend
return fetchSubmissionFunc({ channel: channelId, max_results: 1 }).then(response => {
if (response.results.length > 0) {
return response.results[0];
}
return null;
});
}
return useFetch({
asyncFetchFunc: fetchLatestSubmission,
});
}
8 changes: 8 additions & 0 deletions contentcuration/contentcuration/frontend/shared/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,11 @@ export const CommunityLibraryStatus = {
SUPERSEDED: 'SUPERSEDED',
LIVE: 'LIVE',
};

export const CommunityLibraryResolutionReason = {
INVALID_LICENSING: 'INVALID_LICENSING',
TECHNICAL_QUALITY_ASSURANCE: 'TECHNICAL_QUALITY_ASSURANCE',
INVALID_METADATA: 'INVALID_METADATA',
PORTABILITY_ISSUES: 'PORTABILITY_ISSUES',
OTHER: 'OTHER',
};
14 changes: 14 additions & 0 deletions contentcuration/contentcuration/frontend/shared/data/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -2413,11 +2413,25 @@ export const CommunityLibrarySubmission = new APIResource({
return response.data || [];
});
},
fetchCollectionAsAdmin(params) {
return client
.get(window.Urls.adminCommunityLibrarySubmissionList(), { params })
.then(response => {
return response.data || [];
});
},
create(params) {
return client.post(this.collectionUrl(), params).then(response => {
return response.data;
});
},
resolveAsAdmin(id, params) {
return client
.post(window.Urls.adminCommunityLibrarySubmissionResolve(id), params)
.then(response => {
return response.data;
});
},
Comment on lines +2416 to +2434
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually map these resources to our Viewsets in Django, so it may be a better idea to have a AdminCommunityLibrarySubmissionResource here too.

Then on the submissions loading composable we can just do something like:

const resource = admin ? AdminCommunityLibrarySubmissionResource : CommunityLibrarySubmission;

resource.fetchCollection()...;

});

export const AuditedSpecialPermissionsLicense = new APIResource({
Expand Down
Loading