зеркало из https://github.com/nextcloud/forms.git
Deletion compatibility
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
Родитель
85d6a1be47
Коммит
ef2e32a571
|
@ -33,7 +33,6 @@ return [
|
|||
|
||||
['name' => 'page#goto_form', 'url' => '/{hash}', 'verb' => 'GET'],
|
||||
|
||||
['name' => 'page#delete_form', 'url' => '/delete', 'verb' => 'POST'],
|
||||
['name' => 'page#insert_vote', 'url' => '/insert/vote', 'verb' => 'POST'],
|
||||
['name' => 'page#search', 'url' => '/search', 'verb' => 'POST'],
|
||||
['name' => 'page#get_display_name', 'url' => '/get/displayname', 'verb' => 'POST'],
|
||||
|
@ -44,10 +43,10 @@ return [
|
|||
['name' => 'api#get_votes', 'url' => '/get/votes/{formId}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_shares', 'url' => '/get/shares/{formId}', 'verb' => 'GET'],
|
||||
['name' => 'api#get_event', 'url' => '/get/event/{formId}', 'verb' => 'GET'],
|
||||
['name' => 'api#remove_form', 'url' => '/forms/{id}', 'verb' => 'DELETE'],
|
||||
['name' => 'api#get_forms', 'url' => '/get/forms', 'verb' => 'GET'],
|
||||
|
||||
['name' => 'api#newForm', 'url' => 'api/v1/form', 'verb' => 'POST'],
|
||||
['name' => 'api#deleteForm', 'url' => 'api/v1/form/{id}', 'verb' => 'DELETE'],
|
||||
|
||||
['name' => 'system#get_site_users_and_groups', 'url' => '/get/siteusers', 'verb' => 'POST'],
|
||||
]
|
||||
|
|
|
@ -389,8 +389,9 @@ class ApiController extends Controller {
|
|||
* @NoAdminRequired
|
||||
* @param int $formId
|
||||
* @return DataResponse
|
||||
* TODO: use hash instead of id ?
|
||||
*/
|
||||
public function removeForm(int $id) {
|
||||
public function deleteForm(int $id) {
|
||||
try {
|
||||
$formToDelete = $this->eventMapper->find($id);
|
||||
} catch (DoesNotExistException $e) {
|
||||
|
@ -533,11 +534,6 @@ class ApiController extends Controller {
|
|||
|
||||
$this->eventMapper->insert($event);
|
||||
|
||||
|
||||
|
||||
return new Http\JSONResponse([
|
||||
'id' => $event->getId(),
|
||||
'hash' => $event->getHash(),
|
||||
]);
|
||||
return new Http\JSONResponse($this->getForm($event->getHash()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,10 @@
|
|||
<Content app-name="forms">
|
||||
<AppNavigation>
|
||||
<AppNavigationNew button-class="icon-add" :text="t('forms', 'New form')" @click="onNewForm" />
|
||||
<AppNavigationForm v-for="form in formattedForms" :key="form.id" :form="form" />
|
||||
<AppNavigationForm v-for="form in formattedForms"
|
||||
:key="form.id"
|
||||
:form="form"
|
||||
@delete="onDeleteForm" />
|
||||
</AppNavigation>
|
||||
|
||||
<!-- No forms & loading emptycontents -->
|
||||
|
@ -57,6 +60,7 @@
|
|||
|
||||
<script>
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
import AppContent from '@nextcloud/vue/dist/Components/AppContent'
|
||||
|
@ -118,7 +122,7 @@ export default {
|
|||
async loadForms() {
|
||||
this.loading = true
|
||||
try {
|
||||
const response = await axios.get(OC.generateUrl('apps/forms/get/forms'))
|
||||
const response = await axios.get(generateUrl('apps/forms/get/forms'))
|
||||
this.forms = response.data
|
||||
} catch (error) {
|
||||
showError(t('forms', 'An error occured while loading the forms list'))
|
||||
|
@ -131,8 +135,27 @@ export default {
|
|||
/**
|
||||
*
|
||||
*/
|
||||
onNewForm() {
|
||||
this.$router.push({ name: 'create' })
|
||||
async onNewForm() {
|
||||
try {
|
||||
// Request a new empty form
|
||||
const response = await axios.post(generateUrl('/apps/forms/api/v1/form'))
|
||||
const newForm = response.data
|
||||
this.forms.push(newForm)
|
||||
this.$router.push({ name: 'edit', params: { hash: newForm.event.hash } })
|
||||
} catch (error) {
|
||||
showError(t('forms', 'Unable to create a new form'))
|
||||
console.error(error)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove form from forms list after successful server deletion request
|
||||
*
|
||||
* @param {Number} id the form id
|
||||
*/
|
||||
async onDeleteForm(id) {
|
||||
const formIndex = this.forms.findIndex(form => form.id === id)
|
||||
this.forms.splice(formIndex, 1)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -23,24 +23,25 @@
|
|||
<template>
|
||||
<AppNavigationItem
|
||||
:exact="true"
|
||||
:icon="loading ? 'icon-loading-small' : ''"
|
||||
:title="form.title"
|
||||
:to="{ name: 'edit', params: { hash: form.hash } }">
|
||||
<AppNavigationIconBullet slot="icon" :color="bulletColor" />
|
||||
<template #actions>
|
||||
<template v-if="!loading" #actions>
|
||||
<ActionRouter :close-after-click="true"
|
||||
:exact="true"
|
||||
icon="icon-checkmark"
|
||||
:to="{ name: 'results', params: { hash: form.hash } }">
|
||||
{{ t('forms', 'Show results') }}
|
||||
</ActionRouter>
|
||||
<ActionRouter :close-after-click="true"
|
||||
<!-- <ActionRouter :close-after-click="true"
|
||||
:exact="true"
|
||||
icon="icon-clone"
|
||||
:to="{ name: 'clone', params: { hash: form.hash } }">
|
||||
{{ t('forms', 'Clone form') }}
|
||||
</ActionRouter>
|
||||
</ActionRouter> -->
|
||||
<ActionSeparator />
|
||||
<ActionButton :close-after-click="true" icon="icon-delete" @click="deleteForm">
|
||||
<ActionButton :close-after-click="true" icon="icon-delete" @click="onDeleteForm">
|
||||
{{ t('forms', 'Delete form') }}
|
||||
</ActionButton>
|
||||
</template>
|
||||
|
@ -48,6 +49,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import axios from '@nextcloud/axios'
|
||||
import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem'
|
||||
import AppNavigationIconBullet from '@nextcloud/vue/dist/Components/AppNavigationIconBullet'
|
||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
|
||||
|
@ -72,6 +76,12 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Map form state to bullet color
|
||||
|
@ -88,9 +98,25 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
async deleteForm() {
|
||||
async onDeleteForm() {
|
||||
if (!confirm(t('forms', 'Are you sure you want to delete the form “{title}”', { title: this.form.title }))) {
|
||||
return
|
||||
}
|
||||
|
||||
// All good, let's delete
|
||||
this.loading = true
|
||||
try {
|
||||
await axios.delete(generateUrl('/apps/forms/api/v1/form/{id}', { id: this.form.id }))
|
||||
this.$emit('delete', this.form.id)
|
||||
showSuccess(t('forms', 'Deleted form “{title}”', { title: this.form.title }))
|
||||
} catch (error) {
|
||||
showError(t('forms', 'Error while deleting form “{title}”', { title: this.form.title }))
|
||||
console.error(error.response)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de>
|
||||
*
|
||||
* @author René Gieling <github@dartcafe.de>
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
export default class {
|
||||
|
||||
#data
|
||||
|
||||
/**
|
||||
* Construct the form
|
||||
* @param {Object} data the form data
|
||||
*/
|
||||
constructor(data) {
|
||||
// Id check
|
||||
if (!('id' in data && typeof data.id === 'number')) {
|
||||
throw new Error('A new form must at least contain a valid id')
|
||||
}
|
||||
|
||||
// Hash check
|
||||
if (!('hash' in data && typeof data.id === 'string')) {
|
||||
throw new Error('A new form must at least contain a valid hash')
|
||||
}
|
||||
|
||||
this.#data = data
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.#data.id
|
||||
}
|
||||
|
||||
get hash() {
|
||||
return this.#data.hash
|
||||
}
|
||||
|
||||
}
|
|
@ -31,7 +31,7 @@ const formatForm = function(form) {
|
|||
|
||||
// migrate object architecture
|
||||
Object.assign(newForm, {
|
||||
questions: form.options.formQuizQuestions,
|
||||
questions: form.options && form.options.formQuizQuestions,
|
||||
})
|
||||
|
||||
// cleanup
|
||||
|
|
|
@ -269,8 +269,6 @@ export default {
|
|||
if (this.form.event.title.length === 0 | !(/\S/.test(this.form.event.title))) {
|
||||
this.titleEmpty = true
|
||||
showError(t('forms', 'Title must not be empty!'), { duration: 3000 })
|
||||
} else if (this.form.options.formQuizQuestions.length === 0) {
|
||||
showError(t('forms', 'Must have at least one question!'), { duration: 3000 })
|
||||
} else if (!this.haveAns) {
|
||||
showError(t('forms', 'All questions need answers!'), { duration: 3000 })
|
||||
} else if (this.form.event.expiration & this.form.event.expirationDate === '') {
|
||||
|
@ -323,7 +321,6 @@ input[type="text"] {
|
|||
}
|
||||
|
||||
.workbench {
|
||||
margin-top: 45px;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-wrap: wrap;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<AppSidebar :title="form.event.title" class="forms-sidebar">
|
||||
<AppSidebar :title="form.event.title">
|
||||
<div class="configBox ">
|
||||
<label class="title icon-settings">
|
||||
{{ t('forms', 'Form configurations') }}
|
||||
|
@ -209,27 +209,22 @@ export default {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.forms-sidebar {
|
||||
margin-top: 45px;
|
||||
width: 25%;
|
||||
|
||||
.configBox {
|
||||
.configBox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 8px;
|
||||
& > * {
|
||||
padding-left: 21px;
|
||||
}
|
||||
& > .title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 8px;
|
||||
& > * {
|
||||
padding-left: 21px;
|
||||
}
|
||||
& > .title {
|
||||
display: flex;
|
||||
background-position: 0 2px;
|
||||
padding-left: 24px;
|
||||
opacity: 0.7;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
& > span {
|
||||
padding-left: 4px;
|
||||
}
|
||||
background-position: 0 2px;
|
||||
padding-left: 24px;
|
||||
opacity: 0.7;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
& > span {
|
||||
padding-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче