Replaced studentpicker sidebar by dropdown with arrows
This commit is contained in:
parent
fd1ab079a1
commit
2967f4a5bb
2
amd/build/page-view-plan.min.js
vendored
2
amd/build/page-view-plan.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/report-viewer-components.min.js
vendored
2
amd/build/report-viewer-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/treestudyplan-components.min.js
vendored
2
amd/build/treestudyplan-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -181,6 +181,7 @@ export function init(contextid,categoryid) {
|
||||||
showStudentView(student){
|
showStudentView(student){
|
||||||
app.selectedstudent = student;
|
app.selectedstudent = student;
|
||||||
app.studentstudyplan = null;
|
app.studentstudyplan = null;
|
||||||
|
if (student) {
|
||||||
app.loadingstudyplan = true;
|
app.loadingstudyplan = true;
|
||||||
call([{
|
call([{
|
||||||
methodname: 'local_treestudyplan_get_user_studyplan',
|
methodname: 'local_treestudyplan_get_user_studyplan',
|
||||||
|
@ -194,7 +195,7 @@ export function init(contextid,categoryid) {
|
||||||
notification.exception(error);
|
notification.exception(error);
|
||||||
app.loadingstudyplan = false;
|
app.loadingstudyplan = false;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
showOverview(){
|
showOverview(){
|
||||||
|
|
|
@ -480,9 +480,7 @@ export default {
|
||||||
let firststart = null;
|
let firststart = null;
|
||||||
for(const ix in this.value.pages) {
|
for(const ix in this.value.pages) {
|
||||||
const page = this.value.pages[ix];
|
const page = this.value.pages[ix];
|
||||||
debug.info(`Checking page ${ix} - timing ${studyplanPageTiming(page)}`,page);
|
|
||||||
if(studyplanPageTiming(page) == "present") {
|
if(studyplanPageTiming(page) == "present") {
|
||||||
debug.info(`Found page nr ${ix} to be present`);
|
|
||||||
const s = new Date(page.startdate);
|
const s = new Date(page.startdate);
|
||||||
if( (!firststart) || firststart > s) {
|
if( (!firststart) || firststart > s) {
|
||||||
startpageindex = ix;
|
startpageindex = ix;
|
||||||
|
@ -512,7 +510,7 @@ export default {
|
||||||
let maxLayer = -1;
|
let maxLayer = -1;
|
||||||
for(let i = 0; i <= page.periods; i++){
|
for(let i = 0; i <= page.periods; i++){
|
||||||
const slot = line.slots[i];
|
const slot = line.slots[i];
|
||||||
// Determine the amount of used layers in a studyline slit
|
// Determine the amount of used layers in a studyline slot
|
||||||
for(const ix in line.slots[i].courses){
|
for(const ix in line.slots[i].courses){
|
||||||
const item = line.slots[i].courses[ix];
|
const item = line.slots[i].courses[ix];
|
||||||
if(item.layer > maxLayer){
|
if(item.layer > maxLayer){
|
||||||
|
@ -526,6 +524,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debug.info(`Counted ${maxLayer+1} layers for ${page.shortname}/${line.name}`);
|
||||||
return (maxLayer >= 0)?(maxLayer+1):1;
|
return (maxLayer >= 0)?(maxLayer+1):1;
|
||||||
},
|
},
|
||||||
showslot(page,line,index, layeridx, type){
|
showslot(page,line,index, layeridx, type){
|
||||||
|
@ -630,7 +629,7 @@ export default {
|
||||||
<r-studyline-heading v-for="(line,lineindex) in page.studylines"
|
<r-studyline-heading v-for="(line,lineindex) in page.studylines"
|
||||||
:key="line.id"
|
:key="line.id"
|
||||||
v-model="page.studylines[lineindex]"
|
v-model="page.studylines[lineindex]"
|
||||||
:layers='countLineLayers(page,line)+1'
|
:layers='countLineLayers(line,page)+1'
|
||||||
:class=" 't-studyline' + ((lineindex%2==0)?' odd ' :' even ' )
|
:class=" 't-studyline' + ((lineindex%2==0)?' odd ' :' even ' )
|
||||||
+ ((lineindex==0)?' first ':' ')
|
+ ((lineindex==0)?' first ':' ')
|
||||||
+ ((lineindex==page.studylines.length-1)?' last ':' ')"
|
+ ((lineindex==page.studylines.length-1)?' last ':' ')"
|
||||||
|
@ -652,7 +651,7 @@ export default {
|
||||||
<!-- Line by line add the items -->
|
<!-- Line by line add the items -->
|
||||||
<!-- The grid layout handles putting it in rows and columns -->
|
<!-- The grid layout handles putting it in rows and columns -->
|
||||||
<template v-for="(line,lineindex) in page.studylines"
|
<template v-for="(line,lineindex) in page.studylines"
|
||||||
><template v-for="(layernr,layeridx) in countLineLayers(page,line)"
|
><template v-for="(layernr,layeridx) in countLineLayers(line,page)"
|
||||||
><template v-for="(n,index) in (page.periods+1)"
|
><template v-for="(n,index) in (page.periods+1)"
|
||||||
><r-studyline-slot
|
><r-studyline-slot
|
||||||
v-if="index > 0 && showslot(page,line, index, layeridx, 'gradable')"
|
v-if="index > 0 && showslot(page,line, index, layeridx, 'gradable')"
|
||||||
|
@ -669,7 +668,8 @@ export default {
|
||||||
:layer="layeridx"
|
:layer="layeridx"
|
||||||
:class="'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')
|
:class="'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')
|
||||||
+ ((lineindex==0 && layernr==1)?' first ':' ')
|
+ ((lineindex==0 && layernr==1)?' first ':' ')
|
||||||
+ ((lineindex==page.studylines.length-1)?' last ':' ')"
|
+ ((lineindex==page.studylines.length-1)?' last ':' ')
|
||||||
|
+ ((layernr == countLineLayers(line,page))?' lastlyr ':' ')"
|
||||||
></r-studyline-slot
|
></r-studyline-slot
|
||||||
><r-studyline-slot
|
><r-studyline-slot
|
||||||
v-if="showslot(page,line, index, layeridx, 'filter')"
|
v-if="showslot(page,line, index, layeridx, 'filter')"
|
||||||
|
@ -685,7 +685,8 @@ export default {
|
||||||
:class="'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')
|
:class="'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')
|
||||||
+ ((lineindex==0 && layernr==1)?' first ':'')
|
+ ((lineindex==0 && layernr==1)?' first ':'')
|
||||||
+ ((lineindex==page.studylines.length-1)?' last ':' ')
|
+ ((lineindex==page.studylines.length-1)?' last ':' ')
|
||||||
+ ((index==page.periods)?' rightmost':'')"
|
+ ((index==page.periods)?' rightmost':'')
|
||||||
|
+ ((layernr == countLineLayers(line,page))?' lastlyr ':' ')"
|
||||||
>
|
>
|
||||||
</r-studyline-slot
|
</r-studyline-slot
|
||||||
></template
|
></template
|
||||||
|
|
|
@ -1332,7 +1332,7 @@ export default {
|
||||||
for(let i = 0; i <= page.periods; i++){
|
for(let i = 0; i <= page.periods; i++){
|
||||||
if(line.slots[i]){
|
if(line.slots[i]){
|
||||||
const slot = line.slots[i];
|
const slot = line.slots[i];
|
||||||
// Determine the amount of used layers in a studyline slit
|
// Determine the amount of used layers in a studyline slot
|
||||||
for(const ix in line.slots[i].courses){
|
for(const ix in line.slots[i].courses){
|
||||||
const item = line.slots[i].courses[ix];
|
const item = line.slots[i].courses[ix];
|
||||||
if(item.layer > maxLayer){
|
if(item.layer > maxLayer){
|
||||||
|
|
|
@ -24,6 +24,12 @@ export default {
|
||||||
},
|
},
|
||||||
extrafields: {
|
extrafields: {
|
||||||
show: "show@core"
|
show: "show@core"
|
||||||
|
},
|
||||||
|
prevnext: {
|
||||||
|
prev: "prev@core",
|
||||||
|
previous: "previous@core",
|
||||||
|
next: "next@core",
|
||||||
|
select: "selectanoptions@core",
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Create new eventbus for interaction between item components
|
// Create new eventbus for interaction between item components
|
||||||
|
@ -400,5 +406,155 @@ export default {
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Vue.component('s-prevnext-selector', {
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
default() { return null;}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
},
|
||||||
|
grouped: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
titlefield: {
|
||||||
|
type: String,
|
||||||
|
default: "title",
|
||||||
|
},
|
||||||
|
labelfield: {
|
||||||
|
type: String,
|
||||||
|
default: "label",
|
||||||
|
},
|
||||||
|
optionsfield: {
|
||||||
|
type: String,
|
||||||
|
default: "options",
|
||||||
|
},
|
||||||
|
defaultselectable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
arrows: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
text: strings.prevnext,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
fields() {
|
||||||
|
const f = [];
|
||||||
|
if(this.defaultselectable) {
|
||||||
|
f.push(null);
|
||||||
|
}
|
||||||
|
if (this.grouped) {
|
||||||
|
for ( const gix in this.options) {
|
||||||
|
const group = this.options[gix];
|
||||||
|
for ( const ix in group) {
|
||||||
|
const v = this.options[ix];
|
||||||
|
f.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ( const ix in this.options) {
|
||||||
|
const v = this.options[ix];
|
||||||
|
f.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
},
|
||||||
|
bubblevalue: {
|
||||||
|
get() { return (this.value)?this.value:null;},
|
||||||
|
set(v) { this.$emit('input',(v)?v:null);},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
atFirst() {
|
||||||
|
if (this.fields.length > 0) {
|
||||||
|
return this.fields[0] == this.value;
|
||||||
|
}
|
||||||
|
return true; // Since it disables the button, do so if pressing it would make no sense.
|
||||||
|
},
|
||||||
|
atLast() {
|
||||||
|
if (this.fields.length > 0) {
|
||||||
|
const l = this.fields.length -1;
|
||||||
|
return this.fields[l] == this.value;
|
||||||
|
}
|
||||||
|
return true; // Since it disables the button, do so if pressing it would make no sense.
|
||||||
|
},
|
||||||
|
prev() {
|
||||||
|
if (this.fields.length > 0) {
|
||||||
|
const index = this.fields.indexOf(this.value);
|
||||||
|
if (index > 0) {
|
||||||
|
this.$emit("input",this.fields[index -1]);
|
||||||
|
this.$emit("change",this.fields[index -1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
next() {
|
||||||
|
if (this.fields.length > 0) {
|
||||||
|
const index = this.fields.indexOf(this.value);
|
||||||
|
const l = this.fields.length -1;
|
||||||
|
if (index >= 0 && index < l) {
|
||||||
|
this.$emit("input",this.fields[index + 1]);
|
||||||
|
this.$emit("change",this.fields[index + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedchanged(value) {
|
||||||
|
this.$emit("change",value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div :class="'s-prevnext-selector '">
|
||||||
|
<b-button :variant='variant' @click="prev" :disabled="atFirst()"
|
||||||
|
><i v-if='arrows' class='fa fa-caret-left s-prevnext-arrow'></i
|
||||||
|
><template v-else>{{text.prev}}</template></b-button>
|
||||||
|
<b-form-select v-model="bubblevalue"
|
||||||
|
@change='selectedchanged'
|
||||||
|
>
|
||||||
|
<b-form-select-option
|
||||||
|
:disabled="!defaultselectable"
|
||||||
|
:value="null"
|
||||||
|
:class="(defaultselectable)?'font-italic text-primary ':'font-italic'"
|
||||||
|
><slot name="defaultlabel">{{text.select}}</slot></b-form-select-option>
|
||||||
|
</b-form-select-option-group>
|
||||||
|
<template v-if="grouped">
|
||||||
|
<b-form-select-option-group
|
||||||
|
v-for="(g,gi) in this.options"
|
||||||
|
:key="gi"
|
||||||
|
:label="g[grouptitlefield]"
|
||||||
|
>
|
||||||
|
<b-form-select-option
|
||||||
|
v-for="(o,i) in g[grouplistfield]"
|
||||||
|
:key="i"
|
||||||
|
:value="o"
|
||||||
|
><slot :value="o">{{o[titlefield]}}</slot></b-form-select-option>
|
||||||
|
</b-form-select-option-group>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<b-form-select-option
|
||||||
|
v-for="(o,i) in this.options"
|
||||||
|
:key="i"
|
||||||
|
:value="o"
|
||||||
|
><slot :value="o">{{o[titlefield]}}</slot></b-form-select-option>
|
||||||
|
</template>
|
||||||
|
</b-form-select>
|
||||||
|
<b-button :variant='variant' @click="next" :disabled="atLast()"
|
||||||
|
><i v-if='arrows' class='fa fa-caret-right s-prevnext-arrow'></i
|
||||||
|
><template v-else>{{text.next}}</template></b-button>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -787,12 +787,12 @@
|
||||||
.path-local-treestudyplan .t-studyline-heading.last,
|
.path-local-treestudyplan .t-studyline-heading.last,
|
||||||
.path-local-treestudyplan .t-studyline-slot.last.newlyr,
|
.path-local-treestudyplan .t-studyline-slot.last.newlyr,
|
||||||
.path-local-treestudyplan .r-studyline-heading.last,
|
.path-local-treestudyplan .r-studyline-heading.last,
|
||||||
.path-local-treestudyplan .r-studyline-slot.last,
|
.path-local-treestudyplan .r-studyline-slot.last.lastlyr,
|
||||||
.features-treestudyplan .t-studyline-drag:last-child,
|
.features-treestudyplan .t-studyline-drag:last-child,
|
||||||
.features-treestudyplan .t-studyline-heading.last,
|
.features-treestudyplan .t-studyline-heading.last,
|
||||||
.features-treestudyplan .t-studyline-slot.last.newlyr,
|
.features-treestudyplan .t-studyline-slot.last.newlyr,
|
||||||
.features-treestudyplan .r-studyline-heading.last,
|
.features-treestudyplan .r-studyline-heading.last,
|
||||||
.features-treestudyplan .r-studyline-slot.last {
|
.features-treestudyplan .r-studyline-slot.last.lastlyr {
|
||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
}
|
}
|
||||||
.path-local-treestudyplan .s-studyline-header-period,
|
.path-local-treestudyplan .s-studyline-header-period,
|
||||||
|
@ -1367,6 +1367,15 @@
|
||||||
.features-treestudyplan div.r-item-course-header-details:last-child {
|
.features-treestudyplan div.r-item-course-header-details:last-child {
|
||||||
margin-bottom: 0.3rem;
|
margin-bottom: 0.3rem;
|
||||||
}
|
}
|
||||||
|
.path-local-treestudyplan .s-prevnext-selector,
|
||||||
|
.features-treestudyplan .s-prevnext-selector {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.path-local-treestudyplan .s-prevnext-selector i.s-prevnext-arrow,
|
||||||
|
.features-treestudyplan .s-prevnext-selector i.s-prevnext-arrow {
|
||||||
|
position: relative;
|
||||||
|
top: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
.path-local-treestudyplan .card.s-studyplan-card,
|
.path-local-treestudyplan .card.s-studyplan-card,
|
||||||
.features-treestudyplan .card.s-studyplan-card {
|
.features-treestudyplan .card.s-studyplan-card {
|
||||||
|
|
|
@ -671,7 +671,7 @@
|
||||||
.t-studyline-heading.last,
|
.t-studyline-heading.last,
|
||||||
.t-studyline-slot.last.newlyr,
|
.t-studyline-slot.last.newlyr,
|
||||||
.r-studyline-heading.last,
|
.r-studyline-heading.last,
|
||||||
.r-studyline-slot.last {
|
.r-studyline-slot.last.lastlyr {
|
||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1180,4 +1180,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.s-prevnext-selector {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
i.s-prevnext-arrow {
|
||||||
|
position: relative;
|
||||||
|
top: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
13
styles.css
13
styles.css
|
@ -787,12 +787,12 @@
|
||||||
.path-local-treestudyplan .t-studyline-heading.last,
|
.path-local-treestudyplan .t-studyline-heading.last,
|
||||||
.path-local-treestudyplan .t-studyline-slot.last.newlyr,
|
.path-local-treestudyplan .t-studyline-slot.last.newlyr,
|
||||||
.path-local-treestudyplan .r-studyline-heading.last,
|
.path-local-treestudyplan .r-studyline-heading.last,
|
||||||
.path-local-treestudyplan .r-studyline-slot.last,
|
.path-local-treestudyplan .r-studyline-slot.last.lastlyr,
|
||||||
.features-treestudyplan .t-studyline-drag:last-child,
|
.features-treestudyplan .t-studyline-drag:last-child,
|
||||||
.features-treestudyplan .t-studyline-heading.last,
|
.features-treestudyplan .t-studyline-heading.last,
|
||||||
.features-treestudyplan .t-studyline-slot.last.newlyr,
|
.features-treestudyplan .t-studyline-slot.last.newlyr,
|
||||||
.features-treestudyplan .r-studyline-heading.last,
|
.features-treestudyplan .r-studyline-heading.last,
|
||||||
.features-treestudyplan .r-studyline-slot.last {
|
.features-treestudyplan .r-studyline-slot.last.lastlyr {
|
||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
}
|
}
|
||||||
.path-local-treestudyplan .s-studyline-header-period,
|
.path-local-treestudyplan .s-studyline-header-period,
|
||||||
|
@ -1367,6 +1367,15 @@
|
||||||
.features-treestudyplan div.r-item-course-header-details:last-child {
|
.features-treestudyplan div.r-item-course-header-details:last-child {
|
||||||
margin-bottom: 0.3rem;
|
margin-bottom: 0.3rem;
|
||||||
}
|
}
|
||||||
|
.path-local-treestudyplan .s-prevnext-selector,
|
||||||
|
.features-treestudyplan .s-prevnext-selector {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.path-local-treestudyplan .s-prevnext-selector i.s-prevnext-arrow,
|
||||||
|
.features-treestudyplan .s-prevnext-selector i.s-prevnext-arrow {
|
||||||
|
position: relative;
|
||||||
|
top: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
.path-local-treestudyplan .card.s-studyplan-card,
|
.path-local-treestudyplan .card.s-studyplan-card,
|
||||||
.features-treestudyplan .card.s-studyplan-card {
|
.features-treestudyplan .card.s-studyplan-card {
|
||||||
|
|
|
@ -134,8 +134,24 @@ print $OUTPUT->header();
|
||||||
v-model="displayedstudyplan"
|
v-model="displayedstudyplan"
|
||||||
v-if="displayedstudyplan && displayedstudyplan.description"
|
v-if="displayedstudyplan && displayedstudyplan.description"
|
||||||
></s-studyplan-details>
|
></s-studyplan-details>
|
||||||
<b-button class="ml-1" v-if="activestudyplan" variant='primary' v-b-toggle.toolbox-sidebar
|
<div class="flex-grow-1"><!-- Spacer to align student selector right --></div>
|
||||||
><?php t('selectstudent_btn') ?></b-button>
|
<div v-if="displayedstudyplan && displayedstudyplan.description">
|
||||||
|
<span><?php t('selectstudent_btn') ?></span>
|
||||||
|
<s-prevnext-selector
|
||||||
|
|
||||||
|
:options="associatedstudents"
|
||||||
|
title="firstname"
|
||||||
|
v-model="selectedstudent"
|
||||||
|
defaultselectable
|
||||||
|
arrows
|
||||||
|
@change="showStudentView"
|
||||||
|
class="ml-2"
|
||||||
|
variant="primary"
|
||||||
|
>
|
||||||
|
<template v-slot="{value}">{{value.firstname}} {{value.lastname}}</template>
|
||||||
|
<template #defaultlabel><span class='text-primary'><?php t("showoverview"); ?></span></template>
|
||||||
|
</s-prevnext-selector>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class='t-studyplan-container'>
|
<div class='t-studyplan-container'>
|
||||||
|
@ -161,30 +177,6 @@ print $OUTPUT->header();
|
||||||
</b-card-group>
|
</b-card-group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<b-sidebar
|
|
||||||
id="toolbox-sidebar"
|
|
||||||
right
|
|
||||||
shadow
|
|
||||||
title='<?php t("selectstudent")?>'
|
|
||||||
>
|
|
||||||
<div class='m-2'><?php t("selectstudent_details")?></div>
|
|
||||||
<b-list-group v-if="associatedstudents">
|
|
||||||
<b-list-group-item :active="! selectedstudent"
|
|
||||||
button
|
|
||||||
variant="primary"
|
|
||||||
@click='showOverview()'
|
|
||||||
>
|
|
||||||
<?php t("showoverview"); ?>
|
|
||||||
</b-list-group-item>
|
|
||||||
<b-list-group-item v-for="student in associatedstudents" :key="student.id"
|
|
||||||
:active="selectedstudent && student.id == selectedstudent.id"
|
|
||||||
button
|
|
||||||
@click='showStudentView(student)'
|
|
||||||
>
|
|
||||||
{{student.firstname}} {{student.lastname}}
|
|
||||||
</b-list-group-item>
|
|
||||||
</b-list-group>
|
|
||||||
</b-sidebar>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
|
|
Loading…
Reference in New Issue
Block a user