Roll back TypeScript.

This commit is contained in:
Buster Neece 2022-12-24 08:26:01 -06:00
parent 7c48e69c11
commit 20c2f87986
No known key found for this signature in database
GPG Key ID: F1D2E64A0005E80E
65 changed files with 249 additions and 478 deletions

View File

@ -63,8 +63,6 @@
"sass-loader": "^13",
"store": "^2",
"sweetalert2": "11.4.8",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"vue": "^3.2",
"vue-axios": "^3.5",
"vue-codemirror6": "^1.1.1",
@ -9901,118 +9899,6 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-loader": {
"version": "9.4.2",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz",
"integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==",
"dependencies": {
"chalk": "^4.1.0",
"enhanced-resolve": "^5.0.0",
"micromatch": "^4.0.0",
"semver": "^7.3.4"
},
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"typescript": "*",
"webpack": "^5.0.0"
}
},
"node_modules/ts-loader/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/ts-loader/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/ts-loader/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/ts-loader/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/ts-loader/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/ts-loader/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/ts-loader/node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/ts-loader/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/ts-loader/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
@ -18505,83 +18391,6 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"ts-loader": {
"version": "9.4.2",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz",
"integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==",
"requires": {
"chalk": "^4.1.0",
"enhanced-resolve": "^5.0.0",
"micromatch": "^4.0.0",
"semver": "^7.3.4"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",

View File

@ -64,8 +64,6 @@
"sass-loader": "^13",
"store": "^2",
"sweetalert2": "11.4.8",
"ts-loader": "^9.4.2",
"typescript": "^4.9.4",
"vue": "^3.2",
"vue-axios": "^3.5",
"vue-codemirror6": "^1.1.1",

View File

@ -1,36 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": [
"vue/*"
]
},
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"useDefineForClassFields": true,
"jsx": "preserve",
"isolatedModules": true,
"preserveValueImports": true,
"importsNotUsedAsValues": "error",
"target": "ESNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"lib": [
"ES2016",
"DOM",
"DOM.Iterable"
],
"types": []
},
"include": [
"vue/**/*.ts",
"vue/**/*.vue",
"vue/**/*.js"
],
"exclude": [
"node_modules"
]
}

View File

@ -27,7 +27,7 @@
</p>
</template>
<script setup lang="ts">
<script setup>
import CopyToClipboardButton from "~/components/Common/CopyToClipboardButton.vue";
const props = defineProps({

View File

@ -19,7 +19,7 @@
</section>
</template>
<script setup lang="ts">
<script setup>
import DataTable from "~/components/Common/DataTable.vue";
import {ref} from "vue";
import {useSweetAlert} from "~/vendor/sweetalert";
@ -53,7 +53,7 @@ const fields = ref([
}
]);
const datatable = ref<InstanceType<typeof DataTable>>();
const datatable = ref();
const relist = () => {
datatable.value.relist();

View File

@ -84,7 +84,7 @@ pre.changes {
}
</style>
<script setup lang="ts">
<script setup>
import {DateTime} from "luxon";
import {computed, ref} from "vue";
import {useTranslate} from "~/vendor/gettext";

View File

@ -107,7 +107,7 @@
</div>
</template>
<script setup lang="ts">
<script setup>
import Icon from "~/components/Common/Icon.vue";
import DataTable from "~/components/Common/DataTable.vue";
import AdminBackupsLastOutputModal from "./Backups/LastOutputModal.vue";
@ -131,7 +131,7 @@ const props = defineProps({
isDocker: Boolean,
});
const settingsLoading = ref<Boolean>(false);
const settingsLoading = ref(false);
const blankSettings = {
backupEnabled: false,
@ -168,7 +168,7 @@ const fields = [
}
];
const datatable = ref<InstanceType<typeof DataTable>>();
const datatable = ref(); // DataTable
const {wrapWithLoading, notifySuccess} = useNotify();
const {axios} = useAxios();
@ -203,17 +203,17 @@ const toLocaleTime = (timestamp) => {
);
};
const lastOutputModal = ref<InstanceType<typeof AdminBackupsLastOutputModal>>();
const lastOutputModal = ref(); // AdminBackupsLastOutputModal
const showLastOutput = () => {
lastOutputModal.value.show();
};
const configureModal = ref<InstanceType<typeof AdminBackupsConfigureModal>>();
const configureModal = ref(); // AdminBackupsConfigureModal
const doConfigure = () => {
configureModal.value.open();
};
const runBackupModal = ref<InstanceType<typeof AdminBackupsRunBackupModal>>();
const runBackupModal = ref(); // AdminBackupsRunBackupModal
const doRunBackup = () => {
runBackupModal.value.open();
};

View File

@ -78,7 +78,7 @@
</modal-form>
</template>
<script setup lang="ts">
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import ModalForm from "~/components/Common/ModalForm.vue";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
@ -98,10 +98,10 @@ const props = defineProps({
const emit = defineEmits(['relist']);
const loading = ref<Boolean>(true);
const error = ref<string | null>(null);
const loading = ref(true);
const error = ref(null);
const modal = ref<InstanceType<typeof ModalForm>>();
const modal = ref(); // ModalForm
const {form, resetForm, v$} = useVuelidateOnForm(
{

View File

@ -5,7 +5,7 @@
</b-modal>
</template>
<script setup lang="ts">
<script setup>
import {ref} from "vue";
const props = defineProps({

View File

@ -79,7 +79,7 @@
</b-modal>
</template>
<script setup lang="ts">
<script setup>
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import InvisibleSubmitButton from "~/components/Common/InvisibleSubmitButton.vue";
@ -105,7 +105,7 @@ const storageLocationOptions = computed(() => {
const logUrl = ref(null);
const error = ref(null);
const modal = ref<InstanceType<typeof BModal>>();
const modal = ref(); // BModal
const {form, resetForm, v$} = useVuelidateOnForm(
{

View File

@ -26,7 +26,7 @@
</div>
</template>
<script setup lang="ts">
<script setup>
import CustomAssetForm from "./Branding/CustomAssetForm.vue";
import BrandingForm from "./Branding/BrandingForm.vue";

View File

@ -140,9 +140,9 @@
</template>
<script setup>
import CodemirrorTextarea from "~/components/Common/CodemirrorTextarea";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import CodemirrorTextarea from "~/components/Common/CodemirrorTextarea.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import {computed, onMounted, ref} from "vue";
import {useAxios} from "~/vendor/axios";
import mergeExisting from "~/functions/mergeExisting";
@ -151,7 +151,7 @@ import {useTranslate} from "~/vendor/gettext";
import {useVuelidateOnForm} from "~/components/Form/UseVuelidateOnForm";
const props = defineProps({
apiUrl: String,
apiUrl: String,
});
const loading = ref(true);

View File

@ -43,7 +43,7 @@
@relist="relist"></edit-modal>
</template>
<script setup lang="ts">
<script setup>
import DataTable from '~/components/Common/DataTable.vue';
import EditModal from './CustomFields/EditModal.vue';
import Icon from '~/components/Common/Icon.vue';
@ -72,13 +72,13 @@ const getAutoAssignName = (autoAssign) => {
return _.get(props.autoAssignTypes, autoAssign, $gettext('None'));
};
const datatable = ref<InstanceType<typeof DataTable>>();
const datatable = ref(); // DataTable
const relist = () => {
datatable.value.refresh();
};
const editmodal = ref<InstanceType<typeof EditModal>>();
const editmodal = ref(); // EditModal
const doCreate = () => {
editmodal.value.create();

View File

@ -8,7 +8,7 @@
</modal-form>
</template>
<script lang="ts">
<script>
import {required} from '@vuelidate/validators';
import BaseEditModal from '~/components/Common/BaseEditModal.vue';
import AdminCustomFieldsForm from "~/components/Admin/CustomFields/Form.vue";

View File

@ -42,9 +42,10 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {computed} from "vue";
import {useTranslate} from "~/vendor/gettext";
import {forEach} from "lodash";
const props = defineProps({
form: Object,
@ -61,7 +62,7 @@ const autoAssignOptions = computed(() => {
}
];
_.forEach(props.autoAssignTypes, (typeName, typeKey) => {
forEach(props.autoAssignTypes, (typeName, typeKey) => {
autoAssignOptions.push({
text: typeName,
value: typeKey

View File

@ -86,7 +86,7 @@
</div>
</template>
<script setup lang="ts">
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import InfoCard from "~/components/Common/InfoCard.vue";
import {computed, onMounted, ref} from "vue";
@ -100,7 +100,7 @@ const props = defineProps({
apiUrl: String
});
const loading = ref<Boolean>(true);
const loading = ref(true);
const version = ref(null);
const {form, resetForm, v$} = useVuelidateOnForm(

View File

@ -68,8 +68,9 @@
<script setup>
import {ref} from "vue";
import {BModal} from "bootstrap-vue";
const modal = ref();
const modal = ref(); // BModal
const create = () => {
modal.value.show();

View File

@ -40,8 +40,9 @@
<script setup>
import {ref} from "vue";
import {BModal} from "bootstrap-vue";
const modal = ref(); // Template ref
const modal = ref(); // BModal
const create = () => {
modal.value.show();

View File

@ -30,21 +30,21 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import _ from 'lodash';
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {map} from 'lodash';
import {computed} from "vue";
const props = defineProps({
form: Object,
globalPermissions: Object
form: Object,
globalPermissions: Object
});
const globalPermissionOptions = computed(() => {
return _.map(props.globalPermissions, (permissionName, permissionKey) => {
return {
text: permissionName,
value: permissionKey
};
});
return map(props.globalPermissions, (permissionName, permissionKey) => {
return {
text: permissionName,
value: permissionKey
};
});
});
</script>

View File

@ -22,7 +22,7 @@
</template>
<script setup>
import _ from 'lodash';
import {find, isEmpty, pickBy} from 'lodash';
import PermissionsFormStationRow from "~/components/Admin/Permissions/Form/StationRow.vue";
import {computed} from "vue";
@ -33,13 +33,13 @@ const props = defineProps({
});
const remainingStations = computed(() => {
return _.pickBy(props.stations, (stationName, stationId) => {
return !_.find(props.form.permissions.$model.station, {'station_id': stationId});
return pickBy(props.stations, (stationName, stationId) => {
return !find(props.form.permissions.$model.station, {'station_id': stationId});
});
});
const hasRemainingStations = computed(() => {
return !_.isEmpty(remainingStations.value);
return !isEmpty(remainingStations.value);
});
const remove = (index) => {

View File

@ -39,7 +39,7 @@
<script setup>
import useVuelidate from "@vuelidate/core";
import _ from "lodash";
import {get, map} from "lodash";
import Icon from "~/components/Common/Icon.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {useVModel} from "@vueuse/core";
@ -63,7 +63,7 @@ const validations = {
const v$ = useVuelidate(validations, form);
const stationPermissionOptions = computed(() => {
return _.map(props.stationPermissions, (permissionName, permissionKey) => {
return map(props.stationPermissions, (permissionName, permissionKey) => {
return {
text: permissionName,
value: permissionKey
@ -72,6 +72,6 @@ const stationPermissionOptions = computed(() => {
});
const getStationName = (stationId) => {
return _.get(props.stations, stationId, null);
return get(props.stations, stationId, null);
};
</script>

View File

@ -59,9 +59,9 @@
<script setup>
import {required} from '@vuelidate/validators';
import SettingsGeneralTab from "./Settings/GeneralTab";
import SettingsServicesTab from "./Settings/ServicesTab";
import SettingsSecurityPrivacyTab from "~/components/Admin/Settings/SecurityPrivacyTab";
import SettingsGeneralTab from "./Settings/GeneralTab.vue";
import SettingsServicesTab from "./Settings/ServicesTab.vue";
import SettingsSecurityPrivacyTab from "~/components/Admin/Settings/SecurityPrivacyTab.vue";
import {onMounted, ref} from "vue";
import {useAxios} from "~/vendor/axios";
import mergeExisting from "~/functions/mergeExisting";
@ -80,7 +80,7 @@ const props = defineProps({
}
});
const emits = defineEmits(['saved']);
const emit = defineEmits(['saved']);
const {form, resetForm, v$} = useVuelidateOnForm(
{

View File

@ -92,9 +92,9 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import {computed} from "vue";
import {useTranslate} from "~/vendor/gettext";

View File

@ -79,11 +79,11 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
const props = defineProps({
form: Object
form: Object
});
</script>

View File

@ -220,19 +220,19 @@
</div>
</b-form-fieldset>
<streaming-log-modal ref="acmeModal"></streaming-log-modal>
<streaming-log-modal ref="acmemodal"></streaming-log-modal>
<admin-settings-test-message-modal :test-message-url="testMessageUrl"></admin-settings-test-message-modal>
</template>
<script setup>
import BFormMarkup from "~/components/Form/BFormMarkup";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import AdminSettingsTestMessageModal from "~/components/Admin/Settings/TestMessageModal";
import Icon from "~/components/Common/Icon";
import StreamingLogModal from "~/components/Common/StreamingLogModal";
import BFormMarkup from "~/components/Form/BFormMarkup.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import AdminSettingsTestMessageModal from "~/components/Admin/Settings/TestMessageModal.vue";
import Icon from "~/components/Common/Icon.vue";
import StreamingLogModal from "~/components/Common/StreamingLogModal.vue";
import {computed, ref} from "vue";
import {useTranslate} from "~/vendor/gettext";
import {useNotify} from "~/vendor/bootstrapVue";
@ -270,7 +270,7 @@ const avatarServiceOptions = computed(() => {
]
});
const acmeModal = ref(); // BModal
const acmemodal = ref(); // StreamingLogModal
const {wrapWithLoading} = useNotify();
const {axios} = useAxios();
@ -278,7 +278,7 @@ const generateAcmeCert = () => {
wrapWithLoading(
axios.put(props.acmeUrl)
).then((resp) => {
acmeModal.value.show(resp.data.links.log);
acmemodal.value.show(resp.data.links.log);
});
}
</script>

View File

@ -20,12 +20,13 @@
<script setup>
import {email, required} from '@vuelidate/validators';
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {ref} from "vue";
import {useNotify} from "~/vendor/bootstrapVue";
import {useTranslate} from "~/vendor/gettext";
import {useAxios} from "~/vendor/axios";
import {useVuelidateOnForm} from "~/components/Form/UseVuelidateOnForm";
import {BModal} from "bootstrap-vue";
const props = defineProps({
testMessageUrl: String

View File

@ -52,7 +52,7 @@
import DataTable from '~/components/Common/DataTable';
import Icon from '~/components/Common/Icon';
import InfoCard from '~/components/Common/InfoCard';
import {StationFormProps} from "./Stations/StationForm";
import {stationFormProps} from "./Stations/StationForm.vue";
import AdminStationsEditModal from "./Stations/EditModal";
import _ from "lodash";
import AdminStationsCloneModal from "~/components/Admin/Stations/CloneModal";
@ -60,10 +60,8 @@ import AdminStationsCloneModal from "~/components/Admin/Stations/CloneModal";
export default {
name: 'AdminPermissions',
components: {AdminStationsCloneModal, AdminStationsEditModal, InfoCard, Icon, DataTable},
mixins: [
StationFormProps
],
props: {
...stationFormProps,
listUrl: String,
frontendTypes: Object,
backendTypes: Object

View File

@ -10,8 +10,8 @@
<script setup>
import {required} from '@vuelidate/validators';
import ModalForm from "~/components/Common/ModalForm";
import AdminStationsCloneModalForm from "~/components/Admin/Stations/CloneModalForm";
import ModalForm from "~/components/Common/ModalForm.vue";
import AdminStationsCloneModalForm from "~/components/Admin/Stations/CloneModalForm.vue";
import {ref} from "vue";
import {useTranslate} from "~/vendor/gettext";
import {useNotify} from "~/vendor/bootstrapVue";
@ -37,7 +37,7 @@ const {form, resetForm, v$} = useVuelidateOnForm(
}
);
const modal = ref(); // BVModal
const modal = ref(); // ModalForm
const {$gettext} = useTranslate();
const create = (stationName, stationCloneUrl) => {

View File

@ -30,7 +30,7 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {computed} from "vue";
import {useTranslate} from "~/vendor/gettext";

View File

@ -21,13 +21,14 @@
</template>
<script setup>
import AdminStationsForm, {StationFormProps} from "~/components/Admin/Stations/StationForm";
import InvisibleSubmitButton from "~/components/Common/InvisibleSubmitButton";
import AdminStationsForm, {stationFormProps} from "~/components/Admin/Stations/StationForm.vue";
import InvisibleSubmitButton from "~/components/Common/InvisibleSubmitButton.vue";
import {computed, ref} from "vue";
import {useTranslate} from "~/vendor/gettext";
import {BModal} from "bootstrap-vue";
const props = defineProps({
...StationFormProps.props,
...stationFormProps,
createUrl: String
});
@ -49,7 +50,7 @@ const langTitle = computed(() => {
: $gettext('Add Station');
});
const modal = ref(); // BVModal
const modal = ref(); // BModal
const onValidUpdate = (newValue) => {
disableSaveButton.value = !newValue;
@ -69,7 +70,7 @@ const edit = (recordUrl) => {
modal.value.show();
};
const form = ref(); // Template Ref
const form = ref(); // AdminStationsForm
const resetForm = () => {
form.value.reset();
@ -99,7 +100,9 @@ defineExpose({
</script>
<script>
export default {
import {defineComponent} from "vue";
export default defineComponent({
inheritAttrs: false,
};
});
</script>

View File

@ -67,10 +67,10 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import objectToFormOptions from "~/functions/objectToFormOptions";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import {onMounted, reactive, ref} from "vue";
import {useAxios} from "~/vendor/axios";

View File

@ -223,27 +223,27 @@
</template>
<script setup>
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {
AUDIO_PROCESSING_LIQUIDSOAP,
AUDIO_PROCESSING_NONE,
AUDIO_PROCESSING_STEREO_TOOL,
BACKEND_LIQUIDSOAP,
BACKEND_NONE
AUDIO_PROCESSING_LIQUIDSOAP,
AUDIO_PROCESSING_NONE,
AUDIO_PROCESSING_STEREO_TOOL,
BACKEND_LIQUIDSOAP,
BACKEND_NONE
} from "~/components/Entity/RadioAdapters";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BFormMarkup from "~/components/Form/BFormMarkup";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import BFormMarkup from "~/components/Form/BFormMarkup.vue";
import {computed} from "vue";
import {useTranslate} from "~/vendor/gettext";
const props = defineProps({
form: Object,
station: Object,
isStereoToolInstalled: {
type: Boolean,
default: true
},
form: Object,
station: Object,
isStereoToolInstalled: {
type: Boolean,
default: true
},
showAdvanced: {
type: Boolean,
default: true

View File

@ -172,18 +172,18 @@
</template>
<script setup>
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {FRONTEND_ICECAST, FRONTEND_REMOTE, FRONTEND_SHOUTCAST} from "~/components/Entity/RadioAdapters";
import objectToFormOptions from "~/functions/objectToFormOptions";
import {computed} from "vue";
import {useTranslate} from "~/vendor/gettext";
const props = defineProps({
form: Object,
isShoutcastInstalled: {
type: Boolean,
default: false
form: Object,
isShoutcastInstalled: {
type: Boolean,
default: false
},
countries: Object,
showAdvanced: {

View File

@ -75,18 +75,18 @@
</template>
<script setup>
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {BACKEND_NONE} from "~/components/Entity/RadioAdapters";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import BackendDisabled from "./Common/BackendDisabled.vue";
import {computed} from "vue";
const props = defineProps({
form: Object,
station: Object,
showAdvanced: {
type: Boolean,
form: Object,
station: Object,
showAdvanced: {
type: Boolean,
default: true
},
});

View File

@ -141,10 +141,10 @@
</template>
<script setup>
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import objectToFormOptions from "~/functions/objectToFormOptions";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import {computed} from "vue";
import {useTranslate} from "~/vendor/gettext";

View File

@ -61,18 +61,18 @@
</template>
<script setup>
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {BACKEND_NONE} from "~/components/Entity/RadioAdapters";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import BackendDisabled from "./Common/BackendDisabled.vue";
import {computed} from "vue";
const props = defineProps({
form: Object,
station: Object,
showAdvanced: {
type: Boolean,
form: Object,
station: Object,
showAdvanced: {
type: Boolean,
default: true
},
});

View File

@ -135,18 +135,18 @@
</template>
<script setup>
import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {BACKEND_NONE} from "~/components/Entity/RadioAdapters";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
import BackendDisabled from "./Common/BackendDisabled.vue";
import {computed} from "vue";
const props = defineProps({
form: Object,
station: Object,
showAdvanced: {
type: Boolean,
form: Object,
station: Object,
showAdvanced: {
type: Boolean,
default: true
},
});

View File

@ -87,11 +87,45 @@
</b-overlay>
</template>
<script>
import {defineComponent} from "vue";
export const stationFormProps = {
// Global
showAdminTab: {
type: Boolean,
default: true
},
showAdvanced: {
type: Boolean,
default: true
},
// Profile
timezones: Object,
// Frontend
isShoutcastInstalled: {
type: Boolean,
default: false
},
isStereoToolInstalled: {
type: Boolean,
default: false
},
countries: Object,
// Admin
storageLocationApiUrl: String
};
export default defineComponent({
inheritAttrs: false
});
</script>
<script setup>
import AdminStationsProfileForm from "./Form/ProfileForm";
import AdminStationsFrontendForm from "./Form/FrontendForm";
import AdminStationsBackendForm from "./Form/BackendForm";
import AdminStationsAdminForm from "./Form/AdminForm";
import AdminStationsProfileForm from "./Form/ProfileForm.vue";
import AdminStationsFrontendForm from "./Form/FrontendForm.vue";
import AdminStationsBackendForm from "./Form/BackendForm.vue";
import AdminStationsAdminForm from "./Form/AdminForm.vue";
import AdminStationsHlsForm from "./Form/HlsForm.vue";
import AdminStationsRequestsForm from "./Form/RequestsForm.vue";
import AdminStationsStreamersForm from "./Form/StreamersForm.vue";
@ -102,9 +136,10 @@ import {useNotify} from "~/vendor/bootstrapVue";
import {useAxios} from "~/vendor/axios";
import mergeExisting from "~/functions/mergeExisting";
import {useVuelidateOnForm} from "~/components/Form/UseVuelidateOnForm";
import {isArray, merge, mergeWith} from "lodash";
const props = defineProps({
...StationFormProps.props,
...stationFormProps,
createUrl: String,
editUrl: String,
isEditMode: Boolean,
@ -218,7 +253,7 @@ const buildForm = () => {
};
function mergeCustom(objValue, srcValue) {
if (_.isArray(objValue)) {
if (isArray(objValue)) {
return objValue.concat(srcValue);
}
}
@ -256,7 +291,8 @@ const buildForm = () => {
],
}
};
_.mergeWith(validations, advancedValidations, mergeCustom);
mergeWith(validations, advancedValidations, mergeCustom);
const advancedForm = {
short_name: '',
@ -285,7 +321,8 @@ const buildForm = () => {
duplicate_prevention_time_range: 120,
},
};
_.merge(blankForm, advancedForm);
merge(blankForm, advancedForm);
}
if (props.showAdminTab) {
@ -302,7 +339,7 @@ const buildForm = () => {
}
};
_.mergeWith(validations, adminValidations, mergeCustom);
mergeWith(validations, adminValidations, mergeCustom);
const adminForm = {
media_storage_location: '',
@ -310,7 +347,8 @@ const buildForm = () => {
podcasts_storage_location: '',
is_enabled: true,
};
_.merge(blankForm, adminForm);
merge(blankForm, adminForm);
if (props.showAdvanced) {
const advancedAdminValidations = {
@ -322,12 +360,13 @@ const buildForm = () => {
}
}
_.mergeWith(validations, advancedAdminValidations, mergeCustom);
mergeWith(validations, advancedAdminValidations, mergeCustom);
const adminAdvancedForm = {
radio_base_dir: '',
};
_.merge(blankForm, adminAdvancedForm);
merge(blankForm, adminAdvancedForm);
}
}
@ -441,36 +480,4 @@ defineExpose({
});
</script>
<script>
export const StationFormProps = {
props: {
// Global
showAdminTab: {
type: Boolean,
default: true
},
showAdvanced: {
type: Boolean,
default: true
},
// Profile
timezones: Object,
// Frontend
isShoutcastInstalled: {
type: Boolean,
default: false
},
isStereoToolInstalled: {
type: Boolean,
default: false
},
countries: Object,
// Admin
storageLocationApiUrl: String
}
};
export default {
inheritAttrs: false
}
</script>

View File

@ -181,7 +181,7 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
const props = defineProps({
form: Object

View File

@ -39,7 +39,7 @@
</template>
<script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import objectToFormOptions from "~/functions/objectToFormOptions";
import {computed} from "vue";

View File

@ -2,7 +2,7 @@
<audio ref="audio" v-if="isPlaying" v-bind:title="title"/>
</template>
<script lang="ts">
<script>
import getLogarithmicVolume from '~/functions/getLogarithmicVolume.js';
import Hls from 'hls.js';
import {usePlayerStore} from "~/store.js";

View File

@ -36,10 +36,12 @@ const dark = computed(() => {
</script>
<script>
export default {
import {defineComponent} from "vue";
export default defineComponent({
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
};
});
</script>

View File

@ -153,7 +153,7 @@ table.b-table-selectable {
}
</style>
<script lang="ts">
<script>
import store from 'store';
import _ from 'lodash';
import Icon from './Icon.vue';
@ -210,7 +210,7 @@ export default defineComponent({
},
data() {
let allFields = [];
_.forEach(this.fields, function (field: object) {
_.forEach(this.fields, function (field) {
allFields.push({
...{
label: '',
@ -395,7 +395,7 @@ export default defineComponent({
this.filter = newTerm;
},
loadItems(ctx) {
let queryParams: { [k: string]: any } = {
let queryParams = {
internal: true
};

View File

@ -69,17 +69,18 @@ div.flow-upload {
<script setup>
import formatFileSize from '~/functions/formatFileSize.js';
import Icon from './Icon';
import _ from 'lodash';
import Icon from './Icon.vue';
import {defaultsDeep, forEach, toInteger} from 'lodash';
import {computed, onMounted, onUnmounted, reactive, ref} from "vue";
import Flow from "@flowjs/flow.js";
import {useAzuraCast} from "~/vendor/azuracast";
import {useTranslate} from "~/vendor/gettext";
const props = defineProps({
targetUrl: String,
allowMultiple: {
type: Boolean,
default: false
targetUrl: String,
allowMultiple: {
type: Boolean,
default: false
},
validMimeTypes: {
type: Array,
@ -120,13 +121,13 @@ const files = reactive({
return this.value[file.uniqueIdentifier] ?? {};
},
hideAll() {
_.forEach(this.value, (file) => {
file.isVisible = false;
});
forEach(this.value, (file) => {
file.isVisible = false;
});
},
reset() {
this.value = {};
}
reset() {
this.value = {};
}
});
const file_browse_target = ref(); // Template Ref
@ -134,26 +135,28 @@ const file_drop_target = ref(); // Template Ref
const {apiCsrf} = useAzuraCast();
const {$gettext} = useTranslate();
onMounted(() => {
let defaultConfig = {
target: () => {
return props.targetUrl
},
singleFile: !props.allowMultiple,
headers: {
'Accept': 'application/json',
'X-API-CSRF': apiCsrf
},
withCredentials: true,
allowDuplicateUploads: true,
fileParameterName: 'file_data',
uploadMethod: 'POST',
testMethod: 'GET',
method: 'multipart',
maxChunkRetries: 3,
testChunks: false
};
let config = _.defaultsDeep({}, props.flowConfiguration, defaultConfig);
let defaultConfig = {
target: () => {
return props.targetUrl
},
singleFile: !props.allowMultiple,
headers: {
'Accept': 'application/json',
'X-API-CSRF': apiCsrf
},
withCredentials: true,
allowDuplicateUploads: true,
fileParameterName: 'file_data',
uploadMethod: 'POST',
testMethod: 'GET',
method: 'multipart',
maxChunkRetries: 3,
testChunks: false
};
let config = defaultsDeep({}, props.flowConfiguration, defaultConfig);
flow = new Flow(config);
@ -170,7 +173,7 @@ onMounted(() => {
});
flow.on('fileProgress', (file) => {
files.get(file).progressPercent = parseInt(file.progress() * 100);
files.get(file).progressPercent = toInteger(file.progress() * 100);
});
flow.on('fileSuccess', (file, message) => {
@ -183,7 +186,7 @@ onMounted(() => {
flow.on('error', (message, file, chunk) => {
console.error(message, file, chunk);
let messageText = this.$gettext('Could not upload file.');
let messageText = $gettext('Could not upload file.');
try {
if (typeof message !== 'undefined') {
let messageJson = JSON.parse(message);

View File

@ -33,7 +33,7 @@
</b-modal>
</template>
<script lang="ts">
<script>
import InvisibleSubmitButton from "~/components/Common/InvisibleSubmitButton.vue";
import {defineComponent} from "vue";
import _ from "lodash";

View File

@ -1,10 +1,11 @@
import {ref} from "vue";
import {cloneDeep} from "lodash";
export function useResettableForm(blankForm) {
const form = ref({...blankForm});
const form = ref(cloneDeep(blankForm));
const resetForm = () => {
form.value = {...blankForm};
form.value = cloneDeep(blankForm);
}
return {form, resetForm};

View File

@ -64,7 +64,7 @@
}
</style>
<script setup lang="ts">
<script setup>
import AudioPlayer from '~/components/Common/AudioPlayer.vue';
import formatTime from '~/functions/formatTime.js';
import Icon from '~/components/Common/Icon.vue';
@ -79,7 +79,7 @@ const current = toRef(store, 'current');
const volume = useStorage('player_volume', 55);
const isMuted = useStorage('player_is_muted', false);
const isMounted = useMounted();
const player = ref<InstanceType<typeof AudioPlayer>>();
const player = ref(); // AudioPlayer
const duration = computed(() => {
return player.value?.getDuration();

View File

@ -24,13 +24,13 @@
</template>
<script setup>
import AdminStationsForm, {StationFormProps} from "~/components/Admin/Stations/StationForm";
import AdminStationsForm, {stationFormProps} from "~/components/Admin/Stations/StationForm";
import SetupStep from "./SetupStep";
import InfoCard from "~/components/Common/InfoCard";
import {onMounted, ref} from "vue";
const props = defineProps({
...StationFormProps.props,
...StationFormProps,
createUrl: String,
continueUrl: {
type: String,

View File

@ -12,13 +12,13 @@
</template>
<script>
import AdminStationsForm, {StationFormProps} from "~/components/Admin/Stations/StationForm";
import AdminStationsForm, {stationFormProps} from "~/components/Admin/Stations/StationForm";
export default {
name: 'StationsProfileEdit',
components: {AdminStationsForm},
mixins: [StationFormProps],
props: {
...stationFormProps,
editUrl: String,
continueUrl: {
type: String,

View File

@ -1,5 +0,0 @@
declare module '*.vue' {
import type {DefineComponent} from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

View File

@ -1,17 +1,14 @@
import axios from "axios";
import VueAxios from "vue-axios";
import type {InjectionKey} from "vue";
import {inject} from "vue";
import {useAzuraCast} from "~/vendor/azuracast";
import {useTranslate} from "~/vendor/gettext";
import {useNotify} from "~/vendor/bootstrapVue";
const axiosKey = Symbol() as InjectionKey<typeof axios>;
/* Composition API Axios utilities */
export function useAxios() {
return {
axios: inject(axiosKey)
axios: inject('axios')
};
}
@ -60,5 +57,5 @@ export default function installAxios(vueApp) {
vueApp.use(VueAxios, axios);
vueApp.provide(axiosKey, axios);
vueApp.provide('axios', axios);
}

View File

@ -1,6 +1,4 @@
export function useAzuraCast() {
const App = globalThis.App;
return {
lang: {
confirm: App.lang.confirm ?? 'Are you sure?',

View File

@ -63,7 +63,7 @@ module.exports = {
'~': path.resolve(__dirname, './vue'),
vue: '@vue/compat'
},
extensions: ['.ts', '.js', '.vue', '.json']
extensions: ['.js', '.vue', '.json']
},
output: {
path: path.resolve(__dirname, '../web/static/webpack_dist'),
@ -130,14 +130,6 @@ module.exports = {
test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,
type: 'asset/resource'
},
{
test: /\.ts$/i,
loader: "ts-loader",
options: {
appendTsSuffixTo: [/\.vue$/]
},
exclude: /node_modules/
}
]
},
plugins: [