Vue 3 WIP
This commit is contained in:
parent
37dc95b7d9
commit
a4e1f15e47
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"vueCompilerOptions": {
|
||||
"target": 2.7
|
||||
"target": 3.2
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,7 +16,9 @@
|
|||
"@fullcalendar/daygrid": "^5.9.0",
|
||||
"@fullcalendar/luxon2": "^5.10.2",
|
||||
"@fullcalendar/timegrid": "^5.9.0",
|
||||
"@fullcalendar/vue": "^5.9.0",
|
||||
"@fullcalendar/vue3": "^5.11",
|
||||
"@vue-leaflet/vue-leaflet": "*",
|
||||
"@vue/compat": "^3.2.45",
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"axios": "^1",
|
||||
|
@ -61,14 +63,12 @@
|
|||
"sass-loader": "^13",
|
||||
"store": "^2",
|
||||
"sweetalert2": "11.4.8",
|
||||
"vue": "^2 <3",
|
||||
"vue-axios": "^2 <3",
|
||||
"vue": "^3.2",
|
||||
"vue-axios": "^3.5",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-gettext": "^2.1.12",
|
||||
"vue-loader": "^15 <16",
|
||||
"vue2-daterange-picker": "^0.6.6",
|
||||
"vue2-leaflet": "^2.7.1",
|
||||
"vue2-leaflet-fullscreen": "^1.0.1",
|
||||
"vue-loader": "^17",
|
||||
"vue3-daterange-picker": "^1",
|
||||
"vuedraggable": "^2.24.1",
|
||||
"wavesurfer.js": "^6",
|
||||
"webpack": "^5.52.1",
|
||||
|
|
|
@ -0,0 +1,469 @@
|
|||
$ranges-hover-bg-color: #eee !default;
|
||||
$ranges-hover-text-color: #000 !default;
|
||||
$ranges-active-bg-color: #08c !default;
|
||||
$ranges-active-text-color: #fff !default;
|
||||
|
||||
//Apply/OK buttons
|
||||
$primary-button-bg: #28a745 !default;
|
||||
$primary-button-color: #fff !default;
|
||||
//Cancel button
|
||||
$secondary-button-bg: #6c757d !default;
|
||||
$secondary-button-color: #fff !default;
|
||||
|
||||
$btn-border-width: 1px;
|
||||
|
||||
.daterangepicker {
|
||||
|
||||
.ranges {
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ranges ul {
|
||||
list-style: none;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ranges li {
|
||||
font-size: 12px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ranges li:hover {
|
||||
background-color: $ranges-hover-bg-color;
|
||||
color: $ranges-hover-text-color;
|
||||
}
|
||||
|
||||
.ranges li.active {
|
||||
background-color: $ranges-active-bg-color;
|
||||
color: $ranges-active-text-color;
|
||||
}
|
||||
|
||||
.monthselect, .yearselect {
|
||||
font-size: 12px;
|
||||
padding: 1px;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
cursor: default;
|
||||
width: calc(50% - 1rem);
|
||||
}
|
||||
|
||||
.monthselect {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.calendar-time {
|
||||
text-align: center;
|
||||
margin: 4px auto 0 auto;
|
||||
line-height: 30px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.calendar-time select.disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
select.hourselect, select.minuteselect, select.secondselect, select.ampmselect {
|
||||
width: 50px;
|
||||
margin: 2px;
|
||||
background: #eee;
|
||||
border: 1px solid #eee;
|
||||
padding: 2px;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@import "variables";
|
||||
|
||||
.drp-buttons .btn {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
//font-family: $btn-font-family;
|
||||
//font-weight: $btn-font-weight;
|
||||
//color: $body-color;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
background-color: transparent;
|
||||
border: $btn-border-width solid transparent;
|
||||
}
|
||||
|
||||
.btn-success, .btn-primary {
|
||||
background-color: $primary-button-bg;
|
||||
color: $primary-button-color;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: $secondary-button-bg;
|
||||
color: $secondary-button-color;
|
||||
}
|
||||
}
|
||||
|
||||
.vue-daterange-picker {
|
||||
*, ::after, ::before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.drp-calendar .col .left {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.daterangepicker {
|
||||
&.hide-calendars.show-ranges {
|
||||
.ranges {
|
||||
width: 100%;
|
||||
|
||||
ul {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendars-container {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.daterangepicker[readonly] {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
//imported
|
||||
.daterangepicker {
|
||||
position: absolute;
|
||||
color: inherit;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
width: 278px;
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
margin-top: 7px;
|
||||
top: 100px;
|
||||
left: 20px;
|
||||
z-index: 3001;
|
||||
display: none;
|
||||
font-size: 15px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.daterangepicker:before, .daterangepicker:after {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
content: '';
|
||||
}
|
||||
|
||||
.daterangepicker:before {
|
||||
top: -7px;
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
border-bottom: 7px solid #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker:after {
|
||||
top: -6px;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
border-left: 6px solid transparent;
|
||||
}
|
||||
|
||||
.daterangepicker.opensleft:before {
|
||||
right: 9px;
|
||||
}
|
||||
|
||||
.daterangepicker.opensleft:after {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.daterangepicker.openscenter:before {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.daterangepicker.openscenter:after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.daterangepicker.opensright:before {
|
||||
left: 9px;
|
||||
}
|
||||
|
||||
.daterangepicker.opensright:after {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up {
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up:before {
|
||||
top: initial;
|
||||
bottom: -7px;
|
||||
border-bottom: initial;
|
||||
border-top: 7px solid #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up:after {
|
||||
top: initial;
|
||||
bottom: -6px;
|
||||
border-bottom: initial;
|
||||
border-top: 6px solid #fff;
|
||||
}
|
||||
|
||||
.daterangepicker.single .drp-selected {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .drp-calendar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .drp-buttons {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.daterangepicker.auto-apply .drp-buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar {
|
||||
display: none;
|
||||
max-width: 270px;
|
||||
width: 270px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
padding: 8px 0 8px 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.single .calendar-table {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .next span, .daterangepicker .calendar-table .prev span {
|
||||
color: #fff;
|
||||
border: solid black;
|
||||
border-width: 0 2px 2px 0;
|
||||
border-radius: 0;
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .next span {
|
||||
transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .prev span {
|
||||
transform: rotate(135deg);
|
||||
-webkit-transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table th, .daterangepicker .calendar-table td {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
min-width: 32px;
|
||||
width: 32px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table {
|
||||
border: 1px solid #fff;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table table {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
|
||||
background-color: #eee;
|
||||
border-color: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.daterangepicker td.week, .daterangepicker th.week {
|
||||
font-size: 80%;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date {
|
||||
background-color: #fff;
|
||||
border-color: transparent;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.daterangepicker td.in-range {
|
||||
background-color: #ebf4f8;
|
||||
border-color: transparent;
|
||||
color: #000;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.daterangepicker td.start-date {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.daterangepicker td.end-date {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.daterangepicker td.start-date.end-date {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.daterangepicker td.active, .daterangepicker td.active:hover {
|
||||
background-color: #357ebd;
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.daterangepicker th.month {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.daterangepicker td.disabled, .daterangepicker option.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.daterangepicker select.yearselect {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-buttons {
|
||||
clear: both;
|
||||
text-align: right;
|
||||
padding: 8px;
|
||||
border-top: 1px solid #ddd;
|
||||
display: none;
|
||||
line-height: 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-selected {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges .drp-calendar.left {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
|
||||
.daterangepicker.show-calendar .ranges {
|
||||
margin-top: 8px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Larger Screen Styling */
|
||||
@media (min-width: 564px) {
|
||||
.daterangepicker {
|
||||
width: auto;
|
||||
}
|
||||
.daterangepicker .ranges ul {
|
||||
width: 140px;
|
||||
}
|
||||
.daterangepicker.single .ranges ul {
|
||||
width: 100%;
|
||||
}
|
||||
.daterangepicker.single .drp-calendar.left {
|
||||
clear: none;
|
||||
}
|
||||
.daterangepicker.ltr {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
.daterangepicker.ltr .drp-calendar.left {
|
||||
clear: left;
|
||||
margin-right: 0;
|
||||
}
|
||||
.daterangepicker.ltr .drp-calendar.left .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.daterangepicker.ltr .drp-calendar.right {
|
||||
margin-left: 0;
|
||||
}
|
||||
.daterangepicker.ltr .drp-calendar.right .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.daterangepicker.ltr .drp-calendar.left .calendar-table {
|
||||
padding-right: 8px;
|
||||
}
|
||||
.daterangepicker.rtl {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
.daterangepicker.rtl .drp-calendar.left {
|
||||
clear: right;
|
||||
margin-left: 0;
|
||||
}
|
||||
.daterangepicker.rtl .drp-calendar.left .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.daterangepicker.rtl .drp-calendar.right {
|
||||
margin-right: 0;
|
||||
}
|
||||
.daterangepicker.rtl .drp-calendar.right .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.daterangepicker.rtl .drp-calendar.left .calendar-table {
|
||||
padding-left: 12px;
|
||||
}
|
||||
.daterangepicker.rtl .ranges, .daterangepicker.rtl .drp-calendar {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 730px) {
|
||||
.daterangepicker .drp-calendar.left {
|
||||
clear: none !important;
|
||||
}
|
||||
}
|
|
@ -1,70 +1,65 @@
|
|||
import Vue from 'vue';
|
||||
import axios from 'axios';
|
||||
import VueAxios from 'vue-axios';
|
||||
import GetTextPlugin from 'vue-gettext';
|
||||
import translations from '../../translations/translations.json';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Configure localization
|
||||
Vue.use(GetTextPlugin, {
|
||||
defaultLanguage: 'en_US',
|
||||
translations: translations,
|
||||
silent: true
|
||||
});
|
||||
export default function (vueApp) {
|
||||
return function (el, props) {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Configure localization
|
||||
vueApp.use(GetTextPlugin, {
|
||||
defaultLanguage: 'en_US',
|
||||
translations: translations,
|
||||
silent: true
|
||||
});
|
||||
|
||||
if (typeof App.locale !== 'undefined') {
|
||||
Vue.config.language = App.locale;
|
||||
}
|
||||
if (typeof App.locale !== 'undefined') {
|
||||
vueApp.config.language = App.locale;
|
||||
}
|
||||
|
||||
// Configure auto-CSRF on requests
|
||||
if (typeof App.api_csrf !== 'undefined') {
|
||||
axios.defaults.headers.common['X-API-CSRF'] = App.api_csrf;
|
||||
}
|
||||
// Configure auto-CSRF on requests
|
||||
if (typeof App.api_csrf !== 'undefined') {
|
||||
axios.defaults.headers.common['X-API-CSRF'] = App.api_csrf;
|
||||
}
|
||||
|
||||
Vue.use(VueAxios, axios);
|
||||
|
||||
Vue.prototype.$eventHub = new Vue();
|
||||
});
|
||||
|
||||
export default function (component) {
|
||||
return function (el, props) {
|
||||
return new Vue({
|
||||
el: el,
|
||||
created () {
|
||||
let handleAxiosError = (error) => {
|
||||
let notifyMessage = this.$gettext('An error occurred and your request could not be completed.');
|
||||
if (error.response) {
|
||||
// Request made and server responded
|
||||
notifyMessage = error.response.data.message;
|
||||
console.error(notifyMessage);
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
console.error(error.request);
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
console.error('Error', error.message);
|
||||
}
|
||||
|
||||
if (typeof this.$notifyError === 'function') {
|
||||
this.$notifyError(notifyMessage);
|
||||
}
|
||||
};
|
||||
|
||||
axios.interceptors.request.use((config) => {
|
||||
return config;
|
||||
}, (error) => {
|
||||
handleAxiosError(error);
|
||||
return Promise.reject(error);
|
||||
vueApp.use(VueAxios, axios);
|
||||
});
|
||||
|
||||
axios.interceptors.response.use((response) => {
|
||||
return response;
|
||||
}, (error) => {
|
||||
handleAxiosError(error);
|
||||
return Promise.reject(error);
|
||||
vueApp.created(() => {
|
||||
let handleAxiosError = (error) => {
|
||||
let notifyMessage = this.$gettext('An error occurred and your request could not be completed.');
|
||||
if (error.response) {
|
||||
// Request made and server responded
|
||||
notifyMessage = error.response.data.message;
|
||||
console.error(notifyMessage);
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
console.error(error.request);
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
console.error('Error', error.message);
|
||||
}
|
||||
|
||||
if (typeof this.$notifyError === 'function') {
|
||||
this.$notifyError(notifyMessage);
|
||||
}
|
||||
};
|
||||
|
||||
axios.interceptors.request.use((config) => {
|
||||
return config;
|
||||
}, (error) => {
|
||||
handleAxiosError(error);
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
axios.interceptors.response.use((response) => {
|
||||
return response;
|
||||
}, (error) => {
|
||||
handleAxiosError(error);
|
||||
return Promise.reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
render: createElement => createElement(component, { props: props })
|
||||
});
|
||||
};
|
||||
|
||||
vueApp.mount(el, {props: props});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<permissions-form-station-row
|
||||
v-for="(row, index) in form.permissions.$model.station" :key="index"
|
||||
:stations="stations" :station-permissions="stationPermissions"
|
||||
:row.sync="row" @remove="remove(index)"
|
||||
v-model:row="form.permissions.$model.station[index]" @remove="remove(index)"
|
||||
></permissions-form-station-row>
|
||||
|
||||
<b-button-group v-if="hasRemainingStations">
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
</data-table>
|
||||
</b-card>
|
||||
|
||||
<admin-stations-edit-modal ref="editModal" :create-url="listUrl" v-bind="$props"
|
||||
<admin-stations-edit-modal v-bind="$props" ref="editModal" :create-url="listUrl"
|
||||
@relist="relist"></admin-stations-edit-modal>
|
||||
|
||||
<admin-stations-clone-modal ref="cloneModal" @relist="relist"></admin-stations-clone-modal>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<b-modal size="lg" id="station_edit_modal" ref="modal" :title="langTitle" :busy="loading"
|
||||
@shown="resetForm" @hidden="clearContents">
|
||||
<admin-stations-form ref="form" v-bind="$props" is-modal :create-url="createUrl" :edit-url="editUrl"
|
||||
<admin-stations-form v-bind="$props" ref="form" is-modal :create-url="createUrl" :edit-url="editUrl"
|
||||
:is-edit-mode="isEditMode" @error="close" @submitted="onSubmit"
|
||||
@validUpdate="onValidUpdate" @loadingUpdate="onLoadingUpdate">
|
||||
<template #submitButton>
|
||||
|
|
|
@ -60,14 +60,14 @@
|
|||
</div>
|
||||
<div class="datatable-main">
|
||||
<b-table ref="table" show-empty striped hover :selectable="selectable" :api-url="apiUrl" :per-page="perPage"
|
||||
:current-page.sync="currentPage" @row-selected="onRowSelected" :items="itemProvider"
|
||||
v-model:current-page="currentPage" @row-selected="onRowSelected" :items="itemProvider"
|
||||
:fields="visibleFields"
|
||||
:empty-text="langNoRecords" :empty-filtered-text="langNoRecords" :responsive="responsive"
|
||||
:no-provider-paging="handleClientSide" :no-provider-sorting="handleClientSide"
|
||||
:no-provider-filtering="handleClientSide"
|
||||
tbody-tr-class="align-middle" thead-tr-class="align-middle" selected-variant=""
|
||||
:filter="filter" @filtered="onFiltered" @refreshed="onRefreshed"
|
||||
:sort-by.sync="sortBy" :sort-desc.sync="sortDesc" @sort-changed="onSortChanged">
|
||||
v-model:sort-by="sortBy" v-model:sort-desc="sortDesc" @sort-changed="onSortChanged">
|
||||
<template #head(selected)="data">
|
||||
<b-form-checkbox :aria-label="langSelectAll" :checked="allSelected"
|
||||
@change="toggleSelected"></b-form-checkbox>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<template>
|
||||
<date-range-picker
|
||||
ref="picker" controlContainerClass="" opens="left" show-dropdowns
|
||||
v-bind="$props"
|
||||
v-bind="$props" ref="picker" controlContainerClass="" opens="left" show-dropdowns
|
||||
:time-picker-increment="1" :ranges="ranges" @update="onUpdate">
|
||||
<template #input="datePicker">
|
||||
<a class="btn btn-bg dropdown-toggle" id="reportrange" href="#" @click.prevent="">
|
||||
|
@ -9,19 +8,19 @@
|
|||
{{ datePicker.rangeText }}
|
||||
</a>
|
||||
</template>
|
||||
<slot v-for="(_, name) in $slots" :name="name" :slot="name"/>
|
||||
<template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData">
|
||||
<slot :name="name" v-bind="slotData"/>
|
||||
|
||||
<template v-for="(_, slot) of $slots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
</template>
|
||||
</date-range-picker>
|
||||
</template>
|
||||
|
||||
<style lang="css">
|
||||
@import '../../../node_modules/vue2-daterange-picker/dist/vue2-daterange-picker.css';
|
||||
<style lang="scss">
|
||||
@import '../../../node_modules/vue3-daterange-picker/src/assets/daterangepicker';
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import DateRangePicker from 'vue2-daterange-picker';
|
||||
import DateRangePicker from 'vue3-daterange-picker';
|
||||
import Icon from "./Icon";
|
||||
import {DateTime} from 'luxon';
|
||||
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<template>
|
||||
<div class="flow-upload">
|
||||
<div class="upload-progress">
|
||||
<div class="uploading-file pt-1" v-for="(file, _) in files" :id="'file_upload_' + file.uniqueIdentifier"
|
||||
v-if="file.is_visible" :class="{ 'text-success': file.is_completed, 'text-danger': file.error }">
|
||||
<h6 class="fileuploadname m-0">{{ file.name }}</h6>
|
||||
<b-progress v-if="!file.is_completed" :value="file.progress_percent" :max="100"
|
||||
show-progress class="h-15 my-1"></b-progress>
|
||||
<div class="upload-status" v-if="file.error">
|
||||
{{ file.error }}
|
||||
<template v-for="(file, _) in files">
|
||||
<div v-if="file.is_visible" class="uploading-file pt-1" :id="'file_upload_' + file.uniqueIdentifier"
|
||||
:class="{ 'text-success': file.is_completed, 'text-danger': file.error }">
|
||||
<h6 class="fileuploadname m-0">{{ file.name }}</h6>
|
||||
<b-progress v-if="!file.is_completed" :value="file.progress_percent" :max="100"
|
||||
show-progress class="h-15 my-1"></b-progress>
|
||||
<div class="upload-status" v-if="file.error">
|
||||
{{ file.error }}
|
||||
</div>
|
||||
<div class="size">{{ formatFileSize(file.size) }}</div>
|
||||
</div>
|
||||
<div class="size">{{ formatFileSize(file.size) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="file-drop-target" ref="file_drop_target">
|
||||
<translate key="lang_upload_target">Drag file(s) here to upload or</translate>
|
||||
|
|
|
@ -27,9 +27,8 @@
|
|||
</slot>
|
||||
</template>
|
||||
|
||||
<slot v-for="(_, name) in $slots" :name="name" :slot="name"/>
|
||||
<template v-for="(_, name) in filteredScopedSlots" :slot="name" slot-scope="slotData">
|
||||
<slot :name="name" v-bind="slotData"/>
|
||||
<template v-for="(_, slot) of filteredScopedSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
@ -75,7 +74,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
filteredScopedSlots() {
|
||||
return _.filter(this.$scopedSlots, (slot, name) => {
|
||||
return _.filter(this.$slots, (slot, name) => {
|
||||
return !_.includes([
|
||||
'default', 'modal-footer'
|
||||
], name);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<script>
|
||||
import '@fullcalendar/core/vdom';
|
||||
import FullCalendar from '@fullcalendar/vue';
|
||||
import FullCalendar from '@fullcalendar/vue3';
|
||||
import allLocales from '@fullcalendar/core/locales-all';
|
||||
import luxon2Plugin from '@fullcalendar/luxon2';
|
||||
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||
|
|
|
@ -3,7 +3,7 @@ export default {
|
|||
name: 'BFormFieldset',
|
||||
methods: {
|
||||
getSlot(name, scope = {}) {
|
||||
let slot = this.$scopedSlots[name] || this.$slots[name]
|
||||
let slot = this.$slots[name]
|
||||
return typeof slot === 'function' ? slot(scope) : slot
|
||||
}
|
||||
},
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
<slot name="description" v-bind="slotProps"></slot>
|
||||
</template>
|
||||
|
||||
<slot v-for="(_, name) in $slots" :name="name" :slot="name"/>
|
||||
<template v-for="(_, name) in filteredScopedSlots" :slot="name" slot-scope="slotData">
|
||||
<slot :name="name" v-bind="slotData"/>
|
||||
<template v-for="(_, slot) of filteredScopedSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
</template>
|
||||
</b-form-group>
|
||||
</template>
|
||||
|
@ -33,7 +32,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
filteredScopedSlots() {
|
||||
return _.filter(this.$scopedSlots, (slot, name) => {
|
||||
return _.filter(this.$slots, (slot, name) => {
|
||||
return !_.includes([
|
||||
'default', 'label', 'description'
|
||||
], name);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<b-form-group v-bind="$attrs" :label-for="id" :state="fieldState">
|
||||
<template #default>
|
||||
<slot name="default" v-bind="{ id, field, state: fieldState }">
|
||||
<b-form-checkbox :id="id" :name="name" v-model="field.$model" v-bind="inputAttrs">
|
||||
<b-form-checkbox v-bind="inputAttrs" v-model="field.$model" :id="id" :name="name">
|
||||
<slot name="label" :lang="'lang_'+id">
|
||||
|
||||
</slot>
|
||||
|
@ -25,9 +25,8 @@
|
|||
<slot name="description" v-bind="slotProps" :lang="'lang_'+id+'_desc'"></slot>
|
||||
</template>
|
||||
|
||||
<slot v-for="(_, name) in $slots" :name="name" :slot="name"/>
|
||||
<template v-for="(_, name) in filteredScopedSlots" :slot="name" slot-scope="slotData">
|
||||
<slot :name="name" v-bind="slotData"/>
|
||||
<template v-for="(_, slot) of filteredScopedSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
</template>
|
||||
</b-form-group>
|
||||
</template>
|
||||
|
@ -64,7 +63,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
filteredScopedSlots() {
|
||||
return _.filter(this.$scopedSlots, (slot, name) => {
|
||||
return _.filter(this.$slots, (slot, name) => {
|
||||
return !_.includes([
|
||||
'default', 'description'
|
||||
], name);
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
<b-form-group v-bind="$attrs" :label-for="id" :state="fieldState">
|
||||
<template #default>
|
||||
<slot name="default" v-bind="{ id, field, state: fieldState }">
|
||||
<b-form-textarea v-if="inputType === 'textarea'" ref="input" :id="id" :name="name"
|
||||
v-model="modelValue"
|
||||
:required="isRequired" :number="isNumeric" :trim="inputTrim" v-bind="inputAttrs"
|
||||
<b-form-textarea v-bind="inputAttrs" v-if="inputType === 'textarea'" ref="input" :id="id" :name="name"
|
||||
v-model="modelValue" :required="isRequired" :number="isNumeric" :trim="inputTrim"
|
||||
:autofocus="autofocus" :state="fieldState"></b-form-textarea>
|
||||
<b-form-input v-else ref="input" :type="inputType" :id="id" :name="name" v-model="modelValue"
|
||||
:required="isRequired" :number="isNumeric" :trim="inputTrim"
|
||||
:autofocus="autofocus" v-bind="inputAttrs" :state="fieldState"></b-form-input>
|
||||
<b-form-input v-bind="inputAttrs" v-else ref="input" :type="inputType" :id="id" :name="name"
|
||||
v-model="modelValue" :required="isRequired" :number="isNumeric" :trim="inputTrim"
|
||||
:autofocus="autofocus" :state="fieldState"></b-form-input>
|
||||
</slot>
|
||||
|
||||
<b-form-invalid-feedback :state="fieldState">
|
||||
|
@ -17,7 +16,7 @@
|
|||
</template>
|
||||
|
||||
<template #label="slotProps">
|
||||
<slot name="label" v-bind="slotProps" :lang="'lang_'+id"></slot>
|
||||
<slot v-bind="slotProps" name="label" :lang="'lang_'+id"></slot>
|
||||
<span v-if="isRequired" class="text-danger">
|
||||
<span aria-hidden="true">*</span>
|
||||
<span class="sr-only">Required</span>
|
||||
|
@ -27,12 +26,11 @@
|
|||
</span>
|
||||
</template>
|
||||
<template #description="slotProps">
|
||||
<slot name="description" v-bind="slotProps" :lang="'lang_'+id+'_desc'"></slot>
|
||||
<slot v-bind="slotProps" name="description" :lang="'lang_'+id+'_desc'"></slot>
|
||||
</template>
|
||||
|
||||
<slot v-for="(_, name) in $slots" :name="name" :slot="name"/>
|
||||
<template v-for="(_, name) in filteredScopedSlots" :slot="name" slot-scope="slotData">
|
||||
<slot :name="name" v-bind="slotData"/>
|
||||
<template v-for="(_, slot) of filteredScopedSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
</template>
|
||||
</b-form-group>
|
||||
</template>
|
||||
|
@ -101,7 +99,7 @@ export default {
|
|||
}
|
||||
},
|
||||
filteredScopedSlots() {
|
||||
return _.filter(this.$scopedSlots, (slot, name) => {
|
||||
return _.filter(this.$slots, (slot, name) => {
|
||||
return !_.includes([
|
||||
'default', 'label', 'description'
|
||||
], name);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</div>
|
||||
<div class="break"></div>
|
||||
<small class="date-played text-muted">
|
||||
<span v-html="unixTimestampToDate(row.played_at)">{{ row.played_at }}</span>
|
||||
<span v-html="unixTimestampToDate(row.played_at)"></span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<div class="mt-3" v-if="playing">
|
||||
|
||||
<div class="d-flex flex-row mb-2">
|
||||
<div class="flex-shrink-0 pt-1 pr-2">{{ position | prettifyTime }}</div>
|
||||
<div class="flex-shrink-0 pt-1 pr-2">{{ prettifyTime(position) }}</div>
|
||||
<div class="flex-fill">
|
||||
<input type="range" min="0" max="100" step="0.1" class="custom-range slider"
|
||||
v-bind:value="seekingPosition"
|
||||
|
@ -45,7 +45,7 @@
|
|||
v-on:mousemove="doSeek($event)"
|
||||
v-on:mouseup="isSeeking = false">
|
||||
</div>
|
||||
<div class="flex-shrink-0 pt-1 pl-2">{{ duration | prettifyTime }}</div>
|
||||
<div class="flex-shrink-0 pt-1 pl-2">{{ prettifyTime(duration) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="progress mb-1">
|
||||
|
@ -93,7 +93,7 @@
|
|||
<h5 class="mb-0">{{
|
||||
rowFile.metadata.title ? rowFile.metadata.title : lang_unknown_title
|
||||
}}</h5>
|
||||
<small class="pt-1">{{ rowFile.audio.length | prettifyTime }}</small>
|
||||
<small class="pt-1">{{ prettifyTime(rowFile.audio.length) }}</small>
|
||||
</div>
|
||||
<p class="mb-0">{{ rowFile.metadata.artist ? rowFile.metadata.artist : lang_unknown_artist }}</p>
|
||||
</a>
|
||||
|
@ -155,16 +155,16 @@ export default {
|
|||
this.$root.$on('new-mixer-value', this.setMixGain);
|
||||
this.$root.$on('new-cue', this.onNewCue);
|
||||
},
|
||||
filters: {
|
||||
prettifyTime (time) {
|
||||
methods: {
|
||||
prettifyTime(time) {
|
||||
if (typeof time === 'undefined') {
|
||||
return 'N/A';
|
||||
}
|
||||
|
||||
var hours = parseInt(time / 3600);
|
||||
let hours = parseInt(time / 3600);
|
||||
time %= 3600;
|
||||
var minutes = parseInt(time / 60);
|
||||
var seconds = parseInt(time % 60);
|
||||
let minutes = parseInt(time / 60);
|
||||
let seconds = parseInt(time % 60);
|
||||
|
||||
if (minutes < 10) {
|
||||
minutes = '0' + minutes;
|
||||
|
@ -178,19 +178,17 @@ export default {
|
|||
} else {
|
||||
return minutes + ':' + seconds;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cue () {
|
||||
},
|
||||
cue() {
|
||||
this.resumeStream();
|
||||
this.$root.$emit('new-cue', (this.passThrough) ? 'off' : this.id);
|
||||
},
|
||||
|
||||
onNewCue (new_cue) {
|
||||
onNewCue(new_cue) {
|
||||
this.passThrough = (new_cue === this.id);
|
||||
},
|
||||
|
||||
setMixGain (new_value) {
|
||||
setMixGain(new_value) {
|
||||
if (this.id === 'playlist_1') {
|
||||
this.mixGainObj.gain.value = 1.0 - new_value;
|
||||
} else {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<translate key="lang_hdr_info">Continue the setup process by creating your first radio station below. You can edit any of these details later.</translate>
|
||||
</info-card>
|
||||
|
||||
<admin-stations-form ref="form" v-bind="$props" :is-edit-mode="false" :create-url="createUrl"
|
||||
<admin-stations-form v-bind="$props" ref="form" :is-edit-mode="false" :create-url="createUrl"
|
||||
@submitted="onSubmitted">
|
||||
<template #submitButtonText>
|
||||
<translate key="lang_btn_create_and_continue">Create and Continue</translate>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<h5 class="m-0">{{ row.item.name }}</h5>
|
||||
</template>
|
||||
<template #cell(format)="row">
|
||||
{{ row.item.format|upper }}
|
||||
{{ upper(row.item.format) }}
|
||||
</template>
|
||||
<template #cell(bitrate)="row">
|
||||
{{ row.item.bitrate }}kbps
|
||||
|
@ -70,16 +70,14 @@ export default {
|
|||
]
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
methods: {
|
||||
upper(data) {
|
||||
let upper = [];
|
||||
data.split(' ').forEach((word) => {
|
||||
upper.push(word.toUpperCase());
|
||||
});
|
||||
return upper.join(' ');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
relist() {
|
||||
this.$refs.datatable.refresh();
|
||||
},
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<template v-if="row.item.enable_autodj">
|
||||
<translate key="lang_autodj_enabled">Enabled</translate>
|
||||
-
|
||||
{{ row.item.autodj_bitrate }}kbps {{ row.item.autodj_format|upper }}
|
||||
{{ row.item.autodj_bitrate }}kbps {{ upper(row.item.autodj_format) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<translate key="lang_autodj_disabled">Disabled</translate>
|
||||
|
@ -86,16 +86,14 @@ export default {
|
|||
]
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
methods: {
|
||||
upper(data) {
|
||||
let upper = [];
|
||||
data.split(' ').forEach((word) => {
|
||||
upper.push(word.toUpperCase());
|
||||
});
|
||||
return upper.join(' ');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
relist() {
|
||||
this.$refs.datatable.refresh();
|
||||
},
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<playlists-form-schedule-row v-for="(row, index) in scheduleItems" :key="index"
|
||||
:station-time-zone="stationTimeZone"
|
||||
:index="index" :row.sync="row" @remove="remove(index)">
|
||||
:index="index" v-model:row="scheduleItems[index]" @remove="remove(index)">
|
||||
</playlists-form-schedule-row>
|
||||
|
||||
<b-button-group>
|
||||
|
|
|
@ -4,26 +4,26 @@
|
|||
|
||||
<div class="row" id="profile">
|
||||
<div class="col-lg-7">
|
||||
<profile-now-playing :np="np" v-bind="$props"></profile-now-playing>
|
||||
<profile-now-playing v-bind="$props" :np="np"></profile-now-playing>
|
||||
|
||||
<profile-schedule :station-time-zone="stationTimeZone" :schedule-items="np.schedule"></profile-schedule>
|
||||
|
||||
<profile-streams :np="np" v-bind="$props"></profile-streams>
|
||||
<profile-streams v-bind="$props" :np="np"></profile-streams>
|
||||
|
||||
<profile-public-pages v-bind="$props"></profile-public-pages>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-5">
|
||||
<profile-requests v-if="stationSupportsRequests" v-bind="$props"></profile-requests>
|
||||
<profile-requests v-bind="$props" v-if="stationSupportsRequests"></profile-requests>
|
||||
|
||||
<profile-streamers v-if="stationSupportsStreamers" v-bind="$props"></profile-streamers>
|
||||
<profile-streamers v-bind="$props" v-if="stationSupportsStreamers"></profile-streamers>
|
||||
|
||||
<template v-if="hasActiveFrontend">
|
||||
<profile-frontend :np="np" v-bind="$props"></profile-frontend>
|
||||
<profile-frontend v-bind="$props" :np="np"></profile-frontend>
|
||||
</template>
|
||||
|
||||
<template v-if="hasActiveBackend">
|
||||
<profile-backend :np="np" v-bind="$props"></profile-backend>
|
||||
<profile-backend v-bind="$props" :np="np"></profile-backend>
|
||||
</template>
|
||||
<template v-else>
|
||||
<profile-backend-none></profile-backend-none>
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
<translate key="lang_public_pages_disable">Disable</translate>
|
||||
</a>
|
||||
</div>
|
||||
<embed-modal ref="embed_modal" v-bind="$props"></embed-modal>
|
||||
<embed-modal v-bind="$props" ref="embed_modal"></embed-modal>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="card-header bg-primary-dark">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</h3>
|
||||
</div>
|
||||
|
||||
<admin-stations-form ref="form" v-bind="$props" :is-edit-mode="true" :edit-url="editUrl"
|
||||
<admin-stations-form v-bind="$props" ref="form" :is-edit-mode="true" :edit-url="editUrl"
|
||||
@submitted="onSubmitted"></admin-stations-form>
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<template v-if="row.item.enable_autodj">
|
||||
<translate key="lang_autodj_enabled">Enabled</translate>
|
||||
-
|
||||
{{ row.item.autodj_bitrate }}kbps {{ row.item.autodj_format|upper }}
|
||||
{{ row.item.autodj_bitrate }}kbps {{ upper(row.item.autodj_format) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<translate key="lang_autodj_disabled">Disabled</translate>
|
||||
|
@ -77,7 +77,7 @@ export default {
|
|||
]
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
methods: {
|
||||
upper(data) {
|
||||
if (!data) {
|
||||
return '';
|
||||
|
@ -88,9 +88,7 @@ export default {
|
|||
upper.push(word.toUpperCase());
|
||||
});
|
||||
return upper.join(' ');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
relist() {
|
||||
this.$refs.datatable.refresh();
|
||||
},
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<l-map v-if="mapPoints.length < 3000" style="height: 300px; z-index: 0;" :zoom="1" :center="[40, 0]">
|
||||
<l-control-fullscreen/>
|
||||
<l-tile-layer :url="tileUrl" :attribution="tileAttribution"></l-tile-layer>
|
||||
<l-marker v-for="l in mapPoints" :key="l.hash"
|
||||
:lat-lng="{lat: l.location.lat, lng: l.location.lon}">
|
||||
|
@ -22,8 +21,7 @@
|
|||
|
||||
<script>
|
||||
import L from 'leaflet';
|
||||
import {LMap, LMarker, LTileLayer, LTooltip} from 'vue2-leaflet';
|
||||
import LControlFullscreen from 'vue2-leaflet-fullscreen';
|
||||
import {LMap, LMarker, LTileLayer, LTooltip} from '@vue-leaflet/vue-leaflet';
|
||||
import _ from 'lodash';
|
||||
|
||||
export default {
|
||||
|
@ -36,8 +34,7 @@ export default {
|
|||
LMap,
|
||||
LTileLayer,
|
||||
LMarker,
|
||||
LTooltip,
|
||||
LControlFullscreen
|
||||
LTooltip
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
nonsubscription transmissions other than broadcast simulcasts and transmissions of non-music
|
||||
programming." If your station does not fall within this category, update the transmission
|
||||
category field accordingly.
|
||||
</li>
|
||||
<li>The data collected by AzuraCast meets the SoundExchange standard for Actual Total
|
||||
Performances (ATP) by tracking unique listeners across all song plays. All other information
|
||||
is derived from the metadata of the uploaded songs themselves, and may not be completely
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<streamers-form-schedule-row v-for="(row, index) in scheduleItems" :key="index"
|
||||
:station-time-zone="stationTimeZone"
|
||||
:index="index" :row.sync="row" @remove="remove(index)">
|
||||
:index="index" v-model:row="scheduleItems[index]" @remove="remove(index)">
|
||||
</streamers-form-schedule-row>
|
||||
|
||||
<b-button-group>
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import initBase from '~/base.js';
|
||||
|
||||
import '~/vendor/bootstrapVue.js';
|
||||
import '~/vendor/sweetalert.js';
|
||||
import {createApp} from "vue";
|
||||
import useSweetAlert from '~/vendor/sweetalert.js';
|
||||
import useBootstrapVue from '~/vendor/bootstrapVue.js';
|
||||
|
||||
import AdminApiKeys from '~/components/Admin/ApiKeys.vue';
|
||||
|
||||
export default initBase(AdminApiKeys);
|
||||
const vueApp = createApp(AdminApiKeys);
|
||||
|
||||
useSweetAlert(vueApp);
|
||||
useBootstrapVue(vueApp);
|
||||
|
||||
export default initBase(vueApp);
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import initBase
|
||||
from '~/base.js';
|
||||
|
||||
import '~/vendor/bootstrapVue.js';
|
||||
import initBase from '~/base.js';
|
||||
import {createApp} from "vue";
|
||||
import useBootstrapVue from '~/vendor/bootstrapVue.js';
|
||||
import '~/vendor/luxon.js';
|
||||
|
||||
import AuditLog
|
||||
from '~/components/Admin/AuditLog.vue';
|
||||
import AuditLog from '~/components/Admin/AuditLog.vue';
|
||||
|
||||
export default initBase(AuditLog);
|
||||
const vueApp = createApp(AuditLog);
|
||||
|
||||
useBootstrapVue(vueApp);
|
||||
|
||||
export default initBase(vueApp);
|
||||
|
|
|
@ -6,6 +6,8 @@ Vue.use(PiniaVuePlugin);
|
|||
const pinia = createPinia();
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
|
||||
let inlinePlayer = new Vue({
|
||||
el: '#radio-player-controls',
|
||||
render: createElement => createElement(InlinePlayer),
|
||||
|
|
|
@ -1,111 +1,106 @@
|
|||
import Vue from 'vue';
|
||||
import {BootstrapVue} from 'bootstrap-vue';
|
||||
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css';
|
||||
|
||||
Vue.use(BootstrapVue);
|
||||
export default function useBootstrapVue(vueApp) {
|
||||
vueApp.use(BootstrapVue);
|
||||
|
||||
const BootstrapVueNotifiers = {
|
||||
install(Vue, opts) {
|
||||
Vue.prototype.$notify = function (message = null, options = {}) {
|
||||
if (!!document.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
const defaults = {
|
||||
variant: 'default',
|
||||
toaster: 'b-toaster-top-right',
|
||||
autoHideDelay: 3000,
|
||||
solid: true
|
||||
};
|
||||
vueApp.config.globalProperties.$notify = function (message = null, options = {}) {
|
||||
if (!!document.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$bvToast.toast(message, {...defaults, ...options});
|
||||
const defaults = {
|
||||
variant: 'default',
|
||||
toaster: 'b-toaster-top-right',
|
||||
autoHideDelay: 3000,
|
||||
solid: true
|
||||
};
|
||||
|
||||
Vue.prototype.$notifyError = function (message = null, options = {}) {
|
||||
if (message === null) {
|
||||
message = this.$gettext('An error occurred and your request could not be completed.');
|
||||
}
|
||||
this.$bvToast.toast(message, {...defaults, ...options});
|
||||
};
|
||||
|
||||
const defaults = {
|
||||
variant: 'danger',
|
||||
title: this.$gettext('Error')
|
||||
};
|
||||
vueApp.config.globalProperties.$notifyError = function (message = null, options = {}) {
|
||||
if (message === null) {
|
||||
message = this.$gettext('An error occurred and your request could not be completed.');
|
||||
}
|
||||
|
||||
this.$notify(message, {...defaults, ...options});
|
||||
|
||||
return message;
|
||||
const defaults = {
|
||||
variant: 'danger',
|
||||
title: this.$gettext('Error')
|
||||
};
|
||||
|
||||
Vue.prototype.$notifySuccess = function (message = null, options = {}) {
|
||||
if (message === null) {
|
||||
message = this.$gettext('Changes saved.');
|
||||
}
|
||||
this.$notify(message, {...defaults, ...options});
|
||||
|
||||
const defaults = {
|
||||
variant: 'success',
|
||||
title: this.$gettext('Success')
|
||||
};
|
||||
return message;
|
||||
};
|
||||
|
||||
this.$notify(message, {...defaults, ...options});
|
||||
vueApp.config.globalProperties.$notifySuccess = function (message = null, options = {}) {
|
||||
if (message === null) {
|
||||
message = this.$gettext('Changes saved.');
|
||||
}
|
||||
|
||||
return message;
|
||||
const defaults = {
|
||||
variant: 'success',
|
||||
title: this.$gettext('Success')
|
||||
};
|
||||
|
||||
const LOADING_TOAST_ID = 'toast-loading';
|
||||
this.$notify(message, {...defaults, ...options});
|
||||
|
||||
Vue.prototype.$showLoading = function (message = null, options = {}) {
|
||||
if (message === null) {
|
||||
message = this.$gettext('Applying changes...');
|
||||
}
|
||||
return message;
|
||||
};
|
||||
|
||||
const defaults = {
|
||||
id: LOADING_TOAST_ID,
|
||||
variant: 'warning',
|
||||
title: this.$gettext('Please wait...'),
|
||||
autoHideDelay: 10000,
|
||||
isStatus: true
|
||||
};
|
||||
const LOADING_TOAST_ID = 'toast-loading';
|
||||
|
||||
this.$notify(message, {...defaults, ...options});
|
||||
return message;
|
||||
vueApp.config.globalProperties.$showLoading = function (message = null, options = {}) {
|
||||
if (message === null) {
|
||||
message = this.$gettext('Applying changes...');
|
||||
}
|
||||
|
||||
const defaults = {
|
||||
id: LOADING_TOAST_ID,
|
||||
variant: 'warning',
|
||||
title: this.$gettext('Please wait...'),
|
||||
autoHideDelay: 10000,
|
||||
isStatus: true
|
||||
};
|
||||
|
||||
Vue.prototype.$hideLoading = function () {
|
||||
this.$bvToast.hide(LOADING_TOAST_ID);
|
||||
};
|
||||
this.$notify(message, {...defaults, ...options});
|
||||
return message;
|
||||
};
|
||||
|
||||
let $isAxiosLoading = false;
|
||||
let $axiosLoadCount = 0;
|
||||
vueApp.config.globalProperties.$hideLoading = function () {
|
||||
this.$bvToast.hide(LOADING_TOAST_ID);
|
||||
};
|
||||
|
||||
Vue.prototype.$setLoading = function (isLoading) {
|
||||
let prevIsLoading = $isAxiosLoading;
|
||||
if (isLoading) {
|
||||
$axiosLoadCount++;
|
||||
$isAxiosLoading = true;
|
||||
} else if ($axiosLoadCount > 0) {
|
||||
$axiosLoadCount--;
|
||||
$isAxiosLoading = ($axiosLoadCount > 0);
|
||||
}
|
||||
let $isAxiosLoading = false;
|
||||
let $axiosLoadCount = 0;
|
||||
|
||||
// Handle state changes
|
||||
if (!prevIsLoading && $isAxiosLoading) {
|
||||
this.$showLoading();
|
||||
} else if (prevIsLoading && !$isAxiosLoading) {
|
||||
this.$hideLoading();
|
||||
}
|
||||
};
|
||||
vueApp.config.globalProperties.$setLoading = function (isLoading) {
|
||||
let prevIsLoading = $isAxiosLoading;
|
||||
if (isLoading) {
|
||||
$axiosLoadCount++;
|
||||
$isAxiosLoading = true;
|
||||
} else if ($axiosLoadCount > 0) {
|
||||
$axiosLoadCount--;
|
||||
$isAxiosLoading = ($axiosLoadCount > 0);
|
||||
}
|
||||
|
||||
Vue.prototype.$wrapWithLoading = function (promise) {
|
||||
this.$setLoading(true);
|
||||
// Handle state changes
|
||||
if (!prevIsLoading && $isAxiosLoading) {
|
||||
this.$showLoading();
|
||||
} else if (prevIsLoading && !$isAxiosLoading) {
|
||||
this.$hideLoading();
|
||||
}
|
||||
};
|
||||
|
||||
promise.finally(() => {
|
||||
this.$setLoading(false);
|
||||
});
|
||||
vueApp.config.globalProperties.$wrapWithLoading = function (promise) {
|
||||
this.$setLoading(true);
|
||||
|
||||
return promise;
|
||||
};
|
||||
}
|
||||
promise.finally(() => {
|
||||
this.$setLoading(false);
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
};
|
||||
|
||||
Vue.use(BootstrapVueNotifiers);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import Vue
|
||||
from 'vue';
|
||||
import VueClipboard
|
||||
from 'vue-clipboard2';
|
||||
import VueClipboard from 'vue-clipboard2';
|
||||
|
||||
VueClipboard.config.autoSetContainer = true;
|
||||
|
||||
Vue.use(VueClipboard);
|
||||
export default function useVueClipboard(vueApp) {
|
||||
vueApp.use(VueClipboard);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Settings } from 'luxon';
|
||||
import {Settings} from 'luxon';
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
Settings.defaultLocale = App.locale_with_dashes;
|
||||
|
|
|
@ -1,25 +1,19 @@
|
|||
import Swal from 'sweetalert2';
|
||||
|
||||
import Vue from 'vue';
|
||||
export default function useSweetAlert(vueApp) {
|
||||
vueApp.config.globalProperties.$swal = function (options = {}) {
|
||||
return Swal.fire(options);
|
||||
};
|
||||
|
||||
const ConfirmFunctions = {
|
||||
install(Vue, opts) {
|
||||
Vue.prototype.$swal = function (options = {}) {
|
||||
return Swal.fire(options);
|
||||
vueApp.config.globalProperties.$confirmDelete = function (options = {}) {
|
||||
const defaults = {
|
||||
title: this.$gettext('Delete Record?'),
|
||||
confirmButtonText: this.$gettext('Delete'),
|
||||
confirmButtonColor: '#e64942',
|
||||
showCancelButton: true,
|
||||
focusCancel: true
|
||||
};
|
||||
|
||||
Vue.prototype.$confirmDelete = function (options = {}) {
|
||||
const defaults = {
|
||||
title: this.$gettext('Delete Record?'),
|
||||
confirmButtonText: this.$gettext('Delete'),
|
||||
confirmButtonColor: '#e64942',
|
||||
showCancelButton: true,
|
||||
focusCancel: true
|
||||
};
|
||||
|
||||
return this.$swal({...defaults, ...options});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Vue.use(ConfirmFunctions);
|
||||
return this.$swal({...defaults, ...options});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -60,7 +60,8 @@ module.exports = {
|
|||
resolve: {
|
||||
enforceExtension: false,
|
||||
alias: {
|
||||
'~': path.resolve(__dirname, './vue')
|
||||
'~': path.resolve(__dirname, './vue'),
|
||||
vue: '@vue/compat'
|
||||
},
|
||||
extensions: ['.js', '.vue', '.json']
|
||||
},
|
||||
|
@ -101,14 +102,18 @@ module.exports = {
|
|||
rules: [
|
||||
{
|
||||
test: /\.vue$/i,
|
||||
use: [
|
||||
'vue-loader'
|
||||
]
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
compilerOptions: {
|
||||
compatConfig: {
|
||||
MODE: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.scss$/i,
|
||||
use: [
|
||||
'vue-style-loader',
|
||||
'css-loader',
|
||||
'sass-loader'
|
||||
]
|
||||
|
@ -116,7 +121,6 @@ module.exports = {
|
|||
{
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
'vue-style-loader',
|
||||
'css-loader'
|
||||
]
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue