Merge branch 'master' into loginLinkPublicVote
This commit is contained in:
Коммит
c3787d71e0
|
@ -1,9 +1,10 @@
|
|||
module.exports = {
|
||||
plugins: ['@babel/plugin-syntax-dynamic-import'],
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
useBuiltIns: 'usage',
|
||||
corejs: 3,
|
||||
targets: {
|
||||
browsers: ['last 2 versions', 'ie >= 11']
|
||||
}
|
||||
|
@ -11,4 +12,3 @@ module.exports = {
|
|||
]
|
||||
]
|
||||
}
|
||||
|
||||
|
|
17
.eslintrc.js
17
.eslintrc.js
|
@ -3,9 +3,8 @@ module.exports = {
|
|||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
'nextcloud/nextcloud': true,
|
||||
node: true,
|
||||
jest: true
|
||||
jest: true,
|
||||
},
|
||||
globals: {
|
||||
t: true,
|
||||
|
@ -14,32 +13,32 @@ module.exports = {
|
|||
OCA: true,
|
||||
Vue: true,
|
||||
VueRouter: true,
|
||||
moment:true
|
||||
moment:true,
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
ecmaVersion: 6
|
||||
ecmaVersion: 6,
|
||||
},
|
||||
extends: [
|
||||
'plugin:@nextcloud/recommended',
|
||||
'eslint:recommended',
|
||||
'plugin:nextcloud/recommended',
|
||||
'plugin:node/recommended',
|
||||
'plugin:vue/essential',
|
||||
'plugin:vue/recommended',
|
||||
'standard'
|
||||
'standard',
|
||||
],
|
||||
plugins: [
|
||||
'vue',
|
||||
'node',
|
||||
'nextcloud'
|
||||
],
|
||||
rules: {
|
||||
"@nextcloud/no-deprecations": "warn",
|
||||
"@nextcloud/no-removed-apis": "error",
|
||||
'node/no-missing-import': ['error', {
|
||||
'allowModules': [],
|
||||
'tryExtensions': ['.js', '.vue']
|
||||
}],
|
||||
'nextcloud/no-deprecations': 'warn',
|
||||
'nextcloud/no-removed-apis': 'error',
|
||||
// 'comma-dangle': ['error', 'always-multiline'],
|
||||
// space before function ()
|
||||
'space-before-function-paren': ['error', 'never'],
|
||||
// curly braces always space
|
||||
|
|
|
@ -45,6 +45,7 @@ return [
|
|||
['name' => 'vote#get', 'url' => '/votes/get/{pollId}', 'verb' => 'GET'],
|
||||
['name' => 'vote#set', 'url' => '/vote/set/', 'verb' => 'POST'],
|
||||
['name' => 'vote#write', 'url' => '/vote/write/', 'verb' => 'POST'],
|
||||
['name' => 'vote#delete', 'url' => '/votes/delete/', 'verb' => 'POST'],
|
||||
|
||||
['name' => 'option#get', 'url' => '/options/get/{pollId}', 'verb' => 'GET'],
|
||||
['name' => 'option#add', 'url' => '/option/add/', 'verb' => 'POST'],
|
||||
|
|
12
l10n/nl.js
12
l10n/nl.js
|
@ -74,8 +74,10 @@ OC.L10N.register(
|
|||
"Configuration" : "Configuratie",
|
||||
"Options" : "Opties",
|
||||
"Shares" : "Shares",
|
||||
"As an admin you may edit this poll" : "Als beheerder mag je de peiling bewerken",
|
||||
"Description" : "Beschrijving",
|
||||
"Poll configurations" : "Peilingconfiguratie",
|
||||
"Allow admins to edit this poll" : "Sta beheerders toe de peiling te bewerken",
|
||||
"Allow \"maybe\" vote" : "Sta een Misschien stem toe",
|
||||
"Anonymous poll" : "Anonieme peiling",
|
||||
"Expiration date" : "Vervaldatum",
|
||||
|
@ -89,6 +91,7 @@ OC.L10N.register(
|
|||
"Available Options" : "Beschikbare opties",
|
||||
"Delete option" : "Verwijder optie",
|
||||
"Week" : "Week",
|
||||
"Minute" : "Minuut",
|
||||
"Hour" : "Uur",
|
||||
"Day" : "Dag",
|
||||
"Month" : "Maand",
|
||||
|
@ -98,6 +101,8 @@ OC.L10N.register(
|
|||
"Enter option text" : "Voer een optietekst in",
|
||||
"Invitations" : "Uitnodigingen",
|
||||
"Invited users will get informed immediately via eMail!" : "Uitgenodigde gebruikers worden onmiddellijk op de hoogte gebracht via e-mail!",
|
||||
"Copy link to clipboard" : "Kopiëren link naar klembord",
|
||||
"Remove share" : "Verwijderen share",
|
||||
"Public shares" : "Openbare deellinks",
|
||||
"Public link (" : "Openbare link (",
|
||||
"Add a public link" : "Toevoegen openbare link",
|
||||
|
@ -109,7 +114,9 @@ OC.L10N.register(
|
|||
"Error while adding share" : "Fout bij toevoegen deellink",
|
||||
"Receive notification email on activity" : "Ontvang email melding bij activiteit",
|
||||
"Your personal link to this poll: %n" : "Je persoonlijke link naar deze peiling: %n",
|
||||
"Enter your name" : "Geef je naam in",
|
||||
"Enter your name!" : "Geef je naam op!",
|
||||
"To participate, you need to enter a valid username with at least 3 characters. " : "Om mee te doen, moet je een geldige gebruikersnaam hebben van minimaal 3 tekens.",
|
||||
"Enter your name" : "Geef je naam op",
|
||||
"Username is not valid. Please enter at least 3 characters." : "Gebruikersnaam is niet geldig. Gebruik aub. minstens 3 tekens.",
|
||||
"This username is not valid, i.e. because it is already in use." : "Gebruikersnaam is niet geldig, want deze is reeds in gebruik.",
|
||||
"OK" : "OK",
|
||||
|
@ -117,9 +124,12 @@ OC.L10N.register(
|
|||
"This username can not be chosen." : "Deze gebruikersnaam kan niet worden gekozen.",
|
||||
"Error saving username" : "Fout bij opslaan gebruikersnaam",
|
||||
"The poll does not exist" : "De peiling bestaat niet",
|
||||
"Enter a poll or start a new one." : "Doe mee met een peiling of start een nieuwe.",
|
||||
"Goto Nextcloud" : "Ga naar Nextcloud",
|
||||
"Switch view" : "Omschakelen weergave",
|
||||
"Toggle Sidebar" : "Omschakelen Zijbalk",
|
||||
"There are no vote options, add some in the options section of the right side bar." : "Er zijn geen peilingsopties, voeg een paar toe in de opties sectie in de rechter zijbalk.",
|
||||
"There are no vote options. Maybe the owner did not provide some until now." : "Er zijn geen peilingsopties. Misschien heeft de eigenaar nog geen opties toegevoegd.",
|
||||
"Public access" : "Openbare toegang",
|
||||
"Hidden poll" : "Verborgen peiling",
|
||||
"Error deleting poll." : "Fout bij verwijderen peiling.",
|
||||
|
|
12
l10n/nl.json
12
l10n/nl.json
|
@ -72,8 +72,10 @@
|
|||
"Configuration" : "Configuratie",
|
||||
"Options" : "Opties",
|
||||
"Shares" : "Shares",
|
||||
"As an admin you may edit this poll" : "Als beheerder mag je de peiling bewerken",
|
||||
"Description" : "Beschrijving",
|
||||
"Poll configurations" : "Peilingconfiguratie",
|
||||
"Allow admins to edit this poll" : "Sta beheerders toe de peiling te bewerken",
|
||||
"Allow \"maybe\" vote" : "Sta een Misschien stem toe",
|
||||
"Anonymous poll" : "Anonieme peiling",
|
||||
"Expiration date" : "Vervaldatum",
|
||||
|
@ -87,6 +89,7 @@
|
|||
"Available Options" : "Beschikbare opties",
|
||||
"Delete option" : "Verwijder optie",
|
||||
"Week" : "Week",
|
||||
"Minute" : "Minuut",
|
||||
"Hour" : "Uur",
|
||||
"Day" : "Dag",
|
||||
"Month" : "Maand",
|
||||
|
@ -96,6 +99,8 @@
|
|||
"Enter option text" : "Voer een optietekst in",
|
||||
"Invitations" : "Uitnodigingen",
|
||||
"Invited users will get informed immediately via eMail!" : "Uitgenodigde gebruikers worden onmiddellijk op de hoogte gebracht via e-mail!",
|
||||
"Copy link to clipboard" : "Kopiëren link naar klembord",
|
||||
"Remove share" : "Verwijderen share",
|
||||
"Public shares" : "Openbare deellinks",
|
||||
"Public link (" : "Openbare link (",
|
||||
"Add a public link" : "Toevoegen openbare link",
|
||||
|
@ -107,7 +112,9 @@
|
|||
"Error while adding share" : "Fout bij toevoegen deellink",
|
||||
"Receive notification email on activity" : "Ontvang email melding bij activiteit",
|
||||
"Your personal link to this poll: %n" : "Je persoonlijke link naar deze peiling: %n",
|
||||
"Enter your name" : "Geef je naam in",
|
||||
"Enter your name!" : "Geef je naam op!",
|
||||
"To participate, you need to enter a valid username with at least 3 characters. " : "Om mee te doen, moet je een geldige gebruikersnaam hebben van minimaal 3 tekens.",
|
||||
"Enter your name" : "Geef je naam op",
|
||||
"Username is not valid. Please enter at least 3 characters." : "Gebruikersnaam is niet geldig. Gebruik aub. minstens 3 tekens.",
|
||||
"This username is not valid, i.e. because it is already in use." : "Gebruikersnaam is niet geldig, want deze is reeds in gebruik.",
|
||||
"OK" : "OK",
|
||||
|
@ -115,9 +122,12 @@
|
|||
"This username can not be chosen." : "Deze gebruikersnaam kan niet worden gekozen.",
|
||||
"Error saving username" : "Fout bij opslaan gebruikersnaam",
|
||||
"The poll does not exist" : "De peiling bestaat niet",
|
||||
"Enter a poll or start a new one." : "Doe mee met een peiling of start een nieuwe.",
|
||||
"Goto Nextcloud" : "Ga naar Nextcloud",
|
||||
"Switch view" : "Omschakelen weergave",
|
||||
"Toggle Sidebar" : "Omschakelen Zijbalk",
|
||||
"There are no vote options, add some in the options section of the right side bar." : "Er zijn geen peilingsopties, voeg een paar toe in de opties sectie in de rechter zijbalk.",
|
||||
"There are no vote options. Maybe the owner did not provide some until now." : "Er zijn geen peilingsopties. Misschien heeft de eigenaar nog geen opties toegevoegd.",
|
||||
"Public access" : "Openbare toegang",
|
||||
"Hidden poll" : "Verborgen peiling",
|
||||
"Error deleting poll." : "Fout bij verwijderen peiling.",
|
||||
|
|
|
@ -135,6 +135,7 @@ class VoteController extends Controller {
|
|||
*/
|
||||
public function set($pollId, $option, $userId, $setTo) {
|
||||
|
||||
$this->logger->alert('Deleting vote no. ' . $option);
|
||||
try {
|
||||
$vote = $this->mapper->findSingleVote($pollId, $option['pollOptionText'], $userId);
|
||||
$vote->setVoteAnswer($setTo);
|
||||
|
@ -158,6 +159,39 @@ class VoteController extends Controller {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* delete
|
||||
* @NoAdminRequired
|
||||
* @param integer $voteId
|
||||
* @param string $userId
|
||||
* @param integer $pollId
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function delete($voteId = 0, $userId = '', $pollId = 0) {
|
||||
$this->logger->alert('Deleting vote no. ' . $voteId);
|
||||
|
||||
try {
|
||||
if ($voteId) {
|
||||
$vote = $this->mapper->delete($voteId);
|
||||
$this->logger->alert('Deleting vote no. ' . $voteId);
|
||||
return new DataResponse(null, Http::STATUS_OK);
|
||||
} elseif ($pollId && $userId) {
|
||||
$votes = $this->mapper->deleteByPollAndUser($pollId, $userId);
|
||||
$this->logger->alert('Deleting votes from ' . $userId . ' in poll ' . $pollId);
|
||||
return new DataResponse(null, Http::STATUS_OK);
|
||||
} elseif ($pollId) {
|
||||
$votes = $this->mapper->deleteByPoll($pollId);
|
||||
$this->logger->alert('Deleting all votes in poll ' . $pollId);
|
||||
return new DataResponse(null, Http::STATUS_OK);
|
||||
} else {
|
||||
return DataResponse(null, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
} catch (DoesNotExistException $e) {
|
||||
return DataResponse(null, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public functions
|
||||
*/
|
||||
|
|
|
@ -388,26 +388,6 @@ class Acl implements JsonSerializable {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessLevel(): string {
|
||||
if ($this->getIsOwner()) {
|
||||
return 'owner';
|
||||
} elseif ($this->poll->getAccess() === 'public') {
|
||||
return 'public';
|
||||
} elseif ($this->poll->getAccess() === 'registered' && \OC::$server->getUserSession()->getUser()->getUID() === $this->userId) {
|
||||
return 'registered';
|
||||
} elseif ($this->poll->getAccess() === 'hidden' && $this->getisOwner()) {
|
||||
return 'hidden';
|
||||
} elseif ($this->getIsAdmin()) {
|
||||
return 'admin';
|
||||
} else {
|
||||
return 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
@ -430,8 +410,7 @@ class Acl implements JsonSerializable {
|
|||
'groupShare' => $this->getGroupShare(),
|
||||
'personalShare' => $this->getPersonalShare(),
|
||||
'publicShare' => $this->getPublicShare(),
|
||||
'foundByToken' => $this->getFoundByToken(),
|
||||
'accessLevel' => $this->getAccessLevel()
|
||||
'foundByToken' => $this->getFoundByToken()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
31
package.json
31
package.json
|
@ -35,23 +35,14 @@
|
|||
"stylelint:fix": "stylelint src --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@nextcloud/axios": "^1.3.1",
|
||||
"@nextcloud/router": "^1.0.0",
|
||||
"@nextcloud/vue": "^1.3.0",
|
||||
"acorn": "^7.1.0",
|
||||
"acorn-jsx": "^5.1.0",
|
||||
"babel-plugin-transform-async-to-generator": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-latest": "^6.24.1",
|
||||
"fibers": "^4.0.2",
|
||||
"core-js": "^3.6.4",
|
||||
"lodash": "^4.17.15",
|
||||
"moment": "^2.23.0",
|
||||
"v-click-outside": "^3.0.0",
|
||||
"v-tooltip": "^3.0.0-alpha.11",
|
||||
"vue": "^2.6.11",
|
||||
"vue-click-outside": "^1.0.7",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-router": "^3.1.5",
|
||||
"vuedraggable": "^2.23.2",
|
||||
|
@ -66,37 +57,33 @@
|
|||
"node": ">=10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.3",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.3",
|
||||
"@babel/core": "^7.8.6",
|
||||
"@babel/preset-env": "^7.8.6",
|
||||
"@nextcloud/eslint-plugin": "^1.1.0",
|
||||
"babel-eslint": "^10.0.2",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"css-loader": "^3.4.2",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-loader": "^3.0.3",
|
||||
"eslint-plugin-import": "^2.20.0",
|
||||
"eslint-plugin-nextcloud": "^0.3.0",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"eslint-plugin-vue": "^6.1.2",
|
||||
"file-loader": "^5.0.2",
|
||||
"node-sass": "^4.13.1",
|
||||
"prettier-eslint": "^9.0.1",
|
||||
"raw-loader": "^4.0.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"stylelint": "^13.2.0",
|
||||
"stylelint-config-recommended-scss": "^4.2.0",
|
||||
"stylelint-scss": "^3.14.2",
|
||||
"vue-loader": "^15.7.2",
|
||||
"vue-style-loader": "^4.1.1",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"terser-webpack-plugin": "^2.3.5",
|
||||
"vue-loader": "^15.9.0",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-merge": "^4.1.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<div v-if="description" class="description">
|
||||
{{ description }}
|
||||
</div>
|
||||
<Avatar :disable-menu="true" :user="userId"
|
||||
<Avatar :disable-menu="disableMenu" :menu-position="menuPosition" :user="userId"
|
||||
:is-guest="!Boolean(OC.currentUser)"
|
||||
:display-name="displayName"
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
|||
<div v-if="!hideNames" class="user-name">
|
||||
{{ displayName }}
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -53,6 +54,14 @@ export default {
|
|||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disableMenu: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
menuPosition: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
userId: {
|
||||
type: String,
|
||||
default: undefined
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de>
|
||||
-
|
||||
- @author René Gieling <github@dartcafe.de>
|
||||
-
|
||||
- @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/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2> {{ t('polls', 'Share with') }}</h2>
|
||||
|
||||
<Multiselect id="ajax"
|
||||
v-model="shares"
|
||||
:options="users"
|
||||
:multiple="true"
|
||||
:user-select="true"
|
||||
:tag-width="80"
|
||||
:clear-on-select="false"
|
||||
:preserve-search="true"
|
||||
:options-limit="20"
|
||||
:loading="isLoading"
|
||||
:internal-search="false"
|
||||
:searchable="true"
|
||||
:preselect-first="true"
|
||||
:placeholder="placeholder"
|
||||
label="displayName"
|
||||
track-by="user"
|
||||
@search-change="loadUsersAsync"
|
||||
@close="updateShares">
|
||||
<template slot="selection" slot-scope="{ values, search, isOpen }">
|
||||
<span v-if="values.length && !isOpen" class="multiselect__single">
|
||||
{{ values.length }} users selected
|
||||
</span>
|
||||
</template>
|
||||
</Multiselect>
|
||||
|
||||
<TransitionGroup :css="false" tag="ul" class="shared-list">
|
||||
<li v-for="(item, index) in sortedShares" :key="item.displayName" :data-index="index">
|
||||
<UserDiv :user-id="item.user" :display-name="item.displayName" :type="item.type"
|
||||
:hide-names="hideNames" />
|
||||
<div class="options">
|
||||
<a class="icon icon-delete svg delete-poll" @click="removeShare(index, item)" />
|
||||
</div>
|
||||
</li>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Multiselect } from '@nextcloud/vue'
|
||||
|
||||
export default {
|
||||
name: 'ShareDiv',
|
||||
|
||||
components: {
|
||||
Multiselect
|
||||
},
|
||||
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
activeShares: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
|
||||
hideNames: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
shares: [],
|
||||
users: [],
|
||||
isLoading: false,
|
||||
siteUsersListOptions: {
|
||||
getUsers: true,
|
||||
getGroups: true,
|
||||
query: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
sortedShares() {
|
||||
return this.shares.slice(0).sort(this.sortByDisplayname)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
activeShares(value) {
|
||||
this.shares = value.slice(0)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
removeShare(index, item) {
|
||||
this.$emit('remove-share', item)
|
||||
},
|
||||
|
||||
updateShares() {
|
||||
this.$emit('update-shares', this.shares)
|
||||
},
|
||||
|
||||
loadUsersAsync(query) {
|
||||
this.isLoading = false
|
||||
this.siteUsersListOptions.query = query
|
||||
this.$http.post(OC.generateUrl('apps/polls/siteusers/get/'), this.siteUsersListOptions)
|
||||
.then((response) => {
|
||||
this.users = response.data.siteusers
|
||||
this.isLoading = false
|
||||
}, (error) => {
|
||||
console.error(error.response)
|
||||
})
|
||||
},
|
||||
|
||||
sortByDisplayname(a, b) {
|
||||
if (a.displayName.toLowerCase() < b.displayName.toLowerCase()) return -1
|
||||
if (a.displayName.toLowerCase() > b.displayName.toLowerCase()) return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.shared-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
padding-top: 8px;
|
||||
|
||||
> li {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
position: relative;
|
||||
top: -12px;
|
||||
left: -13px;
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
</style>
|
|
@ -26,8 +26,7 @@
|
|||
{{ t('polls', 'Your personal link to this poll: %n', 1, personalLink) }}
|
||||
<a class="icon icon-clippy" @click="copyLink()" />
|
||||
</div>
|
||||
<Modal v-show="!isValidUser &!expired & modal" class="modal"
|
||||
:can-close="false">
|
||||
<Modal v-show="!isValidUser &!expired & modal" :can-close="false">
|
||||
<div class="modal__content">
|
||||
<h2>{{ t('polls', 'Enter your name!') }}</h2>
|
||||
<p>{{ t('polls', 'To participate, you need to enter a valid username with at least 3 characters.') }}</p>
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
<template lang="html">
|
||||
<div class="vote-table">
|
||||
<div class="header">
|
||||
<div class="sticky" />
|
||||
<div class="vote-table__header">
|
||||
<div class="vote-table__user-column" />
|
||||
|
||||
<VoteTableHeader v-for="(option) in sortedOptions"
|
||||
:key="option.id"
|
||||
|
@ -33,16 +33,37 @@
|
|||
|
||||
<div v-for="(participant) in participants" :key="participant.userId" :class="{currentuser: (participant.userId === currentUser) }">
|
||||
<UserDiv :key="participant.userId"
|
||||
class="sticky"
|
||||
class="vote-table__user-column"
|
||||
:disable-menu="true"
|
||||
:class="{currentuser: (participant.userId === currentUser) }"
|
||||
:user-id="participant.userId"
|
||||
:display-name="participant.displayName" />
|
||||
:display-name="participant.displayName">
|
||||
<Actions v-if="acl.allowEdit" class="action">
|
||||
<ActionButton icon="icon-delete"
|
||||
@click="confirmDelete(participant.userId)">
|
||||
{{ t('polls', 'Delete votes') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
</UserDiv>
|
||||
|
||||
<VoteTableItem v-for="(option) in sortedOptions"
|
||||
:key="option.id"
|
||||
:user-id="participant.userId"
|
||||
:option="option"
|
||||
@voteClick="setVote(option, participant.userId)" />
|
||||
</div>
|
||||
|
||||
<Modal v-if="modal">
|
||||
<div class="modal__content">
|
||||
<h2>{{ t('polls', 'Do you want to remove {username} from poll?', { username: userToRemove }) }}</h2>
|
||||
<div class="modal__buttons">
|
||||
<ButtonDiv :title="t('polls', 'No')"
|
||||
@click="modal = false" />
|
||||
<ButtonDiv :primary="true" :title="t('polls', 'Yes')"
|
||||
@click="removeUser()" />
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -50,14 +71,25 @@
|
|||
import VoteTableItem from './VoteTableItem'
|
||||
import VoteTableHeader from './VoteTableHeader'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import { Actions, ActionButton, Modal } from '@nextcloud/vue'
|
||||
|
||||
export default {
|
||||
name: 'VoteTable',
|
||||
components: {
|
||||
Actions,
|
||||
ActionButton,
|
||||
Modal,
|
||||
VoteTableHeader,
|
||||
VoteTableItem
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
modal: false,
|
||||
userToRemove: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState({
|
||||
poll: state => state.poll,
|
||||
|
@ -75,6 +107,19 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
removeUser() {
|
||||
this.$store.dispatch('deleteVotes', {
|
||||
userId: this.userToRemove
|
||||
})
|
||||
this.modal = false
|
||||
this.userToRemove = ''
|
||||
},
|
||||
|
||||
confirmDelete(userId) {
|
||||
this.userToRemove = userId
|
||||
this.modal = true
|
||||
},
|
||||
|
||||
setVote(option, userId) {
|
||||
this.$store
|
||||
.dispatch('setVoteAsync', {
|
||||
|
@ -94,16 +139,34 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-row.sticky,
|
||||
.header > .sticky {
|
||||
.user-row.vote-table__user-column,
|
||||
.vote-table__header > .vote-table__user-column {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
background-color: var(--color-main-background);
|
||||
width: 170px;
|
||||
width: 230px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
.modal__content {
|
||||
padding: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--color-main-text);
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.modal__buttons {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
.button {
|
||||
margin-left: 10px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.vote-table__header {
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
|
@ -139,7 +202,7 @@ export default {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
&.header {
|
||||
&.vote-table__header {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
|
@ -172,12 +235,6 @@ export default {
|
|||
margin: 0;
|
||||
|
||||
}
|
||||
// &.currentuser {
|
||||
// display: flex;
|
||||
// > .user-row.currentuser {
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
&> .currentuser {
|
||||
|
@ -188,7 +245,7 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
&> .header, {
|
||||
&> .vote-table__header, {
|
||||
height: initial;
|
||||
padding-left: initial;
|
||||
display: flex;
|
||||
|
|
|
@ -36,7 +36,6 @@ import { Tooltip } from '@nextcloud/vue'
|
|||
|
||||
import UserDiv from './components/Base/UserDiv'
|
||||
import ButtonDiv from './components/Base/ButtonDiv'
|
||||
import LoadingOverlay from './components/Base/LoadingOverlay'
|
||||
|
||||
/* eslint-disable-next-line camelcase, no-undef */
|
||||
__webpack_nonce__ = btoa(OC.requestToken)
|
||||
|
@ -57,7 +56,6 @@ Vue.prototype.OCA = OCA
|
|||
|
||||
Vue.component('UserDiv', UserDiv)
|
||||
Vue.component('ButtonDiv', ButtonDiv)
|
||||
Vue.component('LoadingOverlay', LoadingOverlay)
|
||||
Vue.directive('tooltip', Tooltip)
|
||||
|
||||
Vue.use(ClickOutside)
|
||||
|
|
|
@ -67,13 +67,13 @@ const getters = {
|
|||
return (state.expire > 0 && moment.unix(state.expire).diff() < 0)
|
||||
},
|
||||
|
||||
accessType: (state, getters, rootState) => {
|
||||
if (rootState.acl.accessLevel === 'public') {
|
||||
accessType: (state) => {
|
||||
if (state.access === 'public') {
|
||||
return t('polls', 'Public access')
|
||||
} else if (rootState.acl.accessLevel === 'hidden') {
|
||||
} else if (state.access === 'hidden') {
|
||||
return t('polls', 'Hidden poll')
|
||||
} else {
|
||||
return rootState.acl.accessLevel
|
||||
return state.access
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -40,6 +40,10 @@ const mutations = {
|
|||
Object.assign(state, payload)
|
||||
},
|
||||
|
||||
deleteVotes(state, payload) {
|
||||
state.list = state.list.filter(vote => vote.userId !== payload.userId)
|
||||
},
|
||||
|
||||
setVote(state, payload) {
|
||||
const index = state.list.findIndex(vote =>
|
||||
parseInt(vote.pollId) === payload.pollId
|
||||
|
@ -172,6 +176,22 @@ const actions = {
|
|||
})
|
||||
},
|
||||
|
||||
deleteVotes(context, payload) {
|
||||
const endPoint = 'apps/polls/votes/delete/'
|
||||
return axios.post(OC.generateUrl(endPoint), {
|
||||
pollId: context.rootState.poll.id,
|
||||
voteId: 0,
|
||||
userId: payload.userId
|
||||
})
|
||||
.then(() => {
|
||||
context.commit('deleteVotes', payload)
|
||||
OC.Notification.showTemporary(t('polls', 'User {userId} removed', payload), { type: 'success' })
|
||||
}, (error) => {
|
||||
console.error('Error deleting votes', { error: error.response }, { payload: payload })
|
||||
throw error
|
||||
})
|
||||
},
|
||||
|
||||
setVoteAsync(context, payload) {
|
||||
let endPoint = 'apps/polls/vote/set/'
|
||||
|
||||
|
|
|
@ -51,12 +51,14 @@ import { AppContent } from '@nextcloud/vue'
|
|||
import PollListItem from '../components/PollList/PollListItem'
|
||||
import { mapGetters } from 'vuex'
|
||||
import sortBy from 'lodash/sortBy'
|
||||
import LoadingOverlay from '../components/Base/LoadingOverlay'
|
||||
|
||||
export default {
|
||||
name: 'PollList',
|
||||
|
||||
components: {
|
||||
AppContent,
|
||||
LoadingOverlay,
|
||||
PollListItem
|
||||
},
|
||||
|
||||
|
|
|
@ -11,12 +11,15 @@ module.exports = {
|
|||
},
|
||||
module: {
|
||||
rules: [
|
||||
// {
|
||||
// enforce: 'pre',
|
||||
// test: /\.(js|vue)$/,
|
||||
// loader: 'eslint-loader',
|
||||
// exclude: /node_modules/
|
||||
// },
|
||||
{
|
||||
enforce: 'pre',
|
||||
test: /\.(js|vue)$/,
|
||||
loader: 'eslint-loader',
|
||||
exclude: /node_modules/,
|
||||
options: {
|
||||
quiet: true
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
|
@ -34,7 +37,12 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader'
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
compilerOptions: {
|
||||
whitespace: 'condense'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
const merge = require('webpack-merge')
|
||||
const common = require('./webpack.common.js')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'source-map',
|
||||
devServer: {
|
||||
historyApiFallback: true,
|
||||
noInfo: true,
|
||||
overlay: true
|
||||
},
|
||||
devtool: 'source-map'
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: true,
|
||||
cache: true,
|
||||
extractComments: false,
|
||||
terserOptions: {
|
||||
ecma: 6
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
const merge = require('webpack-merge')
|
||||
const common = require('./webpack.common.js')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
devtool: 'source-map'
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: true,
|
||||
cache: true,
|
||||
terserOptions: {
|
||||
ecma: 6
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
})
|
||||
|
|
Загрузка…
Ссылка в новой задаче