TT#40251 PBXConfig: As a Customer, I want to get notified about invalid input

before creating a PBXSeat

Change-Id: I5699e461ee1179bbed8094cefc50e0a6e504964f
changes/62/22762/6
Hans-Peter Herzog 7 years ago
parent c3963b1f35
commit 40e15adff0

@ -10,7 +10,7 @@ import { getList, get, patchReplace } from './common'
var createId = uuid.v4;
export const PBX_CONFIG_ORDER_BY = 'created_timestamp';
export const PBX_CONFIG_ORDER_BY = 'create_timestamp';
export const PBX_CONFIG_ORDER_DIRECTION = 'desc';
export function getGroups(options) {

@ -32,7 +32,7 @@
:after="searchButtonStationName"
/>
<q-chip
class="full-width"
class="full-width csc-search-criteria"
v-if="listStationNameFilter != null"
color="primary"
>{{ listStationNameFilter }}
@ -54,7 +54,7 @@
:after="searchButtonMacAddress"
/>
<q-chip
class="full-width"
class="full-width csc-search-criteria"
v-if="listMacAddressFilter != null"
color="primary"
>{{ listMacAddressFilter }}
@ -79,7 +79,7 @@
@select="filterByProfile"
/>
<q-chip
class="full-width"
class="full-width csc-search-criteria"
v-if="listProfileFilter != null"
:avatar="profileUrl"
color="primary"
@ -533,7 +533,7 @@
.filter-model-select
margin 16px 16px 8px 16px
.q-chip
.q-chip.csc-search-criteria
position relative
.q-chip-main
text-overflow ellipsis

@ -1,94 +1,230 @@
<template>
<q-card class="csc-entity csc-pbx-seat shadow-1">
<q-card-title class="csc-entity-title">
<q-item class="csc-list-item csc-pbx-seat">
<q-item-side
v-if="!expanded"
>
<q-icon
size="32px"
name="person"
color="secondary"
size="24px"
/>
<span class="csc-entity-title-text">
{{ entityTitle }}
</span>
<q-chip
</q-item-side>
<q-item-main>
<q-item-tile
v-if="!expanded"
pointing="left"
color="primary"
class="gt-md"
class="csc-item-title"
label
>
{{ $t('pbxConfig.extension') }}: <span class="csc-important">{{ seat.pbx_extension }}</span>
</q-chip>
<q-btn
:icon="titleIcon"
:small="isMobile"
color="primary"
slot="right"
flat
@click="toggleMain()"
/>
<q-btn
icon="delete"
:small="isMobile"
color="negative"
slot="right"
flat
@click="remove()"
/>
</q-card-title>
<q-card-main
v-if="expanded"
class="transition-generic"
{{ seat.display_name }}
</q-item-tile>
<q-item-tile
v-if="!expanded"
class="csc-item-subtitle"
sublabel
>
<div>
<span class="csc-item-label">{{ $t('pbxConfig.extension') }}:</span>
<span class="csc-item-value">{{ seat.pbx_extension }}</span>
</div>
</q-item-tile>
<q-item-tile
v-if="!expanded"
class="csc-item-subtitle"
sublabel
>
<div
v-if="!hasGroups"
class="csc-form-info"
>
<q-icon name="info" color="info" size="24px"/>
<span class="csc-info-text">{{ $t('pbxConfig.noGroupAssigned') }}</span>
</div>
<div
v-if="hasGroups">
<span
class="csc-item-label">
{{ $t('pbxConfig.groups') }}:
</span>
<span
class="csc-item-value"
v-for="group in seat.groups"
>
{{ group.display_name }}
</span>
</div>
</q-item-tile>
<q-item-tile
class="csc-list-item-main"
v-if="expanded"
>
<q-field :label="$t('pbxConfig.seatName')">
<q-input
v-model="changes.name"
:after="nameButtons"
@keyup.enter="saveName"
/>
</q-field>
<q-field :label="$t('pbxConfig.extension')">
<q-input
v-model="changes.extension"
:after="extensionButtons"
@keyup.enter="saveExtension"
/>
</q-field>
<q-field :label="$t('pbxConfig.primaryNumber')">
<q-input
v-model="primaryNumber"
readonly
disable
/>
</q-field>
<q-field :label="$t('pbxConfig.aliasNumbers')">
<q-select
ref="aliasNumbers"
v-model="changes.aliasNumbers"
:options="aliasNumberOptions"
multiple
chips
clearable
:after="aliasNumberButtons"
/>
</q-field>
<q-field :label="$t('pbxConfig.groups')">
<q-select
v-model="changes.groups"
:options="groupOptions"
multiple
chips
clearable
:after="groupButtons"
/>
</q-field>
</q-item-tile>
</q-item-main>
<q-item-side
right
class="csc-item-buttons"
>
<q-field :label="$t('pbxConfig.seatName')">
<q-input
v-model="changes.name"
:after="nameButtons"
@keyup.enter="saveName"
/>
</q-field>
<q-field :label="$t('pbxConfig.extension')">
<q-input
v-model="changes.extension"
type="number"
:after="extensionButtons"
@keyup.enter="saveExtension"
/>
</q-field>
<q-field :label="$t('pbxConfig.primaryNumber')">
<q-input
v-model="primaryNumber"
readonly
disable
/>
</q-field>
<q-field :label="$t('pbxConfig.aliasNumbers')">
<q-select
ref="aliasNumbers"
v-model="changes.aliasNumbers"
:options="aliasNumberOptions"
multiple
chips
clearable
:after="aliasNumberButtons"
/>
</q-field>
<q-field :label="$t('pbxConfig.groups')">
<q-select
v-model="changes.groups"
:options="groupOptions"
multiple
chips
clearable
:after="groupButtons"
/>
</q-field>
</q-card-main>
<q-item-tile>
<div class="csc-item-button">
<q-icon
size="26px"
:name="titleIcon"
color="primary"
slot="right"
@click="toggleMain()"
/>
</div>
<div class="csc-item-button">
<q-icon
size="26px"
name="delete"
color="negative"
slot="right"
@click="remove()"
/>
</div>
</q-item-tile>
</q-item-side>
<q-inner-loading :visible="isLoading">
<q-spinner-mat
size="60px"
color="primary"
/>
</q-inner-loading>
</q-card>
</q-item>
<!--<q-card class="csc-entity csc-pbx-seat shadow-1">-->
<!--<q-card-title class="csc-entity-title">-->
<!--<q-icon-->
<!--name="person"-->
<!--color="secondary"-->
<!--size="24px"-->
<!--/>-->
<!--<span class="csc-entity-title-text">-->
<!--{{ entityTitle }}-->
<!--</span>-->
<!--<q-chip-->
<!--v-if="!expanded"-->
<!--pointing="left"-->
<!--color="primary"-->
<!--class="gt-md"-->
<!--&gt;-->
<!--{{ $t('pbxConfig.extension') }}: <span class="csc-important">{{ seat.pbx_extension }}</span>-->
<!--</q-chip>-->
<!--<q-btn-->
<!--:icon="titleIcon"-->
<!--:small="isMobile"-->
<!--color="primary"-->
<!--slot="right"-->
<!--flat-->
<!--@click="toggleMain()"-->
<!--/>-->
<!--<q-btn-->
<!--icon="delete"-->
<!--:small="isMobile"-->
<!--color="negative"-->
<!--slot="right"-->
<!--flat-->
<!--@click="remove()"-->
<!--/>-->
<!--</q-card-title>-->
<!--<q-card-main-->
<!--v-if="expanded"-->
<!--class="transition-generic"-->
<!--&gt;-->
<!--<q-field :label="$t('pbxConfig.seatName')">-->
<!--<q-input-->
<!--v-model="changes.name"-->
<!--:after="nameButtons"-->
<!--@keyup.enter="saveName"-->
<!--/>-->
<!--</q-field>-->
<!--<q-field :label="$t('pbxConfig.extension')">-->
<!--<q-input-->
<!--v-model="changes.extension"-->
<!--type="number"-->
<!--:after="extensionButtons"-->
<!--@keyup.enter="saveExtension"-->
<!--/>-->
<!--</q-field>-->
<!--<q-field :label="$t('pbxConfig.primaryNumber')">-->
<!--<q-input-->
<!--v-model="primaryNumber"-->
<!--readonly-->
<!--disable-->
<!--/>-->
<!--</q-field>-->
<!--<q-field :label="$t('pbxConfig.aliasNumbers')">-->
<!--<q-select-->
<!--ref="aliasNumbers"-->
<!--v-model="changes.aliasNumbers"-->
<!--:options="aliasNumberOptions"-->
<!--multiple-->
<!--chips-->
<!--clearable-->
<!--:after="aliasNumberButtons"-->
<!--/>-->
<!--</q-field>-->
<!--<q-field :label="$t('pbxConfig.groups')">-->
<!--<q-select-->
<!--v-model="changes.groups"-->
<!--:options="groupOptions"-->
<!--multiple-->
<!--chips-->
<!--clearable-->
<!--:after="groupButtons"-->
<!--/>-->
<!--</q-field>-->
<!--</q-card-main>-->
<!--<q-inner-loading :visible="isLoading">-->
<!--<q-spinner-mat-->
<!--size="60px"-->
<!--color="primary"-->
<!--/>-->
<!--</q-inner-loading>-->
<!--</q-card>-->
</template>
<script>
@ -108,7 +244,12 @@
QInnerLoading,
QSpinnerMat,
QTransition,
Platform
Platform,
QItem,
QItemSide,
QItemMain,
QItemTile,
QAlert
} from 'quasar-framework'
export default {
name: 'csc-pbx-seat',
@ -137,7 +278,12 @@
QBtn,
QInnerLoading,
QSpinnerMat,
QTransition
QTransition,
QItem,
QItemSide,
QItemMain,
QItemTile,
QAlert
},
computed: {
entityTitle() {
@ -285,6 +431,9 @@
);
}
return buttons;
},
hasGroups() {
return _.isArray(_.get(this.seat, 'groups')) && this.seat.groups.length > 0;
}
},
methods: {

@ -1,44 +1,100 @@
<template>
<q-card class="csc-pbx-seat-add-form shadow-1">
<q-card-title>
<q-icon name="add" color="primary" size="22px"/>
<span>{{ $t('pbxConfig.addSeat') }}</span>
</q-card-title>
<q-card-main>
<q-field>
<q-input :disabled="loading" :readonly="loading" v-model="data.name" autofocus
:float-label="$t('pbxConfig.seatName')" clearable />
</q-field>
<q-field>
<q-input :disabled="loading" :readonly="loading" type="number" v-model="data.extension"
clearable :min="1" :max="1000000" :float-label="$t('pbxConfig.extension')" />
</q-field>
<q-field>
<q-select :disabled="loading" :readonly="loading" v-model="data.aliasNumbers" multiple chips clearable
:float-label="$t('pbxConfig.aliasNumbers')" :options="aliasNumberOptions" />
</q-field>
<q-field>
<q-select :disabled="loading" :readonly="loading" v-model="data.groups" multiple chips clearable
:float-label="$t('pbxConfig.groups')" :options="groupOptions" />
</q-field>
</q-card-main>
<q-card-separator/>
<q-card-actions align="center">
<q-btn v-if="!loading" flat color="secondary" icon="clear"
@click="cancel()">{{ $t('buttons.cancel') }}</q-btn>
<q-btn v-if="!loading" flat color="primary" icon="done"
@click="save()">{{ $t('buttons.save') }}</q-btn>
</q-card-actions>
<div class="csc-form csc-pbx-seat-add-form">
<q-field :error-label="seatNameErrorMessage">
<q-input
@input="$v.data.name.$touch"
:error="$v.data.name.$error"
:disabled="loading"
:readonly="loading"
v-model="data.name"
autofocus
:float-label="$t('pbxConfig.seatName')"
clearable
/>
</q-field>
<q-field :error-label="extensionErrorMessage">
<q-input
@input="$v.data.extension.$touch"
:error="$v.data.extension.$error"
:disabled="loading"
:readonly="loading"
v-model="data.extension"
:float-label="$t('pbxConfig.extension')"
clearable
/>
</q-field>
<q-field>
<q-select
:disabled="loading"
:readonly="loading"
v-model="data.aliasNumbers"
multiple
chips
clearable
:float-label="$t('pbxConfig.aliasNumbers')"
:options="aliasNumberOptions"
/>
</q-field>
<q-field>
<q-select
:disabled="loading"
:readonly="loading"
v-model="data.groups"
multiple
chips
clearable
:float-label="$t('pbxConfig.groups')"
:options="groupOptions"
/>
</q-field>
<div class="csc-form-actions row justify-center">
<q-btn
v-if="!loading"
flat
color="secondary"
icon="clear"
@click="cancel()"
>
{{ $t('buttons.cancel') }}
</q-btn>
<q-btn
v-if="!loading"
:disabled="$v.data.$invalid"
flat
color="primary"
icon="person"
@click="save()"
>
{{ $t('pbxConfig.createSeat') }}
</q-btn>
</div>
<q-inner-loading :visible="loading">
<q-spinner-mat size="60px" color="primary"></q-spinner-mat>
<q-spinner-mat size="60px" color="primary" />
</q-inner-loading>
</q-card>
</div>
</template>
<script>
import { QCard, QCardTitle, QCardMain, QCardActions, QCardSeparator, QBtn,
QInnerLoading, QSpinnerMat, QField, QInput, QSelect, QIcon } from 'quasar-framework'
import {
required,
maxLength,
numeric
} from 'vuelidate/lib/validators'
import {
QCard,
QCardTitle,
QCardMain,
QCardActions,
QCardSeparator,
QBtn,
QInnerLoading,
QSpinnerMat,
QField,
QInput,
QSelect,
QIcon
} from 'quasar-framework'
export default {
name: 'csc-pbx-seat-add-form',
@ -48,14 +104,62 @@
'loading'
],
components: {
QCard, QCardTitle, QCardMain, QCardActions, QCardSeparator, QBtn,
QInnerLoading, QSpinnerMat, QField, QInput, QSelect, QIcon
QCard,
QCardTitle,
QCardMain,
QCardActions,
QCardSeparator,
QBtn,
QInnerLoading,
QSpinnerMat,
QField,
QInput,
QSelect,
QIcon
},
validations: {
data: {
name: {
required,
maxLength: maxLength(64)
},
extension: {
required,
numeric,
maxLength: maxLength(64)
}
}
},
data () {
return {
data: this.getDefaults()
}
},
computed: {
seatNameErrorMessage() {
if (!this.$v.data.name.required) {
return this.$t('pbxConfig.requiredSeatName');
}
else if (!this.$v.data.name.maxLength) {
return this.$t('pbxConfig.seatNameMaxLength', {
maxLength: this.$v.data.name.$params.maxLength.max
});
}
},
extensionErrorMessage() {
if (!this.$v.data.extension.required) {
return this.$t('pbxConfig.requiredExtension');
}
else if (!this.$v.data.name.maxLength) {
return this.$t('pbxConfig.extensionMaxLength', {
maxLength: this.$v.data.extension.$params.maxLength.max
});
}
else if (!this.$v.data.name.numeric) {
return this.$t('pbxConfig.extensionAlphaNum');
}
}
},
methods: {
getDefaults() {
return {
@ -73,16 +177,12 @@
},
reset() {
this.data = this.getDefaults();
this.$v.$reset();
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables.styl';
.csc-pbx-seat-add-form
position: relative
.csc-pbx-seat-add-form
.q-field:last-child
margin-bottom: 36px
@import '../../../themes/app.common.styl';
</style>

@ -1,14 +1,7 @@
<template>
<csc-page :title="$t('pbxConfig.seatsTitle')">
<csc-pbx-seat-add-form
v-show="addFormEnabled"
ref="addForm"
:alias-number-options="aliasNumberOptions"
:group-options="groupOptions"
:loading="isAdding"
@save="addSeat"
@cancel="disableAddForm"
/>
<csc-page
class="csc-list-page"
>
<div
v-show="!addFormEnabled"
class="row justify-center"
@ -22,6 +15,21 @@
{{ $t('pbxConfig.addSeat') }}
</q-btn>
</div>
<div
class="row justify-center"
>
<csc-pbx-seat-add-form
class="col-xs-12 col-md-6"
v-show="addFormEnabled"
ref="addForm"
:alias-number-options="aliasNumberOptions"
:group-options="groupOptions"
:loading="isAdding"
@save="addSeat"
@cancel="disableAddForm"
/>
</div>
<div
v-if="isListLoadingVisible"
class="row justify-center"
@ -41,19 +49,31 @@
@change="changePage"
/>
</div>
<csc-pbx-seat
v-for="seat in seats"
:key="seat.id"
:seat="seat"
:alias-number-options="aliasNumberOptions"
:group-options="groupOptions"
@remove="removeSeat"
:loading="isItemLoading(seat.id)"
@save-name="setSeatName"
@save-extension="setSeatExtension"
@save-alias-numbers="updateAliasNumbers"
@save-groups="updateGroups"
/>
<div
class="">
<q-list
class=""
no-border
separator
sparse
multiline
:highlight="!isMobile"
>
<csc-pbx-seat
v-for="seat in seats"
:key="seat.id"
:seat="seat"
:alias-number-options="aliasNumberOptions"
:group-options="groupOptions"
@remove="removeSeat"
:loading="isItemLoading(seat.id)"
@save-name="setSeatName"
@save-extension="setSeatExtension"
@save-alias-numbers="updateAliasNumbers"
@save-groups="updateGroups"
/>
</q-list>
</div>
<div
v-if="seats.length === 0 && !isListRequesting"
class="row justify-center csc-no-entities"
@ -91,7 +111,8 @@
QSpinnerDots,
QSpinnerMat,
Dialog,
QPagination
QPagination,
Platform
} from 'quasar-framework'
export default {
@ -168,6 +189,9 @@
});
});
return groups;
},
isMobile() {
return Platform.is.mobile;
}
},
watch: {

@ -296,7 +296,7 @@
"removeGroup": "Remove group",
"removeGroupTitle": "Remove group",
"removeGroupText": "You are about to remove group {group}",
"seatName": "Seat Name",
"seatName": "Name",
"addSeat": "Add Seat",
"removeSeat": "Remove seat",
"removeSeatTitle": "Remove seat",
@ -314,6 +314,11 @@
"noStationName": "Could not find any device with station name matching the filter criteria",
"noGroups": "No groups created yet",
"noSeats": "No seats created yet",
"requiredSeatName": "Seat name is required",
"seatNameMaxLength": "Seat name must have at most {maxLength} letters",
"requiredExtension": "Extension is required",
"extensionMaxLength": "Extension must have at most {maxLength} letters",
"extensionAlphaNum": "Only numeric characters are allowed",
"toasts": {
"changedFieldToast": "Changed {type} to {name}",
"updatedAliasNumbersToast": "Alias numbers field updated!",
@ -350,7 +355,9 @@
"filterDevices": "Filter devices",
"filterDevicesShort": "Filter",
"resetFilters": "Reset filters",
"closeFilters": "Close filters"
"closeFilters": "Close filters",
"createSeat": "Create seat",
"noGroupAssigned": "Not assigned to any group"
},
"callBlocking": {
"privacyEnabledToast": "Your number is hidden to the callee",

@ -1,6 +1,53 @@
@import 'quasar.variables'
.csc-list-item
position relative
.csc-list-item-main
padding-top 16px
.csc-item-button
display inline-block
padding 4px
cursor pointer
.csc-item-buttons
z-index 11
position absolute
right 16px
top 16px
margin 0
.q-icon
margin 0
.csc-item-title
text-overflow ellipsis
white-space: nowrap;
width 100%
overflow hidden
padding-right 80px
font-size: 18px;
font-weight: 400;
letter-spacing: normal;
line-height: 1.8rem;
.csc-item-label
font-weight normal
.csc-item-value
font-weight bold
.csc-form-info
display block
.csc-info-text
display inline-block
.csc-form
position relative
.csc-form-actions
margin-top 16px
.margin-xs
margin 8px
@ -51,3 +98,4 @@
.q-btn
padding-left 8px
padding-right 8px

@ -41,3 +41,6 @@ $tooltip-background = $primary
$csc-subtitle-font-size = 18px
$csc-subtitle-line-height = 2rem
$csc-subtitle-font-weight = 400
$item-base-color = $primary
$item-highlight-color = alpha($item-base-color, 15%)

Loading…
Cancel
Save