Replacing admin blocks (#5296)
	
		
	
				
					
				
			* Admin: Refactoring and improve index blocks #2642 * Admin: Include link to Colors page in the AdminBlocks response payload #2642 * Minor: Format code #2642 * Display: Add BaseDivider component #2642 * Internal: Add page categories for admin blocks #2642 * Admin: Allow edit blocks #2642snyk-fix-0707082af6333e258bba6802257d9315
							parent
							
								
									453cfc925a
								
							
						
					
					
						commit
						6e94642113
					
				@ -0,0 +1,25 @@ | 
				
			||||
.divider { | 
				
			||||
  @apply bg-white; | 
				
			||||
 | 
				
			||||
  &[aria-orientation="vertical"] { | 
				
			||||
    @apply before:absolute before:block before:left-1/2 before:top-0 before:h-full before:content-[""] before:border-l before:border-solid before:border-gray-25 | 
				
			||||
      flex min-h-full mx-2 py-2 relative justify-center; | 
				
			||||
 | 
				
			||||
    div { | 
				
			||||
      @apply first:py-2; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  &[aria-orientation="horizontal"] { | 
				
			||||
    @apply before:absolute before:block before:left-0 before:w-full before:top-1/2 before:content-[""] before:border-t before:border-solid before:border-gray-25 | 
				
			||||
      flex w-full relative items-center my-2 px-2; | 
				
			||||
 | 
				
			||||
    div { | 
				
			||||
      @apply first:px-2; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  div { | 
				
			||||
    @apply first:z-[1] first:bg-white first:text-gray-50 first:font-semibold first:text-caption; | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,102 @@ | 
				
			||||
<script setup> | 
				
			||||
import { ref } from "vue" | 
				
			||||
import { useI18n } from "vue-i18n" | 
				
			||||
import Inplace from "primevue/inplace" | 
				
			||||
import BaseTinyEditor from "../basecomponents/BaseTinyEditor.vue" | 
				
			||||
import { useSecurityStore } from "../../store/securityStore" | 
				
			||||
import pageService from "../../services/pageService" | 
				
			||||
import BaseDivider from "../basecomponents/BaseDivider.vue" | 
				
			||||
 | 
				
			||||
const props = defineProps({ | 
				
			||||
  id: { | 
				
			||||
    type: String, | 
				
			||||
    required: true, | 
				
			||||
  }, | 
				
			||||
  editable: { | 
				
			||||
    type: Boolean, | 
				
			||||
    required: true, | 
				
			||||
  }, | 
				
			||||
}) | 
				
			||||
 | 
				
			||||
const modelExtraContent = defineModel({ | 
				
			||||
  type: Object, | 
				
			||||
}) | 
				
			||||
 | 
				
			||||
const securityStore = useSecurityStore() | 
				
			||||
 | 
				
			||||
const { t, locale } = useI18n() | 
				
			||||
 | 
				
			||||
const newExtraContent = ref(modelExtraContent.value.content) | 
				
			||||
 | 
				
			||||
async function saveExtraContent() { | 
				
			||||
  if (modelExtraContent.value["@id"]) { | 
				
			||||
    if (!newExtraContent.value) { | 
				
			||||
      await pageService.delete(modelExtraContent.value["@id"]) | 
				
			||||
 | 
				
			||||
      modelExtraContent.value = { | 
				
			||||
        category: modelExtraContent.value.category, | 
				
			||||
      } | 
				
			||||
 | 
				
			||||
      return | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    const page = await pageService.update(modelExtraContent.value["@id"], { | 
				
			||||
      content: newExtraContent.value, | 
				
			||||
    }) | 
				
			||||
 | 
				
			||||
    modelExtraContent.value.content = page.content | 
				
			||||
 | 
				
			||||
    return | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  if (newExtraContent.value) { | 
				
			||||
    const page = await pageService.post({ | 
				
			||||
      title: props.id, | 
				
			||||
      content: newExtraContent.value, | 
				
			||||
      enabled: true, | 
				
			||||
      locale: locale.value, | 
				
			||||
      url: "/api/access_urls/" + window.access_url_id, | 
				
			||||
      creator: securityStore.user["@id"], | 
				
			||||
      category: modelExtraContent.value.category, | 
				
			||||
    }) | 
				
			||||
 | 
				
			||||
    modelExtraContent.value = { | 
				
			||||
      "@id": page["@id"], | 
				
			||||
      content: page.content, | 
				
			||||
      category: page.category["@id"], | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<template> | 
				
			||||
  <Inplace | 
				
			||||
    v-if="editable" | 
				
			||||
    :closable="true" | 
				
			||||
    @close="saveExtraContent" | 
				
			||||
  > | 
				
			||||
    <template #display> | 
				
			||||
      <BaseDivider | 
				
			||||
        align="right" | 
				
			||||
        :title="t('Editable content')" | 
				
			||||
      /> | 
				
			||||
      <div | 
				
			||||
        v-if="modelExtraContent.content" | 
				
			||||
        class="text-body-2" | 
				
			||||
        v-html="modelExtraContent.content" | 
				
			||||
      /> | 
				
			||||
    </template> | 
				
			||||
    <template #content> | 
				
			||||
      <BaseTinyEditor | 
				
			||||
        v-model="newExtraContent" | 
				
			||||
        :editor-id="'new-description-editor' + id" | 
				
			||||
        :full-page="false" | 
				
			||||
      /> | 
				
			||||
    </template> | 
				
			||||
  </Inplace> | 
				
			||||
  <div | 
				
			||||
    v-else-if="modelExtraContent.content" | 
				
			||||
    class="text-body-2" | 
				
			||||
    v-html="modelExtraContent.content" | 
				
			||||
  /> | 
				
			||||
</template> | 
				
			||||
@ -0,0 +1,32 @@ | 
				
			||||
<script setup> | 
				
			||||
import Divider from "primevue/divider" | 
				
			||||
 | 
				
			||||
defineProps({ | 
				
			||||
  align: { | 
				
			||||
    type: String, | 
				
			||||
    required: false, | 
				
			||||
    default: null, | 
				
			||||
  }, | 
				
			||||
  layout: { | 
				
			||||
    type: String, | 
				
			||||
    required: false, | 
				
			||||
    default: "horizontal", | 
				
			||||
  }, | 
				
			||||
  title: { | 
				
			||||
    type: [String, undefined], | 
				
			||||
    required: false, | 
				
			||||
    default: null, | 
				
			||||
  }, | 
				
			||||
}) | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<template> | 
				
			||||
  <Divider | 
				
			||||
    :align="align" | 
				
			||||
    :layout="layout" | 
				
			||||
    class="divider" | 
				
			||||
    unstyled | 
				
			||||
  > | 
				
			||||
    {{ title }} | 
				
			||||
  </Divider> | 
				
			||||
</template> | 
				
			||||
@ -0,0 +1,92 @@ | 
				
			||||
import { onMounted, ref } from "vue" | 
				
			||||
import { usePlatformConfig } from "../../store/platformConfig" | 
				
			||||
import adminService from "../../services/adminService" | 
				
			||||
import { useToast } from "primevue/usetoast" | 
				
			||||
import { useSecurityStore } from "../../store/securityStore" | 
				
			||||
import { useI18n } from "vue-i18n" | 
				
			||||
 | 
				
			||||
export function useIndexBlocks() { | 
				
			||||
  const { t } = useI18n() | 
				
			||||
 | 
				
			||||
  const toast = useToast() | 
				
			||||
 | 
				
			||||
  const platformConfigStore = usePlatformConfig() | 
				
			||||
  const securityStore = useSecurityStore() | 
				
			||||
 | 
				
			||||
  const blockVersionStatusEl = ref() | 
				
			||||
 | 
				
			||||
  onMounted(() => { | 
				
			||||
    if (!securityStore.isAdmin) { | 
				
			||||
      return | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if ("false" === platformConfigStore.getSetting("admin.admin_chamilo_announcements_disable")) { | 
				
			||||
      adminService.findAnnouncements().then((announcement) => toast.add({ severity: "info", detail: announcement })) | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if ("false" === platformConfigStore.getSetting("platform.registered")) { | 
				
			||||
      blockVersionStatusEl.value = null | 
				
			||||
    } else { | 
				
			||||
      loadVersion() | 
				
			||||
    } | 
				
			||||
  }) | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * @param {boolean} doNotListCampus | 
				
			||||
   */ | 
				
			||||
  function checkVersion(doNotListCampus) { | 
				
			||||
    adminService.registerCampus(doNotListCampus).then(() => { | 
				
			||||
      loadVersion() | 
				
			||||
 | 
				
			||||
      toast.add({ | 
				
			||||
        severity: "success", | 
				
			||||
        detail: t("Version check enabled"), | 
				
			||||
      }) | 
				
			||||
    }) | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  async function loadVersion() { | 
				
			||||
    blockVersionStatusEl.value = t("Loading") | 
				
			||||
 | 
				
			||||
    blockVersionStatusEl.value = await adminService.findVersion() | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  const blockUsers = ref(null) | 
				
			||||
  const blockCourses = ref(null) | 
				
			||||
  const blockSessions = ref(null) | 
				
			||||
  const blockGradebook = ref(null) | 
				
			||||
  const blockSkills = ref(null) | 
				
			||||
  const blockPrivacy = ref(null) | 
				
			||||
  const blockSettings = ref(null) | 
				
			||||
  const blockPlatform = ref(null) | 
				
			||||
  const blockChamilo = ref(null) | 
				
			||||
 | 
				
			||||
  async function loadBlocks() { | 
				
			||||
    const blocks = await adminService.findBlocks() | 
				
			||||
 | 
				
			||||
    blockUsers.value = blocks.users || null | 
				
			||||
    blockCourses.value = blocks.courses || null | 
				
			||||
    blockSessions.value = blocks.sessions || null | 
				
			||||
    blockGradebook.value = blocks.gradebook || null | 
				
			||||
    blockSkills.value = blocks.skills || null | 
				
			||||
    blockPrivacy.value = blocks.data_privacy || null | 
				
			||||
    blockSettings.value = blocks.settings || null | 
				
			||||
    blockPlatform.value = blocks.platform || null | 
				
			||||
    blockChamilo.value = blocks.chamilo || null | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  return { | 
				
			||||
    blockVersionStatusEl, | 
				
			||||
    checkVersion, | 
				
			||||
    blockUsers, | 
				
			||||
    blockCourses, | 
				
			||||
    blockSessions, | 
				
			||||
    blockGradebook, | 
				
			||||
    blockSkills, | 
				
			||||
    blockPrivacy, | 
				
			||||
    blockSettings, | 
				
			||||
    blockPlatform, | 
				
			||||
    blockChamilo, | 
				
			||||
    loadBlocks, | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,40 @@ | 
				
			||||
import axios from "axios" | 
				
			||||
 | 
				
			||||
export default { | 
				
			||||
  /** | 
				
			||||
   * @param {boolean} doNotListCampus | 
				
			||||
   * @returns {Promise<void>} | 
				
			||||
   */ | 
				
			||||
  registerCampus: async (doNotListCampus) => { | 
				
			||||
    await axios.post("/admin/register-campus", { | 
				
			||||
      donotlistcampus: doNotListCampus, | 
				
			||||
    }) | 
				
			||||
  }, | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * @returns {Promise<string>} | 
				
			||||
   */ | 
				
			||||
  findAnnouncements: async () => { | 
				
			||||
    const { data } = await axios.get("/main/inc/ajax/admin.ajax.php?a=get_latest_news") | 
				
			||||
 | 
				
			||||
    return data | 
				
			||||
  }, | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * @returns {Promise<string>} | 
				
			||||
   */ | 
				
			||||
  findVersion: async () => { | 
				
			||||
    const { data } = await axios.get("/main/inc/ajax/admin.ajax.php?a=version") | 
				
			||||
 | 
				
			||||
    return data | 
				
			||||
  }, | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * @returns {Promise<Object>} | 
				
			||||
   */ | 
				
			||||
  findBlocks: async () => { | 
				
			||||
    const { data } = await axios.get("/admin/index") | 
				
			||||
 | 
				
			||||
    return data | 
				
			||||
  }, | 
				
			||||
} | 
				
			||||
@ -0,0 +1,32 @@ | 
				
			||||
import api from "../config/api" | 
				
			||||
 | 
				
			||||
export default { | 
				
			||||
  /** | 
				
			||||
   * @param {Object} params | 
				
			||||
   * @returns {Promise<Object>} | 
				
			||||
   */ | 
				
			||||
  async post(params) { | 
				
			||||
    const { data } = await api.post("/api/pages", params) | 
				
			||||
 | 
				
			||||
    return data | 
				
			||||
  }, | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * @param {string} iri | 
				
			||||
   * @param {Object} params | 
				
			||||
   * @returns {Promise<Object>} | 
				
			||||
   */ | 
				
			||||
  async update(iri, params) { | 
				
			||||
    const { data } = await api.put(iri, params) | 
				
			||||
 | 
				
			||||
    return data | 
				
			||||
  }, | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * @param {string} iri | 
				
			||||
   * @returns {Promise<void>} | 
				
			||||
   */ | 
				
			||||
  async delete(iri) { | 
				
			||||
    await api.delete(iri) | 
				
			||||
  }, | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue