Skip to content

Commit

Permalink
Merge pull request #181 from ConductionNL/feature/IBOC-134/menu-items
Browse files Browse the repository at this point in the history
Menu Items support
SudoThijn authored Jan 29, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 2b9ed53 + 7962933 commit 69ea788
Showing 11 changed files with 855 additions and 106 deletions.
15 changes: 14 additions & 1 deletion src/entities/menu/menu.ts
Original file line number Diff line number Diff line change
@@ -48,7 +48,20 @@ export class Menu implements TMenu {
const schema = z.object({
name: z.string().min(1, 'naam is verplicht'),
position: z.number().min(0, 'positie moet 0 of hoger zijn'),
items: z.array(z.any()), // At least '[]'
items: z.array(z.object({
name: z.string().min(1, 'naam is verplicht'),
slug: z.string().min(1, 'slug is verplicht'),
link: z.string(),
description: z.string(),
icon: z.string(),
items: z.array(z.object({
name: z.string().min(1, 'naam is verplicht'),
slug: z.string().min(1, 'slug is verplicht'),
link: z.string(),
description: z.string(),
icon: z.string(),
})),
})), // At least '[]'
})

const result = schema.safeParse({
2 changes: 2 additions & 0 deletions src/eventBus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Vue from 'vue'
export const EventBus = new Vue()
11 changes: 10 additions & 1 deletion src/modals/Modals.vue
Original file line number Diff line number Diff line change
@@ -28,8 +28,11 @@ import { navigationStore, publicationStore } from './../store/store.js'
<PageForm v-if="navigationStore.modal === 'pageForm'" />
<DeletePage v-if="navigationStore.modal === 'deletePage'" />
<AddPageContentsModal v-if="navigationStore.modal === 'addPageContents'" />
<EditMenuModal />
<!-- Menu -->
<EditMenuModal v-if="navigationStore.modal === 'editMenu'" />
<DeleteMenuModal />
<EditMenuItemModal v-if="navigationStore.modal === 'editMenuItem'" />
<DeleteMenuItemModal v-if="navigationStore.modal === 'deleteMenuItem'" />
</div>
</template>

@@ -59,8 +62,11 @@ import EditThemeModal from './theme/EditThemeModal.vue'
import PageForm from './page/PageForm.vue'
import DeletePage from './page/DeletePage.vue'
import AddPageContentsModal from './pageContents/AddPageContents.vue'
// menu
import EditMenuModal from './menu/EditMenuModal.vue'
import DeleteMenuModal from './menu/DeleteMenuModal.vue'
import EditMenuItemModal from './menuItem/EditMenuItemModal.vue'
import DeleteMenuItemModal from './menuItem/DeleteMenuItemModal.vue'
/**
* Component that contains all modals used in the application
@@ -91,8 +97,11 @@ export default {
PageForm,
DeletePage,
AddPageContentsModal,
// menu
EditMenuModal,
DeleteMenuModal,
EditMenuItemModal,
DeleteMenuItemModal,
},
}
</script>
68 changes: 20 additions & 48 deletions src/modals/menu/EditMenuModal.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
<script setup>
import { navigationStore, menuStore } from '../../store/store.js'
import { getTheme } from '../../services/getTheme.js'
</script>

<template>
<NcDialog v-if="navigationStore.modal === 'editMenu'"
:name="menuStore.menuItem?.id ? 'Edit Menu' : 'Add Menu'"
<NcDialog :name="menuStore.menuItem?.id ? 'Edit Menu' : 'Add Menu'"
size="normal"
:can-close="false">
<NcNoteCard v-if="success" type="success">
@@ -43,30 +41,11 @@ import { getTheme } from '../../services/getTheme.js'
:value.sync="menuItem.name"
:error="!!inputValidation.fieldErrors?.['name']"
:helper-text="inputValidation.fieldErrors?.['name']?.[0]" />
<NcInputField
:disabled="loading"
label="Positie"
type="number"
:value.sync="menuItem.position"
:error="!!inputValidation.fieldErrors?.['position']"
:helper-text="inputValidation.fieldErrors?.['position']?.[0]" />
<div :class="`codeMirrorContainer ${getTheme()}`">
<CodeMirror
v-model="menuItem.items"
:basic="true"
placeholder="[{ &quot;key&quot;: &quot;value&quot; }]"
:dark="getTheme() === 'dark'"
:tab="true"
:gutter="true"
:linter="jsonParseLinter()"
:lang="json()" />
<NcButton class="prettifyButton" :disabled="!menuItem.items || !verifyJsonValidity(menuItem.items)" @click="prettifyJson">
<template #icon>
<AutoFix :size="20" />
</template>
Prettify
</NcButton>
</div>
<NcSelect v-bind="menuPositionOptions"
v-model="menuPositionOptions.value"
input-label="Positie"
:clearable="false"
:disabled="loading" />
</div>
</NcDialog>
</template>
@@ -77,16 +56,13 @@ import {
NcDialog,
NcLoadingIcon,
NcNoteCard,
NcInputField,
NcSelect,
NcTextField,
} from '@nextcloud/vue'
import CodeMirror from 'vue-codemirror6'
import { json, jsonParseLinter } from '@codemirror/lang-json'
import ContentSaveOutline from 'vue-material-design-icons/ContentSaveOutline.vue'
import Cancel from 'vue-material-design-icons/Cancel.vue'
import Plus from 'vue-material-design-icons/Plus.vue'
import AutoFix from 'vue-material-design-icons/AutoFix.vue'
import { Menu } from '../../entities/index.js'
@@ -101,7 +77,7 @@ export default {
NcLoadingIcon,
NcNoteCard,
NcTextField,
NcInputField,
NcSelect,
// Icons
ContentSaveOutline,
Cancel,
@@ -114,17 +90,25 @@ export default {
position: 0,
items: '',
},
menuPositionOptions: {
options: [
{ label: 'rechts boven', position: 0 },
{ label: 'navigatiebalk', position: 1 },
{ label: 'footer', position: 2 },
],
value: { label: 'rechts boven', position: 0 },
},
success: null,
loading: false,
error: false,
hasUpdated: false,
closeDialogTimeout: null,
}
},
computed: {
inputValidation() {
const menuItem = new Menu({
...this.menuItem,
position: this.menuPositionOptions.value?.position,
})
const result = menuItem.validate()
@@ -139,12 +123,6 @@ export default {
mounted() {
this.initializeMenuItem()
},
updated() {
if (navigationStore.modal === 'editMenu' && !this.hasUpdated) {
this.initializeMenuItem()
this.hasUpdated = true
}
},
methods: {
/**
* Initialize menu item data from store
@@ -155,6 +133,8 @@ export default {
...menuStore.menuItem,
items: typeof menuStore.menuItem.items === 'string' ? menuStore.menuItem.items : JSON.stringify(menuStore.menuItem.items, null, 2),
}
this.menuPositionOptions.value = this.menuPositionOptions.options.find((option) => option.position === menuStore.menuItem.position)
}
},
/**
@@ -163,15 +143,6 @@ export default {
closeModal() {
navigationStore.setModal(false)
clearTimeout(this.closeModalTimeout)
this.success = null
this.loading = false
this.error = false
this.hasUpdated = false
this.menuItem = {
name: '',
position: 0,
items: '',
}
},
/**
* Save menu item changes
@@ -182,6 +153,7 @@ export default {
const menuItem = new Menu({
...this.menuItem,
items: this.menuItem.items ? JSON.parse(this.menuItem.items) : [],
position: this.menuPositionOptions.value.position,
})
menuStore.saveMenu(menuItem).then(({ response }) => {
116 changes: 116 additions & 0 deletions src/modals/menuItem/DeleteMenuItemModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<script setup>
import { menuStore, navigationStore } from '../../store/store.js'
import { EventBus } from '../../eventBus.js'
</script>

<template>
<NcDialog name="Delete Menu Item"
size="normal"
:can-close="false">
<p v-if="success === null">
Weet je zeker dat je het menu item <b>{{ menuStore.menuItem?.items[menuStore.menuItemItemsIndex]?.name }}</b> wilt verwijderen? Dit kan niet ongedaan worden gemaakt.
</p>

<NcNoteCard v-if="success" type="success">
<p>Menu item succesvol verwijderd</p>
</NcNoteCard>
<NcNoteCard v-if="error" type="error">
<p>{{ error }}</p>
</NcNoteCard>

<template #actions>
<NcButton @click="closeModal">
<template #icon>
<Cancel :size="20" />
</template>
{{ success === null ? 'Cancel' : 'Close' }}
</NcButton>
<NcButton
v-if="success === null"
:disabled="loading"
type="error"
@click="deleteMenu()">
<template #icon>
<NcLoadingIcon v-if="loading" :size="20" />
<TrashCanOutline v-if="!loading" :size="20" />
</template>
Delete
</NcButton>
</template>
</NcDialog>
</template>

<script>
import {
NcButton,
NcDialog,
NcLoadingIcon,
NcNoteCard,
} from '@nextcloud/vue'
import _ from 'lodash'
import Cancel from 'vue-material-design-icons/Cancel.vue'
import TrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import { Menu } from '../../entities/index.js'
/**
* Component for deleting menu items
*/
export default {
name: 'DeleteMenuItemModal',
components: {
NcDialog,
NcButton,
NcLoadingIcon,
NcNoteCard,
// Icons
TrashCanOutline,
Cancel,
},
data() {
return {
success: null,
loading: false,
error: false,
closeModalTimeout: null,
}
},
methods: {
/**
* Closes the delete dialog and resets state
*/
closeModal() {
navigationStore.setModal(false)
clearTimeout(this.closeModalTimeout)
menuStore.menuItemItemsIndex = null
},
/**
* Deletes the selected menu item
*/
async deleteMenu() {
this.loading = true
const menuItemClone = _.cloneDeep(menuStore.menuItem)
menuItemClone.items.splice(menuStore.menuItemItemsIndex, 1)
const newMenuItem = new Menu(menuItemClone)
menuStore.saveMenu(newMenuItem)
.then(({ response }) => {
this.success = response.ok
this.error = false
response.ok && (this.closeModalTimeout = setTimeout(this.closeModal, 2000))
// Emit a specific event through the eventBus
// which gets picked up by the details page
EventBus.$emit('delete-menu-item-item-success')
}).catch((error) => {
this.success = false
this.error = error.message || 'An error occurred while deleting the menu'
}).finally(() => {
this.loading = false
})
},
},
}
</script>
Loading

0 comments on commit 69ea788

Please sign in to comment.