@@ -80,16 +94,29 @@ const ContainerRow = ({
/>
{title}
- {stateContext[2] ? (
-
-
-
+ {stateContext.message ? (
+
+
+
+
+ {stateContext.message2 && (
+
+
+
+ )}
+
) : (
)}
diff --git a/src/container-comparison/data/api.mock.ts b/src/container-comparison/data/api.mock.ts
index 49dccb95f..d68b564f8 100644
--- a/src/container-comparison/data/api.mock.ts
+++ b/src/container-comparison/data/api.mock.ts
@@ -32,7 +32,7 @@ export async function mockGetCourseContainerChildren(containerId: string): Promi
id: 'block-v1:UNIX+UX1+2025_T3+type@html+block@1',
name: 'Html block 11',
blockType: 'html',
- isModified: true,
+ downstreamCustomized: ['display_name'],
upstream: 'upstream-id',
}];
break;
@@ -44,14 +44,14 @@ export async function mockGetCourseContainerChildren(containerId: string): Promi
id: 'block-v1:UNIX+UX1+2025_T3+type@html+block@1',
name: 'Html block 11',
blockType: 'html',
- isModified: true,
+ downstreamCustomized: ['display_name'],
upstream: 'upstream-id',
},
{
id: 'block-v1:UNIX+UX1+2025_T3+type@html+block@2',
name: 'Html block 22',
blockType: 'html',
- isModified: true,
+ downstreamCustomized: ['display_name'],
upstream: 'upstream-id',
},
];
@@ -78,7 +78,7 @@ export async function mockGetCourseContainerChildren(containerId: string): Promi
versionSynced: 1,
versionAvailable: 2,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
}
));
@@ -107,7 +107,7 @@ mockGetCourseContainerChildren.childTemplate = {
versionSynced: 1,
versionAvailable: 2,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
};
/** Apply this mock. Returns a spy object that can tell you if it's been called. */
diff --git a/src/container-comparison/types.ts b/src/container-comparison/types.ts
index c546e0c48..e980279ed 100644
--- a/src/container-comparison/types.ts
+++ b/src/container-comparison/types.ts
@@ -1,6 +1,6 @@
import { UpstreamInfo } from '@src/data/types';
-export type ContainerState = 'removed' | 'added' | 'modified' | 'childrenModified' | 'locallyContentUpdated' | 'locallyRenamed' | 'moved';
+export type ContainerState = 'removed' | 'added' | 'modified' | 'childrenModified' | 'locallyContentUpdated' | 'locallyRenamed' | 'locallyRenamedAndContentUpdated' | 'moved';
export type WithState = T & { state?: ContainerState, originalName?: string };
export type WithIndex = T & { index: number };
diff --git a/src/container-comparison/utils.test.ts b/src/container-comparison/utils.test.ts
index 2b732b41e..42a36547c 100644
--- a/src/container-comparison/utils.test.ts
+++ b/src/container-comparison/utils.test.ts
@@ -2,7 +2,7 @@ import { ContainerChildBase, CourseContainerChildBase } from './types';
import { diffPreviewContainerChildren } from './utils';
export const getMockCourseContainerData = (
- type: 'added|deleted' | 'moved|deleted' | 'all',
+ type: 'added|deleted' | 'moved|deleted' | 'all' | 'locallyEdited',
): [CourseContainerChildBase[], ContainerChildBase[]] => {
switch (type) {
case 'moved|deleted':
@@ -17,7 +17,7 @@ export const getMockCourseContainerData = (
versionSynced: 11,
versionAvailable: 11,
versionDeclined: null,
- isModified: true,
+ downstreamCustomized: ['display_name'],
},
},
{
@@ -29,7 +29,7 @@ export const getMockCourseContainerData = (
versionSynced: 7,
versionAvailable: 7,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
{
@@ -41,7 +41,7 @@ export const getMockCourseContainerData = (
versionSynced: 2,
versionAvailable: 2,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
{
@@ -53,7 +53,7 @@ export const getMockCourseContainerData = (
versionSynced: 1,
versionAvailable: 1,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
],
@@ -87,7 +87,7 @@ export const getMockCourseContainerData = (
versionSynced: 11,
versionAvailable: 11,
versionDeclined: null,
- isModified: true,
+ downstreamCustomized: ['display_name'],
},
},
{
@@ -99,7 +99,7 @@ export const getMockCourseContainerData = (
versionSynced: 7,
versionAvailable: 7,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
{
@@ -111,7 +111,7 @@ export const getMockCourseContainerData = (
versionSynced: 2,
versionAvailable: 2,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
{
@@ -123,7 +123,7 @@ export const getMockCourseContainerData = (
versionSynced: 1,
versionAvailable: 1,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
],
@@ -162,7 +162,7 @@ export const getMockCourseContainerData = (
versionSynced: 11,
versionAvailable: 11,
versionDeclined: null,
- isModified: true,
+ downstreamCustomized: ['display_name'],
},
},
{
@@ -174,7 +174,7 @@ export const getMockCourseContainerData = (
versionSynced: 7,
versionAvailable: 7,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
{
@@ -186,7 +186,7 @@ export const getMockCourseContainerData = (
versionSynced: 2,
versionAvailable: 2,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
{
@@ -198,7 +198,7 @@ export const getMockCourseContainerData = (
versionSynced: 1,
versionAvailable: 1,
versionDeclined: null,
- isModified: false,
+ downstreamCustomized: [],
},
},
],
@@ -225,6 +225,64 @@ export const getMockCourseContainerData = (
},
],
] as [CourseContainerChildBase[], ContainerChildBase[]];
+ case 'locallyEdited':
+ return [
+ [
+ {
+ id: 'block-v1:UNIX+UX1+2025_T3+type@vertical+block@1',
+ name: 'Unit 1 remote edit - local edit',
+ blockType: 'vertical',
+ upstreamLink: {
+ upstreamRef: 'lct:UNIX:CS1:unit:unit-1-2a1741',
+ versionSynced: 11,
+ versionAvailable: 11,
+ versionDeclined: null,
+ downstreamCustomized: ['display_name'],
+ },
+ },
+ {
+ id: 'block-v1:UNIX+UX1+2025_T3+type@vertical+block@2',
+ name: 'New unit remote edit',
+ blockType: 'vertical',
+ upstreamLink: {
+ upstreamRef: 'lct:UNIX:CS1:unit:new-unit-remote-7eb9d1',
+ versionSynced: 7,
+ versionAvailable: 7,
+ versionDeclined: null,
+ downstreamCustomized: ['data'],
+ },
+ },
+ {
+ id: 'block-v1:UNIX+UX1+2025_T3+type@vertical+block@3',
+ name: 'Unit with tags - local edit',
+ blockType: 'vertical',
+ upstreamLink: {
+ upstreamRef: 'lct:UNIX:CS1:unit:unit-with-tags-bec5f9',
+ versionSynced: 2,
+ versionAvailable: 2,
+ versionDeclined: null,
+ downstreamCustomized: ['display_name', 'data'],
+ },
+ },
+ ],
+ [
+ {
+ id: 'lct:UNIX:CS1:unit:unit-1-2a1741',
+ displayName: 'Unit 1 remote edit - remote edit',
+ containerType: 'unit',
+ },
+ {
+ id: 'lct:UNIX:CS1:unit:new-unit-remote-7eb9d1',
+ displayName: 'New unit remote edit',
+ containerType: 'unit',
+ },
+ {
+ id: 'lct:UNIX:CS1:unit:unit-with-tags-bec5f9',
+ displayName: 'Unit with tags - remote edit',
+ containerType: 'unit',
+ },
+ ],
+ ] as [CourseContainerChildBase[], ContainerChildBase[]];
default:
throw new Error();
}
@@ -280,4 +338,22 @@ describe('diffPreviewContainerChildren', () => {
expect(result[1][2].state).toEqual('added');
expect(result[1][2].id).toEqual(result[0][2].id);
});
+
+ it('should handle locally edited content', () => {
+ const [a, b] = getMockCourseContainerData('locallyEdited');
+ const result = diffPreviewContainerChildren(a as CourseContainerChildBase[], b);
+ expect(result[0].length).toEqual(result[1].length);
+ // renamed
+ expect(result[0][0].state).toEqual('locallyRenamed');
+ expect(result[1][0].state).toEqual('locallyRenamed');
+ expect(result[1][0].id).toEqual(result[0][0].id);
+ // content updated
+ expect(result[0][1].state).toEqual('locallyContentUpdated');
+ expect(result[1][1].state).toEqual('locallyContentUpdated');
+ expect(result[1][1].id).toEqual(result[0][1].id);
+ // renamed and content updated
+ expect(result[0][2].state).toEqual('locallyRenamedAndContentUpdated');
+ expect(result[1][2].state).toEqual('locallyRenamedAndContentUpdated');
+ expect(result[1][2].id).toEqual(result[0][2].id);
+ });
});
diff --git a/src/container-comparison/utils.ts b/src/container-comparison/utils.ts
index 2d4ddb4d2..03382418b 100644
--- a/src/container-comparison/utils.ts
+++ b/src/container-comparison/utils.ts
@@ -54,26 +54,29 @@ export function diffPreviewContainerChildren 0) {
+ if (isRenamed) {
+ state = 'locallyRenamed';
+ originalName = newVersion.displayName;
+ }
+ if (isContentModified) {
+ state = 'locallyContentUpdated';
+ }
+ if (isRenamed && isContentModified) {
+ state = 'locallyRenamedAndContentUpdated';
+ }
} else if (checkIsReadyToSync(oldVersion.upstreamLink)) {
// has a new version ready to sync
state = 'modified';
diff --git a/src/course-outline/section-card/SectionCard.test.tsx b/src/course-outline/section-card/SectionCard.test.tsx
index 35e83057f..f2c37de59 100644
--- a/src/course-outline/section-card/SectionCard.test.tsx
+++ b/src/course-outline/section-card/SectionCard.test.tsx
@@ -74,6 +74,7 @@ const section = {
versionAvailable: 2,
versionDeclined: null,
errorMessage: null,
+ downstreamCustomized: [] as string[],
},
} satisfies Partial as XBlock;
diff --git a/src/course-outline/subsection-card/SubsectionCard.test.tsx b/src/course-outline/subsection-card/SubsectionCard.test.tsx
index 969852070..159f8bd5a 100644
--- a/src/course-outline/subsection-card/SubsectionCard.test.tsx
+++ b/src/course-outline/subsection-card/SubsectionCard.test.tsx
@@ -78,6 +78,7 @@ const subsection: XBlock = {
versionAvailable: 2,
versionDeclined: null,
errorMessage: null,
+ downstreamCustomized: [] as string[],
},
} satisfies Partial as XBlock;
diff --git a/src/course-outline/unit-card/UnitCard.test.tsx b/src/course-outline/unit-card/UnitCard.test.tsx
index e6f8c605c..c8282a273 100644
--- a/src/course-outline/unit-card/UnitCard.test.tsx
+++ b/src/course-outline/unit-card/UnitCard.test.tsx
@@ -68,6 +68,7 @@ const unit = {
versionAvailable: 2,
versionDeclined: null,
errorMessage: null,
+ downstreamCustomized: [] as string[],
},
} satisfies Partial as XBlock;
diff --git a/src/course-unit/data/types.ts b/src/course-unit/data/types.ts
index 99884cae5..6624dac89 100644
--- a/src/course-unit/data/types.ts
+++ b/src/course-unit/data/types.ts
@@ -43,7 +43,7 @@ export interface UpstreamReadyToSyncChildrenInfo {
name: string;
upstream: string;
blockType: string;
- isModified: boolean;
+ downstreamCustomized: string[];
}
export interface CourseContainerChildrenData {
diff --git a/src/data/types.ts b/src/data/types.ts
index 86df4cb40..4906c15c7 100644
--- a/src/data/types.ts
+++ b/src/data/types.ts
@@ -61,7 +61,7 @@ export interface UpstreamInfo {
versionAvailable: number | null,
versionDeclined: number | null,
errorMessage: string | null,
- isModified?: boolean,
+ downstreamCustomized: string[],
hasTopLevelParent?: boolean,
readyToSyncChildren?: UpstreamChildrenInfo[],
isReadyToSyncIndividually?: boolean,
diff --git a/src/studio-home/tabs-section/messages.ts b/src/studio-home/tabs-section/messages.ts
index efb2cc7f1..d69b196eb 100644
--- a/src/studio-home/tabs-section/messages.ts
+++ b/src/studio-home/tabs-section/messages.ts
@@ -118,7 +118,7 @@ const messages = defineMessages({
defaultMessage: 'Welcome to the new Content Libraries experience! Libraries have been redesigned'
+ ' from the ground up, making it much easier to reuse content. You can create, organize and manage'
+ ' new content, reuse your content in as many courses as you\'d like, publish updates, and create/randomize'
- + ' problem sets. See {link} for details.',
+ + ' Problem Banks. See {link} for details.',
description: 'Description for the alert message while there are no libraries pending migration on v2 tab.',
},
alertDescriptionV2MigrationPending: {