Merge pull request #1483 from nextcloud/cleanup

Cleanup
This commit is contained in:
Julius Härtl
2020-01-25 13:49:06 +01:00
committed by GitHub
30 changed files with 601 additions and 1748 deletions

View File

@@ -12,30 +12,30 @@ sign_dir=$(build_dir)/sign
cert_dir=$(HOME)/.nextcloud/certificates
default: package
default: build
clean-build:
rm -rf $(build_dir)
clean-dist:
rm -rf js/node_modules
rm -rf node_modules/
install-deps: install-deps-js
composer install
install-deps-js:
cd js && npm install
npm ci
build: install-deps build-js
build: clean-dist install-deps build-js
build-js: install-deps-js
cd js && npm run build
npm run build
build-js-dev: install-deps
cd js && npm run dev
npm run dev
watch:
cd js && npm run watch
npm run watch
# appstore: clean install-deps
appstore: clean-build build
@@ -96,7 +96,7 @@ test-integration:
cd tests/integration && ./run.sh
test-js: install-deps
cd js && run test
npm run test
package:
krankerl package

View File

@@ -38,7 +38,7 @@ return [
['name' => 'board#deleteUndo', 'url' => '/boards/{boardId}/deleteUndo', 'verb' => 'POST'],
['name' => 'board#getUserPermissions', 'url' => '/boards/{boardId}/permissions', 'verb' => 'GET'],
['name' => 'board#addAcl', 'url' => '/boards/{boardId}/acl', 'verb' => 'POST'],
['name' => 'board#updateAcl', 'url' => '/boards/{boardId}/acl', 'verb' => 'PUT'],
['name' => 'board#updateAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'PUT'],
['name' => 'board#deleteAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'DELETE'],
['name' => 'board#clone', 'url' => '/boards/{boardId}/clone', 'verb' => 'POST'],

1228
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,11 +29,11 @@
"@babel/polyfill": "^7.8.3",
"@babel/runtime": "^7.8.3",
"@nextcloud/auth": "^1.2.1",
"@nextcloud/axios": "^1.3.1",
"@nextcloud/l10n": "^1.0.1",
"@nextcloud/router": "^1.0.0",
"@nextcloud/vue": "^1.2.7",
"fuse.js": "^3.4.5",
"nextcloud-axios": "^0.2.1",
"nextcloud-server": "^0.15.10",
"nextcloud-vue-collections": "^0.7.1",
"tippy.js": "^4.3.5",
@@ -77,17 +77,16 @@
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.1.2",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^5.0.2",
"jest": "^25.1.0",
"jest-serializer-vue": "^2.0.2",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.13.1",
"prettier-eslint": "^9.0.1",
"raw-loader": "^4.0.0",
"sass-loader": "^8.0.2",
"stylelint": "^8.4.0",
"stylelint-config-recommended-scss": "^3.3.0",
"stylelint-scss": "^3.13.0",
"stylelint-webpack-plugin": "^0.10.5",
"url-loader": "^3.0.0",
"vue-jest": "^3.0.5",

View File

@@ -75,7 +75,7 @@
</style>
<script>
import { Modal } from '@nextcloud/vue/dist/Components/Modal'
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
export default {
name: 'BoardSelector',

View File

@@ -47,7 +47,7 @@
<script>
import { Modal } from '@nextcloud/vue/dist/Components/Modal'
import { Multiselect } from '@nextcloud/vue/dist/Components/Multiselect'
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
export default {
name: 'CardSelector',

View File

@@ -28,7 +28,7 @@
<h2><a href="#">{{ board.title }}</a></h2>
</div>
<div v-if="board" class="board-actions">
<div id="stack-add" v-click-outside="hideAddStack">
<div v-if="canManage" id="stack-add" v-click-outside="hideAddStack">
<Actions v-if="!isAddStackVisible">
<ActionButton icon="icon-add" :title="t('deck', 'Add new stack')" @click.stop="showAddStack" />
</Actions>
@@ -77,7 +77,7 @@
</template>
<script>
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import { Actions, ActionButton } from '@nextcloud/vue'
export default {
@@ -101,6 +101,10 @@ export default {
}
},
computed: {
...mapGetters([
'canEdit',
'canManage',
]),
...mapState({
compactMode: state => state.compactMode,
}),

View File

@@ -29,7 +29,10 @@
<p />
</div>
<div v-else-if="board" class="board">
<Container lock-axix="y" orientation="horizontal" @drop="onDropStack">
<Container lock-axix="y"
orientation="horizontal"
:drag-handle-selector="dragHandleSelector"
@drop="onDropStack">
<Draggable v-for="stack in stacksByBoard" :key="stack.id">
<Stack :stack="stack" />
</Draggable>
@@ -46,7 +49,7 @@
<script>
import { Container, Draggable } from 'vue-smooth-dnd'
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls'
import Stack from './Stack'
@@ -77,9 +80,15 @@ export default {
board: state => state.currentBoard,
showArchived: state => state.showArchived,
}),
...mapGetters([
'canEdit',
]),
stacksByBoard() {
return this.$store.getters.stacksByBoard(this.board.id)
},
dragHandleSelector() {
return this.canEdit ? null : '.no-drag'
},
},
watch: {
id: 'fetchData',

View File

@@ -33,7 +33,10 @@
<TagsTabSidebar :board="board" />
</AppSidebarTab>
<AppSidebarTab :order="2" name="Deleted items" icon="icon-delete">
<AppSidebarTab v-if="canEdit"
:order="2"
name="Deleted items"
icon="icon-delete">
<DeletedTabSidebar :board="board" />
</AppSidebarTab>
@@ -44,7 +47,7 @@
</template>
<script>
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import SharingTabSidebar from './SharingTabSidebar'
import TagsTabSidebar from './TagsTabSidebar'
import DeletedTabSidebar from './DeletedTabSidebar'
@@ -73,6 +76,7 @@ export default {
board: state => state.currentBoard,
labels: state => state.labels,
}),
...mapGetters(['canEdit']),
},
methods: {
closeSidebar() {

View File

@@ -1,6 +1,7 @@
<template>
<div>
<Multiselect
v-if="canShare"
v-model="addAcl"
:placeholder="t('deck', 'Share board with a user, group or circle …')"
:options="formatedSharees"
@@ -17,6 +18,9 @@
<Avatar :user="board.owner.uid" />
<span class="has-tooltip username">
{{ board.owner.displayname }}
<span v-if="!isCurrentUser(board.owner.uid)" class="board-owner-label">
{{ t('deck', 'Board owner') }}
</span>
</span>
</li>
<li v-for="acl in board.acl" :key="acl.participant.uid">
@@ -29,17 +33,17 @@
<span v-if="acl.type===7">{{ t('deck', '(Circle)') }}</span>
</span>
<ActionCheckbox :checked="acl.permissionEdit" @change="clickEditAcl(acl)">
<ActionCheckbox v-if="!isCurrentUser(acl.participant.uid) && (canManage || (canEdit && canShare))" :checked="acl.permissionEdit" @change="clickEditAcl(acl)">
{{ t('deck', 'Can edit') }}
</ActionCheckbox>
<Actions>
<ActionCheckbox :checked="acl.permissionShare" @change="clickShareAcl(acl)">
<Actions v-if="!isCurrentUser(acl.participant.uid)" :force-menu="true">
<ActionCheckbox v-if="canManage || canShare" :checked="acl.permissionShare" @change="clickShareAcl(acl)">
{{ t('deck', 'Can share') }}
</ActionCheckbox>
<ActionCheckbox :checked="acl.permissionManage" @change="clickManageAcl(acl)">
<ActionCheckbox v-if="canManage" :checked="acl.permissionManage" @change="clickManageAcl(acl)">
{{ t('deck', 'Can manage') }}
</ActionCheckbox>
<ActionButton icon="icon-delete" @click="clickDeleteAcl(acl)">
<ActionButton v-if="canManage" icon="icon-delete" @click="clickDeleteAcl(acl)">
{{ t('deck', 'Delete') }}
</ActionButton>
</Actions>
@@ -61,6 +65,7 @@ import { ActionButton } from '@nextcloud/vue/dist/Components/ActionButton'
import { ActionCheckbox } from '@nextcloud/vue/dist/Components/ActionCheckbox'
import { CollectionList } from 'nextcloud-vue-collections'
import { mapGetters } from 'vuex'
import { getCurrentUser } from '@nextcloud/auth'
export default {
name: 'SharingTabSidebar',
@@ -86,9 +91,15 @@ export default {
}
},
computed: {
...mapGetters({
sharees: 'sharees',
}),
...mapGetters([
'sharees',
'canEdit',
'canManage',
'canShare',
]),
isCurrentUser() {
return (uid) => uid === getCurrentUser().uid
},
formatedSharees() {
return this.unallocatedSharees.map(item => {
@@ -173,6 +184,9 @@ export default {
padding: 12px 9px;
flex-grow: 1;
}
.board-owner-label {
opacity: .7;
}
.avatarLabel {
padding: 6px
}

View File

@@ -25,7 +25,10 @@
<div class="stack">
<div class="stack--header">
<transition name="fade" mode="out-in">
<h3 v-if="!editing" @click="startEditing(stack)">
<h3 v-if="!canManage">
{{ stack.title }}
</h3>
<h3 v-else-if="!editing" @click="startEditing(stack)">
{{ stack.title }}
</h3>
<form v-else @submit.prevent="finishedEdit(stack)">
@@ -36,12 +39,12 @@
value="">
</form>
</transition>
<Actions :force-menu="true">
<Actions v-if="canManage" :force-menu="true">
<ActionButton icon="icon-delete" @click="deleteStack(stack)">
{{ t('deck', 'Delete stack') }}
</ActionButton>
</Actions>
<Actions>
<Actions v-if="canEdit">
<ActionButton icon="icon-add" @click="showAddCard=true">
{{ t('deck', 'Add card') }}
</ActionButton>
@@ -63,7 +66,11 @@
value="">
</form>
<Container :get-child-payload="payloadForCard(stack.id)" group-name="stack" @drop="($event) => onDropCard(stack.id, $event)">
<Container :get-child-payload="payloadForCard(stack.id)"
group-name="stack"
:drag-handle-selector="dragHandleSelector"
@should-accept-drop="canEdit"
@drop="($event) => onDropCard(stack.id, $event)">
<Draggable v-for="card in cardsByStack(stack.id)" :key="card.id">
<CardItem v-if="card" :id="card.id" />
</Draggable>
@@ -73,6 +80,7 @@
<script>
import { mapGetters } from 'vuex'
import { Container, Draggable } from 'vue-smooth-dnd'
import { Actions } from '@nextcloud/vue/dist/Components/Actions'
import { ActionButton } from '@nextcloud/vue/dist/Components/ActionButton'
@@ -103,13 +111,19 @@ export default {
}
},
computed: {
...mapGetters([
'canManage',
'canEdit',
]),
cardsByStack() {
return (id) => this.$store.getters.cardsByStack(id)
},
dragHandleSelector() {
return this.canEdit ? null : '.no-drag'
},
},
methods: {
onDropCard(stackId, event) {
const { addedIndex, removedIndex, payload } = event
const card = Object.assign({}, payload)

View File

@@ -21,8 +21,14 @@
<div :style="{ backgroundColor: `#${label.color}`, color:textColor(label.color) }" class="label-title">
<span>{{ label.title }}</span>
</div>
<button v-tooltip="t('deck', 'Edit')" class="icon-rename" @click="clickEdit(label)" />
<button v-tooltip="t('deck', 'Delete')" class="icon-delete" @click="deleteLabel(label.id)" />
<button v-if="canManage"
v-tooltip="t('deck', 'Edit')"
class="icon-rename"
@click="clickEdit(label)" />
<button v-if="canManage"
v-tooltip="t('deck', 'Delete')"
class="icon-delete"
@click="deleteLabel(label.id)" />
</template>
</li>
@@ -43,7 +49,7 @@
<ColorPicker :value="'#' + addLabelObj.color" @input="updateColor" />
</template>
</li>
<button @click="clickShowAddLabel()">
<button v-if="canManage" @click="clickShowAddLabel()">
<span class="icon-add" />{{ t('deck', 'Add a new label') }}
</button>
</ul>
@@ -75,6 +81,7 @@ export default {
computed: {
...mapGetters({
labels: 'currentBoardLabels',
canManage: 'canManage',
}),
addLabelObjValidated() {
if (this.addLabelObj.title === '') {

View File

@@ -34,6 +34,7 @@
<div class="section-details">
<Multiselect v-model="allLabels"
:multiple="true"
:disabled="!canEdit"
:options="currentBoard.labels"
:placeholder="t('deck', 'Assign a tag to this card…')"
:taggable="true"
@@ -61,6 +62,7 @@
</div>
<div class="section-details">
<Multiselect v-model="assignedUsers"
:disabled="!canEdit"
:multiple="true"
:options="assignableUsers"
:placeholder="t('deck', 'Assign a user to this card…')"
@@ -85,10 +87,11 @@
:placeholder="t('deck', 'Set a due date')"
type="datetime"
lang="en"
:disabled="!canEdit"
format="YYYY-MM-DD HH:mm"
confirm
@change="setDue()" />
<Actions>
<Actions v-if="canEdit">
<ActionButton v-if="copiedCard.duedate" icon="icon-delete" @click="removeDue()">
{{ t('deck', 'Remove due date') }}
</ActionButton>
@@ -104,6 +107,7 @@
</div>
<h5>{{ t('deck', 'Description') }}</h5>
<!-- FIXME: make sure the editor is disabled when canEdit is false -->
<VueEasymde ref="markdownEditor" v-model="copiedCard.description" :configs="mdeConfig" />
</AppSidebarTab>
@@ -127,7 +131,7 @@ import { Multiselect } from '@nextcloud/vue/dist/Components/Multiselect'
import { AppSidebar } from '@nextcloud/vue/dist/Components/AppSidebar'
import { AppSidebarTab } from '@nextcloud/vue/dist/Components/AppSidebarTab'
import { DatetimePicker } from '@nextcloud/vue/dist/Components/DatetimePicker'
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import VueEasymde from 'vue-easymde/dist/VueEasyMDE.common'
import { Actions } from '@nextcloud/vue/dist/Components/Actions'
import { ActionButton } from '@nextcloud/vue/dist/Components/ActionButton'
@@ -186,6 +190,7 @@ export default {
currentBoard: state => state.currentBoard,
assignableUsers: state => state.assignableUsers,
}),
...mapGetters(['canEdit']),
currentCard() {
return this.$store.getters.cardById(this.id)
},

View File

@@ -30,7 +30,7 @@
class="card"
@click.self="openCard">
<div class="card-upper">
<h3 v-if="showArchived">
<h3 v-if="showArchived || !canEdit">
{{ card.title }}
</h3>
<h3 v-else-if="!editing" @click.stop="startEditing(card)">
@@ -47,7 +47,7 @@
<input type="button" class="icon-confirm" @click="finishedEdit(card)">
</form>
<Actions v-if="!editing" @click.stop.prevent>
<Actions v-if="canEdit && !editing" @click.stop.prevent>
<ActionButton v-if="showArchived === false" icon="icon-user" @click="assignCardToMe()">
{{ t('deck', 'Assign to me') }}
</ActionButton>
@@ -103,8 +103,8 @@ import { Actions } from '@nextcloud/vue/dist/Components/Actions'
import { ActionButton } from '@nextcloud/vue/dist/Components/ActionButton'
import { Multiselect } from '@nextcloud/vue/dist/Components/Multiselect'
import ClickOutside from 'vue-click-outside'
import { mapState } from 'vuex'
import axios from 'nextcloud-axios'
import { mapState, mapGetters } from 'vuex'
import axios from '@nextcloud/axios'
import CardBadges from './CardBadges'
import Color from '../../mixins/color'
@@ -139,6 +139,9 @@ export default {
showArchived: state => state.showArchived,
currentBoard: state => state.currentBoard,
}),
...mapGetters([
'canEdit',
]),
card() {
return this.$store.getters.cardById(this.id)
},

View File

@@ -66,7 +66,7 @@
</template>
<script>
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
import { mapGetters } from 'vuex'
import ClickOutside from 'vue-click-outside'
import { Multiselect } from '@nextcloud/vue/dist/Components/Multiselect'

View File

@@ -124,17 +124,20 @@ export default {
// do not show actions while the item is loading
if (this.loading === false) {
const canManage = this.board.permissions.PERMISSION_MANAGE
actions.push({
action: () => {
this.hideMenu()
this.editTitle = this.board.title
this.editColor = '#' + this.board.color
this.editing = true
},
icon: 'icon-rename',
text: t('deck', 'Edit board'),
})
if (canManage) {
actions.push({
action: () => {
this.hideMenu()
this.editTitle = this.board.title
this.editColor = '#' + this.board.color
this.editing = true
},
icon: 'icon-rename',
text: t('deck', 'Edit board'),
})
}
actions.push({
action: async() => {
@@ -154,46 +157,47 @@ export default {
icon: 'icon-clone',
text: t('deck', 'Clone board'),
})
if (canManage) {
if (!this.board.archived) {
actions.push({
action: () => {
this.hideMenu()
this.loading = true
this.$store.dispatch('archiveBoard', this.board)
},
icon: 'icon-archive',
text: t('deck', 'Archive board'),
})
} else {
actions.push({
action: () => {
this.hideMenu()
this.loading = true
this.$store.dispatch('unarchiveBoard', this.board)
},
icon: 'icon-archive',
text: t('deck', 'Unarchive board'),
})
}
if (!this.board.archived) {
actions.push({
action: () => {
this.hideMenu()
this.loading = true
this.$store.dispatch('archiveBoard', this.board)
this.boardApi.deleteBoard(this.board)
.then(() => {
this.loading = false
this.deleted = true
this.undoTimeoutHandle = setTimeout(() => {
this.$store.dispatch('removeBoard', this.board)
}, 7000)
})
},
icon: 'icon-archive',
text: t('deck', 'Archive board'),
})
} else {
actions.push({
action: () => {
this.hideMenu()
this.loading = true
this.$store.dispatch('unarchiveBoard', this.board)
},
icon: 'icon-archive',
text: t('deck', 'Unarchive board'),
icon: 'icon-delete',
text: t('deck', 'Delete board'),
})
}
actions.push({
action: () => {
this.hideMenu()
this.loading = true
this.boardApi.deleteBoard(this.board)
.then(() => {
this.loading = false
this.deleted = true
this.undoTimeoutHandle = setTimeout(() => {
this.$store.dispatch('removeBoard', this.board)
}, 7000)
})
},
icon: 'icon-delete',
text: t('deck', 'Delete board'),
})
actions.push({
action: () => {
const route = this.routeTo

View File

@@ -20,7 +20,7 @@
*
*/
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
/**
* This class handles all the api communication with the Deck backend.

View File

@@ -20,7 +20,7 @@
*
*/
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
export class CardApi {

View File

@@ -20,7 +20,7 @@
*
*/
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
import { getCurrentUser } from '@nextcloud/auth'
export class CommentApi {

View File

@@ -20,7 +20,7 @@
*
*/
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
export class StackApi {

View File

@@ -24,7 +24,7 @@ import 'url-search-params-polyfill'
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'nextcloud-axios'
import axios from '@nextcloud/axios'
import { BoardApi } from './../services/BoardApi'
import stack from './stack'
import card from './card'
@@ -96,6 +96,15 @@ export default new Vuex.Store({
currentBoardLabels: state => {
return state.currentBoard ? state.currentBoard.labels : []
},
canEdit: state => {
return state.currentBoard ? state.currentBoard.permissions.PERMISSION_EDIT : false
},
canManage: state => {
return state.currentBoard ? state.currentBoard.permissions.PERMISSION_MANAGE : false
},
canShare: state => {
return state.currentBoard ? state.currentBoard.permissions.PERMISSION_SHARE : false
},
},
mutations: {
toggleShowArchived(state) {
@@ -218,7 +227,7 @@ export default new Vuex.Store({
updateAclFromCurrentBoard(state, acl) {
for (const acl_ in state.currentBoard.acl) {
if (state.currentBoard.acl[acl_].participant.uid === acl.participant.uid) {
state.currentBoard.acl[acl_] = acl
Vue.set(state.currentBoard.acl, acl_, acl)
break
}
}
@@ -246,6 +255,12 @@ export default new Vuex.Store({
commit('setAssignableUsers', board.users)
},
async refreshBoard({ commit }, boardId) {
const board = await apiClient.loadById(boardId)
commit('setCurrentBoard', board)
commit('setAssignableUsers', board.users)
},
toggleShowArchived({ commit }) {
commit('toggleShowArchived')
},
@@ -392,7 +407,7 @@ export default new Vuex.Store({
apiClient.addAcl(newAcl)
.then((returnAcl) => {
commit('addAclToCurrentBoard', returnAcl)
dispatch('loadBoardById', newAcl.boardId)
dispatch('refreshBoard', newAcl.boardId)
})
},
updateAclFromCurrentBoard({ commit }, acl) {

View File

@@ -1,31 +0,0 @@
<div id="stack-add" ng-if="boardservice.canManage() && checkCanEdit()">
<form class="ng-pristine ng-valid" ng-submit="createStack()">
<label for="new-stack-input-<?php p($_['headerControlsId']); ?>" class="hidden-visually"><?php p($l->t('Add a new stack')); ?></label>
<input type="text" class="no-close" placeholder="<?php p($l->t('Add a new stack')); ?>"
ng-focus="status.addStack=true"
ng-blur="status.addStack=false"
ng-model="newStack.title" required
id="new-stack-input-<?php p($_['headerControlsId']); ?>"
maxlength="100" />
<button class="button-inline icon icon-add" ng-style="{'opacity':'{{status.addStack ? 1: 0.5}}'}" type="submit" title="<?php p($l->t('Submit')); ?>">
<span class="hidden-visually"><?php p($l->t('Submit')); ?></span>
</button>
</form>
</div>
<button ng-if="params.filter!='archive'" ng-click="switchFilter('archive')" data-toggle="tooltip" data-placement="bottom" title="<?php p($l->t('Show archived cards')); ?>">
<i class="icon icon-archive" style="opacity:0.5;"></i>
<span class="hidden-visually"><?php p($l->t('Show archived cards')); ?></span>
</button>
<button ng-if="params.filter=='archive'" ng-click="switchFilter('')" data-toggle="tooltip" data-placement="bottom" title="<?php p($l->t('Hide archived cards')); ?>">
<i class="icon icon-archive"></i>
<span class="hidden-visually"><?php p($l->t('Hide archived cards')); ?></span>
</button>
<button ng-click="toggleCompactMode()" data-toggle="tooltip" data-placement="bottom" title="<?php p($l->t('Toggle compact mode')); ?>">
<i class="icon" ng-class="{ 'icon-toggle-compact-collapsed': compactMode, 'icon-toggle-compact-expanded': !compactMode }"></i>
<span class="hidden-visually"><?php p($l->t('Toggle compact mode')); ?></span>
</button>
<button ui-sref="board.detail({ id: id, tab: 0})" data-toggle="tooltip" data-placement="bottom" title="<?php p($l->t('Show board details')); ?>">
<i class="icon icon-settings"></i>
<span class="hidden-visually"><?php p($l->t('Show board details')); ?></span>
</button>

View File

@@ -1,187 +0,0 @@
<div id="board-status" ng-if="statusservice.active">
<div id="emptycontent">
<div class="icon-{{ statusservice.icon }}"></div>
<h2>{{ statusservice.title }}</h2>
<p>{{ statusservice.text }}</p></div>
</div>
<div id="controls">
<div class="crumb">
<a href="#" class="icon-home" title="<?php p($l->t('All Boards')); ?>"></a>
</div>
<div class="crumb" ng-if="boardservice.getCurrent().archived">
<a class="icon-archive"></a>
<a ui-sref="list({ filter: 'archived' })"><?php p($l->t('Archived boards')); ?></a>
</div>
<div class="crumb title">
<a class="bullet"><span class="board-bullet" ng-style="{'background-color':'#' + boardservice.getCurrent().color}"></span></a>
<a ui-sref=".({filter: ''})">{{ boardservice.getCurrent().title }}</a>
<a ui-sref=".detail({ tab: 0 })" title="<?php p($l->t('Share board')); ?>"><span class="icon icon-share"></span></a>
</div>
<div class="crumb title" ng-if="params.filter=='archive'">
<a><span class="icon icon-archive"></span></a>
<a><?php p($l->t('Archived cards')); ?></a>
</div>
<div class="board-header-controls hidden">
<?php print_unescaped($this->inc('part.board.headerControls', ['headerControlsId' => 'main'])); ?>
</div>
<div class="board-header-controls app-popover-menu-utils">
<button class="icon-more button" title="<?php p($l->t('Actions')) ?>"></button>
<div class="popovermenu hidden">
<div id="popover-controls">
<?php print_unescaped($this->inc('part.board.headerControls', ['headerControlsId' => 'popover'])); ?>
</div>
</div>
</div>
</div>
<div id="board" class="scroll-container" ng-click="sidebar.show=false" ui-sref="board" ng-class="{'card-selected': params.cardId}">
<search on-search="search" class="ng-hide"></search>
<div id="innerBoard" data-ng-model="stacks" data-as-sortable="sortOptionsStack">
<div class="stack" ng-repeat="s in stacks" data-as-sortable-item
data-columnindex="{{$index}}" id="column{{$index}}"
style="">
<h3 data-as-sortable-item-handle>
<span class="editable-inline"
ng-show="!s.status.editStack"
ng-click="s.status.editStack=true">{{ s.title }}</span>
<form ng-if="s.status.editStack" ng-submit="stackservice.update(s); s.status.editStack=false">
<input type="text" placeholder="<?php p($l->t('Add a new stack')); ?>"
ng-blur="stackservice.update(s); s.status.editStack=false" ng-model="s.title"
autofocus-on-insert required maxlength="100" />
</form>
<button class="icon-delete button-inline stack-actions"
ng-if="!s.status.editStack"
ng-click="stackDelete(s)"></button>
</h3>
<ul data-as-sortable="sortOptions" is-disabled="!boardservice.canEdit() || filter==='archive'" data-ng-model="s.cards" class="card-list" ng-class="{emptyStack: !s.cards.length}">
<li class="card as-sortable-item"
ng-repeat="c in s.cards"
data-as-sortable-item
ng-click="$event.stopPropagation()"
ui-sref="board.card({boardId: id, cardId: c.id})"
ng-class="{'archived': cardservice.get(c.id).archived, 'has-labels': cardservice.get(c.id).labels.length>0, 'current': cardservice.get(c.id).id == params.cardId, 'overdue': cardservice.get(c.id).overdue == 3, 'now': cardservice.get(c.id).overdue == 2, 'next': cardservice.get(c.id).overdue == 1, 'has-tasks': getCheckboxes(cardservice.get(c.id).description)[1] > 0, 'has-tasks-completed': getCheckboxes(cardservice.get(c.id).description)[1] > 0 && getCheckboxes(cardservice.get(c.id).description)[1] == getCheckboxes(cardservice.get(c.id).description)[0] }"
nv-file-drop="" uploader="uploader" options="{cardId: c.id}">
<div class="drop-indicator" uploader="uploader" nv-file-over>
<p><?php p($l->t('Drop your files here to upload it to the card')); ?></p>
</div>
<div data-as-sortable-item-handle>
<div class="card-upper">
<h4>
<span class="editable-inline"
ng-show="!c.status.editCard"
ng-click="$event.stopPropagation(); startTitleEdit(c)">{{cardservice.get(c.id).title}}</span>
<form ng-if="c.status.editCard" ng-submit="finishTitleEdit(c)">
<input
class="input-inline"
type="text"
ng-blur="finishTitleEdit(c)"
ng-model="c.renameTitle"
autofocus-on-insert
required
maxlength="100">
</form>
</h4>
<ul class="labels compact-item" ng-if="!compactMode">
<li ng-repeat="label in cardservice.get(c.id).labels"
ng-style="labelStyle(label.color)" title="{{ label.title }}">
<span>{{ label.title }}</span>
</li>
</ul>
</div>
<div class="card-controls compact-item" ng-if="!compactMode">
<i class="icon icon-description" ng-if="cardservice.get(c.id).description" title="{{ cardservice.get(c.id).description }}"></i>
<span class="due" ng-if="cardservice.get(c.id).duedate" ng-class="{'overdue': cardservice.get(c.id).overdue == 3, 'now': cardservice.get(c.id).overdue == 2, 'next': cardservice.get(c.id).overdue == 1 }" title="{{ cardservice.get(c.id).duedate }}">
<i class="icon icon-badge"></i>
<span data-timestamp="{{ cardservice.get(c.id).duedate | dateToTimestamp }}" class="live-relative-timestamp">{{ cardservice.get(c.id).duedate | relativeDateFilterString }}</span>
</span>
<div class="card-tasks" ng-if="getCheckboxes(cardservice.get(c.id).description)[1] > 0">
<i class="icon icon-checkmark"></i>
<span>{{ getCheckboxes(cardservice.get(c.id).description)[0] }}/{{ getCheckboxes(cardservice.get(c.id).description)[1] }}</span>
</div>
<div class="card-files" ng-if="attachmentCount(cardservice.get(c.id)) > 0">
<i class="icon icon-files-dark"></i>
<span>{{ attachmentCount(cardservice.get(c.id)) }}</span>
</div>
<div class="card-comments" ng-if="unreadCommentCount(cardservice.get(c.id)) > 0">
<i class="icon icon-comment"></i>
<span>{{ unreadCommentCount(cardservice.get(c.id)) }}</span>
</div>
<div class="card-assigned-users">
<div class="assigned-user" ng-repeat="user in cardservice.get(c.id).assignedUsers | limitTo: 3">
<avatar data-user="{{ user.participant.uid }}" data-displayname="{{ user.participant.displayname }}" data-tooltip></avatar>
</div>
</div>
<div class="app-popover-menu-utils" ng-if="!boardservice.isArchived()">
<button class="button-inline card-options icon-more" ng-model="card" title="<?php p($l->t('Actions')) ?>"></button>
<div class="popovermenu hidden">
<ul>
<li ng-if="!isCurrentUserAssigned(c)">
<a class="menuitem action action-rename permanent"
data-action="AssignToMe"
ng-click="cardAssignToMe(c); $event.stopPropagation();"><span
class="icon icon-user"></span><span><?php p($l->t('Assign card to me')); ?></span></a>
</li>
<li ng-if="isCurrentUserAssigned(c)">
<a class="menuitem action action-rename permanent"
data-action="UnassignFromMe"
ng-click="cardUnassignFromMe(c); $event.stopPropagation();"><span
class="icon icon-user"></span><span><?php p($l->t('Unassign card from me')); ?></span></a>
</li>
<li ng-if="params.filter!=='archive'">
<a class="menuitem action action-rename permanent"
data-action="Archive"
ng-click="cardArchive(c); $event.stopPropagation();"><span
class="icon icon-archive"></span><span><?php p($l->t('Archive card')); ?></span></a>
</li>
<li ng-if="params.filter==='archive'">
<a class="menuitem action action-rename permanent"
data-action="Unarchive"
ng-click="cardUnarchive(c); $event.stopPropagation();"><span
class="icon icon-archive"></span><span><?php p($l->t('Unarchive card')); ?></span></a>
</li>
<li>
<a class="menuitem action action-delete permanent"
data-action="Delete"
ng-click="cardDelete(c); $event.stopPropagation();"><span
class="icon icon-delete"></span><span><?php p($l->t('Delete card')); ?></span></a>
</li>
</ul>
</div>
</div>
</div>
</div>
</li>
</ul>
<!-- CREATE CARD //-->
<div
class="card create"
ng-class="{emptyStack: !s.cards.length}"
ng-style="{'border-color':'#{{ boardservice.getCurrent().color }}'}"
ng-if="boardservice.canEdit() && checkCanEdit() && params.filter !== 'archive'">
<form name="addCardForm{{ s.id }}" ng-submit="createCard(s.id, newCard.title)">
<h4 ng-if="status.addCard[s.id]">
<input type="text" autofocus-on-insert
ng-model="newCard.title"
ng-blur="status.addCard[s.id]=false"
ng-style="{'border-color':'{{ boardservice.getCurrent().color | textColorFilter }}'}"
maxlength="100"
required placeholder="<?php p($l->t('Enter a card title')); ?>"/>
</h4>
</form>
<div ng-if="!status.addCard[s.id]" ng-click="status.addCard[s.id]=true" title="<?php p($l->t('Add card')); ?>">
<i class="icon icon-add"></i>
<span class="hidden-visually"><?php p($l->t('Add card')); ?></span>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,174 +0,0 @@
<div id="board-status" ng-if="statusservice.active">
<div id="emptycontent">
<div class="icon-{{ statusservice.icon }}"></div>
<h2>{{ statusservice.title }}</h2>
<p>{{ statusservice.text }}</p></div>
</div>
<div id="sidebar-header">
<a class="icon-close" ui-sref="board" ng-click="sidebar.show=!sidebar.show" title="<?php p($l->t('Close')); ?>"> &nbsp;<?php
?><span class="hidden-visually"><?php p($l->t('Close')); ?></span><?php
?></a>
<h3>{{ boardservice.getCurrent().title }}</h3>
</div>
<ul class="tabHeaders">
<li class="tabHeader" ng-class="{'selected': (params.tab==0 || !params.tab)}" ui-sref="{tab: 0}"><a><?php p($l->t('Sharing')); ?></a></li>
<li class="tabHeader" ng-class="{'selected': (params.tab==1)}" ui-sref="{tab: 1}"><a><?php p($l->t('Tags')); ?></a></li>
<li class="tabHeader" ng-class="{'selected': (params.tab==2)}" ui-sref="{tab: 2}"><a><?php p($l->t('Deleted items')); ?></a></li>
<li class="tabHeader" ng-class="{'selected': (params.tab==4)}" ui-sref="{tab: 4}" ng-if="isTimelineEnabled()"><a><?php p($l->t('Timeline')); ?></a></li>
</ul>
<div class="tabsContainer">
<div id="tabBoardShare" class="tab" ng-if="params.tab==0 || !params.tab">
<ui-select ng-if="boardservice.canShare()" ng-model="status.addSharee" theme="select2"
title="<?php p($l->t('Select users or groups to share with')); ?>"
placeholder="<?php p($l->t('Select users or groups to share with')); ?>"
on-select="aclAdd(status.addSharee)" search-enabled="true">
<ui-select-match placeholder="<?php p($l->t('Select users or groups to share with')); ?>">
<span><i class="icon icon-{{aclTypeString($item)}}"></i> {{ $item.participant.displayname }}</span>
</ui-select-match>
<ui-select-choices refresh="searchForUser($select.search)" refresh-delay="0" repeat="sharee in boardservice.sharees">
<div class="avatardiv" avatar data-user="{{ sharee.participant.uid }}" data-displayname="{{ sharee.participant.displayname }}" ng-if="sharee.type==OC.Share.SHARE_TYPE_USER"></div>
<div class="avatardiv" ng-if="sharee.type==OC.Share.SHARE_TYPE_GROUP"><i class="icon icon-{{aclTypeString(sharee)}}" ></i></div>
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_GROUP">
{{ sharee.participant.displayname }} (<?php p($l->t('Group')); ?>)
</span>
<div class="avatardiv circles" ng-if="sharee.type==OC.Share.SHARE_TYPE_CIRCLE"><i class="icon icon-circles icon-white"></i></div>
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_CIRCLE">
{{ sharee.participant.displayname }} (<?php p($l->t('Circle')); ?>)
</span>
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_USER">
{{ sharee.participant.displayname }}
</span>
</ui-select-choices>
<ui-select-no-choice>
<?php p($l->t('No matching user or group found.')); ?>
</ui-select-no-choice>
</ui-select>
<ul id="shareWithList" class="shareWithList">
<li>
<span class="icon-loading-small" style="display:none;"></span>
<div class="avatardiv" avatar data-user="{{ boardservice.getCurrent().owner.uid }}" data-displayname="{{ boardservice.getCurrent().owner.displayname }}" ng-if="boardservice.id"></div>
<span class="has-tooltip username">
{{ boardservice.getCurrent().owner.displayname }}
</span>
</li>
<li ng-repeat="acl in boardservice.getCurrent().acl track by acl.participant.primaryKey">
<span class="icon-loading-small" style="display:none;" title="<?php p($l->t('Loading')); ?>"></span>
<div class="avatardiv" avatar data-contactsmenu="true" data-user="{{ acl.participant.uid }}" data-displayname="{{ acl.participant.displayname }}" ng-if="acl.type==OC.Share.SHARE_TYPE_USER"></div>
<div class="avatardiv" ng-if="acl.type!=OC.Share.SHARE_TYPE_USER"><i class="icon icon-{{aclTypeString(acl)}}" ></i></div>
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_USER">
{{ acl.participant.displayname }}
</span>
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_GROUP">
{{ acl.participant.displayname }} (<?php p($l->t('Group')); ?>)
</span>
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_CIRCLE">
{{ acl.participant.displayname }} (<?php p($l->t('Circle')); ?> {{ acl.participant.typeString }})
<div>{{ acl.participant.circleOwner.display_name }}</div>
</span>
<span class="sharingOptionsGroup">
<span class="shareOption"ng-if="boardservice.canManage()">
<input type="checkbox" class="permissions checkbox" id="checkbox-permission-{{ acl.id }}-edit" ng-model="acl.permissionEdit" ng-change="aclUpdate(acl)" />
<label for="checkbox-permission-{{ acl.id }}-edit"><?php p($l->t('Edit')); ?></label>
</span>
<span class="shareOption" ng-if="boardservice.canManage()">
<input type="checkbox" class="permissions checkbox" id="checkbox-permission-{{ acl.id }}-share" ng-model="acl.permissionShare" ng-change="aclUpdate(acl)" />
<label for="checkbox-permission-{{ acl.id }}-share"><?php p($l->t('Share')); ?></label>
</span>
<span class="shareOption"ng-if="boardservice.canManage()">
<input type="checkbox" class="permissions checkbox" id="checkbox-permission-{{ acl.id }}-manage" ng-model="acl.permissionManage" ng-change="aclUpdate(acl)" />
<label for="checkbox-permission-{{ acl.id }}-manage"><?php p($l->t('Manage')); ?></label>
</span>
</span>
<a ng-if="boardservice.canManage()" ng-click="aclDelete(acl)"><span class="icon-loading-small hidden"></span><span class="icon icon-delete"></span><span class="hidden-visually"><?php p($l->t('Discard share')); ?></span></a>
</li>
<li ng-if="!boardservice.canShare()">
<?php p($l->t('Sharing has been disabled for your account.')); ?>
</li>
</ul>
<div id="collaborationResources"></div>
</div>
<div id="board-detail-labels" class="tab commentsTabView" ng-if="params.tab==1">
<ul class="labels">
<li ng-repeat="label in boardservice.getCurrent().labels">
<span class="label-title" ng-style="{'background-color':'#{{label.color}}','color':'{{ label.color|textColorFilter }}'}" ng-if="!label.edit">
<span ng-if="label.title">{{ label.title }}</span><i ng-if="!label.title"><br /></i>
</span>
<div class="label-edit" ng-if="label.edit">
<div ng-style="{'background-color':'#{{label.color}}','color':'{{ textColor(label.color) }}','width':'100%'}">
<form ng-submit="labelUpdate(label)">
<input type="text" ng-model="label.title" class="input-inline" ng-style="{'background-color':'#{{label.color}}','color':'{{ label.color|textColorFilter }}'}" autofocus-on-insert maxlength="100"/>
</form>
</div>
<div class="colorselect" ng-controller="ColorPickerController">
<div class="color" ng-repeat="c in defaultColors" ng-style="{'background-color':'#{{ c }}'}" ng-click="label=setColor(label,c);" ng-class="{'selected': (c == label.color) }"><br /></div>
<label class="colorselect-label{{ label.color | iconWhiteFilter }} color" ng-style="getCustomBackground(label.hashedColor)" ng-init="label.hashedColor='#' + label.color">
<input class="color" type="color" ng-model="label.hashedColor" value="#{{label.color}}" ng-change="label=setHashedColor(label)"/>
</label>
</div>
</div>
<a ng-if="boardservice.canManage() && label.edit" ng-click="labelUpdate(label)" class="icon" title="<?php p($l->t('Update tag')); ?>"><i class="icon icon-checkmark" ></i><span class="hidden-visually"><?php p($l->t('Update tag')); ?></span></a>
<a ng-if="boardservice.canManage() && !label.edit" ng-click="labelUpdateBefore(label); label.edit=true" class="icon" title="<?php p($l->t('Edit tag')); ?>"><i class="icon icon-rename"></i><span class="hidden-visually"><?php p($l->t('Edit tag')); ?></span></a>
<a ng-if="boardservice.canManage()" ng-click="labelDelete(label)" class="icon" title="<?php p($l->t('Delete tag')); ?>"><i class="icon icon-delete" ></i><span class="hidden-visually"><?php p($l->t('Delete tag')); ?></span></a>
</li>
<li ng-if="status.createLabel">
<div class="label-edit">
<div ng-style="{'background-color':'#{{newLabel.color}}','color':'{{ textColor(newLabel.color) }}','width':'100%'}">
<form ng-submit="labelCreate(newLabel)">
<input type="text" class="input-inline" ng-model="newLabel.title" ng-style="{'color':'{{ newLabel.color|textColorFilter }}'};" autofocus-on-insert maxlength="100" />
</form>
</div>
<div class="colorselect" ng-controller="ColorPickerController">
<div class="color" ng-repeat="c in defaultColors" ng-style="{'background-color':'#{{ c }}'}" ng-click="newLabel=setColor(newLabel,c)" ng-class="{'selected': (c == newLabel.color), 'dark': (newBoard.color | textColorFilter) === '#ffffff' }"><br /></div>
<label class="colorselect-label{{ newLabel.color | iconWhiteFilter }} color" ng-style="getCustomBackground(newLabel.hashedColor)" ng-init="newLabel.hashedColor='#' + newLabel.color">
<input class="color" type="color" ng-model="newLabel.hashedColor" value="#{{newLabel.color}}" ng-change="newLabel=setHashedColor(newLabel)"/>
</label>
</div>
</div>
<a ng-click="labelCreate(newLabel)" class="icon" title="<?php p($l->t('Create')); ?>"><i class="icon icon-checkmark" ></i><span class="hidden-visually"><?php p($l->t('Create')); ?></span></a>
<a ng-click="status.createLabel=false" class="icon" title="<?php p($l->t('Close')); ?>"><i class="icon icon-close" ></i><span class="hidden-visually"><?php p($l->t('Close')); ?></span></a>
</li>
<li ng-if="boardservice.canManage() && !status.createLabel" class="label-create">
<a ng-click="status.createLabel=true" class="button"><span class="icon icon-add"></span><br /><span><?php p($l->t('Create a new tag')); ?></span></a>
</li>
</ul>
</div>
<div id="board-detail-deleted-stacks" class="tab deletedStacksTabView" ng-if="params.tab==2">
<h3><?php p($l->t('Deleted stacks')); ?></h3>
<ul class='board-detail__deleted-list'>
<li class='board-detail__deleted-list__item' ng-repeat="deletedStack in stackservice.deleted">
<span class="icon icon-deck"></span>
<span class="title">{{deletedStack.title}}</span>
<span class="live-relative-timestamp" data-timestamp="{{ deletedStack.deletedAt*1000 }}">{{deletedStack.deletedAt | relativeDateFilter }}</span>
<a ng-click="stackUndoDelete(deletedStack)"><span class="icon icon-history"></span></a>
</li>
</ul>
<h3><?php p($l->t('Deleted cards')); ?></h3>
<ul class='board-detail__deleted-list'>
<li class='board-detail__deleted-list__item' ng-repeat="deletedCard in cardservice.deleted">
<span class="icon icon-deck"></span>
<span class="title">{{deletedCard.title}} ({{stackservice.tryAllThenDeleted(deletedCard.stackId).title}})</span>
<span class="live-relative-timestamp" data-timestamp="{{ deletedCard.deletedAt*1000 }}">{{deletedCard.deletedAt | relativeDateFilter }}</span>
<a ng-click="cardOrCardAndStackUndoDelete(deletedCard)">
<span class="icon icon-history"></span>
</a>
</li>
</ul>
</div>
<div id="board-detail-activity" class="tab activityTabView" ng-if="isTimelineEnabled() && params.tab==4">
<activity-component ng-if="boardservice.getCurrent()" type="deck_board" element="boardservice.getCurrent()"></activity-component>
</div>
</div>

View File

@@ -1,134 +0,0 @@
<div id="board-status" ng-if="statusservice.active">
<div id="emptycontent">
<div class="icon-{{ statusservice.icon }}" title="<?php p($l->t('Status')); ?>"><span class="hidden-visually"><?php p($l->t('Status')); ?></span></div>
<h2>{{ statusservice.title }}</h2>
<p>{{ statusservice.text }}</p></div>
</div>
<div id="controls">
<div class="breadcrumb">
<div class="crumb svg last">
<a href="#" class="icon-home" title="<?php p($l->t('All Boards')); ?>">
<span class="hidden-visually"><?php p($l->t('All Boards')); ?></span>
</a>
</div>
</div>
</div>
<div id="emptycontent" ng-if="boardservice.sorted.length == 0 && status.filter == 'archived'">
<div class="icon-archive"></div>
<h2><?php p($l->t('No archived boards to display')); ?></h2>
</div>
<div id="emptycontent" ng-if="boardservice.sorted.length == 0 && status.filter == 'shared'">
<div class="icon-share"></div>
<h2> <?php p($l->t('No shared boards to display')); ?> </h2>
</div>
<div id="boardlist" ng-if="boardservice.sorted.length > 0 || !status.filter">
<table width="100%">
<thead>
<tr>
<td class="cell-board-bullet"></td>
<td class="cell-board-title" width="90%"><?php p($l->t('Title')); ?></td>
<td class="cell-board-members"><?php p($l->t('Members')); ?></td>
<td></td>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="b in boardservice.sorted track by b.id" ng-class="{deleted: b.deletedAt > 0}">
<td ng-click="gotoBoard(b)">
<div class="board-bullet" ng-style="{'background-color':'#'+b.color}"> </div>
</td>
<td>
<div ng-click="gotoBoard(b)" ng-show="!b.status.edit">{{ b.title }}</div>
<div class="app-navigation-entry-edit" ng-show="b.status.edit">
<form ng-disabled="isAddingList" class="ng-pristine ng-valid" ng-submit="boardUpdate(b)">
<input class="edit ng-valid ng-empty" type="text" autofocus-on-insert ng-model="b.title" maxlength="100" ng-model-options="{ debounce: 250 }">
<div class="colorselect" ng-controller="ColorPickerController">
<div class="color" ng-repeat="c in ::colors" ng-style="{'background-color':'#{{ c }}'}" ng-click="b=setColor(b,c)" ng-class="{'selected': (c == b.color) }"></div>
<label class="colorselect-label{{ b.color | iconWhiteFilter }} color" ng-style="getCustomBackground(b.hashedColor)" ng-init="b.hashedColor='#' + b.color">
<input class="color" type="color" ng-model="b.hashedColor" value="#{{b.color}}" ng-change="b=setHashedColor(b)"/>
</label>
</div>
</form>
</div>
</td>
<td>
<div id="assigned-users">
<avatar data-contactsmenu data-tooltip data-user="{{ b.owner.uid }}" data-displayname="{{ b.owner.displayname }}"></avatar>
<avatar data-contactsmenu data-tooltip data-user="{{ acl.participant.uid }}" data-displayname="{{ acl.participant.displayname }}" ng-repeat="acl in b.acl | limitTo: 7 track by acl.id"></avatar>
</div>
</td>
<td>
<div class="app-popover-menu-utils" ng-if="b.deletedAt == 0" ng-show="!b.status.edit">
<button class="icon icon-more button-inline" title="<?php p($l->t('Actions')); ?>">
<span class="hidden-visually"><?php p($l->t('More actions')); ?></span>
</button>
<div class="popovermenu bubble hidden">
<ul>
<li ng-click="boardUpdateBegin(b); b.status.edit = true">
<a class="menuitem"><span class="icon-rename"></span> <?php p($l->t('Edit board')); ?>
</a>
</li>
<li ng-if="boardservice.canManage(b) && !b.archived" ng-click="boardArchive(b)">
<a class="menuitem"><span class="icon-archive"></span> <?php p($l->t('Archive board')); ?>
</a>
</li>
<li ng-if="boardservice.canManage(b) && b.archived" ng-click="boardUnarchive(b)">
<a class="menuitem"><span class="icon-archive"></span> <?php p($l->t('Unarchive board')); ?>
</a>
</li>
<li ng-if="boardservice.canManage(b)" ng-click="boardDelete(b)">
<a class="menuitem"><span class="icon-delete"></span> <?php p($l->t('Delete board')); ?>
</a>
</li>
<li ui-sref="board.detail({boardId: b.id})">
<a class="menuitem"><span class="icon-settings-dark"></span> <?php p($l->t('Show board details')); ?>
</a>
</li>
</ul>
</div>
</div>
<div class="board-edit-controls" ng-show="b.status.edit">
<span class="icon icon-checkmark" ng-click="boardUpdate(b)" title="<?php p($l->t('Update board')); ?>"><span class="hidden-visually"><?php p($l->t('Update board')); ?></span></span>
<span class="icon icon-close" ng-click="boardUpdateReset(b)" title="<?php p($l->t('Reset board')); ?>"><span class="hidden-visually"><?php p($l->t('Reset board')); ?></span></span>
</div>
<div class="app-popover-menu-utils" ng-if="b.deletedAt > 0">
<button class="icon icon-history button-inline" ng-click="boardDeleteUndo(b)" title="<?php p($l->t('Undo board deletion - Otherwise the board will be deleted during the next cronjob run.')); ?>"><span class="hidden-visually"><?php p($l->t('Undo board deletion - Otherwise the board will be deleted during the next cronjob run.')); ?></span></button>
</div>
</td>
</tr>
<tr ng-if="canCreate && status.filter === '' && !status.addBoard" ng-click="status.addBoard=!status.addBoard" class="board-create">
<td><span class="icon icon-add"></span></td>
<td colspan="3">
<a ng-click="status.addBoard=!status.addBoard"
ng-show="!status.addBoard">
<?php p($l->t('Create new board')); ?>
</a>
</td>
</tr>
<tr ng-if="status.filter === '' && status.addBoard">
<td><span class="icon icon-add"></span></td>
<td>
<form ng-disabled="isAddingList"
class="ng-pristine ng-valid" ng-submit="boardCreate()">
<input class="edit ng-valid ng-empty"
type="text" placeholder="<?php p($l->t('New board title')); ?>"
autofocus-on-insert ng-model="newBoard.title" maxlength="100" ng-model-options="{ debounce: 250 }">
<div class="colorselect" ng-controller="ColorPickerController">
<div class="color" ng-repeat="c in ::colors" ng-style="{'background-color':'#{{ c }}'}" ng-click="selectColor(c);b=setColor(b,c);"ng-class="{'selected': (c == newBoard.color), 'dark': (newBoard.color | textColorFilter) === '#ffffff' }"></div>
<label class="colorselect-label{{ newBoard.color | iconWhiteFilter }} color" ng-style="getCustomBackground(newBoard.hashedColor)" ng-init="newBoard.hashedColor='#' + newBoard.color">
<input class="color" type="color" ng-model="newBoard.hashedColor" value="#{{newBoard.color}}" ng-change="newBoard=setHashedColor(newBoard)"/>
</label>
</div>
</form>
</td>
<td></td>
<td>
<div class="board-edit-controls">
<span class="icon icon-checkmark" ng-click="boardCreate()" title="<?php p($l->t('Create board')); ?>"><span class="hidden-visually"><?php p($l->t('Create board')); ?></span></span>
<span class="icon icon-close" ng-click="status.addBoard=!status.addBoard" title="<?php p($l->t('Close')); ?>"><span class="hidden-visually"><?php p($l->t('Close')); ?></span></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>

View File

@@ -1,47 +0,0 @@
<div id="commentsTabView">
<div class="newCommentRow comment" data-id="" ng-show="$ctrl.type === 'deck_card'">
<div class="authorRow">
<div class="avatardiv" avatar ng-attr-user="{{ $ctrl.currentUser.uid }}" ng-attr-displayname="{{ $ctrl.currentUser.displayName }}" ng-attr-size="24"></div>
<div class="author currentUser">{{ $ctrl.currentUser.displayName }}</div>
</div>
<form class="newCommentForm" ng-submit="$ctrl.postComment()">
<div ng-contenteditable contenteditable="true" class="message" ng-submit="$ctrl.postComment()" data-placeholder="{{ newCommentString }}" ng-model="$ctrl.$scope.newComment" ng-disabled="$ctrl.status.commentCreateLoading"></div>
<input class="submit icon-confirm has-tooltip" type="submit"
value="" title="" data-original-title="Post" ng-if="!$ctrl.status.commentCreateLoading">
<div class="submitLoading icon-loading-small" ng-if="$ctrl.status.commentCreateLoading"></div>
</form>
</div>
<ul class="activities" infinite-scroll="$ctrl.page()" infinite-scroll-container="'#app-sidebar'" infinite-scroll-disabled="$ctrl.activityservice.running" infinite-scroll-immediate-check="false">
<li ng-if="$ctrl.loadingNewer()"><div class="icon-loading-small"></div></li>
<li class="activity box" ng-repeat="activity in $ctrl.getActivityStream() track by $index">
<div class="activity-icon">
<img ng-if="!activity.commentModel" src="{{activity.icon}}" alt="">
<div ng-if="activity.commentModel" avatar ng-attr-contactsmenu="true" ng-attr-size="24" ng-attr-user="{{ activity.commentModel.get('actorId') }}" ng-attr-displayname="{{ activity.actorDisplayName }}"></div>
</div>
<span class="activitytime has-tooltip live-relative-timestamp"
data-timestamp="{{ activity.timestamp }}">{{ activity.timestamp/1000 | relativeDateFilter }}</span>
<div class="activitysubject" ng-if="!activity.commentModel" bind-html-compile="$ctrl.parseMessage(activity)"></div>
<div class="activitysubject commentAuthor" ng-if="activity.commentModel">
{{ activity.subject_rich[1].user.name }}
<div class="app-popover-menu-utils">
<button class="button-inline icon-more ng-pristine ng-valid ng-empty ng-touched" aria-label="Actions"></button>
<div class="popovermenu hidden menu-left">
<ul>
<li><a ng-click="$ctrl.updateComment(activity)" class="menuitem action edit permanent" data-action="edit"><span class="icon icon-rename"></span><span>Edit comment</span></a></li>
<li><a ng-click="$ctrl.deleteComment(activity)" class="menuitem action delete permanent" data-action="delete"><span class="icon icon-delete"></span><span>Delete comment</span></a></li>
</ul>
</div>
</div>
</div>
<div class="activitymessage" ng-if="!activity.commentModel" ng-bind-html="activity.message"></div>
<div class="activitymessage" ng-if="activity.commentModel && !activity.commentEdit" bind-html-compile="$ctrl.formatMessage(activity)"></div>
<form class="newCommentForm" ng-show="activity.commentEdit">
<div ng-contenteditable contenteditable="true" class="message" ng-model="activity.commentEdit"></div>
<input class="submit icon-confirm has-tooltip" type="submit"
value="" title="" data-original-title="Post" ng-click="$ctrl.editComment(activity)">
</form>
</li>
<li ng-if="$ctrl.loading"><div class="icon-loading-small"></div></li>
</ul>
</div>

View File

@@ -1,55 +0,0 @@
<div ng-class="{'attachment-list-wrapper': $ctrl.isFileSelector}">
<div class="attachment-list" ng-class="{selector: $ctrl.isFileSelector}">
<h3 class="attachment-selector" ng-if="$ctrl.isFileSelector"><?php p($l->t('Select an attachment')); ?> <a class="icon-close" ng-click="$ctrl.abort()"></a></h3>
<ul>
<li class="attachment"
ng-repeat="attachment in $ctrl.fileservice.getProgressItemsForCard($ctrl.cardservice.getCurrent().id)">
<a class="fileicon icon-file"></a>
<div class="details">
<div class="filename">
<span class="basename">{{ attachment.file.name }}</span>
</div>
<progress ng-attr-value="{{ attachment.progress }}" max="100"></progress>
</div>
<button class="icon icon-close button-inline" ng-click="attachment.cancel()">
<span class="hidden-visually"><?php p($l->t('Cancel upload')); ?></span>
</button>
</li>
<li class="attachment"
ng-repeat="attachment in $ctrl.cardservice.getCurrent().attachments | filter: {type: 'deck_file'} | orderBy: ['deletedAt', '-lastModified']"
ng-class="{deleted: attachment.deletedAt > 0, selector: $ctrl.isFileSelector}"
ng-if="!$ctrl.isFileSelector || attachment.deletedAt == 0">
<a class="fileicon" ng-style="$ctrl.mimetypeForAttachment(attachment)" ng-href="{{ attachmentUrl(attachment) }}"></a>
<div class="details">
<a ng-href="{{ $ctrl.attachmentUrl(attachment) }}" target="_blank">
<div class="filename">
<span class="basename">{{ attachment.extendedData.info.filename}}</span>
<span class="extension">.{{ attachment.extendedData.info.extension}}</span>
</div>
<span class="filesize">{{ attachment.extendedData.filesize | bytes }}</span>
<span class="filedate">{{ attachment.lastModified|relativeDateFilter }}</span>
<span class="filedate"><?php p($l->t('by')); ?> {{ attachment.createdBy }}</span>
</a>
</div>
<button class="icon icon-history button-inline" ng-click="$ctrl.cardservice.attachmentRemoveUndo(attachment)" ng-if="!$ctrl.isFileSelector && attachment.deletedAt > 0" title="<?php p($l->t('Undo file deletion - Otherwise the file will be deleted during the next cronjob run.')); ?>">
<span class="hidden-visually"><?php p($l->t('Undo file deletion')); ?></span>
</button>
<button class="icon icon-confirm button-inline" ng-click="$ctrl.select(attachment)" ng-if="$ctrl.isFileSelector">
<span class="hidden-visually"><?php p($l->t('Insert the file into the description')); ?></span>
</button>
<div class="app-popover-menu-utils" ng-if="!$ctrl.isFileSelector && attachment.deletedAt == 0">
<button class="button-inline icon icon-more" title="<?php p($l->t('Actions')) ?>"></button>
<div class="popovermenu hidden">
<ul>
<li>
<a class="menuitem action action-delete"
ng-click="$ctrl.cardservice.attachmentRemove(attachment); $event.stopPropagation();"><span
class="icon icon-delete"></span><span><?php p($l->t('Delete attachment')); ?></span></a>
</li>
</ul>
</div>
</div>
</a>
</li>
</ul>
</div>

View File

@@ -1,139 +0,0 @@
<div nv-file-drop="" uploader="fileservice.uploader" class="drop-zone" options="{cardId: cardservice.getCurrent().id}">
<div class="drop-indicator" nv-file-over uploader="fileservice.uploader">
<p><?php p($l->t('Drop your files here to upload it to the card')); ?></p>
</div>
<div id="board-status" ng-if="statusservice.active">
<div id="emptycontent">
<div class="icon-{{ statusservice.icon }}" title="<?php p($l->t('Status')); ?>"><span class="hidden-visually"><?php p($l->t('Status')); ?></span></div>
<h2>{{ statusservice.title }}</h2>
<p>{{ statusservice.text }}</p></div>
</div>
{{card=cardservice.getCurrent();""}}
<div id="sidebar-header">
<a class="icon-close" ui-sref="board" ng-click="sidebar.show=!sidebar.show">&nbsp;</a>
<h3>
<!-- TODO: change to textarea elastic //-->
<form ng-submit="cardRename(cardservice.getCurrent())">
<input class="input-inline" type="text" ng-if="status.cardRename"
ng-model="status.renameTitle"
ng-blur="cardRename(cardservice.getCurrent())"
autofocus-on-insert required maxlength="100">
</form>
<div ng-click="cardRenameShow()" ng-if="!status.cardRename">
{{ cardservice.getCurrent().title }}
</div>
</h3>
<div id="card-dates">
<?php p($l->t('Modified:')); ?> <span class="live-relative-timestamp" data-timestamp="{{cardservice.getCurrent().lastModified*1000}}">{{ cardservice.getCurrent().lastModified|relativeDateFilter }}</span>
<?php p($l->t('Created:')); ?> <span class="live-relative-timestamp" data-timestamp="{{cardservice.getCurrent().createdAt*1000}}">{{ cardservice.getCurrent().createdAt|relativeDateFilter }}</span>
</div>
</div>
<div id="card-meta" class="card-block">
<div class="section-wrapper" ng-if="!(boardservice.isArchived() || card.archived) && card.labels">
<div class="section-label icon-tag" data-toggle="tooltip" data-placement="right" title="<?php p($l->t('Tags')); ?>"><span class="hidden-visually"><?php p($l->t('Tags')); ?></span></div>
<div class="section-details">
<ui-select multiple tagging="" ng-model="card.labels" theme="select2"
ng-disabled="boardservice.isArchived() || card.archived"
title="<?php p($l->t('Choose a tag')); ?>"
placeholder="<?php p($l->t('Add a tag')); ?>"
on-select="labelAssign($item, $model)"
on-remove="labelRemove($item, $model)" ng-disabled="!boardservice.canEdit() || archived">
<ui-select-match placeholder="<?php p($l->t('Select tags')); ?>">
<span class="select-label" ng-style="labelStyle($item.color)">{{$item.title}}&nbsp;</span>
</ui-select-match>
<ui-select-choices
repeat="label in boardservice.getCurrent().labels | filter:$select.search track by label.id">
<span class="choose-label" ng-style="labelStyle(label.color)">{{label.title}}</span>
</ui-select-choices>
</ui-select>
</div>
</div>
<div class="section-wrapper card-details-assign-users">
<div class="section-label icon-user" data-toggle="tooltip" data-placement="right" title="<?php p($l->t('Assign users')); ?>" ng-click="toggleAssignUser()"><span class="hidden-visually"><?php p($l->t('Assign users')); ?></span></div>
<div class="section-details" ng-if="cardservice.getCurrent()">
<ui-select id="assignUserSelect" class="card-details-assign-user" ng-model="status.assignedUser" ng-show="status.showAssignUser" uis-open-close="assingUserOpenClose(isOpen)"
theme="select2"
title="<?php p($l->t('Choose a user to assign')); ?>" placeholder="<?php p($l->t('Choose a user to assign')); ?>"
on-select="addAssignedUser($item)">
<ui-select-match placeholder="<?php p($l->t('Assign this card to a user')); ?>">
<span><i class="icon icon-{{$item.type}}"></i> {{ $item.participant.displayname }}</span>
</ui-select-match>
<ui-select-choices repeat="acl in boardservice.getUsers() | filter: $select.search | withoutAssignedUsers: cardservice.getCurrent().assignedUsers track by acl.uid">
<div class="avatardiv" avatar ng-attr-user="{{ acl.uid }}" ng-attr-displayname="{{ acl.displayname }}" ng-if="boardservice.id"></div><span>{{ acl.displayname }}</span>
</ui-select-choices>
</ui-select>
<div class="card-details-assign-users-list">
<div class="assigned-user" ng-repeat="user in cardservice.getCurrent().assignedUsers track by user.participant.uid">
<avatar ng-attr-contactsmenu ng-attr-tooltip ng-attr-user="{{ user.participant.uid }}" ng-attr-displayname="{{ user.participant.displayname }}" contactsmenudelete ></avatar>
</div>
<a class="icon-add icon-inline" ng-click="toggleAssignUser()"></a>
</div>
</div>
</div>
<div class="section-wrapper">
<div class="section-label icon-calendar-dark" data-placement="right" title="<?php p($l->t('Due date')); ?>"><span class="hidden-visually"><?php p($l->t('Due date')); ?></span></div>
<div class="section-details duedate">
<input class="datepicker-input medium focus" type="text" placeholder="<?php p($l->t('Click to set')); ?>" value="{{ cardservice.getCurrent().duedate | parseDate }}" datepicker="due" ng-disabled="(boardservice.isArchived() || card.archived)" />
<input class="timepicker-input medium focus" type="text" placeholder="00:00" ng-disabled="!cardservice.getCurrent().duedate || (boardservice.isArchived() || card.archived)" value="{{ cardservice.getCurrent().duedate | parseTime }}" timepicker="due" />
<button class="icon icon-delete button-inline" title="<?php p($l->t('Remove due date')); ?>" ng-if="cardservice.getCurrent().duedate" ng-click="resetDuedate()"><span class="hidden-visually"><?php p($l->t('Remove due date')); ?></span></button>
</div>
</div>
<div class="section-header-tabbed">
<ul class="tabHeaders ng-scope">
<li class="tabHeader" ng-class="{'selected': (params.tab==0 || !params.tab)}" ui-sref="{tab: 0}"><span class="icon icon-description"></span><a><?php p($l->t('Description')); ?></a></li>
<li class="tabHeader" ng-class="{'selected': (params.tab==1)}" ui-sref="{tab: 1}"><span class="icon icon-files-dark"></span><a><?php p($l->t('Attachments')); ?></a></li>
<li class="tabHeader" ng-class="{'selected': (params.tab==2)}" ui-sref="{tab: 2}" ng-if="isTimelineEnabled()"><span class="icon icon-activity"></span><a><?php p($l->t('Timeline')); ?></a></li>
</ul>
</div>
<div class="tabDetails" ng-if="params.tab === 0">
<span class="save-indicator saved"><?php p($l->t('Saved')); ?></span>
<span class="save-indicator unsaved"><?php p($l->t('Unsaved changes')); ?></span>
<div style="flex-grow: 1;"> </div>
<input ng-if="status.cardEditDescription" type="button" ng-mousedown="status.continueEdit = true; status.selectAttachment = true;" class="icon-files-dark" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Insert attachment')); ?>"/>
<a href="https://deck.readthedocs.io/en/latest/Markdown/" target="_blank" class="icon icon-help" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Formatting help')); ?>"><span class="hidden-visually"><?php p($l->t('Formatting help')); ?></span></a>
</div>
<div class="section-content card-attachments">
<div>
<label ng-if="params.tab === 1" for="attachment-upload" class="button data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Upload attachment')); ?>">
<span class="icon-upload" ng-class="{'icon-loading-small': fileservice.uploader.isUploading}"></span>
<?php p($l->t('Upload attachment')); ?>
</label>
<input id="attachment-upload" type="file" nv-file-select="" uploader="fileservice.uploader" class="hidden" options="{cardId: cardservice.getCurrent().id}"/>
</div>
<div class="error icon-error" ng-if="fileservice.status"><strong>{{ fileservice.status.error }}</strong><br />{{ fileservice.status.message }}</div>
<attachment-list-component ng-if="params.tab === 1 && cardservice.getCurrent() && isArray(cardservice.getCurrent().attachments)" attachments="cardservice.getCurrent().attachments"></attachment-list-component>
</div>
<div class="section-content card-description" ng-if="params.tab === 0">
<attachment-list-component
ng-if="status.selectAttachment"
attachments="cardservice.getCurrent().attachments"
is-file-selector="true"
on-select="addAttachmentToDescription(attachment)" on-abort="abortAttachmentSelection()">
</attachment-list-component>
<textarea elastic ng-if="status.cardEditDescription"
placeholder="<?php p($l->t('Add a card description…')); ?>"
ng-blur="!status.continueEdit && cardUpdate(status.edit)"
ng-model="status.edit.description"
ng-change="cardEditDescriptionChanged(); updateMarkdown(status.edit.description)"
autofocus-on-insert> </textarea>
<div class="container" ng-click="clickCardDescription($event)"
ng-if="!status.cardEditDescription" ng-animate>
<div class="placeholder"
ng-if="!description()"><?php p($l->t('Add a card description…')); ?></div>
<div id="markdown" ng-bind-html="description()">{{ description() }}</div>
</div>
</div>
<div class="section-content card-activity activityTabView" ng-if="isTimelineEnabled() && params.tab === 2">
<activity-component type="deck_card" element="cardservice.getCurrent()"></activity-component>
</div>
</div>

View File

@@ -1,73 +0,0 @@
<ul class="with-icon">
<li ng-class="{active: status.filter === '' && !boardservice.getCurrent()}"><a ui-sref="list({ filter: ''})" class="icon-deck"><?php p($l->t('All Boards')); ?></a></li>
<li ng-class="{active: status.filter === 'archived' || (boardservice.getCurrent() && boardservice.getCurrent().archived)}"><a ui-sref="list({ filter: 'archived' })" class="icon-archive"><?php p($l->t('Archived boards')); ?></a></li>
<li ng-class="{active: status.filter === 'shared'}"><a ui-sref="list({ filter: 'shared' })" class="icon-share"><?php p($l->t('Shared boards')); ?></a></li>
<li class="with-icon with-menu" ng-class="{active: b.id === boardservice.getCurrent().id, editing: b.status.editNavigation}" data-ng-repeat="b in boardservice.sidebar track by b.id" ng-if="b.deletedAt == 0">
<span class="board-bullet" ng-style="{'background-color': '#' + b.color}"> </span>
<a href="#!/board/{{b.id}}/">{{ b.title }}</a>
<div class="app-navigation-entry-utils">
<ul>
<li class="app-navigation-entry-utils-menu-button svg" ng-show="!status.deleteUndo[b.id]"><button class="icon-more" title="<?php p($l->t('Actions')); ?>"><span class="hidden-visually"><?php p($l->t('Actions')); ?></span></button></li>
</ul>
</div>
<div class="app-navigation-entry-menu" ng-show="!b.status.editNavigation">
<ul>
<li ng-show="boardservice.canManage(b)">
<a class="icon-rename" title="<?php p($l->t('Edit board')); ?>" ng-click="b.status.editNavigation=true">
<?php p($l->t('Edit board')); ?>
</a>
</li>
<li ng-show="boardservice.canManage(b)">
<a class="icon-archive" title="<?php p($l->t('Move board to archive')); ?>" ng-click="boardArchive(b)">
<?php p($l->t('Archive board')); ?>
</a>
</li>
<li ng-if="boardservice.canManage(b)">
<a class="icon-delete" title ="<?php p($l->t('Delete board')); ?>" ng-click="boardDelete(b)">
<?php p($l->t('Delete board')); ?>
</a>
</li>
<li ui-sref="board.detail({boardId: b.id})">
<a class="icon-settings-dark">
<?php p($l->t('Show board details')); ?>
</a>
</li>
</ul>
</div>
<div class="app-navigation-entry-edit">
<form ng-disabled="isAddingList" class="ng-pristine ng-valid" ng-submit="boardUpdate(b)">
<input class="edit ng-valid ng-empty" type="text" autofocus-on-insert ng-model="b.title" maxlength="100" ng-model-options="{ debounce: 250 }">
<input type="submit" value="" class="action icon-checkmark svg">
</form>
<div class="colorselect" ng-controller="ColorPickerController">
<div class="color" ng-repeat="c in ::colors" ng-style="{'background-color':'#{{ c }}'}" ng-click="b=setColor(b,c)" ng-class="{'selected': (c == b.color) }"></div>
<label class="colorselect-label{{ b.color | iconWhiteFilter }} color" ng-style="getCustomBackground(b.hashedColor)" ng-init="b.hashedColor='#' + b.color">
<input class="color" type="color" ng-model="b.hashedColor" ng-value="colorValue(b.color)" ng-change="b=setHashedColor(b)"/>
</label>
</div>
</div>
</li>
<li ng-class="{editing: status.addBoard}" ng-if="canCreate">
<a ng-click="status.addBoard=!status.addBoard" class="icon-add app-navigation-noclose">
<?php p($l->t('Create a new board')); ?>
</a>
<div class="app-navigation-entry-edit" ng-if="status.addBoard">
<form ng-disabled="isAddingList" class="ng-pristine ng-valid" ng-submit="boardCreate()">
<input class="edit ng-valid ng-empty" type="text" placeholder="<?php p($l->t('New board title')); ?>" autofocus-on-insert ng-model="newBoard.title" maxlength="100" ng-model-options="{ debounce: 250 }">
<input type="submit" value="" class="action icon-checkmark svg">
</form>
<div class="colorselect" ng-controller="ColorPickerController">
<div class="color" ng-repeat="c in ::colors" ng-style="{'background-color':'#{{ c }}'}" ng-click="selectColor(c);newBoard=setColor(newBoard,c)" ng-class="{'selected': (c == newBoard.color), 'dark': (newBoard.color | textColorFilter) === '#ffffff' }"><br /></div>
<label class="colorselect-label{{ newBoard.color | iconWhiteFilter }} color" ng-style="getCustomBackground(newBoard.hashedColor)" ng-init="newBoard.hashedColor='#' + newBoard.color">
<input class="color" type="color" ng-model="newBoard.hashedColor" ng-value="colorValue(newBoard.color)" ng-change="newBoard=setHashedColor(newBoard)"/>
</label>
</div>
</div>
</li>
</ul>

View File

@@ -1,21 +0,0 @@
<div id="app-settings" ng-if="isAdmin">
<div id="app-settings-header">
<button class="settings-button" data-apps-slide-toggle="#app-settings-content"><?php p($l->t('Settings')); ?></button>
</div>
<div id="app-settings-content" class="hidden">
<ui-select multiple tagging="" ng-model="groupLimit" theme="select2"
title="<?php p($l->t('Limit deck to groups')); ?>"
placeholder="<?php p($l->t('Limit deck to groups')); ?>"
on-select="groupLimitAdd($item, $model)"
on-remove="groupLimitRemove($item, $model)" ng-disabled="groupLimitDisabled">
<ui-select-match placeholder="<?php p($l->t('Limit deck to groups')); ?>">
<span class="select-label">{{$item.displayname}}&nbsp;</span>
</ui-select-match>
<ui-select-choices
repeat="group in groups | filter: $select.search | limitTo: 3 track by group.id" position="down">
<span class="choose-label">{{group.displayname}}</span>
</ui-select-choices>
</ui-select>
<p class="hint"><?php p($l->t('Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them.')); ?></p>
</div>
</div>