Skip to content

Commit

Permalink
Implement QuotaModal component
Browse files Browse the repository at this point in the history
  • Loading branch information
JanAckermann committed Mar 3, 2022
1 parent 2976911 commit 046ed01
Show file tree
Hide file tree
Showing 8 changed files with 471 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
:cancel="closeReadmeContentModal"
:space="resources[0]"
></readme-content-modal>
<quota-modal
v-if="quotaModalIsOpen"
:cancel="closeQuotaModal"
:space="resources[0]"
></quota-modal>
<input
id="space-image-upload-input"
ref="spaceImageInput"
Expand Down Expand Up @@ -37,15 +42,26 @@ import Restore from '../../../mixins/spaces/actions/restore'
import EditDescription from '../../../mixins/spaces/actions/editDescription'
import EditReadmeContent from '../../../mixins/spaces/actions/editReadmeContent'
import UploadImage from '../../../mixins/spaces/actions/uploadImage'
import EditQuota from '../../../mixins/spaces/actions/editQuota'
import QuotaModal from '../../Spaces/QuotaModal.vue'
import ReadmeContentModal from '../../../components/Spaces/ReadmeContentModal.vue'
export default {
name: 'SpaceActions',
title: ($gettext) => {
return $gettext('Actions')
},
components: { ActionMenuItem, ReadmeContentModal },
mixins: [Rename, Delete, EditDescription, EditReadmeContent, Disable, Restore, UploadImage],
components: { ActionMenuItem, QuotaModal, ReadmeContentModal },
mixins: [
Rename,
Delete,
EditDescription,
EditReadmeContent,
Disable,
Restore,
UploadImage,
EditQuota
],
computed: {
...mapGetters('Files', ['highlightedFile']),
resources() {
Expand All @@ -57,18 +73,25 @@ export default {
...this.$_editDescription_items,
...this.$_uploadImage_items,
...this.$_editReadmeContent_items,
...this.$_editQuota_items,
...this.$_restore_items,
...this.$_delete_items,
...this.$_disable_items
].filter((item) => item.isEnabled({ resources: this.resources }))
},
readmeContentModalIsOpen() {
return this.$data.$_editReadmeContent_modalOpen
},
quotaModalIsOpen() {
return this.$data.$_editQuota_modalOpen
}
},
methods: {
closeReadmeContentModal() {
this.$_editReadmeContent_closeModal()
},
closeQuotaModal() {
this.$_editQuota_closeModal()
}
}
}
Expand Down
215 changes: 215 additions & 0 deletions packages/web-app-files/src/components/Spaces/QuotaModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
<template>
<portal to="app.runtime.modal">
<oc-modal
id="edit-quota-modal"
:title="modalTitle"
:button-cancel-text="$gettext('Cancel')"
:button-confirm-text="$gettext('Confirm')"
:button-confirm-disabled="confirmButtonDisabled"
@confirm="editQuota"
@cancel="cancel"
>
<template #content>
<oc-select
id="quota-input-select"
v-model="selectedOption"
:selectable="optionSelectable"
taggable
push-tags
:clearable="false"
:options="options"
:create-option="createOption"
option-label="displayValue"
:label="$gettext('Space quota')"
>
<template #selected-option="{ displayValue, displayUnit }">
<span>{{ displayValue }}</span>
<span v-if="displayUnit" class="oc-text-muted oc-ml-s">{{ displayUnit }}</span>
</template>
<template #search="{ attributes, events }">
<input class="vs__search" v-bind="attributes" v-on="events" />
</template>
<template #option="{ displayValue, displayUnit, error }">
<div class="oc-flex oc-flex-between">
<span>{{ displayValue }}</span>
<span v-if="displayUnit" class="oc-text-muted">{{ displayUnit }}</span>
</div>
<div v-if="error" class="oc-text-input-danger">{{ error }}</div>
</template>
</oc-select>
<p
class="oc-mt-xs oc-text-meta"
v-text="$gettext('Select an item or enter your own value')"
/>
</template>
</oc-modal>
</portal>
</template>

<script>
import { mapActions, mapGetters, mapMutations } from 'vuex'
import { clientService } from 'web-pkg/src/services'
export default {
name: 'SpaceQuotaModal',
props: {
space: {
type: Object,
required: true
},
cancel: {
type: Function,
required: true
}
},
data: function () {
return {
selectedOption: {},
options: [],
DEFAULT_OPTIONS: [
{
displayValue: '1',
displayUnit: 'GB',
value: Math.pow(10, 9)
},
{
displayValue: '5',
displayUnit: 'GB',
value: 5 * Math.pow(10, 9)
},
{
displayValue: '10',
displayUnit: 'GB',
value: 10 * Math.pow(10, 9)
},
{
displayValue: '50',
displayUnit: 'GB',
value: 50 * Math.pow(10, 9)
},
{
displayValue: '100',
displayUnit: 'GB',
value: 100 * Math.pow(10, 9)
},
{
displayValue: '500',
displayUnit: 'GB',
value: 500 * Math.pow(10, 9)
},
{
displayValue: '1000',
displayUnit: 'GB',
value: 10000 * Math.pow(10, 9)
}
]
}
},
computed: {
...mapGetters(['getToken', 'configuration']),
confirmButtonDisabled() {
return this.space.spaceQuota.total === this.selectedOption.value
},
modalTitle() {
return this.$gettextInterpolate(this.$gettext('Edit quota for space %{name}'), {
name: this.space.name
})
}
},
mounted() {
this.setOptions()
},
methods: {
...mapActions(['showMessage']),
...mapMutations('Files', ['UPDATE_RESOURCE_FIELD']),
editQuota() {
const newTotalQuota = this.selectedOption.value
if (isNaN(newTotalQuota)) {
return this.showMessage({
title: this.$gettext('Editing space quota failed…'),
status: 'danger'
})
}
const graphClient = clientService.graphAuthenticated(this.configuration.server, this.getToken)
return graphClient.drives
.updateDrive(this.space.id, { quota: { total: this.selectedOption.value } }, {})
.then(({ data }) => {
this.cancel()
this.UPDATE_RESOURCE_FIELD({
id: this.space.id,
field: 'spaceQuota',
value: data.quota
})
this.showMessage({
title: this.$gettext('Space quota was edited successfully')
})
})
.catch((error) => {
console.error(error)
this.showMessage({
title: this.$gettext('Failed to change space quota'),
desc: error,
status: 'danger'
})
})
},
optionSelectable(option) {
if (!option.value) {
return false
}
return !isNaN(option.value)
},
createOption(option) {
if (option.endsWith('.') || option.endsWith(',')) {
option = option.slice(0, -1)
}
const optionIsNumberRegex = /^[1-9]\d*(([.,])\d+)?$/g
if (!optionIsNumberRegex.test(option)) {
return {
displayValue: option,
error: this.$gettext('Please enter only numbers')
}
}
option = option.replace(',', '.')
return {
displayValue: parseFloat(option).toFixed(2).toString().replace('.00', ''),
displayUnit: 'GB',
value: parseFloat(option).toFixed(2) * Math.pow(10, 9)
}
},
setOptions() {
this.options = [...this.DEFAULT_OPTIONS]
const selectedQuotaInOptions = this.options.find(
(option) => option.value === this.space.spaceQuota.total
)
if (selectedQuotaInOptions) {
this.selectedOption = selectedQuotaInOptions
} else {
const newOption = {
displayValue: (this.space.spaceQuota.total * Math.pow(10, -9))
.toFixed(2)
.toString()
.replace('.00', ''),
displayUnit: 'GB',
value: this.space.spaceQuota.total
}
this.options.push(newOption)
this.options = [
...this.options.filter((o) => o.value).sort((a, b) => a.value - b.value),
...this.options.filter((o) => !o.value)
]
this.selectedOption = newOption
}
}
}
}
</script>
41 changes: 41 additions & 0 deletions packages/web-app-files/src/mixins/spaces/actions/editQuota.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { mapState } from 'vuex'

export default {
data: () => {
return {
$_editQuota_modalOpen: false
}
},
computed: {
...mapState('Files', ['currentFolder']),
$_editQuota_items() {
return [
{
name: 'editQuota',
icon: 'hard-drive',
label: () => {
return this.$gettext('Edit quota')
},
handler: this.$_editQuota_trigger,
isEnabled: ({ resources }) => {
if (resources.length !== 1) {
return false
}

return resources[0].spaceQuota
},
componentType: 'oc-button',
class: 'oc-files-actions-edit-quota-content-trigger'
}
]
}
},
methods: {
$_editQuota_trigger() {
this.$data.$_editQuota_modalOpen = true
},
$_editQuota_closeModal() {
this.$data.$_editQuota_modalOpen = false
}
}
}
16 changes: 14 additions & 2 deletions packages/web-app-files/src/views/spaces/Project.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
:cancel="closeReadmeContentModal"
:space="space"
></readme-content-modal>
<quota-modal v-if="quotaModalIsOpen" :cancel="closeQuotaModal" :space="space"></quota-modal>
<div
class="oc-grid oc-px-m oc-mt-m"
:class="{ 'oc-child-width-1-1@s': imageExpanded, 'oc-child-width-1-3@s': !imageExpanded }"
Expand Down Expand Up @@ -157,7 +158,9 @@ import Restore from '../../mixins/spaces/actions/restore'
import EditDescription from '../../mixins/spaces/actions/editDescription'
import ShowDetails from '../../mixins/spaces/actions/showDetails'
import UploadImage from '../../mixins/spaces/actions/uploadImage'
import EditQuota from '../../mixins/spaces/actions/editQuota'
import EditReadmeContent from '../../mixins/spaces/actions/editReadmeContent'
import QuotaModal from '../../components/Spaces/QuotaModal.vue'
import ReadmeContentModal from '../../components/Spaces/ReadmeContentModal.vue'
const visibilityObserver = new VisibilityObserver()
Expand All @@ -171,7 +174,8 @@ export default {
ListInfo,
Pagination,
ContextActions,
ReadmeContentModal
ReadmeContentModal,
QuotaModal
},
mixins: [
MixinAccessibleBreadcrumb,
Expand All @@ -184,7 +188,8 @@ export default {
ShowDetails,
Restore,
UploadImage,
EditReadmeContent
EditReadmeContent,
EditQuota
],
setup() {
const router = useRouter()
Expand Down Expand Up @@ -313,6 +318,9 @@ export default {
displayThumbnails() {
return !this.configuration.options.disablePreviews
},
quotaModalIsOpen() {
return this.$data.$_editQuota_modalOpen
},
readmeContentModalIsOpen() {
return this.$data.$_editReadmeContent_modalOpen
}
Expand Down Expand Up @@ -419,6 +427,7 @@ export default {
...this.$_editDescription_items,
...this.$_editReadmeContent_items,
...this.$_uploadImage_items,
...this.$_editQuota_items,
...this.$_restore_items,
...this.$_delete_items,
...this.$_disable_items,
Expand Down Expand Up @@ -471,6 +480,9 @@ export default {
isResourceInSelection(resource) {
return this.selected?.includes(resource)
},
closeQuotaModal() {
this.$_editQuota_closeModal()
},
closeReadmeContentModal() {
this.$_editReadmeContent_closeModal()
}
Expand Down
Loading

0 comments on commit 046ed01

Please sign in to comment.