Skip to content

Commit 79cb4cc

Browse files
Merge remote-tracking branch 'upstream/master' into GH-7121
2 parents c682189 + 577984b commit 79cb4cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+217290
-97032
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ Install the software stack and Chamilo using the commands below.
5959
apt update && apt -y upgrade
6060
apt install -y apache2 libapache2-mod-php mariadb-client mariadb-server redis php-pear php-{apcu,bcmath,cli,curl,dev,gd,intl,ldap,mbstring,mysql,redis,soap,xml,zip} git unzip curl certbot
6161
mysql -e "GRANT ALL PRIVILEGES ON chamilo2.* TO chamilo2@localhost IDENTIFIED BY 'chamilo2';"
62-
cd /var/www && wget https://github.com/chamilo/chamilo-lms/releases/download/v2.0.0-alpha.2/chamilo-2.0.0-alpha.2.tar.gz
63-
tar zxf chamilo-2.0.0-alpha.2.tar.gz
64-
mv chamilo-2.0.0-alpha.2 chamilo
62+
cd /var/www && wget https://github.com/chamilo/chamilo-lms/releases/download/v2.0.0-beta.1/chamilo-2.0.0-beta.1.tar.gz
63+
tar zxf chamilo-2.0.0-beta.1.tar.gz
64+
mv chamilo-2.0.0-beta.1 chamilo
6565
cd chamilo
6666
cp public/main/install/apache.dist.conf /etc/apache2/sites-available/my.chamilo.net.conf
6767
a2ensite my.chamilo.net

assets/vue/components/Breadcrumb.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ watchEffect(() => {
303303
const toolBase = matchedRoutes[0]
304304
const currentMatched = matchedRoutes[matchedRoutes.length - 1]
305305
306-
let toolLabel = formatToolName(mainToolName)
306+
let toolLabel = toolBase.meta?.breadcrumb || formatToolName(mainToolName)
307+
307308
if (mainToolName === "ccalendarevent") {
308309
const cid = Number(route.query?.cid || 0)
309310
const gid = Number(route.query?.gid || 0)

assets/vue/components/lp/LpCategorySection.vue

Lines changed: 159 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,43 +22,60 @@ const props = defineProps({
2222
buildDates: { type: Function, required: false },
2323
})
2424
const emit = defineEmits([
25-
"open","edit","report","settings","build",
26-
"toggle-visible","toggle-publish","delete",
27-
"export-scorm","export-pdf",
28-
"reorder","toggle-auto-launch",
25+
"open",
26+
"edit",
27+
"report",
28+
"settings",
29+
"build",
30+
"toggle-visible",
31+
"toggle-publish",
32+
"delete",
33+
"export-scorm",
34+
"export-pdf",
35+
"reorder",
36+
"toggle-auto-launch",
2937
])
3038
3139
const displayTitle = computed(() => props.title || t("Learning path categories"))
3240
3341
const localList = ref([...(props.list ?? [])])
3442
const dragging = ref(false)
3543
36-
watch(() => props.list, (nv) => {
37-
if (dragging.value) return
38-
localList.value = [...(nv ?? [])]
39-
}, { immediate: true })
44+
watch(
45+
() => props.list,
46+
(nv) => {
47+
if (dragging.value) return
48+
localList.value = [...(nv ?? [])]
49+
},
50+
{ immediate: true },
51+
)
4052
4153
function onEndCat() {
4254
dragging.value = false
43-
emit("reorder", localList.value.map(i => i.iid))
55+
emit(
56+
"reorder",
57+
localList.value.map((i) => i.iid),
58+
)
4459
}
4560
4661
const route = useRoute()
47-
const cid = computed(() => Number(route.query?.cid ?? 0) || undefined)
48-
const sid = computed(() => Number(route.query?.sid ?? 0) || undefined)
62+
const cid = computed(() => Number(route.query?.cid ?? 0) || undefined)
63+
const sid = computed(() => Number(route.query?.sid ?? 0) || undefined)
4964
const node = computed(() => Number(route.params?.node ?? 0) || undefined)
5065
5166
const goCat = (action, extraParams = {}) => {
5267
const url = lpService.buildLegacyActionUrl(action, {
53-
cid: cid.value, sid: sid.value, node: node.value,
68+
cid: cid.value,
69+
sid: sid.value,
70+
node: node.value,
5471
params: { id: props.category.iid, ...extraParams },
5572
})
5673
window.location.assign(url)
5774
}
58-
const onCatEdit = () => goCat("add_lp_category")
59-
const onCatAddUsers = () => goCat("add_users_to_category")
75+
const onCatEdit = () => goCat("add_lp_category")
76+
const onCatAddUsers = () => goCat("add_users_to_category")
6077
const onCatToggleVisibility = () => {
61-
const vis = props.category.visibility ?? props.category.visible
78+
const vis = props.category.visibility ?? props.category.visible
6279
const next = typeof vis === "number" ? (vis ? 0 : 1) : 1
6380
goCat("toggle_category_visibility", { new_status: next })
6481
}
@@ -70,6 +87,12 @@ const onCatTogglePublish = () => {
7087
goCat("toggle_category_publish", { new_status: next })
7188
}
7289
const onCatDelete = () => {
90+
// Do not allow deletion if category is not empty
91+
if (localList.value.length > 0) {
92+
alert(t("You must move or remove all learning paths from this category before deleting it."))
93+
return
94+
}
95+
7396
const label = (props.category.title || "").trim() || t("Category")
7497
const msg = `${t("Are you sure you want to delete")} ${label}?`
7598
if (confirm(msg)) {
@@ -83,41 +106,82 @@ onMounted(() => {
83106
const saved = localStorage.getItem(storageKey.value)
84107
if (saved !== null) isOpen.value = saved === "1"
85108
})
86-
watch(isOpen, v => localStorage.setItem(storageKey.value, v ? "1" : "0"))
109+
watch(isOpen, (v) => localStorage.setItem(storageKey.value, v ? "1" : "0"))
87110
const panelId = computed(() => `cat-panel-${props.category?.iid || props.title}`)
88-
const toggleOpen = () => { if (localList.value.length) isOpen.value = !isOpen.value }
89-
function onChangeCat() {
90-
emit("reorder", localList.value.map(i => i.iid))
111+
const toggleOpen = () => {
112+
if (localList.value.length) isOpen.value = !isOpen.value
91113
}
92114
</script>
93115
94116
<template>
95117
<section class="relative ml-2 rounded-2xl shadow-lg">
96118
<header class="relative bg-support-6 rounded-t-2xl flex items-center justify-between pl-0 pr-4 py-3">
97-
<span class="pointer-events-none absolute inset-y-0 -left-1.5 w-1.5 bg-support-5 rounded-l-2xl" aria-hidden />
119+
<span
120+
class="pointer-events-none absolute inset-y-0 -left-1.5 w-1.5 bg-support-5 rounded-l-2xl"
121+
aria-hidden
122+
/>
98123
<div class="flex items-center gap-3">
99124
<template v-if="canEdit">
100125
<button
101126
class="w-8 h-8 grid place-content-center rounded-lg text-gray-50 hover:bg-gray-15 hover:text-gray-90"
102-
:title="t('Drag to reorder')" :aria-label="t('Drag to reorder')"
127+
:title="t('Drag to reorder')"
128+
:aria-label="t('Drag to reorder')"
103129
>
104-
<svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" aria-hidden>
105-
<circle cx="4" cy="3" r="1.2" /><circle cx="4" cy="7" r="1.2" /><circle cx="4" cy="11" r="1.2" />
106-
<circle cx="10" cy="3" r="1.2" /><circle cx="10" cy="7" r="1.2" /><circle cx="10" cy="11" r="1.2" />
130+
<svg
131+
width="14"
132+
height="14"
133+
viewBox="0 0 14 14"
134+
fill="currentColor"
135+
aria-hidden
136+
>
137+
<circle
138+
cx="4"
139+
cy="3"
140+
r="1.2"
141+
/>
142+
<circle
143+
cx="4"
144+
cy="7"
145+
r="1.2"
146+
/>
147+
<circle
148+
cx="4"
149+
cy="11"
150+
r="1.2"
151+
/>
152+
<circle
153+
cx="10"
154+
cy="3"
155+
r="1.2"
156+
/>
157+
<circle
158+
cx="10"
159+
cy="7"
160+
r="1.2"
161+
/>
162+
<circle
163+
cx="10"
164+
cy="11"
165+
r="1.2"
166+
/>
107167
</svg>
108168
</button>
109169
</template>
110170
<template v-else>
111-
<span class="inline-block w-8 h-8" aria-hidden></span>
171+
<span
172+
class="inline-block w-8 h-8"
173+
aria-hidden
174+
></span>
112175
</template>
113176
114177
<h2 class="text-body-1 font-semibold text-gray-90">{{ displayTitle }}</h2>
115178
</div>
116179
117180
<div class="flex items-center gap-2">
118-
<div class="text-tiny text-gray-50">{{ localList.length }} {{ t('Learning paths') }}</div>
181+
<div class="text-tiny text-gray-50">{{ localList.length }} {{ t("Learning paths") }}</div>
119182
120-
<BaseDropdownMenu v-if="canEdit"
183+
<BaseDropdownMenu
184+
v-if="canEdit"
121185
:dropdown-id="`category-${category.iid}`"
122186
class="relative z-30"
123187
>
@@ -127,18 +191,48 @@ function onChangeCat() {
127191
:title="t('Options')"
128192
:aria-label="t('Options')"
129193
>
130-
<i class="mdi mdi-dots-vertical text-lg" aria-hidden></i>
194+
<i
195+
class="mdi mdi-dots-vertical text-lg"
196+
aria-hidden
197+
></i>
131198
</span>
132199
</template>
133200
<template #menu>
134-
<div class="absolute right-0 top-full mt-2 w-60 bg-white border border-gray-25 rounded-xl shadow-xl p-1 z-50">
135-
<button class="w-full text-left px-3 py-2 rounded hover:bg-gray-15" @click="onCatEdit">{{ t('Edit category') }}</button>
136-
<button class="w-full text-left px-3 py-2 rounded hover:bg-gray-15" @click="onCatAddUsers">{{ t('Subscribe users to category') }}</button>
201+
<div
202+
class="absolute right-0 top-full mt-2 w-60 bg-white border border-gray-25 rounded-xl shadow-xl p-1 z-50"
203+
>
204+
<button
205+
class="w-full text-left px-3 py-2 rounded hover:bg-gray-15"
206+
@click="onCatEdit"
207+
>
208+
{{ t("Edit category") }}
209+
</button>
210+
<button
211+
class="w-full text-left px-3 py-2 rounded hover:bg-gray-15"
212+
@click="onCatAddUsers"
213+
>
214+
{{ t("Subscribe users to category") }}
215+
</button>
137216
<div class="my-1 h-px bg-gray-15"></div>
138-
<button class="w-full text-left px-3 py-2 rounded hover:bg-gray-15" @click="onCatToggleVisibility">{{ t('Toggle visibility') }}</button>
139-
<button class="w-full text-left px-3 py-2 rounded hover:bg-gray-15" @click="onCatTogglePublish">{{ t('Publish / Hide') }}</button>
217+
<button
218+
class="w-full text-left px-3 py-2 rounded hover:bg-gray-15"
219+
@click="onCatToggleVisibility"
220+
>
221+
{{ t("Toggle visibility") }}
222+
</button>
223+
<button
224+
class="w-full text-left px-3 py-2 rounded hover:bg-gray-15"
225+
@click="onCatTogglePublish"
226+
>
227+
{{ t("Publish / Hide") }}
228+
</button>
140229
<div class="my-1 h-px bg-gray-15"></div>
141-
<button class="w-full text-left px-3 py-2 rounded hover:bg-gray-15 text-danger" @click="onCatDelete">{{ t('Delete') }}</button>
230+
<button
231+
class="w-full text-left px-3 py-2 rounded hover:bg-gray-15 text-danger"
232+
@click="onCatDelete"
233+
>
234+
{{ t("Delete") }}
235+
</button>
142236
</div>
143237
</template>
144238
</BaseDropdownMenu>
@@ -151,16 +245,31 @@ function onChangeCat() {
151245
:title="t('Expand') / t('Collapse')"
152246
@click="toggleOpen"
153247
>
154-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
155-
class="transition-transform duration-200"
156-
:class="isOpen ? 'rotate-180' : ''">
157-
<path d="M6 9l6 6 6-6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
248+
<svg
249+
width="18"
250+
height="18"
251+
viewBox="0 0 24 24"
252+
fill="none"
253+
stroke="currentColor"
254+
class="transition-transform duration-200"
255+
:class="isOpen ? 'rotate-180' : ''"
256+
>
257+
<path
258+
d="M6 9l6 6 6-6"
259+
stroke-width="2"
260+
stroke-linecap="round"
261+
stroke-linejoin="round"
262+
/>
158263
</svg>
159264
</button>
160265
</div>
161266
</header>
162267
163-
<div v-if="isOpen && localList.length" :id="panelId" class="sm:px-4 sm:pb-4 px-2 pb-2 bg-white rounded-b-2xl">
268+
<div
269+
v-if="isOpen && localList.length"
270+
:id="panelId"
271+
class="sm:px-4 sm:pb-4 px-2 pb-2 bg-white rounded-b-2xl"
272+
>
164273
<Draggable
165274
v-model="localList"
166275
item-key="iid"
@@ -189,17 +298,17 @@ function onChangeCat() {
189298
:canExportPdf="canExportPdf"
190299
:canAutoLaunch="canAutoLaunch"
191300
:buildDates="buildDates"
192-
@toggle-auto-launch="$emit('toggle-auto-launch', element)"
193-
@open="$emit('open', element)"
194-
@edit="$emit('edit', element)"
195-
@report="$emit('report', element)"
196-
@settings="$emit('settings', element)"
197-
@build="$emit('build', element)"
198-
@toggle-visible="$emit('toggle-visible', element)"
199-
@toggle-publish="$emit('toggle-publish', element)"
200-
@delete="$emit('delete', element)"
201-
@export-scorm="$emit('export-scorm', element)"
202-
@export-pdf="$emit('export-pdf', element)"
301+
@toggle-auto-launch="$emit('toggle-auto-launch', element)"
302+
@open="$emit('open', element)"
303+
@edit="$emit('edit', element)"
304+
@report="$emit('report', element)"
305+
@settings="$emit('settings', element)"
306+
@build="$emit('build', element)"
307+
@toggle-visible="$emit('toggle-visible', element)"
308+
@toggle-publish="$emit('toggle-publish', element)"
309+
@delete="$emit('delete', element)"
310+
@export-scorm="$emit('export-scorm', element)"
311+
@export-pdf="$emit('export-pdf', element)"
203312
/>
204313
</template>
205314
</Draggable>

assets/vue/router/lp.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
export default {
22
path: "/resources/lp/:node(\\d+)",
3-
meta: { requiresAuth: true, showBreadcrumb: true },
43
name: "lp",
4+
meta: {
5+
requiresAuth: true,
6+
showBreadcrumb: true,
7+
breadcrumb: "Learning paths",
8+
},
59
component: () => import("../components/lp/LpLayout.vue"),
610
redirect: { name: "LpList" },
711
children: [
8-
{ name: "LpList", path: "", component: () => import("../views/lp/LpList.vue") },
12+
{
13+
name: "LpList",
14+
path: "",
15+
component: () => import("../views/lp/LpList.vue"),
16+
meta: {
17+
breadcrumb: "",
18+
},
19+
},
920
],
1021
}

assets/vue/services/courseService.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,12 @@ export default {
7373
* @returns {Promise<Object>}
7474
*/
7575
updateToolOrder: async (tool, newIndex, courseId, sessionId = 0) => {
76-
const { data } = await api.post(`/course/${courseId}/home.json?sid=${sessionId}`, {
76+
const payload = {
77+
toolId: tool.iid,
7778
index: newIndex,
78-
toolItem: tool,
79-
})
79+
}
80+
81+
const { data } = await api.post(`/course/${courseId}/home.json?sid=${sessionId}`, payload)
8082

8183
return data
8284
},

assets/vue/views/course/CourseHome.vue

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -444,18 +444,14 @@ watch(isSorting, (isSortingEnabled) => {
444444
})
445445
446446
async function updateDisplayOrder(htmlItem, newIndex) {
447-
const tool = htmlItem.dataset.tool
448-
let toolItem = null
449-
450-
if (typeof tools.value !== "undefined" && Array.isArray(tools.value)) {
451-
const toolList = tools.value
452-
toolItem = toolList.find((element) => element.title === tool)
453-
} else {
454-
console.error("Error: tools.value is undefined")
447+
const toolTitle = htmlItem.dataset.tool
448+
const toolItem = tools.value.find((element) => element.title === toolTitle)
449+
450+
if (!toolItem || !toolItem.iid) {
451+
console.error("[CourseHome] Tool item or iid missing", toolItem)
455452
return
456453
}
457454
458-
console.log(toolItem, newIndex)
459455
460456
// Send the updated values to the server
461457
await courseService.updateToolOrder(toolItem, newIndex, course.value.id, session.value?.id)

0 commit comments

Comments
 (0)