Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e4a589d
Create ChannelVersion model with token support
taoerman Dec 3, 2025
66f50b7
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 3, 2025
31039f6
fix linting
taoerman Dec 3, 2025
82dad0f
fix code
taoerman Dec 4, 2025
7743900
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 4, 2025
50f0355
fix code
taoerman Dec 4, 2025
64311a2
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 4, 2025
50398cf
fix code
taoerman Dec 4, 2025
17c9e4c
fix code
taoerman Dec 4, 2025
4819470
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 4, 2025
2573dcd
fix test
taoerman Dec 4, 2025
3339633
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 4, 2025
2a4e5ef
fix bug
taoerman Dec 5, 2025
54867ca
Merge branch 'issue-5460-Create-ChannelVersion-model-with-token-suppo…
taoerman Dec 5, 2025
4b73ac1
fix bug
taoerman Dec 5, 2025
33e0391
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 5, 2025
e355fb1
fix code
taoerman Dec 5, 2025
9792dab
fix code
taoerman Dec 5, 2025
ca6856f
Merge branch 'unstable' into issue-5460-Create-ChannelVersion-model-w…
taoerman Dec 5, 2025
b213fd0
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 5, 2025
609e651
fix code
taoerman Dec 6, 2025
9c1fa51
fix linting
taoerman Dec 6, 2025
a7c0245
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 6, 2025
458cc76
fix linting
taoerman Dec 6, 2025
a3c2798
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Dec 6, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,10 @@ const nonPublishedChannel = {
};

const publishedData = {
2: {
included_languages: ['en', null],
included_licenses: [1],
included_categories: [Categories.SCHOOL],
},
1: {
included_languages: ['en', null],
included_licenses: [1],
included_categories: [Categories.SCHOOL],
},
version: 2,
included_languages: ['en', null],
included_licenses: [1],
included_categories: [Categories.SCHOOL],
};

const submittedLatestSubmission = { channel_version: 2, status: CommunityLibraryStatus.PENDING };
Expand Down Expand Up @@ -149,7 +143,7 @@ describe('SubmitToCommunityLibrarySidePanel', () => {
it('when channel is not published', async () => {
const wrapper = await makeWrapper({
channel: nonPublishedChannel,
publishedData: {},
publishedData: null,
latestSubmission: null,
});

Expand Down Expand Up @@ -301,12 +295,10 @@ describe('SubmitToCommunityLibrarySidePanel', () => {

const channel = { ...publishedNonPublicChannel, publishing: true };
const publishedDataWithVersion3 = {
...publishedData,
3: {
included_languages: ['en', null],
included_licenses: [1],
included_categories: [Categories.SCHOOL],
},
version: 3,
included_languages: ['en', null],
included_licenses: [1],
included_categories: [Categories.SCHOOL],
};
const wrapper = await makeWrapper({
channel,
Expand Down Expand Up @@ -434,7 +426,7 @@ describe('SubmitToCommunityLibrarySidePanel', () => {
it('when channel is not published', async () => {
const wrapper = await makeWrapper({
channel: nonPublishedChannel,
publishedData: {},
publishedData: null,
latestSubmission: null,
});

Expand Down Expand Up @@ -470,7 +462,7 @@ describe('SubmitToCommunityLibrarySidePanel', () => {
it('when channel is not published', async () => {
const wrapper = await makeWrapper({
channel: nonPublishedChannel,
publishedData: {},
publishedData: null,
latestSubmission: null,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,19 @@ export function useLicenseAudit(channelRef, channelVersionRef) {
}

return (
'community_library_invalid_licenses' in versionData &&
'community_library_special_permissions' in versionData
'non_distributable_licenses_included' in versionData &&
'special_permissions_included' in versionData
);
});

const invalidLicenses = computed(() => {
const versionData = currentVersionData.value;
return versionData?.community_library_invalid_licenses || [];
return versionData?.non_distributable_licenses_included || [];
});

const specialPermissions = computed(() => {
const versionData = currentVersionData.value;
return versionData?.community_library_special_permissions || [];
return versionData?.special_permissions_included || [];
});

const includedLicenses = computed(() => {
Expand Down Expand Up @@ -123,5 +123,6 @@ export function useLicenseAudit(channelRef, channelVersionRef) {
checkAndTriggerAudit,
triggerAudit,
fetchPublishedData,
currentVersionData,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { useFetch } from '../../../../composables/useFetch';
import { Channel } from 'shared/data/resources';

export function usePublishedData(channelId) {
return useFetch({ asyncFetchFunc: () => Channel.getPublishedData(channelId) });
return useFetch({ asyncFetchFunc: () => Channel.getVersionDetail(channelId) });
Copy link
Member

Choose a reason for hiding this comment

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

Just noting that we should also update this here to use the new info (since this would directly return the latestPublishedData object).

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed, Thanks!

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const ITEMS_PER_PAGE = 3;
* Reactive state for the fetched, flattened permissions and pagination
* helpers used by `SpecialPermissionsList.vue`.
*/
export function useSpecialPermissions(permissionIds) {
export function useSpecialPermissions(channelVersionId, permissionIds) {
Copy link
Member

Choose a reason for hiding this comment

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

Here we don't actually need the permissionIds anymore, since now the only identifier needed to fetch these special permissions will be the channelVersionId.

const permissions = ref([]);
const isLoading = ref(false);
const error = ref(null);
Expand All @@ -39,20 +39,24 @@ export function useSpecialPermissions(permissionIds) {
return permissions.value.slice(start, end);
});

async function fetchPermissions(ids) {
if (!ids || ids.length === 0) {
permissions.value = [];
return;
}

async function fetchPermissions(versionId, ids) {
isLoading.value = true;
error.value = null;
permissions.value = [];

try {
const response = await AuditedSpecialPermissionsLicense.fetchCollection({
by_ids: ids.join(','),
distributable: false,
});
let response = [];
if (versionId) {
response = await AuditedSpecialPermissionsLicense.fetchCollection({
channel_version: versionId,
distributable: false,
});
} else if (ids && ids.length > 0) {
response = await AuditedSpecialPermissionsLicense.fetchCollection({
by_ids: ids.join(','),
distributable: false,
});
}
Comment on lines +49 to +59
Copy link
Member

Choose a reason for hiding this comment

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

We can just provide support for the versionId filter. If we need the ids filter in the future, we can reimplement this, but for now, it wouldn't be needed!


permissions.value = response.map(permission => ({
id: permission.id,
Expand All @@ -79,18 +83,10 @@ export function useSpecialPermissions(permissionIds) {
}
}

const resolvedPermissionIds = computed(() => {
const ids = unref(permissionIds);
if (!ids || ids.length === 0) {
return [];
}
return ids;
});

watch(
resolvedPermissionIds,
ids => {
fetchPermissions(ids);
[() => unref(channelVersionId), () => unref(permissionIds)],
([versionId, ids]) => {
fetchPermissions(versionId, ids);
},
{ immediate: true },
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@
<SpecialPermissionsList
v-if="licenseAuditIsFinished && specialPermissions.length > 0"
v-model="checkedSpecialPermissions"
:permissionIds="specialPermissions"
:channel-version-id="versionDetail && versionDetail.id"
:permission-ids="specialPermissions"
Copy link
Member

Choose a reason for hiding this comment

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

Just a note that since right now, we don't return the permissionIds anymore in https://github.com/learningequality/studio/pull/5589/files#diff-ec56ff797d006d93cd91d7ececcc9d801eb660f39d34edebeae499ad1c64a39bR902, then we won't have this specialPermissions defined at this point. Now the channelVersionId will be the reference point to fetch the special permissions descriptions.

Copy link
Member

Choose a reason for hiding this comment

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

Also note that in the useLicenseAudit.js we are still using the getPublishedData. And this will fail because this method no longer exists in the ChannelResource.

@update:allChecked="allSpecialPermissionsChecked = $event"
/>
<div class="country-area">
Expand Down Expand Up @@ -417,17 +418,15 @@
const {
isLoading: publishedDataIsLoading,
isFinished: publishedDataIsFinished,
data: publishedData,
data: versionDetail,
fetchData: fetchPublishedData,
} = usePublishedData(props.channel.id);
// Use the latest version available from either channel or publishedData
// Use the latest version available from either channel or versionDetail
const displayedVersion = computed(() => {
const channelVersion = currentChannelVersion.value || 0;
if (publishedData.value && Object.keys(publishedData.value).length > 0) {
const publishedVersions = Object.keys(publishedData.value).map(v => parseInt(v, 10));
const maxPublishedVersion = Math.max(...publishedVersions);
return Math.max(channelVersion, maxPublishedVersion);
if (versionDetail.value && versionDetail.value.version) {
return Math.max(channelVersion, versionDetail.value.version);
}
return channelVersion;
});
Expand Down Expand Up @@ -465,11 +464,6 @@
return conditions.every(condition => condition);
});
const latestPublishedData = computed(() => {
if (!publishedData.value || !displayedVersion.value) return undefined;
return publishedData.value[displayedVersion.value];
});
// Watch for when publishing completes - fetch publishedData to get the new version's data
watch(isPublishing, async (newIsPublishing, oldIsPublishing) => {
if (oldIsPublishing === true && newIsPublishing === false) {
Expand All @@ -488,11 +482,7 @@
});
const detectedLanguages = computed(() => {
// We need to filter out null values due to a backend bug
// causing null values to sometimes be included in the list
const languageCodes = latestPublishedData.value?.included_languages.filter(
code => code !== null,
);
const languageCodes = versionDetail.value?.included_languages;
// We distinguish here between "not loaded yet" (undefined)
// and "loaded and none present" (null). This distinction is
Expand All @@ -502,7 +492,7 @@
if (!languageCodes) return undefined;
if (languageCodes.length === 0) return null;
return languageCodes.map(code => LanguagesMap.get(code).readable_name).join(', ');
return languageCodes.map(code => LanguagesMap.get(code)?.readable_name || code).join(', ');
Copy link
Member

Choose a reason for hiding this comment

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

Were there some invalid languages or languages whose readable_name was undefined?

});
function categoryIdToName(categoryId) {
Expand All @@ -515,10 +505,10 @@
// not used in the UI and is mostly intended to convey the
// state more accurately to the developer in case of debugging.
// UI code should rely on XXXIsLoading and XXXIsFinished instead.
if (!latestPublishedData.value?.included_categories) return undefined;
if (latestPublishedData.value.included_categories.length === 0) return null;
if (!versionDetail.value?.included_categories) return undefined;
if (versionDetail.value.included_categories.length === 0) return null;
return latestPublishedData.value.included_categories
return versionDetail.value.included_categories
.map(categoryId => categoryIdToName(categoryId))
.join(', ');
});
Expand All @@ -544,7 +534,7 @@
description: description.value,
channel: props.channel.id,
countries: countries.value.map(country => countriesUtil.getAlpha2Code(country, 'en')),
categories: latestPublishedData.value.included_categories,
categories: versionDetail.value.included_categories,
})
.then(() => {
showSnackbar({ text: submittedSnackbar$() });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
totalPages,
nextPage,
previousPage,
} = useSpecialPermissions(props.permissionIds);
} = useSpecialPermissions(props.channelVersionId, props.permissionIds);

function togglePermission(permissionId) {
const currentChecked = [...props.value];
Expand Down Expand Up @@ -128,6 +128,11 @@
};
},
props: {
channelVersionId: {
type: String,
required: false,
default: null,
},
permissionIds: {
type: Array,
required: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1412,8 +1412,8 @@ export const Channel = new CreateModelResource({
.then(response => response.data.languages);
return uniq(compact(localLanguages.concat(remoteLanguages)));
},
async getPublishedData(id) {
const response = await client.get(window.Urls.channel_published_data(id));
async getVersionDetail(id) {
const response = await client.get(window.Urls.channel_version_detail(id));
return response.data;
},
async auditLicenses(id) {
Expand Down
Loading