Skip to content

Commit

Permalink
Implement space actions (#6254)
Browse files Browse the repository at this point in the history
* Implement space create- and rename-actions
* Add delete action
* Add unit tests

Co-authored-by: Jan <jackermann@owncloud.com>
Co-authored-by: Pascal Wengerter <pwengerter@owncloud.com>
  • Loading branch information
3 people authored Jan 27, 2022
1 parent 1e7b1a1 commit 024ff8c
Show file tree
Hide file tree
Showing 9 changed files with 533 additions and 19 deletions.
10 changes: 10 additions & 0 deletions changelog/unreleased/enhancement-add-spaces-actions
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Enhancement: Add spaces actions

We added the following actions to the spaces overview:

* Create a new space
* Rename a space
* Delete a space

https://github.com/owncloud/web/pull/6254
https://github.com/owncloud/web/issues/6255
62 changes: 62 additions & 0 deletions packages/web-app-files/src/mixins/spaces/actions/delete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { mapActions } from 'vuex'

export default {
computed: {
$_delete_items() {
return [
{
name: 'delete',
icon: 'delete-bin-5',
label: () => {
return this.$gettext('Delete')
},
handler: this.$_delete_showModal,
isEnabled: () => true,
componentType: 'oc-button',
class: 'oc-files-actions-delete-trigger'
}
]
}
},
methods: {
...mapActions([
'createModal',
'hideModal',
'setModalInputErrorMessage',
'showMessage',
'toggleModalConfirmButton'
]),

$_delete_showModal(space) {
const modal = {
variation: 'danger',
title: this.$gettext('Delete space') + ' ' + space.name,
cancelText: this.$gettext('Cancel'),
confirmText: this.$gettext('Delete'),
icon: 'alarm-warning',
message: this.$gettext('Are you sure you want to delete this space?'),
hasInput: false,
onCancel: this.hideModal,
onConfirm: () => this.$_delete_deleteSpace(space.id)
}

this.createModal(modal)
},

$_delete_deleteSpace(id) {
return this.graph.drives
.deleteDrive(id)
.then(() => {
this.hideModal()
this.loadSpacesTask.perform(this)
})
.catch((error) => {
this.showMessage({
title: this.$gettext('Deleting space failed…'),
desc: error,
status: 'danger'
})
})
}
}
}
69 changes: 69 additions & 0 deletions packages/web-app-files/src/mixins/spaces/actions/rename.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { mapActions } from 'vuex'

export default {
computed: {
$_rename_items() {
return [
{
name: 'rename',
icon: 'edit',
label: () => {
return this.$gettext('Rename')
},
handler: this.$_rename_showModal,
isEnabled: () => true,
componentType: 'oc-button',
class: 'oc-files-actions-rename-trigger'
}
]
}
},
methods: {
...mapActions([
'createModal',
'hideModal',
'setModalInputErrorMessage',
'showMessage',
'toggleModalConfirmButton'
]),

$_rename_showModal(space) {
const modal = {
variation: 'passive',
title: this.$gettext('Rename space') + ' ' + space.name,
cancelText: this.$gettext('Cancel'),
confirmText: this.$gettext('Rename'),
hasInput: true,
inputLabel: this.$gettext('Space name'),
inputValue: space.name,
onCancel: this.hideModal,
onConfirm: (name) => this.$_rename_renameSpace(space.id, name),
onInput: this.$_rename_checkName
}

this.createModal(modal)
},

$_rename_checkName(name) {
if (name.trim() === '') {
this.setModalInputErrorMessage(this.$gettext('Space name cannot be empty'))
}
},

$_rename_renameSpace(id, name) {
return this.graph.drives
.updateDrive(id, { name }, {})
.then(() => {
this.hideModal()
this.loadSpacesTask.perform(this)
})
.catch((error) => {
this.showMessage({
title: this.$gettext('Renaming space failed…'),
desc: error,
status: 'danger'
})
})
}
}
}
134 changes: 125 additions & 9 deletions packages/web-app-files/src/views/spaces/Projects.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
<template>
<div class="oc-p-s">
<oc-button
v-if="hasCreatePermission"
id="new-space-menu-btn"
ref="createNewSpaceButton"
key="new-space-menu-btn-enabled"
:aria-label="$gettext('Create a new space')"
variation="primary"
appearance="filled"
class="oc-mb-xs"
data-testid="spaces-list-create-space-btn"
@click="showCreateSpaceModal"
>
<oc-icon name="add" />
<translate>Create Space</translate>
</oc-button>
<h2 v-text="$gettext('Spaces')" />
<span v-text="$gettext('Access all project related files in one place.')" />
<a href="#" v-text="$gettext('Learn more about spaces.')" />
Expand All @@ -18,7 +33,7 @@
</template>
</no-content-message>
<div v-else class="spaces-list">
<div
<ul
class="
oc-grid
oc-grid-match
Expand All @@ -28,18 +43,52 @@
oc-child-width-1-3@s
"
>
<a v-for="space in spaces" :key="space.id" href="#" class="oc-mb-m">
<span class="spaces-list-card oc-border oc-card oc-card-default">
<span class="oc-card-media-top oc-border-b">
<li v-for="space in spaces" :key="space.id" class="oc-mb-m">
<div class="spaces-list-card oc-border oc-card oc-card-default">
<div class="oc-card-media-top oc-border-b">
<oc-button
:id="`space-context-btn-${space.id}`"
v-oc-tooltip="$gettext('Show context menu')"
:aria-label="$gettext('Show context menu')"
class="oc-position-absolute oc-position-top-right oc-mr-s oc-mt-s"
>
<oc-icon name="more-2" />
</oc-button>
<oc-drop
:drop-id="`space-context-drop-${space.id}`"
:toggle="`#space-context-btn-${sanitizeSpaceId(space.id)}`"
mode="click"
close-on-click
:options="{ delayHide: 0 }"
padding-size="small"
position="bottom-end"
>
<ul class="oc-list oc-files-context-actions">
<li
v-for="(action, actionIndex) in contextMenuActions"
:key="`action-${actionIndex}`"
class="oc-spaces-context-action oc-py-xs oc-px-s"
>
<oc-button
appearance="raw"
justify-content="left"
@click="action.handler(space)"
>
<oc-icon :name="action.icon" />
{{ action.label() }}
</oc-button>
</li>
</ul>
</oc-drop>
<img v-if="space.image" :src="space.image" alt="" />
<oc-icon v-else name="layout-grid" size="xxlarge" class="oc-px-m oc-py-m" />
</span>
</div>
<span class="oc-card-body">
<span class="oc-card-title" v-text="space.name" />
<a href="#" class="oc-card-title" v-text="space.name" />
</span>
</span>
</a>
</div>
</div>
</li>
</ul>
</div>
</template>
</div>
Expand All @@ -52,12 +101,16 @@ import { client } from 'web-client'
import { ref } from '@vue/composition-api'
import { useStore } from 'web-pkg/src/composables'
import { useTask } from 'vue-concurrency'
import Rename from '../../mixins/spaces/actions/rename'
import { mapActions } from 'vuex'
import Delete from '../../mixins/spaces/actions/delete'
export default {
components: {
NoContentMessage,
ListLoader
},
mixins: [Rename, Delete],
setup() {
const store = useStore()
const spaces = ref([])
Expand All @@ -74,8 +127,66 @@ export default {
return {
spaces,
graph,
loadSpacesTask
}
},
computed: {
hasCreatePermission() {
// @TODO
return true
},
contextMenuActions() {
return [...this.$_rename_items, ...this.$_delete_items].filter((item) => item.isEnabled())
}
},
methods: {
...mapActions(['createModal', 'hideModal', 'setModalInputErrorMessage']),
showCreateSpaceModal() {
const modal = {
variation: 'passive',
title: this.$gettext('Create a new space'),
cancelText: this.$gettext('Cancel'),
confirmText: this.$gettext('Create'),
hasInput: true,
inputLabel: this.$gettext('Space name'),
inputValue: this.$gettext('New space'),
onCancel: this.hideModal,
onConfirm: this.addNewSpace,
onInput: this.checkSpaceName
}
this.createModal(modal)
},
checkSpaceName(name) {
if (name.trim() === '') {
this.setModalInputErrorMessage(this.$gettext('Space name cannot be empty'))
}
},
addNewSpace(name) {
this.$refs.createNewSpaceButton.$el.blur()
return this.graph.drives
.createDrive({ name }, {})
.then(() => {
this.hideModal()
this.loadSpacesTask.perform(this)
})
.catch((error) => {
this.showMessage({
title: this.$gettext('Creating space failed…'),
desc: error,
status: 'danger'
})
})
},
sanitizeSpaceId(id) {
return id.replace('!', '\\!')
}
}
}
</script>
Expand All @@ -88,6 +199,11 @@ export default {
.spaces-list {
&-card {
box-shadow: none !important;
.oc-card-media-top button {
top: 0;
right: 0;
}
}
.oc-card-media-top {
Expand Down
Loading

0 comments on commit 024ff8c

Please sign in to comment.