diff --git a/app/views/course/object_duplications/new.json.jbuilder b/app/views/course/object_duplications/new.json.jbuilder index 070191e3552..98036754a9d 100644 --- a/app/views/course/object_duplications/new.json.jbuilder +++ b/app/views/course/object_duplications/new.json.jbuilder @@ -16,7 +16,8 @@ json.destinationCourses @destination_courses do |course| end) end -json.destinationInstances @destination_instances do |instance| +sorted_destination_instances = @destination_instances.sort_by { |i| [i.id == current_tenant.id ? 0 : 1, i.name] } +json.destinationInstances sorted_destination_instances do |instance| json.id instance.id json.name instance.name json.host instance.host diff --git a/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/InstanceDropdown.tsx b/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/InstanceDropdown.tsx index 21c3fc789ba..df9a5e1a06d 100644 --- a/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/InstanceDropdown.tsx +++ b/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/InstanceDropdown.tsx @@ -3,9 +3,11 @@ import { ControllerFieldState, ControllerRenderProps, FieldValues, + UseFormSetValue, } from 'react-hook-form'; import { defineMessages, FormattedMessage } from 'react-intl'; -import { Autocomplete, Box } from '@mui/material'; +import MyLocation from '@mui/icons-material/MyLocation'; +import { Autocomplete, Box, IconButton, Tooltip } from '@mui/material'; import { selectDestinationInstances, @@ -14,59 +16,89 @@ import { import TextField from 'lib/components/core/fields/TextField'; import { formatErrorMessage } from 'lib/components/form/fields/utils/mapError'; import { useAppSelector } from 'lib/hooks/store'; +import useTranslation from 'lib/hooks/useTranslation'; interface InstanceDropdownProps { + currentInstanceId: number; disabled: boolean; field: ControllerRenderProps; fieldState: ControllerFieldState; + setValue: UseFormSetValue; } const translations = defineMessages({ destinationInstance: { id: 'course.duplication.Duplication.DestinationCourseSelector.InstanceDropdown.destinationInstance', - defaultMessage: 'Destination Instance', + defaultMessage: 'Destination instance', + }, + currentInstance: { + id: 'course.duplication.Duplication.DestinationCourseSelector.InstanceDropdown.currentInstance', + defaultMessage: 'Select current instance', }, }); const InstanceDropdown: FC = (props) => { - const { disabled, field, fieldState } = props; + const { currentInstanceId, disabled, field, fieldState, setValue } = props; const instances = useAppSelector(selectDestinationInstances); const metadata = useAppSelector(selectMetadata); - const instanceIds = useMemo(() => Object.keys(instances), [instances]); + const instanceIds = useMemo( + () => + Object.keys(instances).toSorted( + (a, b) => instances[a].weight - instances[b].weight, + ), + [instances], + ); + const { t } = useTranslation(); return ( - 1 - } - fullWidth - getOptionLabel={(instanceId): string => instances[instanceId]?.name ?? ''} - onChange={(_, instanceId): void => - field.onChange(parseInt(instanceId, 10)) - } - options={instanceIds} - renderInput={(inputProps): JSX.Element => ( - } - required - variant="standard" - /> - )} - renderOption={(optionProps, instanceId): JSX.Element => ( - - {instances[instanceId]?.name ?? ''} - - )} - value={field.value?.toString()} - /> +
+ + instances[instanceId]?.name ?? '' + } + onChange={(_, instanceId): void => + field.onChange(parseInt(instanceId, 10)) + } + options={instanceIds} + renderInput={(inputProps): JSX.Element => ( + } + required + variant="standard" + /> + )} + renderOption={(optionProps, instanceId): JSX.Element => ( + + {instances[instanceId]?.name ?? ''} + + )} + value={field.value?.toString()} + /> +
+ + + setValue('destination_instance_id', currentInstanceId) + } + > + + + +
+
); }; diff --git a/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/NewCourseForm.jsx b/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/NewCourseForm.jsx index b551053b04c..5e34c922e75 100644 --- a/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/NewCourseForm.jsx +++ b/client/app/bundles/course/duplication/pages/Duplication/DestinationCourseSelector/NewCourseForm.jsx @@ -38,6 +38,7 @@ const NewCourseForm = (props) => { handleSubmit, setError, formState: { errors }, + setValue, } = useForm({ mode: 'onSubmit', defaultValues: initialValues, @@ -56,9 +57,11 @@ const NewCourseForm = (props) => { name="destination_instance_id" render={({ field, fieldState }) => ( )} /> diff --git a/client/app/bundles/course/duplication/selectors/destinationInstance.ts b/client/app/bundles/course/duplication/selectors/destinationInstance.ts index 70effbd5767..8185d4702e0 100644 --- a/client/app/bundles/course/duplication/selectors/destinationInstance.ts +++ b/client/app/bundles/course/duplication/selectors/destinationInstance.ts @@ -8,7 +8,10 @@ const selectDuplicationStore = (state: AppState): any => state.duplication; export const selectDestinationInstances = createSelector( selectDuplicationStore, (duplicationStore) => - duplicationStore.destinationInstances as DuplicationInstanceListData[], + duplicationStore.destinationInstances as Record< + number, + DuplicationInstanceListData + >, ); export const selectMetadata = createSelector( diff --git a/client/app/bundles/course/duplication/store.js b/client/app/bundles/course/duplication/store.js index afe38da2147..02e9d1e69f8 100644 --- a/client/app/bundles/course/duplication/store.js +++ b/client/app/bundles/course/duplication/store.js @@ -1,5 +1,4 @@ import { produce } from 'immer'; -import { arrayToObjectWithKey } from 'utilities/array'; import actionTypes, { duplicationModes } from 'course/duplication/constants'; import { getEmptySelectedItems, nestFolders } from 'course/duplication/utils'; @@ -64,7 +63,12 @@ const reducer = produce((state, action) => { isLoading: false, currentCourseId: data.sourceCourse.id, destinationCourses: sortedDestinationCourses, - destinationInstances: arrayToObjectWithKey(destinationInstances, 'id'), + destinationInstances: Object.fromEntries( + destinationInstances.map((instance, index) => [ + instance.id, + { ...instance, weight: index }, + ]), + ), materialsComponent: nestedFolders, }; }