mirror of
https://github.com/AzuraCast/AzuraCast.git
synced 2024-06-14 13:16:37 +00:00
Auto-fix ESlint rules.
This commit is contained in:
parent
04fc47ee1e
commit
e3b877cc9c
|
@ -5,52 +5,100 @@
|
|||
</h2>
|
||||
|
||||
<b-row>
|
||||
<b-col sm="12" md="6" lg="5">
|
||||
<section class="card mb-3" role="region">
|
||||
<b-col
|
||||
sm="12"
|
||||
md="6"
|
||||
lg="5"
|
||||
>
|
||||
<section
|
||||
class="card mb-3"
|
||||
role="region"
|
||||
>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('Profile') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Profile') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<b-overlay variant="card" :show="userLoading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="userLoading"
|
||||
>
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-media right-align vertical-align="center">
|
||||
<template v-if="user.avatar.url" #aside>
|
||||
<avatar :url="user.avatar.url" :service="user.avatar.service"
|
||||
:service-url="user.avatar.serviceUrl"></avatar>
|
||||
<b-media
|
||||
right-align
|
||||
vertical-align="center"
|
||||
>
|
||||
<template
|
||||
v-if="user.avatar.url"
|
||||
#aside
|
||||
>
|
||||
<avatar
|
||||
:url="user.avatar.url"
|
||||
:service="user.avatar.service"
|
||||
:service-url="user.avatar.serviceUrl"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<h2 v-if="user.name" class="card-title">{{ user.name }}</h2>
|
||||
<h2 v-else class="card-title">
|
||||
<h2
|
||||
v-if="user.name"
|
||||
class="card-title"
|
||||
>
|
||||
{{ user.name }}
|
||||
</h2>
|
||||
<h2
|
||||
v-else
|
||||
class="card-title"
|
||||
>
|
||||
{{ $gettext('AzuraCast User') }}
|
||||
</h2>
|
||||
<h3 class="card-subtitle">{{ user.email }}</h3>
|
||||
<h3 class="card-subtitle">
|
||||
{{ user.email }}
|
||||
</h3>
|
||||
|
||||
<div v-if="user.roles.length > 0" class="mt-2">
|
||||
<span v-for="role in user.roles" :key="role.id"
|
||||
class="badge badge-secondary mr-2">{{ role.name }}</span>
|
||||
<div
|
||||
v-if="user.roles.length > 0"
|
||||
class="mt-2"
|
||||
>
|
||||
<span
|
||||
v-for="role in user.roles"
|
||||
:key="role.id"
|
||||
class="badge badge-secondary mr-2"
|
||||
>{{ role.name }}</span>
|
||||
</div>
|
||||
</b-media>
|
||||
</b-card-body>
|
||||
</b-overlay>
|
||||
|
||||
<div class="card-actions">
|
||||
<b-button variant="outline-primary" @click.prevent="doEditProfile">
|
||||
<icon icon="edit"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doEditProfile"
|
||||
>
|
||||
<icon icon="edit" />
|
||||
{{ $gettext('Edit Profile') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" role="region">
|
||||
<section
|
||||
class="card"
|
||||
role="region"
|
||||
>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('Security') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Security') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<b-overlay variant="card" :show="securityLoading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="securityLoading"
|
||||
>
|
||||
<b-card-body>
|
||||
<h5>
|
||||
{{ $gettext('Two-Factor Authentication') }}
|
||||
<enabled-badge :enabled="security.twoFactorEnabled"></enabled-badge>
|
||||
<enabled-badge :enabled="security.twoFactorEnabled" />
|
||||
</h5>
|
||||
|
||||
<p class="card-text mt-2">
|
||||
|
@ -62,49 +110,80 @@
|
|||
</b-overlay>
|
||||
|
||||
<div class="card-actions">
|
||||
<b-button variant="outline-primary" @click.prevent="doChangePassword">
|
||||
<icon icon="vpn_key"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doChangePassword"
|
||||
>
|
||||
<icon icon="vpn_key" />
|
||||
{{ $gettext('Change Password') }}
|
||||
</b-button>
|
||||
<b-button v-if="security.twoFactorEnabled" variant="outline-danger"
|
||||
@click.prevent="disableTwoFactor">
|
||||
<icon icon="lock_open"></icon>
|
||||
<b-button
|
||||
v-if="security.twoFactorEnabled"
|
||||
variant="outline-danger"
|
||||
@click.prevent="disableTwoFactor"
|
||||
>
|
||||
<icon icon="lock_open" />
|
||||
{{ $gettext('Disable Two-Factor') }}
|
||||
</b-button>
|
||||
<b-button v-else variant="outline-success" @click.prevent="enableTwoFactor">
|
||||
<icon icon="lock"></icon>
|
||||
<b-button
|
||||
v-else
|
||||
variant="outline-success"
|
||||
@click.prevent="enableTwoFactor"
|
||||
>
|
||||
<icon icon="lock" />
|
||||
{{ $gettext('Enable Two-Factor') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</section>
|
||||
</b-col>
|
||||
<b-col sm="12" md="6" lg="7">
|
||||
<b-col
|
||||
sm="12"
|
||||
md="6"
|
||||
lg="7"
|
||||
>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('API Keys') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('API Keys') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<info-card>
|
||||
{{
|
||||
$gettext('Use API keys to authenticate with the AzuraCast API using the same permissions as your user account.')
|
||||
}}
|
||||
<a href="/api" target="_blank">
|
||||
<a
|
||||
href="/api"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('API Documentation') }}
|
||||
</a>
|
||||
</info-card>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button variant="outline-primary" @click.prevent="createApiKey">
|
||||
<icon icon="add"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="createApiKey"
|
||||
>
|
||||
<icon icon="add" />
|
||||
{{ $gettext('Add API Key') }}
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
|
||||
<data-table ref="$dataTable" id="account_api_keys" :show-toolbar="false" :fields="apiKeyFields"
|
||||
:api-url="apiKeysApiUrl">
|
||||
<data-table
|
||||
id="account_api_keys"
|
||||
ref="$dataTable"
|
||||
:show-toolbar="false"
|
||||
:fields="apiKeyFields"
|
||||
:api-url="apiKeysApiUrl"
|
||||
>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="danger" @click.prevent="deleteApiKey(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="deleteApiKey(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -114,16 +193,30 @@
|
|||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<account-edit-modal ref="$editModal" :user-url="userUrl" :supported-locales="supportedLocales"
|
||||
@reload="reload"></account-edit-modal>
|
||||
<account-edit-modal
|
||||
ref="$editModal"
|
||||
:user-url="userUrl"
|
||||
:supported-locales="supportedLocales"
|
||||
@reload="reload"
|
||||
/>
|
||||
|
||||
<account-change-password-modal ref="$changePasswordModal" :change-password-url="changePasswordUrl"
|
||||
@relist="relist"></account-change-password-modal>
|
||||
<account-change-password-modal
|
||||
ref="$changePasswordModal"
|
||||
:change-password-url="changePasswordUrl"
|
||||
@relist="relist"
|
||||
/>
|
||||
|
||||
<account-two-factor-modal ref="$twoFactorModal" :two-factor-url="twoFactorUrl"
|
||||
@relist="relist"></account-two-factor-modal>
|
||||
<account-two-factor-modal
|
||||
ref="$twoFactorModal"
|
||||
:two-factor-url="twoFactorUrl"
|
||||
@relist="relist"
|
||||
/>
|
||||
|
||||
<account-api-key-modal ref="$apiKeyModal" :create-url="apiKeysApiUrl" @relist="relist"></account-api-key-modal>
|
||||
<account-api-key-modal
|
||||
ref="$apiKeyModal"
|
||||
:create-url="apiKeysApiUrl"
|
||||
@relist="relist"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,13 +1,32 @@
|
|||
<template>
|
||||
<b-modal size="md" centered id="api_keys_modal" ref="$modal" :title="$gettext('Add API Key')"
|
||||
<b-modal
|
||||
id="api_keys_modal"
|
||||
ref="$modal"
|
||||
size="md"
|
||||
centered
|
||||
:title="$gettext('Add API Key')"
|
||||
no-enforce-focus
|
||||
@hidden="clearContents"
|
||||
no-enforce-focus>
|
||||
>
|
||||
<template #default="slotProps">
|
||||
<b-alert variant="danger" :show="error != null">{{ error }}</b-alert>
|
||||
<b-alert
|
||||
variant="danger"
|
||||
:show="error != null"
|
||||
>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
|
||||
<b-form v-if="newKey === null" class="form vue-form" @submit.prevent="doSubmit">
|
||||
<b-form
|
||||
v-if="newKey === null"
|
||||
class="form vue-form"
|
||||
@submit.prevent="doSubmit"
|
||||
>
|
||||
<b-form-fieldset>
|
||||
<b-wrapped-form-group id="form_comments" :field="v$.comment" autofocus>
|
||||
<b-wrapped-form-group
|
||||
id="form_comments"
|
||||
:field="v$.comment"
|
||||
autofocus
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('API Key Description/Comments') }}
|
||||
</template>
|
||||
|
@ -18,17 +37,28 @@
|
|||
</b-form>
|
||||
|
||||
<div v-else>
|
||||
<account-api-key-new-key :new-key="newKey"></account-api-key-new-key>
|
||||
<account-api-key-new-key :new-key="newKey" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #modal-footer="slotProps">
|
||||
<slot name="modal-footer" v-bind="slotProps">
|
||||
<b-button variant="default" type="button" @click="close">
|
||||
<slot
|
||||
name="modal-footer"
|
||||
v-bind="slotProps"
|
||||
>
|
||||
<b-button
|
||||
variant="default"
|
||||
type="button"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
<b-button v-if="newKey === null" :variant="(v$.$invalid) ? 'danger' : 'primary'" type="submit"
|
||||
@click="doSubmit">
|
||||
<b-button
|
||||
v-if="newKey === null"
|
||||
:variant="(v$.$invalid) ? 'danger' : 'primary'"
|
||||
type="submit"
|
||||
@click="doSubmit"
|
||||
>
|
||||
{{ $gettext('Create New Key') }}
|
||||
</b-button>
|
||||
</slot>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<h3 class="card-subtitle">{{ $gettext('New Key Generated') }}</h3>
|
||||
<h3 class="card-subtitle">
|
||||
{{ $gettext('New Key Generated') }}
|
||||
</h3>
|
||||
|
||||
<p class="card-text">
|
||||
<b>{{ $gettext('Important: copy the key below before continuing!') }}</b>
|
||||
|
@ -13,7 +15,7 @@
|
|||
<div class="px-2">
|
||||
<code id="api_key">{{ newKey }}</code>
|
||||
<div class="buttons pt-2">
|
||||
<copy-to-clipboard-button :text="newKey"></copy-to-clipboard-button>
|
||||
<copy-to-clipboard-button :text="newKey" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,21 +1,40 @@
|
|||
<template>
|
||||
<modal-form ref="$modal" size="md" centered :title="$gettext('Change Password')" :disable-save-button="v$.$invalid"
|
||||
@submit="onSubmit" @hidden="clearContents">
|
||||
<modal-form
|
||||
ref="$modal"
|
||||
size="md"
|
||||
centered
|
||||
:title="$gettext('Change Password')"
|
||||
:disable-save-button="v$.$invalid"
|
||||
@submit="onSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<b-form-fieldset>
|
||||
<b-wrapped-form-group id="form_current_password" :field="v$.current_password"
|
||||
input-type="password" autofocus>
|
||||
<b-wrapped-form-group
|
||||
id="form_current_password"
|
||||
:field="v$.current_password"
|
||||
input-type="password"
|
||||
autofocus
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Current Password') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group id="form_new_password" :field="v$.new_password" input-type="password">
|
||||
<b-wrapped-form-group
|
||||
id="form_new_password"
|
||||
:field="v$.new_password"
|
||||
input-type="password"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('New Password') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group id="form_current_password" :field="v$.new_password2" input-type="password">
|
||||
<b-wrapped-form-group
|
||||
id="form_current_password"
|
||||
:field="v$.new_password2"
|
||||
input-type="password"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Confirm New Password') }}
|
||||
</template>
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
<template>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="form_name" :field="form.name">
|
||||
<b-wrapped-form-group
|
||||
id="form_name"
|
||||
class="col-md-6"
|
||||
:field="form.name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Name') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_email" :field="form.email">
|
||||
<b-wrapped-form-group
|
||||
id="form_email"
|
||||
class="col-md-6"
|
||||
:field="form.email"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('E-mail Address') }}
|
||||
</template>
|
||||
|
@ -22,40 +30,55 @@
|
|||
|
||||
<div class="form-row">
|
||||
<b-col md="6">
|
||||
<b-wrapped-form-group id="edit_form_locale"
|
||||
:field="form.locale">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_locale"
|
||||
:field="form.locale"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Language') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="localeOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="localeOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</b-col>
|
||||
<b-col md="6">
|
||||
<b-wrapped-form-group id="edit_form_theme"
|
||||
:field="form.theme">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_theme"
|
||||
:field="form.theme"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Site Theme') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="themeOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="themeOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group id="edit_form_show_24_hour_time"
|
||||
:field="form.show_24_hour_time">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_show_24_hour_time"
|
||||
:field="form.show_24_hour_time"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Time Display') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="show24hourOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="show24hourOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</b-col>
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
<template>
|
||||
<modal-form ref="$modal" :loading="loading" :title="$gettext('Edit Profile')" :error="error"
|
||||
<modal-form
|
||||
ref="$modal"
|
||||
:loading="loading"
|
||||
:title="$gettext('Edit Profile')"
|
||||
:error="error"
|
||||
:disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents">
|
||||
|
||||
<account-edit-form :form="v$" :supported-locales="supportedLocales"></account-edit-form>
|
||||
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<account-edit-form
|
||||
:form="v$"
|
||||
:supported-locales="supportedLocales"
|
||||
/>
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
<template>
|
||||
<modal-form ref="$modal" :loading="loading" :title="$gettext('Enable Two-Factor Authentication')"
|
||||
:error="error" :disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents" no-enforce-focus>
|
||||
|
||||
<modal-form
|
||||
ref="$modal"
|
||||
:loading="loading"
|
||||
:title="$gettext('Enable Two-Factor Authentication')"
|
||||
:error="error"
|
||||
:disable-save-button="v$.$invalid"
|
||||
no-enforce-focus
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<b-row>
|
||||
<b-col md="7">
|
||||
<h5 class="mt-2">{{ $gettext('Step 1: Scan QR Code') }}</h5>
|
||||
<h5 class="mt-2">
|
||||
{{ $gettext('Step 1: Scan QR Code') }}
|
||||
</h5>
|
||||
|
||||
<p class="card-text">
|
||||
{{
|
||||
|
@ -24,7 +32,11 @@
|
|||
</p>
|
||||
|
||||
<b-form-fieldset>
|
||||
<b-wrapped-form-group id="form_otp" :field="v$.otp" autofocus>
|
||||
<b-wrapped-form-group
|
||||
id="form_otp"
|
||||
:field="v$.otp"
|
||||
autofocus
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Code from Authenticator App') }}
|
||||
</template>
|
||||
|
@ -37,18 +49,27 @@
|
|||
</b-form-fieldset>
|
||||
</b-col>
|
||||
<b-col md="5">
|
||||
<b-img :src="totp.qr_code"></b-img>
|
||||
<b-img :src="totp.qr_code" />
|
||||
|
||||
<div v-if="totp.totp_uri" class="mt-2">
|
||||
<code id="totp_uri" class="d-inline-block text-truncate" style="width: 100%;">
|
||||
<div
|
||||
v-if="totp.totp_uri"
|
||||
class="mt-2"
|
||||
>
|
||||
<code
|
||||
id="totp_uri"
|
||||
class="d-inline-block text-truncate"
|
||||
style="width: 100%;"
|
||||
>
|
||||
{{ totp.totp_uri }}
|
||||
</code>
|
||||
<copy-to-clipboard-button :text="totp.totp_uri"></copy-to-clipboard-button>
|
||||
<copy-to-clipboard-button :text="totp.totp_uri" />
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<template #save-button-name>{{ $gettext('Submit Code') }}</template>
|
||||
<template #save-button-name>
|
||||
{{ $gettext('Submit Code') }}
|
||||
</template>
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
<template>
|
||||
<section class="card" role="region">
|
||||
<section
|
||||
class="card"
|
||||
role="region"
|
||||
>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('API Keys') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('API Keys') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<data-table ref="$dataTable" id="api_keys" :fields="fields" :api-url="apiUrl">
|
||||
<data-table
|
||||
id="api_keys"
|
||||
ref="$dataTable"
|
||||
:fields="fields"
|
||||
:api-url="apiUrl"
|
||||
>
|
||||
<template #cell(owner)="row">
|
||||
{{ row.item.user.email }}
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
|
|
@ -6,26 +6,53 @@
|
|||
{{ $gettext('Audit Log') }}
|
||||
</h2>
|
||||
<div class="flex-shrink">
|
||||
<date-range-dropdown v-model="dateRange" @update="relist"></date-range-dropdown>
|
||||
<date-range-dropdown
|
||||
v-model="dateRange"
|
||||
@update="relist"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<data-table ref="$dataTable" responsive paginated
|
||||
:fields="fields" :apiUrl="apiUrl">
|
||||
<data-table
|
||||
ref="$dataTable"
|
||||
responsive
|
||||
paginated
|
||||
:fields="fields"
|
||||
:api-url="apiUrl"
|
||||
>
|
||||
<template #cell(date_time)="row">
|
||||
{{ formatTimestamp(row.item.timestamp) }}
|
||||
</template>
|
||||
<template #cell(operation)="row">
|
||||
<span class="text-success" v-if="row.item.operation_text === 'insert'"
|
||||
:title="$gettext('Insert')">
|
||||
<icon class="lg inline" icon="add_circle"></icon>
|
||||
<span
|
||||
v-if="row.item.operation_text === 'insert'"
|
||||
class="text-success"
|
||||
:title="$gettext('Insert')"
|
||||
>
|
||||
<icon
|
||||
class="lg inline"
|
||||
icon="add_circle"
|
||||
/>
|
||||
</span>
|
||||
<span class="text-danger" v-else-if="row.item.operation_text === 'delete'"
|
||||
:title="$gettext('Delete')">
|
||||
<icon class="lg inline" icon="remove_circle"></icon>
|
||||
<span
|
||||
v-else-if="row.item.operation_text === 'delete'"
|
||||
class="text-danger"
|
||||
:title="$gettext('Delete')"
|
||||
>
|
||||
<icon
|
||||
class="lg inline"
|
||||
icon="remove_circle"
|
||||
/>
|
||||
</span>
|
||||
<span class="text-primary" v-else :title="$gettext('Update')">
|
||||
<icon class="lg inline" icon="swap_horizontal_circle"></icon>
|
||||
<span
|
||||
v-else
|
||||
class="text-primary"
|
||||
:title="$gettext('Update')"
|
||||
>
|
||||
<icon
|
||||
class="lg inline"
|
||||
icon="swap_horizontal_circle"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(identifier)="row">
|
||||
|
@ -37,11 +64,17 @@
|
|||
<small>{{ row.item.target_class }}</small><br>
|
||||
{{ row.item.target }}
|
||||
</template>
|
||||
<template v-else>{{ $gettext('N/A') }}</template>
|
||||
<template v-else>
|
||||
{{ $gettext('N/A') }}
|
||||
</template>
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<template v-if="row.item.changes.length > 0">
|
||||
<b-button size="sm" variant="primary" @click="row.toggleDetails">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
@click="row.toggleDetails"
|
||||
>
|
||||
{{ $gettext('Changes') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
@ -61,7 +94,10 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="change in row.item.changes" :key="change.field">
|
||||
<tr
|
||||
v-for="change in row.item.changes"
|
||||
:key="change.field"
|
||||
>
|
||||
<td>{{ change.field }}</td>
|
||||
<td>
|
||||
<pre class="changes">{{ change.from }}</pre>
|
||||
|
@ -77,13 +113,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
pre.changes {
|
||||
max-width: 250px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import {DateTime} from "luxon";
|
||||
import {computed, ref} from "vue";
|
||||
|
@ -137,3 +166,10 @@ const formatTimestamp = (unix_timestamp) => {
|
|||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
pre.changes {
|
||||
max-width: 250px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,42 +1,68 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2 class="outside-card-header mb-1">{{ $gettext('Backups') }}</h2>
|
||||
<h2 class="outside-card-header mb-1">
|
||||
{{ $gettext('Backups') }}
|
||||
</h2>
|
||||
|
||||
<div class="card-deck">
|
||||
<section class="card mb-3" role="region">
|
||||
<section
|
||||
class="card mb-3"
|
||||
role="region"
|
||||
>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Automatic Backups') }}
|
||||
<enabled-badge :enabled="settings.backupEnabled"></enabled-badge>
|
||||
<enabled-badge :enabled="settings.backupEnabled" />
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<b-overlay variant="card" :show="settingsLoading">
|
||||
<div v-if="settings.backupEnabled" class="card-body">
|
||||
<p v-if="settings.backupLastRun > 0" class="card-text">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="settingsLoading"
|
||||
>
|
||||
<div
|
||||
v-if="settings.backupEnabled"
|
||||
class="card-body"
|
||||
>
|
||||
<p
|
||||
v-if="settings.backupLastRun > 0"
|
||||
class="card-text"
|
||||
>
|
||||
{{ $gettext('Last run:') }}
|
||||
{{ toRelativeTime(settings.backupLastRun) }}
|
||||
</p>
|
||||
<p v-else class="card-text">
|
||||
<p
|
||||
v-else
|
||||
class="card-text"
|
||||
>
|
||||
{{ $gettext('Never run') }}
|
||||
</p>
|
||||
</div>
|
||||
</b-overlay>
|
||||
|
||||
<div class="card-actions">
|
||||
<b-button variant="outline-primary" @click.prevent="doConfigure">
|
||||
<icon icon="settings"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doConfigure"
|
||||
>
|
||||
<icon icon="settings" />
|
||||
{{ $gettext('Configure') }}
|
||||
</b-button>
|
||||
<b-button v-if="settings.backupEnabled && settings.backupLastOutput !== ''"
|
||||
variant="outline-secondary" @click.prevent="showLastOutput">
|
||||
<icon icon="assignment"></icon>
|
||||
<b-button
|
||||
v-if="settings.backupEnabled && settings.backupLastOutput !== ''"
|
||||
variant="outline-secondary"
|
||||
@click.prevent="showLastOutput"
|
||||
>
|
||||
<icon icon="assignment" />
|
||||
{{ $gettext('Most Recent Backup Log') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card mb-3" role="region">
|
||||
<section
|
||||
class="card mb-3"
|
||||
role="region"
|
||||
>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Restoring Backups') }}
|
||||
|
@ -60,7 +86,10 @@
|
|||
</section>
|
||||
</div>
|
||||
|
||||
<section class="card mb-3" role="region">
|
||||
<section
|
||||
class="card mb-3"
|
||||
role="region"
|
||||
>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Backups') }}
|
||||
|
@ -68,13 +97,21 @@
|
|||
</b-card-header>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button variant="outline-primary" @click.prevent="doRunBackup">
|
||||
<icon icon="send"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doRunBackup"
|
||||
>
|
||||
<icon icon="send" />
|
||||
{{ $gettext('Run Manual Backup') }}
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
|
||||
<data-table ref="$dataTable" id="api_keys" :fields="fields" :api-url="listUrl">
|
||||
<data-table
|
||||
id="api_keys"
|
||||
ref="$dataTable"
|
||||
:fields="fields"
|
||||
:api-url="listUrl"
|
||||
>
|
||||
<template #cell(timestamp)="row">
|
||||
{{ toLocaleTime(row.item.timestamp) }}
|
||||
</template>
|
||||
|
@ -83,10 +120,19 @@
|
|||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="primary" :href="row.item.links.download" target="_blank">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
:href="row.item.links.download"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Download') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.delete)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.delete)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -94,16 +140,24 @@
|
|||
</data-table>
|
||||
</section>
|
||||
|
||||
<admin-backups-configure-modal ref="$configureModal" :settings-url="settingsUrl"
|
||||
<admin-backups-configure-modal
|
||||
ref="$configureModal"
|
||||
:settings-url="settingsUrl"
|
||||
:storage-locations="storageLocations"
|
||||
@relist="relist"></admin-backups-configure-modal>
|
||||
@relist="relist"
|
||||
/>
|
||||
|
||||
<admin-backups-run-backup-modal ref="$runBackupModal" :run-backup-url="runBackupUrl"
|
||||
<admin-backups-run-backup-modal
|
||||
ref="$runBackupModal"
|
||||
:run-backup-url="runBackupUrl"
|
||||
:storage-locations="storageLocations"
|
||||
@relist="relist"></admin-backups-run-backup-modal>
|
||||
@relist="relist"
|
||||
/>
|
||||
|
||||
<admin-backups-last-output-modal ref="$lastOutputModal"
|
||||
:last-output="settings.backupLastOutput"></admin-backups-last-output-modal>
|
||||
<admin-backups-last-output-modal
|
||||
ref="$lastOutputModal"
|
||||
:last-output="settings.backupLastOutput"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
<template>
|
||||
<modal-form ref="$modal" size="lg" :title="$gettext('Configure Backups')" :loading="loading"
|
||||
:disable-save-button="v$.$invalid" @submit="submit" @hidden="resetForm">
|
||||
<modal-form
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
:title="$gettext('Configure Backups')"
|
||||
:loading="loading"
|
||||
:disable-save-button="v$.$invalid"
|
||||
@submit="submit"
|
||||
@hidden="resetForm"
|
||||
>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row mb-3">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="form_edit_backup_enabled"
|
||||
:field="v$.backup_enabled">
|
||||
<b-wrapped-form-checkbox
|
||||
id="form_edit_backup_enabled"
|
||||
class="col-md-12"
|
||||
:field="v$.backup_enabled"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Run Automatic Nightly Backups') }}
|
||||
</template>
|
||||
|
@ -16,8 +26,15 @@
|
|||
</b-wrapped-form-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-row" v-if="v$.backup_enabled.$model">
|
||||
<b-wrapped-form-group class="col-md-6" id="form_backup_time_code" :field="v$.backup_time_code">
|
||||
<div
|
||||
v-if="v$.backup_enabled.$model"
|
||||
class="form-row"
|
||||
>
|
||||
<b-wrapped-form-group
|
||||
id="form_backup_time_code"
|
||||
class="col-md-6"
|
||||
:field="v$.backup_time_code"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Scheduled Backup Time') }}
|
||||
</template>
|
||||
|
@ -25,12 +42,19 @@
|
|||
{{ $gettext('If the end time is before the start time, the playlist will play overnight.') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<time-code :id="props.id" v-model="props.field.$model" :state="props.state"></time-code>
|
||||
<time-code
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:state="props.state"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="form_edit_exclude_media"
|
||||
:field="v$.backup_exclude_media">
|
||||
<b-wrapped-form-checkbox
|
||||
id="form_edit_exclude_media"
|
||||
class="col-md-6"
|
||||
:field="v$.backup_exclude_media"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Exclude Media from Backup') }}
|
||||
</template>
|
||||
|
@ -41,8 +65,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_backup_keep_copies" :field="v$.backup_keep_copies"
|
||||
input-type="number" :input-attrs="{min: '0', max: '365'}">
|
||||
<b-wrapped-form-group
|
||||
id="form_backup_keep_copies"
|
||||
class="col-md-6"
|
||||
:field="v$.backup_keep_copies"
|
||||
input-type="number"
|
||||
:input-attrs="{min: '0', max: '365'}"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Number of Backup Copies to Keep') }}
|
||||
</template>
|
||||
|
@ -53,24 +82,38 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backup_storage_location"
|
||||
:field="v$.backup_storage_location">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backup_storage_location"
|
||||
class="col-md-6"
|
||||
:field="v$.backup_storage_location"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Storage Location') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="storageLocationOptions"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="storageLocationOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backup_format" :field="v$.backup_format">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backup_format"
|
||||
class="col-md-6"
|
||||
:field="v$.backup_format"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Backup Format') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" v-model="props.field.$model"
|
||||
:options="formatOptions"></b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="formatOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
<template>
|
||||
<b-modal size="md" id="log_view_modal" ref="$modal" :title="$gettext('Log Viewer')">
|
||||
<pre id="modal-log-view-contents" class="form-control log-viewer"
|
||||
style="height: 300px; overflow-y: auto;">{{ lastOutput }}</pre>
|
||||
<b-modal
|
||||
id="log_view_modal"
|
||||
ref="$modal"
|
||||
size="md"
|
||||
:title="$gettext('Log Viewer')"
|
||||
>
|
||||
<pre
|
||||
id="modal-log-view-contents"
|
||||
class="form-control log-viewer"
|
||||
style="height: 300px; overflow-y: auto;"
|
||||
>{{ lastOutput }}</pre>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,25 +1,49 @@
|
|||
<template>
|
||||
<b-modal size="md" centered id="run_backup_modal" ref="$modal" :title="$gettext('Run Manual Backup')"
|
||||
@hidden="clearContents">
|
||||
<b-modal
|
||||
id="run_backup_modal"
|
||||
ref="$modal"
|
||||
size="md"
|
||||
centered
|
||||
:title="$gettext('Run Manual Backup')"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<template #default="slotProps">
|
||||
<b-alert variant="danger" :show="error != null">{{ error }}</b-alert>
|
||||
<b-alert
|
||||
variant="danger"
|
||||
:show="error != null"
|
||||
>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
|
||||
<b-form v-if="logUrl === null" class="form vue-form" @submit.prevent="submit">
|
||||
<b-form
|
||||
v-if="logUrl === null"
|
||||
class="form vue-form"
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_storage_location"
|
||||
:field="v$.storage_location">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_storage_location"
|
||||
class="col-md-12"
|
||||
:field="v$.storage_location"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Storage Location') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="storageLocationOptions"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="storageLocationOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_path"
|
||||
:field="v$.path">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_path"
|
||||
class="col-md-12"
|
||||
:field="v$.path"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('File Name') }}
|
||||
</template>
|
||||
|
@ -35,7 +59,8 @@
|
|||
<ul class="m-0">
|
||||
<li>.zip</li>
|
||||
<li>.tar.gz</li>
|
||||
<li>.tzst (
|
||||
<li>
|
||||
.tzst (
|
||||
{{ $gettext('ZStandard compression') }}
|
||||
)
|
||||
</li>
|
||||
|
@ -43,8 +68,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_exclude_media"
|
||||
:field="v$.exclude_media">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_exclude_media"
|
||||
class="col-md-12"
|
||||
:field="v$.exclude_media"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Exclude Media from Backup') }}
|
||||
</template>
|
||||
|
@ -61,17 +89,28 @@
|
|||
</b-form>
|
||||
|
||||
<div v-else>
|
||||
<streaming-log-view :log-url="logUrl"></streaming-log-view>
|
||||
<streaming-log-view :log-url="logUrl" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #modal-footer="slotProps">
|
||||
<slot name="modal-footer" v-bind="slotProps">
|
||||
<b-button variant="default" type="button" @click="close">
|
||||
<slot
|
||||
name="modal-footer"
|
||||
v-bind="slotProps"
|
||||
>
|
||||
<b-button
|
||||
variant="default"
|
||||
type="button"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
<b-button v-if="logUrl === null" :variant="(v$.$invalid) ? 'danger' : 'primary'" type="submit"
|
||||
@click="submit">
|
||||
<b-button
|
||||
v-if="logUrl === null"
|
||||
:variant="(v$.$invalid) ? 'danger' : 'primary'"
|
||||
type="submit"
|
||||
@click="submit"
|
||||
>
|
||||
{{ $gettext('Run Manual Backup') }}
|
||||
</b-button>
|
||||
</slot>
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
{{ $gettext('Custom Branding') }}
|
||||
</h2>
|
||||
|
||||
<section class="card mb-3" role="region">
|
||||
<section
|
||||
class="card mb-3"
|
||||
role="region"
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Upload Custom Assets') }}
|
||||
|
@ -12,17 +15,28 @@
|
|||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled">
|
||||
<custom-asset-form id="asset_background" class="mb-3" :api-url="backgroundApiUrl"
|
||||
:caption="$gettext('Public Page Background')"></custom-asset-form>
|
||||
<custom-asset-form id="asset_album_art" class="mb-3" :api-url="albumArtApiUrl"
|
||||
:caption="$gettext('Default Album Art')"></custom-asset-form>
|
||||
<custom-asset-form id="asset_browser_icon" :api-url="browserIconApiUrl"
|
||||
:caption="$gettext('Browser Icon')"></custom-asset-form>
|
||||
<custom-asset-form
|
||||
id="asset_background"
|
||||
class="mb-3"
|
||||
:api-url="backgroundApiUrl"
|
||||
:caption="$gettext('Public Page Background')"
|
||||
/>
|
||||
<custom-asset-form
|
||||
id="asset_album_art"
|
||||
class="mb-3"
|
||||
:api-url="albumArtApiUrl"
|
||||
:caption="$gettext('Default Album Art')"
|
||||
/>
|
||||
<custom-asset-form
|
||||
id="asset_browser_icon"
|
||||
:api-url="browserIconApiUrl"
|
||||
:caption="$gettext('Browser Icon')"
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<branding-form :api-url="settingsApiUrl"></branding-form>
|
||||
<branding-form :api-url="settingsApiUrl" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,20 +1,37 @@
|
|||
<template>
|
||||
<form class="form vue-form" @submit.prevent="submit">
|
||||
<section class="card mb-3" role="region">
|
||||
<form
|
||||
class="form vue-form"
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
<section
|
||||
class="card mb-3"
|
||||
role="region"
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Branding Settings') }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<b-alert variant="danger" :show="error != null">{{ error }}</b-alert>
|
||||
<b-alert
|
||||
variant="danger"
|
||||
:show="error != null"
|
||||
>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<div class="card-body">
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_public_theme"
|
||||
:field="v$.public_theme">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_public_theme"
|
||||
class="col-md-6"
|
||||
:field="v$.public_theme"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Base Theme for Public Pages') }}
|
||||
</template>
|
||||
|
@ -24,15 +41,21 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="publicThemeOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="publicThemeOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-col md="6">
|
||||
<b-wrapped-form-checkbox class="mb-2" id="form_edit_hide_album_art"
|
||||
:field="v$.hide_album_art">
|
||||
<b-wrapped-form-checkbox
|
||||
id="form_edit_hide_album_art"
|
||||
class="mb-2"
|
||||
:field="v$.hide_album_art"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Hide Album Art on Public Pages') }}
|
||||
</template>
|
||||
|
@ -43,8 +66,10 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-checkbox id="form_edit_hide_product_name"
|
||||
:field="v$.hide_product_name">
|
||||
<b-wrapped-form-checkbox
|
||||
id="form_edit_hide_product_name"
|
||||
:field="v$.hide_product_name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Hide AzuraCast Branding on Public Pages') }}
|
||||
</template>
|
||||
|
@ -56,8 +81,11 @@
|
|||
</b-wrapped-form-checkbox>
|
||||
</b-col>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_homepage_redirect_url"
|
||||
:field="v$.homepage_redirect_url">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_homepage_redirect_url"
|
||||
class="col-md-6"
|
||||
:field="v$.homepage_redirect_url"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Homepage Redirect URL') }}
|
||||
</template>
|
||||
|
@ -68,8 +96,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_default_album_art_url"
|
||||
:field="v$.default_album_art_url">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_default_album_art_url"
|
||||
class="col-md-6"
|
||||
:field="v$.default_album_art_url"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Default Album Art URL') }}
|
||||
</template>
|
||||
|
@ -80,8 +111,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_public_custom_css"
|
||||
:field="v$.public_custom_css">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_public_custom_css"
|
||||
class="col-md-12"
|
||||
:field="v$.public_custom_css"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Custom CSS for Public Pages') }}
|
||||
</template>
|
||||
|
@ -91,13 +125,19 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<codemirror-textarea :id="props.id" mode="css"
|
||||
v-model="props.field.$model"></codemirror-textarea>
|
||||
<codemirror-textarea
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
mode="css"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_public_custom_js"
|
||||
:field="v$.public_custom_js">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_public_custom_js"
|
||||
class="col-md-12"
|
||||
:field="v$.public_custom_js"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Custom JS for Public Pages') }}
|
||||
</template>
|
||||
|
@ -107,13 +147,19 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<codemirror-textarea :id="props.id" mode="javascript"
|
||||
v-model="props.field.$model"></codemirror-textarea>
|
||||
<codemirror-textarea
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
mode="javascript"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_internal_custom_css"
|
||||
:field="v$.internal_custom_css">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_internal_custom_css"
|
||||
class="col-md-12"
|
||||
:field="v$.internal_custom_css"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Custom CSS for Internal Pages') }}
|
||||
</template>
|
||||
|
@ -123,13 +169,21 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<codemirror-textarea :id="props.id" mode="css"
|
||||
v-model="props.field.$model"></codemirror-textarea>
|
||||
<codemirror-textarea
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
mode="css"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
||||
<b-button size="lg" type="submit" class="mt-3" variant="primary">
|
||||
<b-button
|
||||
size="lg"
|
||||
type="submit"
|
||||
class="mt-3"
|
||||
variant="primary"
|
||||
>
|
||||
{{ $gettext('Save Changes') }}
|
||||
</b-button>
|
||||
</b-form-group>
|
||||
|
|
|
@ -1,16 +1,37 @@
|
|||
<template>
|
||||
<b-media tag="li">
|
||||
<template #aside>
|
||||
<a :href="url" data-fancybox target="_blank">
|
||||
<b-img :src="url" width="125" :alt="caption"></b-img>
|
||||
<a
|
||||
:href="url"
|
||||
data-fancybox
|
||||
target="_blank"
|
||||
>
|
||||
<b-img
|
||||
:src="url"
|
||||
width="125"
|
||||
:alt="caption"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<b-form-group :label-for="id">
|
||||
<template #label>{{ caption }}</template>
|
||||
<b-form-file :id="id" v-model="file" accept="image/*"></b-form-file>
|
||||
<template #label>
|
||||
{{ caption }}
|
||||
</template>
|
||||
<b-form-file
|
||||
:id="id"
|
||||
v-model="file"
|
||||
accept="image/*"
|
||||
/>
|
||||
</b-form-group>
|
||||
<b-button v-if="isUploaded" variant="outline-danger" @click.prevent="clear()">
|
||||
<b-button
|
||||
v-if="isUploaded"
|
||||
variant="outline-danger"
|
||||
@click.prevent="clear()"
|
||||
>
|
||||
{{ $gettext('Clear Image') }}
|
||||
</b-button>
|
||||
</b-overlay>
|
||||
|
@ -34,9 +55,6 @@ export default {
|
|||
file: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.relist();
|
||||
},
|
||||
watch: {
|
||||
file(newFile) {
|
||||
if (null === newFile) {
|
||||
|
@ -53,6 +71,9 @@ export default {
|
|||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.relist();
|
||||
},
|
||||
methods: {
|
||||
relist() {
|
||||
this.file = null;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('Custom Fields') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Custom Fields') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<info-card>
|
||||
|
@ -13,13 +15,22 @@
|
|||
</info-card>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button variant="outline-primary" @click.prevent="doCreate">
|
||||
<icon icon="add"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doCreate"
|
||||
>
|
||||
<icon icon="add" />
|
||||
{{ $gettext('Add Custom Field') }}
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
|
||||
<data-table ref="$dataTable" id="custom_fields" :fields="fields" :show-toolbar="false" :api-url="listUrl">
|
||||
<data-table
|
||||
id="custom_fields"
|
||||
ref="$dataTable"
|
||||
:fields="fields"
|
||||
:show-toolbar="false"
|
||||
:api-url="listUrl"
|
||||
>
|
||||
<template #cell(name)="row">
|
||||
{{ row.item.name }} <code>{{ row.item.short_name }}</code>
|
||||
</template>
|
||||
|
@ -28,10 +39,18 @@
|
|||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="primary" @click.prevent="doEdit(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
@click.prevent="doEdit(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Edit') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -39,8 +58,12 @@
|
|||
</data-table>
|
||||
</b-card>
|
||||
|
||||
<edit-modal ref="$editModal" :create-url="listUrl" :auto-assign-types="autoAssignTypes"
|
||||
@relist="relist"></edit-modal>
|
||||
<edit-modal
|
||||
ref="$editModal"
|
||||
:create-url="listUrl"
|
||||
:auto-assign-types="autoAssignTypes"
|
||||
@relist="relist"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
<template>
|
||||
<modal-form ref="modal" :loading="loading" :title="langTitle" :error="error" :disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents">
|
||||
|
||||
<admin-custom-fields-form :form="v$" :auto-assign-types="autoAssignTypes">
|
||||
</admin-custom-fields-form>
|
||||
|
||||
<modal-form
|
||||
ref="modal"
|
||||
:loading="loading"
|
||||
:title="langTitle"
|
||||
:error="error"
|
||||
:disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<admin-custom-fields-form
|
||||
:form="v$"
|
||||
:auto-assign-types="autoAssignTypes"
|
||||
/>
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
|
@ -17,8 +24,11 @@ import {defineComponent} from "vue";
|
|||
|
||||
export default defineComponent({
|
||||
name: 'AdminCustomFieldsEditModal',
|
||||
mixins: [BaseEditModal],
|
||||
components: {AdminCustomFieldsForm},
|
||||
mixins: [BaseEditModal],
|
||||
props: {
|
||||
autoAssignTypes: Object
|
||||
},
|
||||
setup() {
|
||||
const {form, resetForm, v$} = useVuelidateOnForm(
|
||||
{
|
||||
|
@ -39,9 +49,6 @@ export default defineComponent({
|
|||
v$
|
||||
};
|
||||
},
|
||||
props: {
|
||||
autoAssignTypes: Object
|
||||
},
|
||||
computed: {
|
||||
langTitle() {
|
||||
return this.isEditMode
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
<template>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_name" :field="form.name">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_name"
|
||||
class="col-md-6"
|
||||
:field="form.name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Field Name') }}
|
||||
</template>
|
||||
|
@ -12,7 +16,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_short_name" :field="form.short_name">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_short_name"
|
||||
class="col-md-6"
|
||||
:field="form.short_name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Programmatic Name') }}
|
||||
</template>
|
||||
|
@ -23,7 +31,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_auto_assign" :field="form.auto_assign">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_auto_assign"
|
||||
class="col-md-6"
|
||||
:field="form.auto_assign"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Automatically Set from ID3v2 Value') }}
|
||||
</template>
|
||||
|
@ -33,8 +45,11 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="autoAssignOptions"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="autoAssignOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
</info-card>
|
||||
|
||||
<div class="card-body">
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<div class="form-row">
|
||||
<div class="col-md-7">
|
||||
<fieldset>
|
||||
|
@ -31,7 +34,10 @@
|
|||
<li>
|
||||
{{ $gettext('Create an account on the MaxMind developer site.') }}
|
||||
<br>
|
||||
<a href="https://www.maxmind.com/en/geolite2/signup" target="_blank">
|
||||
<a
|
||||
href="https://www.maxmind.com/en/geolite2/signup"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('MaxMind Developer Site') }}
|
||||
</a>
|
||||
</li>
|
||||
|
@ -53,17 +59,26 @@
|
|||
{{ $gettext('Current Installed Version') }}
|
||||
</legend>
|
||||
|
||||
<p v-if="version" class="text-success card-text">
|
||||
<p
|
||||
v-if="version"
|
||||
class="text-success card-text"
|
||||
>
|
||||
{{ langInstalledVersion }}
|
||||
</p>
|
||||
<p v-else class="text-danger card-text">
|
||||
<p
|
||||
v-else
|
||||
class="text-danger card-text"
|
||||
>
|
||||
{{ $gettext('GeoLite is not currently installed on this installation.') }}
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<form @submit.prevent="doUpdate">
|
||||
<fieldset>
|
||||
<b-wrapped-form-group id="edit_form_key" :field="v$.key">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_key"
|
||||
:field="v$.key"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('MaxMind License Key') }}
|
||||
</template>
|
||||
|
@ -71,10 +86,17 @@
|
|||
</fieldset>
|
||||
|
||||
<div class="buttons">
|
||||
<b-button variant="primary" type="submit">
|
||||
<b-button
|
||||
variant="primary"
|
||||
type="submit"
|
||||
>
|
||||
{{ $gettext('Save Changes') }}
|
||||
</b-button>
|
||||
<b-button variant="danger" type="button" @click.prevent="doDelete">
|
||||
<b-button
|
||||
variant="danger"
|
||||
type="button"
|
||||
@click.prevent="doDelete"
|
||||
>
|
||||
{{ $gettext('Remove Key') }}
|
||||
</b-button>
|
||||
</div>
|
||||
|
|
|
@ -5,19 +5,38 @@
|
|||
</h2>
|
||||
|
||||
<b-row>
|
||||
<b-col v-for="(panel, key) in adminPanels" :key="key" sm="12" lg="4" class="mb-4">
|
||||
<b-col
|
||||
v-for="(panel, key) in adminPanels"
|
||||
:key="key"
|
||||
sm="12"
|
||||
lg="4"
|
||||
class="mb-4"
|
||||
>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
||||
<b-card-header
|
||||
header-bg-variant="primary-dark"
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<div class="flex-fill">
|
||||
<h2 class="card-title">{{ panel.label }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ panel.label }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="flex-shrink-0 pt-1">
|
||||
<icon class="lg" :icon="panel.icon"></icon>
|
||||
<icon
|
||||
class="lg"
|
||||
:icon="panel.icon"
|
||||
/>
|
||||
</div>
|
||||
</b-card-header>
|
||||
|
||||
<b-list-group>
|
||||
<b-list-group-item v-for="(item, key) in panel.items" :key="key" :href="item.url">{{
|
||||
<b-list-group-item
|
||||
v-for="(item, key) in panel.items"
|
||||
:key="key"
|
||||
:href="item.url"
|
||||
>
|
||||
{{
|
||||
item.label
|
||||
}}
|
||||
</b-list-group-item>
|
||||
|
@ -31,9 +50,17 @@
|
|||
</h2>
|
||||
|
||||
<b-row>
|
||||
<b-col sm="12" lg="6" xl="6" class="mb-4">
|
||||
<b-col
|
||||
sm="12"
|
||||
lg="6"
|
||||
xl="6"
|
||||
class="mb-4"
|
||||
>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
||||
<b-card-header
|
||||
header-bg-variant="primary-dark"
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<div class="flex-fill">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Memory') }}
|
||||
|
@ -41,9 +68,13 @@
|
|||
</div>
|
||||
|
||||
<div class="flex-shrink-0">
|
||||
<b-button variant="outline-light" size="sm" class="py-2"
|
||||
@click.prevent="showMemoryStatsHelpModal">
|
||||
<icon icon="help_outline"></icon>
|
||||
<b-button
|
||||
variant="outline-light"
|
||||
size="sm"
|
||||
class="py-2"
|
||||
@click.prevent="showMemoryStatsHelpModal"
|
||||
>
|
||||
<icon icon="help_outline" />
|
||||
</b-button>
|
||||
</div>
|
||||
</b-card-header>
|
||||
|
@ -55,21 +86,39 @@
|
|||
{{ stats.memory.readable.total }}
|
||||
</h6>
|
||||
|
||||
<b-progress :max="stats.memory.bytes.total" :label="stats.memory.readable.used"
|
||||
class="h-20 mb-3 mt-2">
|
||||
<b-progress-bar variant="primary" :value="stats.memory.bytes.used"></b-progress-bar>
|
||||
<b-progress-bar variant="warning"
|
||||
:value="stats.memory.bytes.cached"></b-progress-bar>
|
||||
<b-progress
|
||||
:max="stats.memory.bytes.total"
|
||||
:label="stats.memory.readable.used"
|
||||
class="h-20 mb-3 mt-2"
|
||||
>
|
||||
<b-progress-bar
|
||||
variant="primary"
|
||||
:value="stats.memory.bytes.used"
|
||||
/>
|
||||
<b-progress-bar
|
||||
variant="warning"
|
||||
:value="stats.memory.bytes.cached"
|
||||
/>
|
||||
</b-progress>
|
||||
|
||||
<b-row>
|
||||
<b-col>
|
||||
<b-badge pill variant="primary"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="primary"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Used') }}
|
||||
: {{ stats.memory.readable.used }}
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-badge pill variant="warning"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="warning"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Cached') }}
|
||||
: {{ stats.memory.readable.cached }}
|
||||
</b-col>
|
||||
|
@ -78,7 +127,12 @@
|
|||
</b-card>
|
||||
</b-col>
|
||||
|
||||
<b-col sm="12" lg="6" xl="6" class="mb-4">
|
||||
<b-col
|
||||
sm="12"
|
||||
lg="6"
|
||||
xl="6"
|
||||
class="mb-4"
|
||||
>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">
|
||||
|
@ -93,14 +147,25 @@
|
|||
{{ stats.disk.readable.total }}
|
||||
</h6>
|
||||
|
||||
<b-progress :max="stats.disk.bytes.total" :label="stats.disk.readable.used"
|
||||
class="h-20 mb-3 mt-2">
|
||||
<b-progress-bar variant="primary" :value="stats.disk.bytes.used"></b-progress-bar>
|
||||
<b-progress
|
||||
:max="stats.disk.bytes.total"
|
||||
:label="stats.disk.readable.used"
|
||||
class="h-20 mb-3 mt-2"
|
||||
>
|
||||
<b-progress-bar
|
||||
variant="primary"
|
||||
:value="stats.disk.bytes.used"
|
||||
/>
|
||||
</b-progress>
|
||||
|
||||
<b-row>
|
||||
<b-col>
|
||||
<b-badge pill variant="primary"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="primary"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Used') }}
|
||||
:
|
||||
{{ stats.disk.readable.used }}
|
||||
|
@ -112,9 +177,17 @@
|
|||
</b-row>
|
||||
|
||||
<b-row>
|
||||
<b-col sm="12" lg="8" xl="6" class="mb-4">
|
||||
<b-col
|
||||
sm="12"
|
||||
lg="8"
|
||||
xl="6"
|
||||
class="mb-4"
|
||||
>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
||||
<b-card-header
|
||||
header-bg-variant="primary-dark"
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<div class="flex-fill">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('CPU Load') }}
|
||||
|
@ -122,36 +195,69 @@
|
|||
</div>
|
||||
|
||||
<div class="flex-shrink-0">
|
||||
<b-button variant="outline-light" size="sm" class="py-2"
|
||||
@click.prevent="showCpuStatsHelpModal">
|
||||
<icon icon="help_outline"></icon>
|
||||
<b-button
|
||||
variant="outline-light"
|
||||
size="sm"
|
||||
class="py-2"
|
||||
@click.prevent="showCpuStatsHelpModal"
|
||||
>
|
||||
<icon icon="help_outline" />
|
||||
</b-button>
|
||||
</div>
|
||||
</b-card-header>
|
||||
|
||||
<b-card-body>
|
||||
<h5 class="mb-1 text-center">{{ formatCpuName(stats.cpu.total.name) }}</h5>
|
||||
<h5 class="mb-1 text-center">
|
||||
{{ formatCpuName(stats.cpu.total.name) }}
|
||||
</h5>
|
||||
|
||||
<b-progress max="100" :label="formatPercentageString(stats.cpu.total.usage)"
|
||||
class="h-20 mb-3 mt-2">
|
||||
<b-progress-bar variant="danger" :value="stats.cpu.total.steal"></b-progress-bar>
|
||||
<b-progress-bar variant="warning" :value="stats.cpu.total.io_wait"></b-progress-bar>
|
||||
<b-progress-bar variant="primary" :value="stats.cpu.total.usage"></b-progress-bar>
|
||||
<b-progress
|
||||
max="100"
|
||||
:label="formatPercentageString(stats.cpu.total.usage)"
|
||||
class="h-20 mb-3 mt-2"
|
||||
>
|
||||
<b-progress-bar
|
||||
variant="danger"
|
||||
:value="stats.cpu.total.steal"
|
||||
/>
|
||||
<b-progress-bar
|
||||
variant="warning"
|
||||
:value="stats.cpu.total.io_wait"
|
||||
/>
|
||||
<b-progress-bar
|
||||
variant="primary"
|
||||
:value="stats.cpu.total.usage"
|
||||
/>
|
||||
</b-progress>
|
||||
|
||||
<b-row>
|
||||
<b-col>
|
||||
<b-badge pill variant="danger"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="danger"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Steal') }}
|
||||
: {{ stats.cpu.total.steal }}%
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-badge pill variant="warning"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="warning"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Wait') }}
|
||||
: {{ stats.cpu.total.io_wait }}%
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-badge pill variant="primary"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="primary"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Use') }}
|
||||
: {{ stats.cpu.total.usage }}%
|
||||
</b-col>
|
||||
|
@ -160,16 +266,38 @@
|
|||
<hr>
|
||||
|
||||
<b-row>
|
||||
<b-col v-for="core in stats.cpu.cores" :key="core.name" lg="6">
|
||||
<h6 class="mb-1 text-center">{{ formatCpuName(core.name) }}</h6>
|
||||
<b-col
|
||||
v-for="core in stats.cpu.cores"
|
||||
:key="core.name"
|
||||
lg="6"
|
||||
>
|
||||
<h6 class="mb-1 text-center">
|
||||
{{ formatCpuName(core.name) }}
|
||||
</h6>
|
||||
|
||||
<b-progress max="100" :label="formatPercentageString(core.usage)" class="h-20">
|
||||
<b-progress-bar variant="danger" :value="core.steal"></b-progress-bar>
|
||||
<b-progress-bar variant="warning" :value="core.io_wait"></b-progress-bar>
|
||||
<b-progress-bar variant="primary" :value="core.usage"></b-progress-bar>
|
||||
<b-progress
|
||||
max="100"
|
||||
:label="formatPercentageString(core.usage)"
|
||||
class="h-20"
|
||||
>
|
||||
<b-progress-bar
|
||||
variant="danger"
|
||||
:value="core.steal"
|
||||
/>
|
||||
<b-progress-bar
|
||||
variant="warning"
|
||||
:value="core.io_wait"
|
||||
/>
|
||||
<b-progress-bar
|
||||
variant="primary"
|
||||
:value="core.usage"
|
||||
/>
|
||||
</b-progress>
|
||||
|
||||
<b-row no-gutters class="mb-2 mt-1">
|
||||
<b-row
|
||||
no-gutters
|
||||
class="mb-2 mt-1"
|
||||
>
|
||||
<b-col>
|
||||
St: {{ core.steal }}%
|
||||
</b-col>
|
||||
|
@ -188,7 +316,10 @@
|
|||
<h6 class="mb-1 text-center">
|
||||
{{ $gettext('Load Average') }}
|
||||
</h6>
|
||||
<b-row class="text-center" no-gutters>
|
||||
<b-row
|
||||
class="text-center"
|
||||
no-gutters
|
||||
>
|
||||
<b-col>
|
||||
<h6>1-Min</h6>
|
||||
{{ stats.cpu.load[0].toFixed(2) }}
|
||||
|
@ -206,9 +337,17 @@
|
|||
</b-card>
|
||||
</b-col>
|
||||
|
||||
<b-col sm="12" lg="4" xl="6" class="mb-4">
|
||||
<b-col
|
||||
sm="12"
|
||||
lg="4"
|
||||
xl="6"
|
||||
class="mb-4"
|
||||
>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
||||
<b-card-header
|
||||
header-bg-variant="primary-dark"
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<div class="flex-fill">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Services') }}
|
||||
|
@ -223,16 +362,28 @@
|
|||
<col style="width: 20%;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr class="align-middle" v-for="service in services" :key="service.name">
|
||||
<tr
|
||||
v-for="service in services"
|
||||
:key="service.name"
|
||||
class="align-middle"
|
||||
>
|
||||
<td class="text-center pr-2">
|
||||
<template v-if="service.running">
|
||||
<b-badge pill variant="success" :title="langServiceRunning">
|
||||
<b-badge
|
||||
pill
|
||||
variant="success"
|
||||
:title="langServiceRunning"
|
||||
>
|
||||
|
||||
<span class="sr-only">{{ langServiceRunning }}</span>
|
||||
</b-badge>
|
||||
</template>
|
||||
<template v-else>
|
||||
<b-badge pill variant="danger" :title="langServiceStopped">
|
||||
<b-badge
|
||||
pill
|
||||
variant="danger"
|
||||
:title="langServiceStopped"
|
||||
>
|
||||
|
||||
<span class="sr-only">{{ langServiceStopped }}</span>
|
||||
</b-badge>
|
||||
|
@ -245,9 +396,15 @@
|
|||
</h6>
|
||||
</td>
|
||||
<td>
|
||||
<b-button-group size="sm" v-if="service.links.restart">
|
||||
<b-button size="sm" :variant="service.running ? 'bg' : 'danger'"
|
||||
@click.prevent="doRestart(service.links.restart)">
|
||||
<b-button-group
|
||||
v-if="service.links.restart"
|
||||
size="sm"
|
||||
>
|
||||
<b-button
|
||||
size="sm"
|
||||
:variant="service.running ? 'bg' : 'danger'"
|
||||
@click.prevent="doRestart(service.links.restart)"
|
||||
>
|
||||
{{ $gettext('Restart') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -268,27 +425,38 @@
|
|||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<b-tabs content-class="mt-3" pills card>
|
||||
<b-tab v-for="netInterface in stats.network" :key="netInterface.interface_name"
|
||||
:title="netInterface.interface_name">
|
||||
<b-tabs
|
||||
content-class="mt-3"
|
||||
pills
|
||||
card
|
||||
>
|
||||
<b-tab
|
||||
v-for="netInterface in stats.network"
|
||||
:key="netInterface.interface_name"
|
||||
:title="netInterface.interface_name"
|
||||
>
|
||||
<b-row class="mb-3">
|
||||
<b-col class="mb-3">
|
||||
<h5 class="mb-1 text-center">
|
||||
{{ $gettext('Received') }}
|
||||
</h5>
|
||||
<b-table striped responsive
|
||||
<b-table
|
||||
striped
|
||||
responsive
|
||||
:items="getNetworkInterfaceTableItems(netInterface.received)"
|
||||
:fields="getNetworkInterfaceTableFields(netInterface.received)">
|
||||
</b-table>
|
||||
:fields="getNetworkInterfaceTableFields(netInterface.received)"
|
||||
/>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<h5 class="mb-1 text-center">
|
||||
{{ $gettext('Transmitted') }}
|
||||
</h5>
|
||||
<b-table striped responsive
|
||||
<b-table
|
||||
striped
|
||||
responsive
|
||||
:items="getNetworkInterfaceTableItems(netInterface.transmitted)"
|
||||
:fields="getNetworkInterfaceTableFields(netInterface.transmitted)">
|
||||
</b-table>
|
||||
:fields="getNetworkInterfaceTableFields(netInterface.transmitted)"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-tab>
|
||||
|
@ -297,8 +465,8 @@
|
|||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<cpu-stats-help-modal ref="cpuStatsHelpModal"></cpu-stats-help-modal>
|
||||
<memory-stats-help-modal ref="memoryStatsHelpModal"></memory-stats-help-modal>
|
||||
<cpu-stats-help-modal ref="cpuStatsHelpModal" />
|
||||
<memory-stats-help-modal ref="memoryStatsHelpModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -361,10 +529,6 @@ export default {
|
|||
services: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.updateStats();
|
||||
this.updateServices();
|
||||
},
|
||||
computed: {
|
||||
langServiceRunning() {
|
||||
return this.$gettext('Service Running');
|
||||
|
@ -373,6 +537,10 @@ export default {
|
|||
return this.$gettext('Service Stopped');
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.updateStats();
|
||||
this.updateServices();
|
||||
},
|
||||
methods: {
|
||||
formatCpuName(cpuName) {
|
||||
return _.upperFirst(cpuName);
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
<template>
|
||||
<b-modal size="lg" centered id="cpu_stats_help_modal" ref="$modal" :title="$gettext('CPU Stats Help')">
|
||||
<b-modal
|
||||
id="cpu_stats_help_modal"
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
centered
|
||||
:title="$gettext('CPU Stats Help')"
|
||||
>
|
||||
<div class="mb-2">
|
||||
<h6>
|
||||
<b-badge pill variant="danger"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="danger"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Steal (St)') }}:
|
||||
{{ $gettext('Time stolen by other virtual machines on the same physical server.') }}
|
||||
</h6>
|
||||
|
@ -26,7 +37,12 @@
|
|||
</div>
|
||||
<div class="mb-2">
|
||||
<h6>
|
||||
<b-badge pill variant="warning"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="warning"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Wait (Wa)') }}:
|
||||
{{ $gettext('Time spent waiting for disk I/O to be completed.') }}
|
||||
</h6>
|
||||
|
@ -50,7 +66,12 @@
|
|||
</div>
|
||||
<div class="mb-1">
|
||||
<h6>
|
||||
<b-badge pill variant="primary"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="primary"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Use (Us)') }}:
|
||||
{{ $gettext('The current CPU usage including I/O Wait and Steal.') }}
|
||||
</h6>
|
||||
|
@ -58,7 +79,11 @@
|
|||
|
||||
<template #modal-footer>
|
||||
<slot name="modal-footer">
|
||||
<b-button variant="default" type="button" @click="close">
|
||||
<b-button
|
||||
variant="default"
|
||||
type="button"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
</slot>
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
<template>
|
||||
<b-modal size="lg" centered id="cpu_stats_help_modal" ref="$modal" :title="$gettext('Memory Stats Help')">
|
||||
<b-modal
|
||||
id="cpu_stats_help_modal"
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
centered
|
||||
:title="$gettext('Memory Stats Help')"
|
||||
>
|
||||
<div class="mb-2">
|
||||
<h6>
|
||||
<b-badge pill variant="danger"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="danger"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Cached') }}:
|
||||
{{ $gettext('The amount of memory Linux is using for disk caching.') }}
|
||||
</h6>
|
||||
|
@ -22,7 +33,12 @@
|
|||
|
||||
<div class="mb-2">
|
||||
<h6>
|
||||
<b-badge pill variant="primary"> </b-badge>
|
||||
<b-badge
|
||||
pill
|
||||
variant="primary"
|
||||
>
|
||||
|
||||
</b-badge>
|
||||
{{ $gettext('Used') }}:
|
||||
{{ $gettext('The current Memory usage excluding cached memory.') }}
|
||||
</h6>
|
||||
|
@ -30,7 +46,11 @@
|
|||
|
||||
<template #modal-footer>
|
||||
<slot name="modal-footer">
|
||||
<b-button variant="default" type="button" @click="close">
|
||||
<b-button
|
||||
variant="default"
|
||||
type="button"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
</slot>
|
||||
|
|
|
@ -6,24 +6,42 @@
|
|||
</h2>
|
||||
</div>
|
||||
|
||||
<log-list :url="systemLogsUrl" @view="viewLog"></log-list>
|
||||
<log-list
|
||||
:url="systemLogsUrl"
|
||||
@view="viewLog"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="card" v-if="stationLogs.length > 0">
|
||||
<div
|
||||
v-if="stationLogs.length > 0"
|
||||
class="card"
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Logs by Station') }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<b-tabs pills lazy nav-class="card-header-pills" nav-wrapper-class="card-header">
|
||||
<b-tab v-for="row in stationLogs" :key="row.id" :title="row.name">
|
||||
<log-list :url="row.url" @view="viewLog"></log-list>
|
||||
<b-tabs
|
||||
pills
|
||||
lazy
|
||||
nav-class="card-header-pills"
|
||||
nav-wrapper-class="card-header"
|
||||
>
|
||||
<b-tab
|
||||
v-for="row in stationLogs"
|
||||
:key="row.id"
|
||||
:title="row.name"
|
||||
>
|
||||
<log-list
|
||||
:url="row.url"
|
||||
@view="viewLog"
|
||||
/>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
</div>
|
||||
|
||||
<streaming-log-modal ref="$modal"></streaming-log-modal>
|
||||
<streaming-log-modal ref="$modal" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('Roles & Permissions') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Roles & Permissions') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<info-card>
|
||||
|
@ -13,31 +15,54 @@
|
|||
</info-card>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button variant="outline-primary" @click.prevent="doCreate">
|
||||
<icon icon="add"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doCreate"
|
||||
>
|
||||
<icon icon="add" />
|
||||
{{ $gettext('Add Role') }}
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
|
||||
<data-table ref="datatable" id="permissions" paginated :fields="fields" :api-url="listUrl">
|
||||
<data-table
|
||||
id="permissions"
|
||||
ref="datatable"
|
||||
paginated
|
||||
:fields="fields"
|
||||
:api-url="listUrl"
|
||||
>
|
||||
<template #cell(permissions)="row">
|
||||
<div v-if="row.item.permissions.global.length > 0">
|
||||
{{ $gettext('Global') }}
|
||||
:
|
||||
{{ getGlobalPermissionNames(row.item.permissions.global).join(', ') }}
|
||||
</div>
|
||||
<div v-for="(permissions, stationId) in row.item.permissions.station" :key="stationId">
|
||||
<div
|
||||
v-for="(permissions, stationId) in row.item.permissions.station"
|
||||
:key="stationId"
|
||||
>
|
||||
<b>{{ getStationName(stationId) }}</b>:
|
||||
{{ getStationPermissionNames(permissions).join(', ') }}
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm" v-if="!row.item.is_super_admin">
|
||||
<b-button size="sm" variant="primary" @click.prevent="doEdit(row.item.links.self)">
|
||||
<b-button-group
|
||||
v-if="!row.item.is_super_admin"
|
||||
size="sm"
|
||||
>
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
@click.prevent="doEdit(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Edit') }}
|
||||
</b-button>
|
||||
<b-button v-if="row.item.id !== 1" size="sm" variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.self)">
|
||||
<b-button
|
||||
v-if="row.item.id !== 1"
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -45,8 +70,14 @@
|
|||
</data-table>
|
||||
</b-card>
|
||||
|
||||
<edit-modal ref="editModal" :create-url="listUrl" :station-permissions="stationPermissions" :stations="stations"
|
||||
:global-permissions="globalPermissions" @relist="relist"></edit-modal>
|
||||
<edit-modal
|
||||
ref="editModal"
|
||||
:create-url="listUrl"
|
||||
:station-permissions="stationPermissions"
|
||||
:stations="stations"
|
||||
:global-permissions="globalPermissions"
|
||||
@relist="relist"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
<template>
|
||||
<modal-form ref="modal" :loading="loading" :title="langTitle" :error="error" :disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents">
|
||||
<modal-form
|
||||
ref="modal"
|
||||
:loading="loading"
|
||||
:title="langTitle"
|
||||
:error="error"
|
||||
:disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<b-tabs
|
||||
content-class="mt-3"
|
||||
pills
|
||||
>
|
||||
<admin-permissions-global-form
|
||||
:form="v$"
|
||||
:global-permissions="globalPermissions"
|
||||
/>
|
||||
|
||||
<b-tabs content-class="mt-3" pills>
|
||||
<admin-permissions-global-form :form="v$" :global-permissions="globalPermissions">
|
||||
</admin-permissions-global-form>
|
||||
|
||||
<admin-permissions-station-form :form="v$" :stations="stations"
|
||||
:station-permissions="stationPermissions">
|
||||
</admin-permissions-station-form>
|
||||
<admin-permissions-station-form
|
||||
:form="v$"
|
||||
:stations="stations"
|
||||
:station-permissions="stationPermissions"
|
||||
/>
|
||||
</b-tabs>
|
||||
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
<template>
|
||||
<b-tab :title="$gettext('Global Permissions')" active>
|
||||
<b-tab
|
||||
:title="$gettext('Global Permissions')"
|
||||
active
|
||||
>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_name" :field="form.name">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_name"
|
||||
class="col-md-12"
|
||||
:field="form.name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Role Name') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_global_permissions"
|
||||
:field="form.permissions.global">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_global_permissions"
|
||||
class="col-md-12"
|
||||
:field="form.permissions.global"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Global Permissions') }}
|
||||
</template>
|
||||
|
@ -19,9 +29,12 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-checkbox-group :id="props.id" :options="globalPermissionOptions"
|
||||
v-model="props.field.$model" stacked>
|
||||
</b-form-checkbox-group>
|
||||
<b-form-checkbox-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="globalPermissionOptions"
|
||||
stacked
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
|
|
@ -1,19 +1,29 @@
|
|||
<template>
|
||||
<b-tab :title="$gettext('Station Permissions')">
|
||||
<permissions-form-station-row
|
||||
v-for="(row, index) in form.permissions.$model.station" :key="index"
|
||||
:stations="stations" :station-permissions="stationPermissions"
|
||||
v-model:row="form.permissions.$model.station[index]" @remove="remove(index)"
|
||||
></permissions-form-station-row>
|
||||
v-for="(row, index) in form.permissions.$model.station"
|
||||
:key="index"
|
||||
v-model:row="form.permissions.$model.station[index]"
|
||||
:stations="stations"
|
||||
:station-permissions="stationPermissions"
|
||||
@remove="remove(index)"
|
||||
/>
|
||||
|
||||
<b-button-group v-if="hasRemainingStations">
|
||||
<b-dropdown size="sm" variant="outline-primary">
|
||||
<b-dropdown
|
||||
size="sm"
|
||||
variant="outline-primary"
|
||||
>
|
||||
<template #button-content>
|
||||
{{ $gettext('Add Station') }}
|
||||
</template>
|
||||
<div style="max-height: 300px; overflow-y: auto;">
|
||||
<b-dropdown-item-button v-for="(stationName, stationId) in remainingStations" :key="stationId"
|
||||
@click="add(stationId)">{{ stationName }}
|
||||
<b-dropdown-item-button
|
||||
v-for="(stationName, stationId) in remainingStations"
|
||||
:key="stationId"
|
||||
@click="add(stationId)"
|
||||
>
|
||||
{{ stationName }}
|
||||
</b-dropdown-item-button>
|
||||
</div>
|
||||
</b-dropdown>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<b-card class="mb-3" no-body>
|
||||
<b-card
|
||||
class="mb-3"
|
||||
no-body
|
||||
>
|
||||
<div class="card-header bg-primary-dark d-flex align-items-center">
|
||||
<div class="flex-fill">
|
||||
<h2 class="card-title">
|
||||
|
@ -7,8 +10,13 @@
|
|||
</h2>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<b-button size="sm" variant="outline-light" class="py-2 pr-0" @click.prevent="$emit('remove')">
|
||||
<icon icon="remove"></icon>
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="outline-light"
|
||||
class="py-2 pr-0"
|
||||
@click.prevent="$emit('remove')"
|
||||
>
|
||||
<icon icon="remove" />
|
||||
{{ $gettext('Remove') }}
|
||||
</b-button>
|
||||
</div>
|
||||
|
@ -16,9 +24,11 @@
|
|||
<b-card-body>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12"
|
||||
<b-wrapped-form-group
|
||||
:id="'edit_form_station_permissions_'+row.station_id"
|
||||
:field="v$.permissions">
|
||||
class="col-md-12"
|
||||
:field="v$.permissions"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Station Permissions') }}
|
||||
</template>
|
||||
|
@ -26,9 +36,12 @@
|
|||
{{ $gettext('Users with this role will have these permissions for this single station.') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-checkbox-group :id="props.id" :options="stationPermissionOptions"
|
||||
v-model="props.field.$model" stacked>
|
||||
</b-form-checkbox-group>
|
||||
<b-form-checkbox-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="stationPermissionOptions"
|
||||
stacked
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<template>
|
||||
<form class="form vue-form" @submit.prevent="submit">
|
||||
<slot name="preCard"></slot>
|
||||
<form
|
||||
class="form vue-form"
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
<slot name="preCard" />
|
||||
|
||||
<b-card no-body>
|
||||
<div class="card-header bg-primary-dark">
|
||||
|
@ -11,18 +14,30 @@
|
|||
</h2>
|
||||
</div>
|
||||
|
||||
<slot name="cardUpper"></slot>
|
||||
<slot name="cardUpper" />
|
||||
|
||||
<b-alert variant="danger" :show="error != null">{{ error }}</b-alert>
|
||||
<b-alert
|
||||
variant="danger"
|
||||
:show="error != null"
|
||||
>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-tabs pills card lazy>
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<b-tabs
|
||||
pills
|
||||
card
|
||||
lazy
|
||||
>
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.generalTab)">
|
||||
<template #title>
|
||||
{{ $gettext('Settings') }}
|
||||
</template>
|
||||
|
||||
<settings-general-tab :form="v$"></settings-general-tab>
|
||||
<settings-general-tab :form="v$" />
|
||||
</b-tab>
|
||||
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.securityPrivacyTab)">
|
||||
|
@ -30,7 +45,7 @@
|
|||
{{ $gettext('Security & Privacy') }}
|
||||
</template>
|
||||
|
||||
<settings-security-privacy-tab :form="v$"></settings-security-privacy-tab>
|
||||
<settings-security-privacy-tab :form="v$" />
|
||||
</b-tab>
|
||||
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.servicesTab)">
|
||||
|
@ -38,16 +53,22 @@
|
|||
{{ $gettext('Services') }}
|
||||
</template>
|
||||
|
||||
<settings-services-tab :form="v$"
|
||||
<settings-services-tab
|
||||
:form="v$"
|
||||
:release-channel="releaseChannel"
|
||||
:test-message-url="testMessageUrl"
|
||||
:acme-url="acmeUrl"></settings-services-tab>
|
||||
:acme-url="acmeUrl"
|
||||
/>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
</b-overlay>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button size="lg" type="submit" :variant="(v$.$invalid) ? 'danger' : 'primary'">
|
||||
<b-button
|
||||
size="lg"
|
||||
type="submit"
|
||||
:variant="(v$.$invalid) ? 'danger' : 'primary'"
|
||||
>
|
||||
<slot name="submitButtonName">
|
||||
{{ $gettext('Save Changes') }}
|
||||
</slot>
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
<template>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_base_url" :field="form.base_url" input-type="url">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_base_url"
|
||||
class="col-md-6"
|
||||
:field="form.base_url"
|
||||
input-type="url"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Site Base URL') }}
|
||||
</template>
|
||||
|
@ -13,7 +17,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_instance_name" :field="form.instance_name">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_instance_name"
|
||||
class="col-md-6"
|
||||
:field="form.instance_name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('AzuraCast Instance Name') }}
|
||||
</template>
|
||||
|
@ -24,8 +32,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="edit_form_prefer_browser_url"
|
||||
:field="form.prefer_browser_url">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_prefer_browser_url"
|
||||
class="col-md-6"
|
||||
:field="form.prefer_browser_url"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Prefer Browser URL (If Available)') }}
|
||||
</template>
|
||||
|
@ -36,8 +47,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="edit_form_use_radio_proxy"
|
||||
:field="form.use_radio_proxy">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_use_radio_proxy"
|
||||
class="col-md-6"
|
||||
:field="form.use_radio_proxy"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Use Web Proxy for Radio') }}
|
||||
</template>
|
||||
|
@ -48,7 +62,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_history_keep_days" :field="form.history_keep_days">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_history_keep_days"
|
||||
class="col-md-6"
|
||||
:field="form.history_keep_days"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Days of Playback History to Keep') }}
|
||||
</template>
|
||||
|
@ -58,13 +76,20 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" v-model="props.field.$model"
|
||||
:options="historyKeepDaysOptions"></b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="historyKeepDaysOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="edit_form_enable_static_nowplaying"
|
||||
:field="form.enable_static_nowplaying">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_enable_static_nowplaying"
|
||||
class="col-md-6"
|
||||
:field="form.enable_static_nowplaying"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Use High-Performance Now Playing Updates') }}
|
||||
</template>
|
||||
|
@ -75,8 +100,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="edit_form_enable_advanced_features"
|
||||
:field="form.enable_advanced_features">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_enable_advanced_features"
|
||||
class="col-md-6"
|
||||
:field="form.enable_advanced_features"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Enable Advanced Features') }}
|
||||
</template>
|
||||
|
@ -86,7 +114,6 @@
|
|||
}}
|
||||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
</div>
|
||||
</b-form-fieldset>
|
||||
</template>
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_analytics" :field="form.analytics">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_analytics"
|
||||
class="col-md-12"
|
||||
:field="form.analytics"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Listener Analytics Collection') }}
|
||||
</template>
|
||||
|
@ -15,7 +19,11 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" v-model="props.field.$model">
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
>
|
||||
<b-form-radio value="all">
|
||||
<b>
|
||||
{{ $gettext('Full:') }}
|
||||
|
@ -46,8 +54,11 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_always_use_ssl"
|
||||
:field="form.always_use_ssl">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_always_use_ssl"
|
||||
class="col-md-12"
|
||||
:field="form.always_use_ssl"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Always Use HTTPS') }}
|
||||
</template>
|
||||
|
@ -58,8 +69,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_api_access_control"
|
||||
:field="form.api_access_control">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_api_access_control"
|
||||
class="col-md-12"
|
||||
:field="form.api_access_control"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('API "Access-Control-Allow-Origin" Header') }}
|
||||
</template>
|
||||
|
@ -68,8 +82,10 @@
|
|||
$gettext('Set to * to allow all sources, or specify a list of origins separated by a comma (,).')
|
||||
}}
|
||||
<br>
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin"
|
||||
target="_blank">
|
||||
<a
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Learn more about this header.') }}
|
||||
</a>
|
||||
</template>
|
||||
|
|
|
@ -5,13 +5,18 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-form-markup class="col-md-6" id="form_release_channel">
|
||||
<b-form-markup
|
||||
id="form_release_channel"
|
||||
class="col-md-6"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Release Channel') }}
|
||||
</template>
|
||||
<template #description>
|
||||
<a href="https://docs.azuracast.com/en/getting-started/updates/release-channels"
|
||||
target="_blank">
|
||||
<a
|
||||
href="https://docs.azuracast.com/en/getting-started/updates/release-channels"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Learn more about release channels in the AzuraCast docs.') }}
|
||||
</a>
|
||||
</template>
|
||||
|
@ -21,8 +26,11 @@
|
|||
</p>
|
||||
</b-form-markup>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="edit_form_check_for_updates"
|
||||
:field="form.check_for_updates">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_check_for_updates"
|
||||
class="col-md-6"
|
||||
:field="form.check_for_updates"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Show Update Announcements') }}
|
||||
</template>
|
||||
|
@ -44,8 +52,11 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_acme_domains"
|
||||
:field="form.acme_domains">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_acme_domains"
|
||||
class="col-md-6"
|
||||
:field="form.acme_domains"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Domain Name(s)') }}
|
||||
</template>
|
||||
|
@ -56,8 +67,12 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_acme_email"
|
||||
:field="form.acme_email" input-type="email">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_acme_email"
|
||||
class="col-md-6"
|
||||
:field="form.acme_email"
|
||||
input-type="email"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('E-mail Address (Optional)') }}
|
||||
</template>
|
||||
|
@ -67,8 +82,13 @@
|
|||
</b-wrapped-form-group>
|
||||
|
||||
<div class="form-group col">
|
||||
<b-button size="sm" variant="primary" :disabled="form.$anyDirty" @click="generateAcmeCert">
|
||||
<icon icon="badge"></icon>
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
:disabled="form.$anyDirty"
|
||||
@click="generateAcmeCert"
|
||||
>
|
||||
<icon icon="badge" />
|
||||
{{ $gettext('Generate/Renew Certificate') }}
|
||||
<span v-if="form.$anyDirty">
|
||||
({{ $gettext('Save Changes first') }})
|
||||
|
@ -87,45 +107,68 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_mail_enabled"
|
||||
:field="form.mail_enabled">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_mail_enabled"
|
||||
class="col-md-12"
|
||||
:field="form.mail_enabled"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Enable Mail Delivery') }}
|
||||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-row mt-2" v-if="form.mail_enabled.$model">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_mail_sender_name"
|
||||
:field="form.mail_sender_name">
|
||||
<div
|
||||
v-if="form.mail_enabled.$model"
|
||||
class="form-row mt-2"
|
||||
>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_mail_sender_name"
|
||||
class="col-md-6"
|
||||
:field="form.mail_sender_name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Sender Name') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_mail_sender_email"
|
||||
:field="form.mail_sender_email" input-type="email">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_mail_sender_email"
|
||||
class="col-md-6"
|
||||
:field="form.mail_sender_email"
|
||||
input-type="email"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Sender E-mail Address') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-4" id="edit_form_mail_smtp_host"
|
||||
:field="form.mail_smtp_host">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_mail_smtp_host"
|
||||
class="col-md-4"
|
||||
:field="form.mail_smtp_host"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SMTP Host') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-3" id="edit_form_mail_smtp_port"
|
||||
:field="form.mail_smtp_port" input-type="number">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_mail_smtp_port"
|
||||
class="col-md-3"
|
||||
:field="form.mail_smtp_port"
|
||||
input-type="number"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SMTP Port') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-5" id="edit_form_mail_smtp_secure"
|
||||
:field="form.mail_smtp_secure">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_mail_smtp_secure"
|
||||
class="col-md-5"
|
||||
:field="form.mail_smtp_secure"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Use Secure (TLS) SMTP Connection') }}
|
||||
</template>
|
||||
|
@ -134,23 +177,35 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_mail_smtp_username"
|
||||
:field="form.mail_smtp_username">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_mail_smtp_username"
|
||||
class="col-md-6"
|
||||
:field="form.mail_smtp_username"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SMTP Username') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_mail_smtp_password"
|
||||
:field="form.mail_smtp_password" input-type="password">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_mail_smtp_password"
|
||||
class="col-md-6"
|
||||
:field="form.mail_smtp_password"
|
||||
input-type="password"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SMTP Password') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<div class="form-group col">
|
||||
<b-button size="sm" variant="primary" :disabled="form.$anyDirty" v-b-modal.send_test_message>
|
||||
<icon icon="send"></icon>
|
||||
<b-button
|
||||
v-b-modal.send_test_message
|
||||
size="sm"
|
||||
variant="primary"
|
||||
:disabled="form.$anyDirty"
|
||||
>
|
||||
<icon icon="send" />
|
||||
{{ $gettext('Send Test Message') }}
|
||||
<span v-if="form.$anyDirty">
|
||||
({{ $gettext('Save Changes first') }})
|
||||
|
@ -166,18 +221,29 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_avatar_service" :field="form.avatar_service">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_avatar_service"
|
||||
class="col-md-6"
|
||||
:field="form.avatar_service"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Avatar Service') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" v-model="props.field.$model"
|
||||
:options="avatarServiceOptions"></b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="avatarServiceOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_avatar_default_url"
|
||||
:field="form.avatar_default_url">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_avatar_default_url"
|
||||
class="col-md-6"
|
||||
:field="form.avatar_default_url"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Default Avatar URL') }}
|
||||
</template>
|
||||
|
@ -191,28 +257,41 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="use_external_album_art_in_apis"
|
||||
:field="form.use_external_album_art_in_apis">
|
||||
<b-wrapped-form-checkbox
|
||||
id="use_external_album_art_in_apis"
|
||||
class="col-md-6"
|
||||
:field="form.use_external_album_art_in_apis"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Check Web Services for Album Art for "Now Playing" Tracks') }}
|
||||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="use_external_album_art_when_processing_media"
|
||||
:field="form.use_external_album_art_when_processing_media">
|
||||
<b-wrapped-form-checkbox
|
||||
id="use_external_album_art_when_processing_media"
|
||||
class="col-md-6"
|
||||
:field="form.use_external_album_art_when_processing_media"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Check Web Services for Album Art When Uploading Media') }}
|
||||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_last_fm_api_key" :field="form.last_fm_api_key">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_last_fm_api_key"
|
||||
class="col-md-12"
|
||||
:field="form.last_fm_api_key"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Last.fm API Key') }}
|
||||
</template>
|
||||
<template #description>
|
||||
{{ $gettext('This service can provide album art for tracks where none is available locally.') }}
|
||||
<br>
|
||||
<a href="https://www.last.fm/api/account/create" target="_blank">
|
||||
<a
|
||||
href="https://www.last.fm/api/account/create"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Apply for an API key at Last.fm') }}
|
||||
</a>
|
||||
</template>
|
||||
|
@ -220,9 +299,9 @@
|
|||
</div>
|
||||
</b-form-fieldset>
|
||||
|
||||
<streaming-log-modal ref="$acmeModal"></streaming-log-modal>
|
||||
<streaming-log-modal ref="$acmeModal" />
|
||||
|
||||
<admin-settings-test-message-modal :test-message-url="testMessageUrl"></admin-settings-test-message-modal>
|
||||
<admin-settings-test-message-modal :test-message-url="testMessageUrl" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,17 +1,32 @@
|
|||
<template>
|
||||
<b-modal id="send_test_message" centered ref="$modal" :title="$gettext('Send Test Message')">
|
||||
<b-modal
|
||||
id="send_test_message"
|
||||
ref="$modal"
|
||||
centered
|
||||
:title="$gettext('Send Test Message')"
|
||||
>
|
||||
<b-form @submit.prevent="doSendTest">
|
||||
<b-wrapped-form-group id="email_address" :field="v$.emailAddress" autofocus>
|
||||
<b-wrapped-form-group
|
||||
id="email_address"
|
||||
:field="v$.emailAddress"
|
||||
autofocus
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('E-mail Address') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</b-form>
|
||||
<template #modal-footer>
|
||||
<b-button variant="default" @click="close">
|
||||
<b-button
|
||||
variant="default"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
<b-button :variant="(v$.$invalid) ? 'danger' : 'primary'" @click="doSendTest">
|
||||
<b-button
|
||||
:variant="(v$.$invalid) ? 'danger' : 'primary'"
|
||||
@click="doSendTest"
|
||||
>
|
||||
{{ $gettext('Send Test Message') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<b-overlay variant="card" :show="loading">
|
||||
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<div class="form-row">
|
||||
<div class="col-md-7">
|
||||
<fieldset>
|
||||
|
@ -30,8 +32,10 @@
|
|||
<li>
|
||||
{{ $gettext('Download the Linux x64 binary from the Shoutcast Radio Manager:') }}
|
||||
<br>
|
||||
<a href="https://radiomanager.shoutcast.com/register/serverSoftwareFreemium"
|
||||
target="_blank">
|
||||
<a
|
||||
href="https://radiomanager.shoutcast.com/register/serverSoftwareFreemium"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Shoutcast Radio Manager') }}
|
||||
</a>
|
||||
</li>
|
||||
|
@ -54,15 +58,24 @@
|
|||
{{ $gettext('Current Installed Version') }}
|
||||
</legend>
|
||||
|
||||
<p v-if="version" class="text-success card-text">
|
||||
<p
|
||||
v-if="version"
|
||||
class="text-success card-text"
|
||||
>
|
||||
{{ langInstalledVersion }}
|
||||
</p>
|
||||
<p v-else class="text-danger card-text">
|
||||
<p
|
||||
v-else
|
||||
class="text-danger card-text"
|
||||
>
|
||||
{{ $gettext('Shoutcast 2 DNAS is not currently installed on this installation.') }}
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<flow-upload :target-url="apiUrl" @complete="relist"></flow-upload>
|
||||
<flow-upload
|
||||
:target-url="apiUrl"
|
||||
@complete="relist"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</b-overlay>
|
||||
|
|
|
@ -1,19 +1,32 @@
|
|||
<template>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('Stations') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Stations') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button variant="outline-primary" @click.prevent="doCreate">
|
||||
<icon icon="add"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doCreate"
|
||||
>
|
||||
<icon icon="add" />
|
||||
{{ $gettext('Add Station') }}
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
|
||||
<data-table ref="datatable" id="stations" paginated :fields="fields" :api-url="listUrl">
|
||||
<data-table
|
||||
id="stations"
|
||||
ref="datatable"
|
||||
paginated
|
||||
:fields="fields"
|
||||
:api-url="listUrl"
|
||||
>
|
||||
<template #cell(name)="row">
|
||||
<div class="typography-subheading">{{ row.item.name }}</div>
|
||||
<div class="typography-subheading">
|
||||
{{ row.item.name }}
|
||||
</div>
|
||||
<code>{{ row.item.short_name }}</code>
|
||||
</template>
|
||||
<template #cell(frontend_type)="row">
|
||||
|
@ -24,17 +37,33 @@
|
|||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="secondary" :href="row.item.links.manage" target="_blank">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:href="row.item.links.manage"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Manage') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="secondary"
|
||||
@click.prevent="doClone(row.item.name, row.item.links.clone)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
@click.prevent="doClone(row.item.name, row.item.links.clone)"
|
||||
>
|
||||
{{ $gettext('Clone') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="primary" @click.prevent="doEdit(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
@click.prevent="doEdit(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Edit') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -42,10 +71,17 @@
|
|||
</data-table>
|
||||
</b-card>
|
||||
|
||||
<admin-stations-edit-modal v-bind="$props" ref="editModal" :create-url="listUrl"
|
||||
@relist="relist"></admin-stations-edit-modal>
|
||||
<admin-stations-edit-modal
|
||||
v-bind="$props"
|
||||
ref="editModal"
|
||||
:create-url="listUrl"
|
||||
@relist="relist"
|
||||
/>
|
||||
|
||||
<admin-stations-clone-modal ref="cloneModal" @relist="relist"></admin-stations-clone-modal>
|
||||
<admin-stations-clone-modal
|
||||
ref="cloneModal"
|
||||
@relist="relist"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<template>
|
||||
<modal-form ref="$modal" :loading="loading" :title="$gettext('Clone Station')" :error="error"
|
||||
<modal-form
|
||||
ref="$modal"
|
||||
:loading="loading"
|
||||
:title="$gettext('Clone Station')"
|
||||
:error="error"
|
||||
:disable-save-button="v$.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents">
|
||||
|
||||
<admin-stations-clone-modal-form :form="v$"></admin-stations-clone-modal-form>
|
||||
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<admin-stations-clone-modal-form :form="v$" />
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
<template>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_name" :field="form.name">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_name"
|
||||
class="col-md-12"
|
||||
:field="form.name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('New Station Name') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_description" :field="form.description"
|
||||
input-type="textarea">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_description"
|
||||
class="col-md-12"
|
||||
:field="form.description"
|
||||
input-type="textarea"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('New Station Description') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_clone" :field="form.clone">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_clone"
|
||||
class="col-md-12"
|
||||
:field="form.clone"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Copy to New Station') }}
|
||||
</template>
|
||||
|
@ -23,7 +35,7 @@
|
|||
v-model="props.field.$model"
|
||||
:options="cloneOptions"
|
||||
stacked
|
||||
></b-form-checkbox-group>
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
|
|
@ -1,19 +1,43 @@
|
|||
<template>
|
||||
<b-modal size="lg" id="station_edit_modal" ref="$modal" :title="langTitle" :busy="loading"
|
||||
@shown="resetForm" @hidden="clearContents">
|
||||
<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">
|
||||
<b-modal
|
||||
id="station_edit_modal"
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
:title="langTitle"
|
||||
:busy="loading"
|
||||
@shown="resetForm"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<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>
|
||||
<invisible-submit-button></invisible-submit-button>
|
||||
<invisible-submit-button />
|
||||
</template>
|
||||
</admin-stations-form>
|
||||
|
||||
<template #modal-footer>
|
||||
<b-button variant="default" type="button" @click="close">
|
||||
<b-button
|
||||
variant="default"
|
||||
type="button"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
<b-button :variant="(disableSaveButton) ? 'danger' : 'primary'" type="submit" @click="doSubmit">
|
||||
<b-button
|
||||
:variant="(disableSaveButton) ? 'danger' : 'primary'"
|
||||
type="submit"
|
||||
@click="doSubmit"
|
||||
>
|
||||
{{ $gettext('Save Changes') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
<b-form-group>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-6" id="edit_form_is_enabled" :field="form.is_enabled">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_is_enabled"
|
||||
class="col-md-6"
|
||||
:field="form.is_enabled"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Enable Broadcasting') }}
|
||||
</template>
|
||||
|
@ -11,8 +15,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-group v-if="showAdvanced" class="col-md-6" id="edit_form_radio_base_dir"
|
||||
:field="form.radio_base_dir" advanced>
|
||||
<b-wrapped-form-group
|
||||
v-if="showAdvanced"
|
||||
id="edit_form_radio_base_dir"
|
||||
class="col-md-6"
|
||||
:field="form.radio_base_dir"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Base Station Directory') }}
|
||||
</template>
|
||||
|
@ -26,38 +35,59 @@
|
|||
</b-form-fieldset>
|
||||
|
||||
<b-form-fieldset>
|
||||
<b-overlay variant="card" :show="storageLocationsLoading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="storageLocationsLoading"
|
||||
>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_media_storage_location"
|
||||
:field="form.media_storage_location">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_media_storage_location"
|
||||
class="col-md-12"
|
||||
:field="form.media_storage_location"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Media Storage Location') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="storageLocationOptions.media_storage_location"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="storageLocationOptions.media_storage_location"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_recordings_storage_location"
|
||||
:field="form.recordings_storage_location">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_recordings_storage_location"
|
||||
class="col-md-12"
|
||||
:field="form.recordings_storage_location"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Live Recordings Storage Location') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="storageLocationOptions.recordings_storage_location"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="storageLocationOptions.recordings_storage_location"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_podcasts_storage_location"
|
||||
:field="form.podcasts_storage_location">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_podcasts_storage_location"
|
||||
class="col-md-12"
|
||||
:field="form.podcasts_storage_location"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Podcasts Storage Location') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="storageLocationOptions.podcasts_storage_location"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="storageLocationOptions.podcasts_storage_location"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<template>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_backend_type"
|
||||
:field="form.backend_type">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_type"
|
||||
class="col-md-12"
|
||||
:field="form.backend_type"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('AutoDJ Service') }}
|
||||
</template>
|
||||
|
@ -12,9 +15,12 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="backendTypeOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="backendTypeOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
@ -23,8 +29,11 @@
|
|||
<b-form-fieldset v-if="isBackendEnabled">
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-7" id="edit_form_backend_crossfade_type"
|
||||
:field="form.backend_config.crossfade_type">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_crossfade_type"
|
||||
class="col-md-7"
|
||||
:field="form.backend_config.crossfade_type"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Crossfade Method') }}
|
||||
</template>
|
||||
|
@ -34,15 +43,22 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="crossfadeOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="crossfadeOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-5" id="edit_form_backend_crossfade"
|
||||
:field="form.backend_config.crossfade" input-type="number"
|
||||
:input-attrs="{ min: '0.0', max: '30.0', step: '0.1' }">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_crossfade"
|
||||
class="col-md-5"
|
||||
:field="form.backend_config.crossfade"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0.0', max: '30.0', step: '0.1' }"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Crossfade Duration (Seconds)') }}
|
||||
</template>
|
||||
|
@ -52,8 +68,11 @@
|
|||
</b-wrapped-form-group>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_backend_config_audio_processing_method"
|
||||
:field="form.backend_config.audio_processing_method">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_config_audio_processing_method"
|
||||
class="col-md-12"
|
||||
:field="form.backend_config.audio_processing_method"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Audio Processing Method') }}
|
||||
</template>
|
||||
|
@ -63,9 +82,12 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="audioProcessingOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="audioProcessingOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
@ -79,15 +101,22 @@
|
|||
{{
|
||||
$gettext('Stereo Tool is an industry standard for software audio processing. For more information on how to configure it, please refer to the')
|
||||
}}
|
||||
<a href="https://www.thimeo.com/stereo-tool/" target="_blank">
|
||||
<a
|
||||
href="https://www.thimeo.com/stereo-tool/"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Stereo Tool documentation.') }}
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-7" id="edit_form_backend_stereo_tool_license_key"
|
||||
:field="form.backend_config.stereo_tool_license_key" input-type="text">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_stereo_tool_license_key"
|
||||
class="col-md-7"
|
||||
:field="form.backend_config.stereo_tool_license_key"
|
||||
input-type="text"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Stereo Tool License Key') }}
|
||||
</template>
|
||||
|
@ -98,7 +127,10 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-form-markup class="col-md-5" id="edit_form_backend_stereo_tool_config">
|
||||
<b-form-markup
|
||||
id="edit_form_backend_stereo_tool_config"
|
||||
class="col-md-5"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Upload Stereo Tool Configuration') }}
|
||||
</template>
|
||||
|
@ -119,9 +151,12 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-6"
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_backend_use_manual_autodj"
|
||||
:field="form.backend_config.use_manual_autodj" advanced>
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.use_manual_autodj"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Manual AutoDJ Mode') }}
|
||||
</template>
|
||||
|
@ -132,9 +167,12 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-6"
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_backend_enable_replaygain_metadata"
|
||||
:field="form.backend_config.enable_replaygain_metadata" advanced>
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.enable_replaygain_metadata"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Use Replaygain Metadata') }}
|
||||
</template>
|
||||
|
@ -145,9 +183,14 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_telnet_port"
|
||||
:field="form.backend_config.telnet_port" input-type="number"
|
||||
:input-attrs="{ min: '0' }" advanced>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_telnet_port"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.telnet_port"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0' }"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Customize Internal Request Processing Port') }}
|
||||
</template>
|
||||
|
@ -158,9 +201,14 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_autodj_queue_length"
|
||||
:field="form.backend_config.autodj_queue_length" input-type="number"
|
||||
:input-attrs="{ min: '2', max: '25' }" advanced>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_autodj_queue_length"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.autodj_queue_length"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '2', max: '25' }"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('AutoDJ Queue Length') }}
|
||||
</template>
|
||||
|
@ -171,8 +219,12 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_charset"
|
||||
:field="form.backend_config.charset" advanced>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_charset"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.charset"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Character Set Encoding') }}
|
||||
</template>
|
||||
|
@ -182,14 +234,21 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="charsetOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="charsetOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_performance_mode"
|
||||
:field="form.backend_config.performance_mode" advanced>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_performance_mode"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.performance_mode"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Liquidsoap Performance Tuning') }}
|
||||
</template>
|
||||
|
@ -199,15 +258,23 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="performanceModeOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="performanceModeOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_duplicate_prevention_time_range"
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_duplicate_prevention_time_range"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.duplicate_prevention_time_range"
|
||||
input-type="number" :input-attrs="{ min: '0', max: '1440' }" advanced>
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0', max: '1440' }"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Duplicate Prevention Time Range (Minutes)') }}
|
||||
</template>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<template>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_frontend_type"
|
||||
:field="form.frontend_type">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_type"
|
||||
class="col-md-12"
|
||||
:field="form.frontend_type"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Broadcasting Service') }}
|
||||
</template>
|
||||
|
@ -10,9 +13,12 @@
|
|||
{{ $gettext('This software delivers your broadcast to the listening audience.') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="frontendTypeOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="frontendTypeOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
@ -21,15 +27,21 @@
|
|||
<b-form-fieldset v-if="isLocalFrontend">
|
||||
<b-form-fieldset v-if="isShoutcastFrontend">
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_frontend_sc_license_id"
|
||||
:field="form.frontend_config.sc_license_id">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_sc_license_id"
|
||||
class="col-md-6"
|
||||
:field="form.frontend_config.sc_license_id"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Shoutcast License ID') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_frontend_sc_user_id"
|
||||
:field="form.frontend_config.sc_user_id">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_sc_user_id"
|
||||
class="col-md-6"
|
||||
:field="form.frontend_config.sc_user_id"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Shoutcast User ID') }}
|
||||
</template>
|
||||
|
@ -39,8 +51,11 @@
|
|||
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_frontend_source_pw"
|
||||
:field="form.frontend_config.source_pw">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_source_pw"
|
||||
class="col-md-6"
|
||||
:field="form.frontend_config.source_pw"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Customize Source Password') }}
|
||||
</template>
|
||||
|
@ -49,8 +64,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_frontend_admin_pw"
|
||||
:field="form.frontend_config.admin_pw">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_admin_pw"
|
||||
class="col-md-6"
|
||||
:field="form.frontend_config.admin_pw"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Customize Administrator Password') }}
|
||||
</template>
|
||||
|
@ -59,9 +77,15 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group v-if="showAdvanced" class="col-md-6" id="edit_form_frontend_port"
|
||||
:field="form.frontend_config.port" input-type="number"
|
||||
:input-attrs="{min: '0'}" advanced>
|
||||
<b-wrapped-form-group
|
||||
v-if="showAdvanced"
|
||||
id="edit_form_frontend_port"
|
||||
class="col-md-6"
|
||||
:field="form.frontend_config.port"
|
||||
input-type="number"
|
||||
:input-attrs="{min: '0'}"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Customize Broadcasting Port') }}
|
||||
</template>
|
||||
|
@ -72,8 +96,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group v-if="showAdvanced" class="col-md-6" id="edit_form_max_listeners"
|
||||
:field="form.frontend_config.max_listeners" advanced>
|
||||
<b-wrapped-form-group
|
||||
v-if="showAdvanced"
|
||||
id="edit_form_max_listeners"
|
||||
class="col-md-6"
|
||||
:field="form.frontend_config.max_listeners"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Maximum Listeners') }}
|
||||
</template>
|
||||
|
@ -89,9 +118,13 @@
|
|||
<b-form-fieldset v-if="showAdvanced">
|
||||
<div class="form-row">
|
||||
<b-col md="5">
|
||||
<b-wrapped-form-group id="edit_form_frontend_banned_ips"
|
||||
:field="form.frontend_config.banned_ips" input-type="textarea"
|
||||
:input-attrs="{class: 'text-preformatted'}" advanced>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_banned_ips"
|
||||
:field="form.frontend_config.banned_ips"
|
||||
input-type="textarea"
|
||||
:input-attrs="{class: 'text-preformatted'}"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Banned IP Addresses') }}
|
||||
</template>
|
||||
|
@ -100,9 +133,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group id="edit_form_frontend_allowed_ips"
|
||||
:field="form.frontend_config.allowed_ips" input-type="textarea"
|
||||
:input-attrs="{class: 'text-preformatted'}" advanced>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_allowed_ips"
|
||||
:field="form.frontend_config.allowed_ips"
|
||||
input-type="textarea"
|
||||
:input-attrs="{class: 'text-preformatted'}"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Allowed IP Addresses') }}
|
||||
</template>
|
||||
|
@ -111,9 +148,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group id="edit_form_frontend_banned_user_agents"
|
||||
:field="form.frontend_config.banned_user_agents" input-type="textarea"
|
||||
:input-attrs="{class: 'text-preformatted'}" advanced>
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_banned_user_agents"
|
||||
:field="form.frontend_config.banned_user_agents"
|
||||
input-type="textarea"
|
||||
:input-attrs="{class: 'text-preformatted'}"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Banned User Agents') }}
|
||||
</template>
|
||||
|
@ -123,9 +164,12 @@
|
|||
</b-wrapped-form-group>
|
||||
</b-col>
|
||||
|
||||
<b-wrapped-form-group class="col-md-7" id="edit_form_frontend_banned_countries"
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_banned_countries"
|
||||
class="col-md-7"
|
||||
:field="form.frontend_config.banned_countries"
|
||||
advanced>
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Banned Countries') }}
|
||||
</template>
|
||||
|
@ -133,11 +177,19 @@
|
|||
{{ $gettext('Select the countries that are not allowed to connect to the streams.') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="countryOptions" style="min-height: 300px;"
|
||||
multiple></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="countryOptions"
|
||||
style="min-height: 300px;"
|
||||
multiple
|
||||
/>
|
||||
|
||||
<b-button block variant="outline-primary" @click.prevent="clearCountries">
|
||||
<b-button
|
||||
block
|
||||
variant="outline-primary"
|
||||
@click.prevent="clearCountries"
|
||||
>
|
||||
{{ $gettext('Clear List') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
@ -158,10 +210,14 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_frontend_custom_config"
|
||||
:field="form.frontend_config.custom_config" input-type="textarea"
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_frontend_custom_config"
|
||||
class="col-md-12"
|
||||
:field="form.frontend_config.custom_config"
|
||||
input-type="textarea"
|
||||
:input-attrs="{class: 'text-preformatted', spellcheck: 'false', 'max-rows': 25, rows: 5}"
|
||||
advanced>
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Custom Configuration') }}
|
||||
</template>
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_enable_hls"
|
||||
:field="form.enable_hls">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_enable_hls"
|
||||
class="col-md-12"
|
||||
:field="form.enable_hls"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Enable HTTP Live Streaming (HLS)') }}
|
||||
</template>
|
||||
|
@ -23,15 +26,21 @@
|
|||
|
||||
<b-form-fieldset v-if="form.enable_hls.$model">
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_backend_hls_enable_on_public_player"
|
||||
:field="form.backend_config.hls_enable_on_public_player">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_backend_hls_enable_on_public_player"
|
||||
class="col-md-12"
|
||||
:field="form.backend_config.hls_enable_on_public_player"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Show HLS Stream on Public Player') }}
|
||||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_backend_hls_is_default"
|
||||
:field="form.backend_config.hls_is_default">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_backend_hls_is_default"
|
||||
class="col-md-12"
|
||||
:field="form.backend_config.hls_is_default"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Make HLS Stream Default in Public Player') }}
|
||||
</template>
|
||||
|
@ -41,28 +50,40 @@
|
|||
|
||||
<b-form-fieldset v-if="showAdvanced && form.enable_hls.$model">
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-4"
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_hls_segment_length"
|
||||
:field="form.backend_config.hls_segment_length" input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }" advanced>
|
||||
class="col-md-4"
|
||||
:field="form.backend_config.hls_segment_length"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Segment Length (Seconds)') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-4"
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_hls_segments_in_playlist"
|
||||
:field="form.backend_config.hls_segments_in_playlist" input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }" advanced>
|
||||
class="col-md-4"
|
||||
:field="form.backend_config.hls_segments_in_playlist"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Segments in Playlist') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-4"
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_hls_segments_overhead"
|
||||
:field="form.backend_config.hls_segments_overhead" input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }" advanced>
|
||||
class="col-md-4"
|
||||
:field="form.backend_config.hls_segments_overhead"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Segments Overhead') }}
|
||||
</template>
|
||||
|
@ -71,7 +92,7 @@
|
|||
</b-form-fieldset>
|
||||
</b-form-fieldset>
|
||||
</b-form-fieldset>
|
||||
<backend-disabled v-else></backend-disabled>
|
||||
<backend-disabled v-else />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,26 +1,43 @@
|
|||
<template>
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_name" :field="form.name">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_name"
|
||||
class="col-md-12"
|
||||
:field="form.name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Name') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_description" :field="form.description"
|
||||
input-type="textarea">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_description"
|
||||
class="col-md-12"
|
||||
:field="form.description"
|
||||
input-type="textarea"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Description') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_genre" :field="form.genre">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_genre"
|
||||
class="col-md-6"
|
||||
:field="form.genre"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Genre') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_url" :field="form.url" input-type="url">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_url"
|
||||
class="col-md-6"
|
||||
:field="form.url"
|
||||
input-type="url"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Web Site URL') }}
|
||||
</template>
|
||||
|
@ -31,7 +48,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_timezone" :field="form.timezone">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_timezone"
|
||||
class="col-md-12"
|
||||
:field="form.timezone"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Time Zone') }}
|
||||
</template>
|
||||
|
@ -41,13 +62,19 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="timezoneOptions"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="timezoneOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_default_album_art_url"
|
||||
:field="form.default_album_art_url">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_default_album_art_url"
|
||||
class="col-md-6"
|
||||
:field="form.default_album_art_url"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Default Album Art URL') }}
|
||||
</template>
|
||||
|
@ -58,8 +85,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group v-if="showAdvanced" class="col-md-6" id="edit_form_short_name"
|
||||
:field="form.short_name" advanced>
|
||||
<b-wrapped-form-group
|
||||
v-if="showAdvanced"
|
||||
id="edit_form_short_name"
|
||||
class="col-md-6"
|
||||
:field="form.short_name"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('URL Stub') }}
|
||||
</template>
|
||||
|
@ -70,8 +102,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group v-if="showAdvanced" class="col-md-6" id="edit_form_api_history_items"
|
||||
:field="form.api_history_items" advanced>
|
||||
<b-wrapped-form-group
|
||||
v-if="showAdvanced"
|
||||
id="edit_form_api_history_items"
|
||||
class="col-md-6"
|
||||
:field="form.api_history_items"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Number of Visible Recent Songs') }}
|
||||
</template>
|
||||
|
@ -81,8 +118,11 @@
|
|||
}}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-select :id="props.id" v-model="props.field.$model"
|
||||
:options="historyItemsOptions"></b-form-select>
|
||||
<b-form-select
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="historyItemsOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
@ -94,8 +134,11 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_enable_public_page"
|
||||
:field="form.enable_public_page">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_enable_public_page"
|
||||
class="col-md-12"
|
||||
:field="form.enable_public_page"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Enable Public Pages') }}
|
||||
</template>
|
||||
|
@ -112,8 +155,11 @@
|
|||
</template>
|
||||
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_enable_on_demand"
|
||||
:field="form.enable_on_demand">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_enable_on_demand"
|
||||
class="col-md-12"
|
||||
:field="form.enable_on_demand"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Enable On-Demand Streaming') }}
|
||||
</template>
|
||||
|
@ -124,9 +170,12 @@
|
|||
</template>
|
||||
</b-wrapped-form-checkbox>
|
||||
|
||||
<b-wrapped-form-checkbox v-if="form.enable_on_demand.$model" class="col-md-12"
|
||||
<b-wrapped-form-checkbox
|
||||
v-if="form.enable_on_demand.$model"
|
||||
id="edit_form_enable_on_demand_download"
|
||||
:field="form.enable_on_demand_download">
|
||||
class="col-md-12"
|
||||
:field="form.enable_on_demand_download"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Enable Downloads on On-Demand Page') }}
|
||||
</template>
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_enable_requests"
|
||||
:field="form.enable_requests">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_enable_requests"
|
||||
class="col-md-12"
|
||||
:field="form.enable_requests"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Allow Song Requests') }}
|
||||
</template>
|
||||
|
@ -28,9 +31,13 @@
|
|||
|
||||
<b-form-fieldset v-if="form.enable_requests.$model">
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_request_delay"
|
||||
:field="form.request_delay" input-type="number"
|
||||
:input-attrs="{ min: '0', max: '1440' }">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_request_delay"
|
||||
class="col-md-6"
|
||||
:field="form.request_delay"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0', max: '1440' }"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Request Minimum Delay (Minutes)') }}
|
||||
</template>
|
||||
|
@ -41,9 +48,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_request_threshold"
|
||||
:field="form.request_threshold" input-type="number"
|
||||
:input-attrs="{ min: '0', max: '1440' }">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_request_threshold"
|
||||
class="col-md-6"
|
||||
:field="form.request_threshold"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0', max: '1440' }"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Request Last Played Threshold (Minutes)') }}
|
||||
</template>
|
||||
|
@ -57,7 +68,7 @@
|
|||
</b-form-fieldset>
|
||||
</b-form-fieldset>
|
||||
</b-form-fieldset>
|
||||
<backend-disabled v-else></backend-disabled>
|
||||
<backend-disabled v-else />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_enable_streamers"
|
||||
:field="form.enable_streamers">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_enable_streamers"
|
||||
class="col-md-12"
|
||||
:field="form.enable_streamers"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Allow Streamers / DJs') }}
|
||||
</template>
|
||||
|
@ -24,8 +27,11 @@
|
|||
<b-form-fieldset v-if="form.enable_streamers.$model">
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-checkbox class="col-md-12" id="edit_form_backend_record_streams"
|
||||
:field="form.backend_config.record_streams">
|
||||
<b-wrapped-form-checkbox
|
||||
id="edit_form_backend_record_streams"
|
||||
class="col-md-12"
|
||||
:field="form.backend_config.record_streams"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Record Live Broadcasts') }}
|
||||
</template>
|
||||
|
@ -40,29 +46,41 @@
|
|||
|
||||
<b-form-fieldset v-if="form.backend_config.record_streams.$model">
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_record_streams_format"
|
||||
:field="form.backend_config.record_streams_format">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_record_streams_format"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.record_streams_format"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Live Broadcast Recording Format') }}
|
||||
</template>
|
||||
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="recordStreamsOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="recordStreamsOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_record_streams_bitrate"
|
||||
:field="form.backend_config.record_streams_bitrate">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_record_streams_bitrate"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.record_streams_bitrate"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Live Broadcast Recording Bitrate (kbps)') }}
|
||||
</template>
|
||||
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" :options="recordBitrateOptions"
|
||||
v-model="props.field.$model">
|
||||
</b-form-radio-group>
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
:options="recordBitrateOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
@ -70,9 +88,13 @@
|
|||
|
||||
<b-form-fieldset>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_disconnect_deactivate_streamer"
|
||||
:field="form.disconnect_deactivate_streamer" input-type="number"
|
||||
:input-attrs="{ min: '0' }">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_disconnect_deactivate_streamer"
|
||||
class="col-md-6"
|
||||
:field="form.disconnect_deactivate_streamer"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0' }"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Deactivate Streamer on Disconnect (Seconds)') }}
|
||||
</template>
|
||||
|
@ -83,10 +105,15 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group v-if="showAdvanced" class="col-md-6"
|
||||
<b-wrapped-form-group
|
||||
v-if="showAdvanced"
|
||||
id="edit_form_backend_dj_port"
|
||||
:field="form.backend_config.dj_port" input-type="number"
|
||||
:input-attrs="{ min: '0' }" advanced>
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.dj_port"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0' }"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Customize DJ/Streamer Port') }}
|
||||
</template>
|
||||
|
@ -101,9 +128,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_backend_dj_buffer"
|
||||
:field="form.backend_config.dj_buffer" input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_backend_dj_buffer"
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.dj_buffer"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0', max: '60' }"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('DJ/Streamer Buffer Time (Seconds)') }}
|
||||
</template>
|
||||
|
@ -114,9 +145,13 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group v-if="showAdvanced" class="col-md-6"
|
||||
<b-wrapped-form-group
|
||||
v-if="showAdvanced"
|
||||
id="edit_form_backend_dj_mount_point"
|
||||
:field="form.backend_config.dj_mount_point" advanced>
|
||||
class="col-md-6"
|
||||
:field="form.backend_config.dj_mount_point"
|
||||
advanced
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Customize DJ/Streamer Mount Point') }}
|
||||
</template>
|
||||
|
@ -131,7 +166,7 @@
|
|||
</b-form-fieldset>
|
||||
</b-form-fieldset>
|
||||
</b-form-fieldset>
|
||||
<backend-disabled v-else></backend-disabled>
|
||||
<backend-disabled v-else />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,16 +1,37 @@
|
|||
<template>
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-alert variant="danger" :show="error != null">{{ error }}</b-alert>
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<b-alert
|
||||
variant="danger"
|
||||
:show="error != null"
|
||||
>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
|
||||
<b-form class="form vue-form" @submit.prevent="submit">
|
||||
<b-tabs :card="!isModal" pills :content-class="tabContentClass">
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.profileTab)" active>
|
||||
<b-form
|
||||
class="form vue-form"
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
<b-tabs
|
||||
:card="!isModal"
|
||||
pills
|
||||
:content-class="tabContentClass"
|
||||
>
|
||||
<b-tab
|
||||
:title-link-class="getTabClass(v$.$validationGroups.profileTab)"
|
||||
active
|
||||
>
|
||||
<template #title>
|
||||
{{ $gettext('Profile') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-profile-form :form="v$" :timezones="timezones"
|
||||
:show-advanced="showAdvanced"></admin-stations-profile-form>
|
||||
<admin-stations-profile-form
|
||||
:form="v$"
|
||||
:timezones="timezones"
|
||||
:show-advanced="showAdvanced"
|
||||
/>
|
||||
</b-tab>
|
||||
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.frontendTab)">
|
||||
|
@ -18,10 +39,12 @@
|
|||
{{ $gettext('Broadcasting') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-frontend-form :form="v$"
|
||||
<admin-stations-frontend-form
|
||||
:form="v$"
|
||||
:is-shoutcast-installed="isShoutcastInstalled"
|
||||
:countries="countries"
|
||||
:show-advanced="showAdvanced"></admin-stations-frontend-form>
|
||||
:show-advanced="showAdvanced"
|
||||
/>
|
||||
</b-tab>
|
||||
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.backendTab)">
|
||||
|
@ -29,9 +52,12 @@
|
|||
{{ $gettext('AutoDJ') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-backend-form :form="v$" :station="station"
|
||||
<admin-stations-backend-form
|
||||
:form="v$"
|
||||
:station="station"
|
||||
:is-stereo-tool-installed="isStereoToolInstalled"
|
||||
:show-advanced="showAdvanced"></admin-stations-backend-form>
|
||||
:show-advanced="showAdvanced"
|
||||
/>
|
||||
</b-tab>
|
||||
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.hlsTab)">
|
||||
|
@ -39,8 +65,11 @@
|
|||
{{ $gettext('HLS') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-hls-form :form="v$" :station="station" :show-advanced="showAdvanced">
|
||||
</admin-stations-hls-form>
|
||||
<admin-stations-hls-form
|
||||
:form="v$"
|
||||
:station="station"
|
||||
:show-advanced="showAdvanced"
|
||||
/>
|
||||
</b-tab>
|
||||
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.requestsTab)">
|
||||
|
@ -48,8 +77,11 @@
|
|||
{{ $gettext('Song Requests') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-requests-form :form="v$" :station="station" :show-advanced="showAdvanced">
|
||||
</admin-stations-requests-form>
|
||||
<admin-stations-requests-form
|
||||
:form="v$"
|
||||
:station="station"
|
||||
:show-advanced="showAdvanced"
|
||||
/>
|
||||
</b-tab>
|
||||
|
||||
<b-tab :title-link-class="getTabClass(v$.$validationGroups.streamersTab)">
|
||||
|
@ -57,26 +89,37 @@
|
|||
{{ $gettext('Streamers/DJs') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-streamers-form :form="v$" :station="station" :show-advanced="showAdvanced">
|
||||
</admin-stations-streamers-form>
|
||||
<admin-stations-streamers-form
|
||||
:form="v$"
|
||||
:station="station"
|
||||
:show-advanced="showAdvanced"
|
||||
/>
|
||||
</b-tab>
|
||||
|
||||
<b-tab v-if="showAdminTab" :title-link-class="getTabClass(v$.$validationGroups.adminTab)">
|
||||
<b-tab
|
||||
v-if="showAdminTab"
|
||||
:title-link-class="getTabClass(v$.$validationGroups.adminTab)"
|
||||
>
|
||||
<template #title>
|
||||
{{ $gettext('Administration') }}
|
||||
</template>
|
||||
|
||||
<admin-stations-admin-form :form="v$"
|
||||
<admin-stations-admin-form
|
||||
:form="v$"
|
||||
:is-edit-mode="isEditMode"
|
||||
:storage-location-api-url="storageLocationApiUrl"
|
||||
:show-advanced="showAdvanced">
|
||||
</admin-stations-admin-form>
|
||||
:show-advanced="showAdvanced"
|
||||
/>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
|
||||
<slot name="submitButton">
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button size="lg" type="submit" :variant="(!isValid) ? 'danger' : 'primary'">
|
||||
<b-button
|
||||
size="lg"
|
||||
type="submit"
|
||||
:variant="(!isValid) ? 'danger' : 'primary'"
|
||||
>
|
||||
<slot name="submitButtonText">
|
||||
{{ $gettext('Save Changes') }}
|
||||
</slot>
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<div class="form-row">
|
||||
<div class="col-md-7">
|
||||
<fieldset>
|
||||
|
@ -37,8 +40,10 @@
|
|||
$gettext('Download the appropriate binary from the Stereo Tool downloads page:')
|
||||
}}
|
||||
<br>
|
||||
<a href="https://www.thimeo.com/stereo-tool/download/"
|
||||
target="_blank">
|
||||
<a
|
||||
href="https://www.thimeo.com/stereo-tool/download/"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Stereo Tool Downloads') }}
|
||||
</a>
|
||||
</li>
|
||||
|
@ -61,15 +66,25 @@
|
|||
{{ $gettext('Current Installed Version') }}
|
||||
</legend>
|
||||
|
||||
<p v-if="version" class="text-success card-text">
|
||||
<p
|
||||
v-if="version"
|
||||
class="text-success card-text"
|
||||
>
|
||||
{{ langInstalledVersion }}
|
||||
</p>
|
||||
<p v-else class="text-danger card-text">
|
||||
<p
|
||||
v-else
|
||||
class="text-danger card-text"
|
||||
>
|
||||
{{ $gettext('Stereo Tool is not currently installed on this installation.') }}
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<flow-upload :target-url="apiUrl" @complete="relist" @error="onError"></flow-upload>
|
||||
<flow-upload
|
||||
:target-url="apiUrl"
|
||||
@complete="relist"
|
||||
@error="onError"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</b-overlay>
|
||||
|
|
|
@ -1,42 +1,78 @@
|
|||
<template>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('Storage Locations') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Storage Locations') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
<b-tabs pills card lazy>
|
||||
<b-tab v-for="tab in tabs" :key="tab.type" :active="activeType === tab.type" @click="setType(tab.type)"
|
||||
:title="tab.title" no-body></b-tab>
|
||||
<b-tabs
|
||||
pills
|
||||
card
|
||||
lazy
|
||||
>
|
||||
<b-tab
|
||||
v-for="tab in tabs"
|
||||
:key="tab.type"
|
||||
:active="activeType === tab.type"
|
||||
:title="tab.title"
|
||||
no-body
|
||||
@click="setType(tab.type)"
|
||||
/>
|
||||
</b-tabs>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button variant="outline-primary" @click.prevent="doCreate">
|
||||
<icon icon="add"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doCreate"
|
||||
>
|
||||
<icon icon="add" />
|
||||
{{ $gettext('Add Storage Location') }}
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
|
||||
<data-table ref="datatable" id="admin_storage_locations" :show-toolbar="false" :fields="fields"
|
||||
<data-table
|
||||
id="admin_storage_locations"
|
||||
ref="datatable"
|
||||
:show-toolbar="false"
|
||||
:fields="fields"
|
||||
:responsive="false"
|
||||
:api-url="listUrlForType">
|
||||
:api-url="listUrlForType"
|
||||
>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="primary" @click.prevent="doEdit(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
@click.prevent="doEdit(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Edit') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
</template>
|
||||
<template #cell(adapter)="row">
|
||||
<h5 class="m-0">{{ getAdapterName(row.item.adapter) }}</h5>
|
||||
<p class="card-text">{{ row.item.uri }}</p>
|
||||
<h5 class="m-0">
|
||||
{{ getAdapterName(row.item.adapter) }}
|
||||
</h5>
|
||||
<p class="card-text">
|
||||
{{ row.item.uri }}
|
||||
</p>
|
||||
</template>
|
||||
<template #cell(space)="row">
|
||||
<template v-if="row.item.storageAvailable">
|
||||
<b-progress :value="row.item.storageUsedPercent" show-progress height="15px" class="mb-1"
|
||||
:variant="getProgressVariant(row.item.storageUsedPercent)">
|
||||
</b-progress>
|
||||
<b-progress
|
||||
:value="row.item.storageUsedPercent"
|
||||
show-progress
|
||||
height="15px"
|
||||
class="mb-1"
|
||||
:variant="getProgressVariant(row.item.storageUsedPercent)"
|
||||
/>
|
||||
|
||||
{{ getSpaceUsed(row.item) }}
|
||||
</template>
|
||||
|
@ -50,7 +86,12 @@
|
|||
</data-table>
|
||||
</b-card>
|
||||
|
||||
<edit-modal ref="editModal" :create-url="listUrl" :type="activeType" @relist="relist"></edit-modal>
|
||||
<edit-modal
|
||||
ref="editModal"
|
||||
:create-url="listUrl"
|
||||
:type="activeType"
|
||||
@relist="relist"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<template>
|
||||
<modal-form ref="modal" :loading="loading" :title="langTitle" :error="error" :disable-save-button="v$.form.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents">
|
||||
|
||||
<storage-location-form :form="v$.form"></storage-location-form>
|
||||
|
||||
<modal-form
|
||||
ref="modal"
|
||||
:loading="loading"
|
||||
:title="langTitle"
|
||||
:error="error"
|
||||
:disable-save-button="v$.form.$invalid"
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<storage-location-form :form="v$.form" />
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
<template>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_adapter" :field="form.adapter">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_adapter"
|
||||
class="col-md-12"
|
||||
:field="form.adapter"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Storage Adapter') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-radio-group stacked :id="props.id" v-model="props.field.$model">
|
||||
<b-form-radio-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
stacked
|
||||
>
|
||||
<b-form-radio value="local">
|
||||
{{ $gettext('Local Filesystem') }}
|
||||
</b-form-radio>
|
||||
|
@ -23,7 +31,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_path" :field="form.path">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_path"
|
||||
class="col-md-12"
|
||||
:field="form.path"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Path/Suffix') }}
|
||||
</template>
|
||||
|
@ -34,7 +46,11 @@
|
|||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_storageQuota" :field="form.storageQuota">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_storageQuota"
|
||||
class="col-md-12"
|
||||
:field="form.storageQuota"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Storage Quota') }}
|
||||
</template>
|
||||
|
@ -47,7 +63,11 @@
|
|||
</div>
|
||||
</b-form-group>
|
||||
|
||||
<b-card v-show="form.adapter.$model === 's3'" class="mb-3" no-body>
|
||||
<b-card
|
||||
v-show="form.adapter.$model === 's3'"
|
||||
class="mb-3"
|
||||
no-body
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Remote: S3 Compatible') }}
|
||||
|
@ -56,39 +76,61 @@
|
|||
<b-card-body>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_s3CredentialKey"
|
||||
:field="form.s3CredentialKey">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_s3CredentialKey"
|
||||
class="col-md-6"
|
||||
:field="form.s3CredentialKey"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Access Key ID') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_s3CredentialSecret"
|
||||
:field="form.s3CredentialSecret">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_s3CredentialSecret"
|
||||
class="col-md-6"
|
||||
:field="form.s3CredentialSecret"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Secret Key') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_s3Endpoint" :field="form.s3Endpoint">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_s3Endpoint"
|
||||
class="col-md-6"
|
||||
:field="form.s3Endpoint"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Endpoint') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_s3Bucket" :field="form.s3Bucket">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_s3Bucket"
|
||||
class="col-md-6"
|
||||
:field="form.s3Bucket"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Bucket Name') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_s3Region" :field="form.s3Region">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_s3Region"
|
||||
class="col-md-6"
|
||||
:field="form.s3Region"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Region') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="form_edit_s3Version" :field="form.s3Version">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_s3Version"
|
||||
class="col-md-6"
|
||||
:field="form.s3Version"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('API Version') }}
|
||||
</template>
|
||||
|
@ -98,7 +140,11 @@
|
|||
</b-card-body>
|
||||
</b-card>
|
||||
|
||||
<b-card v-show="form.adapter.$model === 'dropbox'" class="mb-3" no-body>
|
||||
<b-card
|
||||
v-show="form.adapter.$model === 'dropbox'"
|
||||
class="mb-3"
|
||||
no-body
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Remote: Dropbox') }}
|
||||
|
@ -107,8 +153,11 @@
|
|||
<b-card-body>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_dropboxAuthToken"
|
||||
:field="form.dropboxAuthToken">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_dropboxAuthToken"
|
||||
class="col-md-12"
|
||||
:field="form.dropboxAuthToken"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Dropbox Generated Access Token') }}
|
||||
</template>
|
||||
|
@ -123,7 +172,11 @@
|
|||
</b-card-body>
|
||||
</b-card>
|
||||
|
||||
<b-card v-show="form.adapter.$model === 'sftp'" class="mb-3" no-body>
|
||||
<b-card
|
||||
v-show="form.adapter.$model === 'sftp'"
|
||||
class="mb-3"
|
||||
no-body
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Remote: SFTP') }}
|
||||
|
@ -132,44 +185,65 @@
|
|||
<b-card-body>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpHost"
|
||||
:field="form.sftpHost">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_sftpHost"
|
||||
class="col-md-12 col-lg-6"
|
||||
:field="form.sftpHost"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SFTP Host') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpPort" input-type="number" min="1"
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_sftpPort"
|
||||
class="col-md-12 col-lg-6"
|
||||
input-type="number"
|
||||
min="1"
|
||||
step="1"
|
||||
:field="form.sftpPort">
|
||||
:field="form.sftpPort"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SFTP Port') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpUsername"
|
||||
:field="form.sftpUsername">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_sftpUsername"
|
||||
class="col-md-12 col-lg-6"
|
||||
:field="form.sftpUsername"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SFTP Username') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12 col-lg-6" id="form_edit_sftpPassword"
|
||||
:field="form.sftpPassword">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_sftpPassword"
|
||||
class="col-md-12 col-lg-6"
|
||||
:field="form.sftpPassword"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SFTP Password') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_sftpPrivateKeyPassPhrase"
|
||||
:field="form.sftpPrivateKeyPassPhrase">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_sftpPrivateKeyPassPhrase"
|
||||
class="col-md-12"
|
||||
:field="form.sftpPrivateKeyPassPhrase"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SFTP Private Key Pass Phrase') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="form_edit_sftpPrivateKey" input-type="textarea"
|
||||
:field="form.sftpPrivateKey">
|
||||
<b-wrapped-form-group
|
||||
id="form_edit_sftpPrivateKey"
|
||||
class="col-md-12"
|
||||
input-type="textarea"
|
||||
:field="form.sftpPrivateKey"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('SFTP Private Key') }}
|
||||
</template>
|
||||
|
|
|
@ -1,38 +1,76 @@
|
|||
<template>
|
||||
<b-card no-body>
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">{{ $gettext('Users') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Users') }}
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<b-card-body body-class="card-padding-sm">
|
||||
<b-button variant="outline-primary" @click.prevent="doCreate">
|
||||
<icon icon="add"></icon>
|
||||
<b-button
|
||||
variant="outline-primary"
|
||||
@click.prevent="doCreate"
|
||||
>
|
||||
<icon icon="add" />
|
||||
{{ $gettext('Add User') }}
|
||||
</b-button>
|
||||
</b-card-body>
|
||||
|
||||
<data-table ref="datatable" id="users" paginated :fields="fields" :api-url="listUrl">
|
||||
<data-table
|
||||
id="users"
|
||||
ref="datatable"
|
||||
paginated
|
||||
:fields="fields"
|
||||
:api-url="listUrl"
|
||||
>
|
||||
<template #cell(name)="row">
|
||||
<h5 class="mb-0" v-if="row.item.name !== ''">{{ row.item.name }}</h5>
|
||||
<h5
|
||||
v-if="row.item.name !== ''"
|
||||
class="mb-0"
|
||||
>
|
||||
{{ row.item.name }}
|
||||
</h5>
|
||||
<a :href="'mailto:'+row.item.email">{{ row.item.email }}</a>
|
||||
<span v-if="row.item.is_me" class="badge badge-primary">
|
||||
<span
|
||||
v-if="row.item.is_me"
|
||||
class="badge badge-primary"
|
||||
>
|
||||
{{ $gettext('You') }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(roles)="row">
|
||||
<div v-for="role in row.item.roles" :key="role.id">
|
||||
<div
|
||||
v-for="role in row.item.roles"
|
||||
:key="role.id"
|
||||
>
|
||||
{{ role.name }}
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm" v-if="!row.item.is_me">
|
||||
<b-button size="sm" variant="secondary" :href="row.item.links.masquerade" target="_blank">
|
||||
<b-button-group
|
||||
v-if="!row.item.is_me"
|
||||
size="sm"
|
||||
>
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
:href="row.item.links.masquerade"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Log In') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="primary" @click.prevent="doEdit(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
@click.prevent="doEdit(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Edit') }}
|
||||
</b-button>
|
||||
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
@click.prevent="doDelete(row.item.links.self)"
|
||||
>
|
||||
{{ $gettext('Delete') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -40,7 +78,12 @@
|
|||
</data-table>
|
||||
</b-card>
|
||||
|
||||
<edit-modal ref="editModal" :create-url="listUrl" :roles="roles" @relist="relist"></edit-modal>
|
||||
<edit-modal
|
||||
ref="editModal"
|
||||
:create-url="listUrl"
|
||||
:roles="roles"
|
||||
@relist="relist"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
<template>
|
||||
<modal-form ref="modal" :loading="loading" :title="langTitle" :error="error"
|
||||
<modal-form
|
||||
ref="modal"
|
||||
:loading="loading"
|
||||
:title="langTitle"
|
||||
:error="error"
|
||||
:disable-save-button="v$.form.$invalid"
|
||||
@submit="doSubmit" @hidden="clearContents">
|
||||
|
||||
<admin-users-form :form="v$.form" :roles="roles" :is-edit-mode="isEditMode"></admin-users-form>
|
||||
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<admin-users-form
|
||||
:form="v$.form"
|
||||
:roles="roles"
|
||||
:is-edit-mode="isEditMode"
|
||||
/>
|
||||
</modal-form>
|
||||
</template>
|
||||
|
||||
|
@ -19,13 +27,13 @@ import validatePassword from "~/functions/validatePassword";
|
|||
export default {
|
||||
name: 'AdminUsersEditModal',
|
||||
components: {AdminUsersForm},
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
mixins: [BaseEditModal],
|
||||
props: {
|
||||
roles: Object
|
||||
},
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
computed: {
|
||||
langTitle() {
|
||||
return this.isEditMode
|
||||
|
|
|
@ -1,37 +1,59 @@
|
|||
<template>
|
||||
<b-form-group>
|
||||
<div class="form-row">
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_email" :field="form.email" input-type="email">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_email"
|
||||
class="col-md-6"
|
||||
:field="form.email"
|
||||
input-type="email"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('E-mail Address') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-6" id="edit_form_new_password" :field="form.new_password"
|
||||
input-type="password">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_new_password"
|
||||
class="col-md-6"
|
||||
:field="form.new_password"
|
||||
input-type="password"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Reset Password') }}
|
||||
{{ $gettext('Password') }}
|
||||
</template>
|
||||
<template v-if="isEditMode" #description="{lang}">
|
||||
<template
|
||||
v-if="isEditMode"
|
||||
#description="{lang}"
|
||||
>
|
||||
{{ $gettext('Leave blank to use the current password.') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_name" :field="form.name">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_name"
|
||||
class="col-md-12"
|
||||
:field="form.name"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Display Name') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-wrapped-form-group class="col-md-12" id="edit_form_roles"
|
||||
:field="form.roles">
|
||||
<b-wrapped-form-group
|
||||
id="edit_form_roles"
|
||||
class="col-md-12"
|
||||
:field="form.roles"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Roles') }}
|
||||
</template>
|
||||
<template #default="props">
|
||||
<b-form-checkbox-group :id="props.id" :options="roleOptions" v-model="props.field.$model">
|
||||
</b-form-checkbox-group>
|
||||
<b-form-checkbox-group
|
||||
:id="props.id"
|
||||
v-model="props.field.$model"
|
||||
:options="roleOptions"
|
||||
/>
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
</div>
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
<template>
|
||||
<a v-if="src" :href="src" class="album-art" target="_blank" data-fancybox="gallery">
|
||||
<img class="album_art" :src="src" loading="lazy" alt="">
|
||||
<a
|
||||
v-if="src"
|
||||
:href="src"
|
||||
class="album-art"
|
||||
target="_blank"
|
||||
data-fancybox="gallery"
|
||||
>
|
||||
<img
|
||||
class="album_art"
|
||||
:src="src"
|
||||
loading="lazy"
|
||||
alt=""
|
||||
>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
img.album_art {
|
||||
width: v-bind(widthPx);
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import {computed} from "vue";
|
||||
|
||||
|
@ -27,3 +30,11 @@ const widthPx = computed(() => {
|
|||
return props.width + 'px';
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
img.album_art {
|
||||
width: v-bind(widthPx);
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<template>
|
||||
<audio ref="audio" v-if="isPlaying" v-bind:title="title"/>
|
||||
<audio
|
||||
v-if="isPlaying"
|
||||
ref="audio"
|
||||
:title="title"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
<template>
|
||||
<a :href="serviceUrl" class="avatar" target="_blank" v-b-tooltip.hover.right :title="langAvatar"
|
||||
v-if="'' !== serviceUrl">
|
||||
<img :src="url" :style="{ width: this.width+'px', height: 'auto' }" alt="">
|
||||
<a
|
||||
v-if="'' !== serviceUrl"
|
||||
v-b-tooltip.hover.right
|
||||
:href="serviceUrl"
|
||||
class="avatar"
|
||||
target="_blank"
|
||||
:title="langAvatar"
|
||||
>
|
||||
<img
|
||||
:src="url"
|
||||
:style="{ width: width+'px', height: 'auto' }"
|
||||
alt=""
|
||||
>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<small class="badge badge-pill ml-2" :class="badgeClass">{{ badgeText }}</small>
|
||||
<small
|
||||
class="badge badge-pill ml-2"
|
||||
:class="badgeClass"
|
||||
>{{ badgeText }}</small>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<small class="badge badge-pill ml-2" :class="badgeClass">{{ badgeText }}</small>
|
||||
<small
|
||||
class="badge badge-pill ml-2"
|
||||
:class="badgeClass"
|
||||
>{{ badgeText }}</small>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<b-modal ref="modal"></b-modal>
|
||||
<b-modal ref="modal" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -10,13 +10,13 @@ import mergeExisting from "~/functions/mergeExisting";
|
|||
export default {
|
||||
name: 'BaseEditModal',
|
||||
components: {ModalForm},
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
emits: ['relist'],
|
||||
props: {
|
||||
createUrl: String
|
||||
},
|
||||
emits: ['relist'],
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<canvas ref="$canvas">
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</canvas>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<canvas ref="$canvas">
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</canvas>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<canvas ref="$canvas">
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</canvas>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<template>
|
||||
<code-mirror basic v-model="textValue" :lang="lang" :dark="dark"></code-mirror>
|
||||
<code-mirror
|
||||
v-model="textValue"
|
||||
basic
|
||||
:lang="lang"
|
||||
:dark="dark"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
<template>
|
||||
<button ref="btn" class="btn btn-copy btn-link btn-xs" @click.prevent="doCopy"
|
||||
:aria-label="$gettext('Copy to Clipboard')">
|
||||
<icon class="sm" icon="file_copy"></icon>
|
||||
<button
|
||||
ref="btn"
|
||||
class="btn btn-copy btn-link btn-xs"
|
||||
:aria-label="$gettext('Copy to Clipboard')"
|
||||
@click.prevent="doCopy"
|
||||
>
|
||||
<icon
|
||||
class="sm"
|
||||
icon="file_copy"
|
||||
/>
|
||||
<span v-if="!hideText">{{ $gettext('Copy to Clipboard') }}</span>
|
||||
</button>
|
||||
</template>
|
||||
|
|
|
@ -1,52 +1,113 @@
|
|||
<template>
|
||||
<div :id="id" style="display: contents">
|
||||
<div class="datatable-toolbar-top card-body" v-if="showToolbar">
|
||||
<div
|
||||
:id="id"
|
||||
style="display: contents"
|
||||
>
|
||||
<div
|
||||
v-if="showToolbar"
|
||||
class="datatable-toolbar-top card-body"
|
||||
>
|
||||
<b-row class="align-items-center mb-2">
|
||||
<b-col xl="6" lg="5" md="12" sm="12" v-if="showPagination">
|
||||
<b-pagination v-model="currentPage" :total-rows="totalRows" :per-page="perPage"
|
||||
class="mb-0" v-if="showPagination">
|
||||
</b-pagination>
|
||||
<b-col
|
||||
v-if="showPagination"
|
||||
xl="6"
|
||||
lg="5"
|
||||
md="12"
|
||||
sm="12"
|
||||
>
|
||||
<b-pagination
|
||||
v-if="showPagination"
|
||||
v-model="currentPage"
|
||||
:total-rows="totalRows"
|
||||
:per-page="perPage"
|
||||
class="mb-0"
|
||||
/>
|
||||
</b-col>
|
||||
<b-col xl="6" lg="5" md="12" sm="12" v-else>
|
||||
<b-col
|
||||
v-else
|
||||
xl="6"
|
||||
lg="5"
|
||||
md="12"
|
||||
sm="12"
|
||||
>
|
||||
|
||||
</b-col>
|
||||
<b-col xl="6" lg="7" md="12" sm="12" class="d-flex my-2">
|
||||
<b-col
|
||||
xl="6"
|
||||
lg="7"
|
||||
md="12"
|
||||
sm="12"
|
||||
class="d-flex my-2"
|
||||
>
|
||||
<div class="flex-fill">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend text-muted">
|
||||
<icon icon="search"></icon>
|
||||
<icon icon="search" />
|
||||
</div>
|
||||
<b-form-input debounce="200" v-model="filter" type="search"
|
||||
<b-form-input
|
||||
v-model="filter"
|
||||
debounce="200"
|
||||
type="search"
|
||||
class="search-field form-control"
|
||||
:placeholder="langSearch"></b-form-input>
|
||||
:placeholder="langSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-shrink-1 pl-3 pr-3">
|
||||
<b-btn-group class="actions">
|
||||
<b-button variant="default" title="Refresh" @click="onClickRefresh" v-b-tooltip.hover
|
||||
:title="langRefreshTooltip">
|
||||
<icon icon="refresh"></icon>
|
||||
<b-button
|
||||
v-b-tooltip.hover
|
||||
variant="default"
|
||||
title="Refresh"
|
||||
:title="langRefreshTooltip"
|
||||
@click="onClickRefresh"
|
||||
>
|
||||
<icon icon="refresh" />
|
||||
</b-button>
|
||||
<b-dropdown variant="default" :text="perPageLabel" v-b-tooltip.hover v-if="paginated"
|
||||
:title="langPerPageTooltip">
|
||||
<b-dropdown-item v-for="pageOption in pageOptions" :key="pageOption"
|
||||
:active="(pageOption === perPage)" @click="setPerPage(pageOption)">
|
||||
<b-dropdown
|
||||
v-if="paginated"
|
||||
v-b-tooltip.hover
|
||||
variant="default"
|
||||
:text="perPageLabel"
|
||||
:title="langPerPageTooltip"
|
||||
>
|
||||
<b-dropdown-item
|
||||
v-for="pageOption in pageOptions"
|
||||
:key="pageOption"
|
||||
:active="(pageOption === perPage)"
|
||||
@click="setPerPage(pageOption)"
|
||||
>
|
||||
{{ getPerPageLabel(pageOption) }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
<b-dropdown variant="default" v-if="selectFields" v-b-tooltip.hover
|
||||
:title="langSelectFieldsTooltip">
|
||||
<b-dropdown
|
||||
v-if="selectFields"
|
||||
v-b-tooltip.hover
|
||||
variant="default"
|
||||
:title="langSelectFieldsTooltip"
|
||||
>
|
||||
<template #button-content>
|
||||
<icon icon="filter_list"></icon>
|
||||
<span class="caret"></span>
|
||||
<icon icon="filter_list" />
|
||||
<span class="caret" />
|
||||
</template>
|
||||
<b-dropdown-form class="pt-3">
|
||||
<div v-for="field in selectableFields" class="form-group">
|
||||
<div
|
||||
v-for="field in selectableFields"
|
||||
class="form-group"
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input"
|
||||
v-bind:id="'chk_field_' + field.key" name="is_field_visible"
|
||||
v-model="field.visible" @change="storeSettings">
|
||||
<label class="custom-control-label" v-bind:for="'chk_field_'+field.key">
|
||||
<input
|
||||
:id="'chk_field_' + field.key"
|
||||
v-model="field.visible"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
name="is_field_visible"
|
||||
@change="storeSettings"
|
||||
>
|
||||
<label
|
||||
class="custom-control-label"
|
||||
:for="'chk_field_'+field.key"
|
||||
>
|
||||
{{ field.label }}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -59,43 +120,68 @@
|
|||
</b-row>
|
||||
</div>
|
||||
<div class="datatable-main">
|
||||
<b-table ref="table" show-empty striped hover :selectable="selectable" :api-url="apiUrl" :per-page="perPage"
|
||||
v-model:current-page="currentPage" @row-selected="onRowSelected" :items="itemProvider"
|
||||
<b-table
|
||||
ref="table"
|
||||
v-model:current-page="currentPage"
|
||||
show-empty
|
||||
striped
|
||||
hover
|
||||
:selectable="selectable"
|
||||
:api-url="apiUrl"
|
||||
:per-page="perPage"
|
||||
:items="itemProvider"
|
||||
:fields="visibleFields"
|
||||
:empty-text="langNoRecords" :empty-filtered-text="langNoRecords" :responsive="responsive"
|
||||
:no-provider-paging="handleClientSide" :no-provider-sorting="handleClientSide"
|
||||
: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"
|
||||
v-model:sort-by="sortBy" v-model:sort-desc="sortDesc" @sort-changed="onSortChanged">
|
||||
tbody-tr-class="align-middle"
|
||||
@row-selected="onRowSelected"
|
||||
thead-tr-class="align-middle"
|
||||
selected-variant=""
|
||||
:filter="filter"
|
||||
v-model:sort-by="sortBy"
|
||||
v-model:sort-desc="sortDesc"
|
||||
@filtered="onFiltered"
|
||||
@refreshed="onRefreshed"
|
||||
@sort-changed="onSortChanged"
|
||||
>
|
||||
<template #head(selected)="data">
|
||||
<b-form-checkbox :aria-label="langSelectAll" :checked="allSelected"
|
||||
@change="toggleSelected"></b-form-checkbox>
|
||||
<b-form-checkbox
|
||||
:aria-label="langSelectAll"
|
||||
:checked="allSelected"
|
||||
@change="toggleSelected"
|
||||
/>
|
||||
</template>
|
||||
<template #cell(selected)="{ rowSelected }">
|
||||
<div class="text-muted">
|
||||
<template v-if="rowSelected">
|
||||
<span class="sr-only">{{ langDeselectRow }}</span>
|
||||
<icon icon="check_box"></icon>
|
||||
<icon icon="check_box" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="sr-only">{{ langSelectRow }}</span>
|
||||
<icon icon="check_box_outline_blank"></icon>
|
||||
<icon icon="check_box_outline_blank" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template #table-busy>
|
||||
<div role="alert" aria-live="polite">
|
||||
<div
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div class="text-center my-2">
|
||||
<div class="progress-circular progress-circular-primary mx-auto mb-3">
|
||||
<div class="progress-circular-wrapper">
|
||||
<div class="progress-circular-inner">
|
||||
<div class="progress-circular-left">
|
||||
<div class="progress-circular-spinner"></div>
|
||||
<div class="progress-circular-spinner" />
|
||||
</div>
|
||||
<div class="progress-circular-gap"></div>
|
||||
<div class="progress-circular-gap" />
|
||||
<div class="progress-circular-right">
|
||||
<div class="progress-circular-spinner"></div>
|
||||
<div class="progress-circular-spinner" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,53 +192,29 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<template v-for="(_, slot) of $slots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
<template
|
||||
v-for="(_, slot) of $slots"
|
||||
#[slot]="scope"
|
||||
>
|
||||
<slot
|
||||
:name="slot"
|
||||
v-bind="scope"
|
||||
/>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
<div class="datatable-toolbar-bottom card-body">
|
||||
<b-pagination v-model="currentPage" :total-rows="totalRows" :per-page="perPage"
|
||||
class="mb-0 mt-2" v-if="showPagination">
|
||||
</b-pagination>
|
||||
<b-pagination
|
||||
v-if="showPagination"
|
||||
v-model="currentPage"
|
||||
:total-rows="totalRows"
|
||||
:per-page="perPage"
|
||||
class="mb-0 mt-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
div.datatable-main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
div.datatable-toolbar-top,
|
||||
div.datatable-toolbar-bottom {
|
||||
flex: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table.b-table {
|
||||
td.shrink {
|
||||
width: 0.1%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
table.b-table-selectable {
|
||||
thead tr th:nth-child(1),
|
||||
tbody tr td:nth-child(1),
|
||||
tbody tr th:nth-child(1) {
|
||||
padding-right: 0.75rem;
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
thead tr th:nth-child(2),
|
||||
tbody tr td:nth-child(2),
|
||||
tbody tr th:nth-child(2) {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import store from 'store';
|
||||
import _ from 'lodash';
|
||||
|
@ -237,9 +299,6 @@ export default defineComponent({
|
|||
flushCache: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.loadStoredSettings();
|
||||
},
|
||||
computed: {
|
||||
langRefreshTooltip() {
|
||||
return this.$gettext('Refresh rows');
|
||||
|
@ -325,6 +384,9 @@ export default defineComponent({
|
|||
this.currentPage = 1;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadStoredSettings();
|
||||
},
|
||||
methods: {
|
||||
loadStoredSettings() {
|
||||
if (store.enabled && store.get(this.storeKey) !== undefined) {
|
||||
|
@ -463,3 +525,37 @@ export default defineComponent({
|
|||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
div.datatable-main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
div.datatable-toolbar-top,
|
||||
div.datatable-toolbar-bottom {
|
||||
flex: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table.b-table {
|
||||
td.shrink {
|
||||
width: 0.1%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
table.b-table-selectable {
|
||||
thead tr th:nth-child(1),
|
||||
tbody tr td:nth-child(1),
|
||||
tbody tr th:nth-child(1) {
|
||||
padding-right: 0.75rem;
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
thead tr th:nth-child(2),
|
||||
tbody tr td:nth-child(2),
|
||||
tbody tr th:nth-child(2) {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,25 +1,40 @@
|
|||
<template>
|
||||
<date-range-picker
|
||||
v-bind="$props" ref="picker" controlContainerClass="" opens="left" show-dropdowns
|
||||
:time-picker-increment="1" :ranges="ranges" v-model="dateRange" v-model:date-range="dateRange"
|
||||
@select="onSelect">
|
||||
v-bind="$props"
|
||||
ref="picker"
|
||||
v-model="dateRange"
|
||||
v-model:date-range="dateRange"
|
||||
control-container-class=""
|
||||
opens="left"
|
||||
show-dropdowns
|
||||
:time-picker-increment="1"
|
||||
:ranges="ranges"
|
||||
@select="onSelect"
|
||||
>
|
||||
<template #input="datePicker">
|
||||
<a class="btn btn-bg dropdown-toggle" id="reportrange" href="#" @click.prevent="">
|
||||
<icon icon="date_range"></icon>
|
||||
<a
|
||||
id="reportrange"
|
||||
class="btn btn-bg dropdown-toggle"
|
||||
href="#"
|
||||
@click.prevent=""
|
||||
>
|
||||
<icon icon="date_range" />
|
||||
{{ datePicker.rangeText }}
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<template v-for="(_, slot) of $slots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
<template
|
||||
v-for="(_, slot) of $slots"
|
||||
#[slot]="scope"
|
||||
>
|
||||
<slot
|
||||
:name="slot"
|
||||
v-bind="scope"
|
||||
/>
|
||||
</template>
|
||||
</date-range-picker>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import 'vue3-daterange-picker/src/assets/daterangepicker';
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import DateRangePicker from 'vue3-daterange-picker';
|
||||
import Icon from "./Icon";
|
||||
|
@ -28,7 +43,6 @@ import {DateTime} from 'luxon';
|
|||
export default {
|
||||
name: 'DateRangeDropdown',
|
||||
components: {DateRangePicker, Icon},
|
||||
emits: ['update:modelValue', 'update'],
|
||||
inheritAttrs: false,
|
||||
model: {
|
||||
prop: 'modelValue',
|
||||
|
@ -64,6 +78,7 @@ export default {
|
|||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'update'],
|
||||
computed: {
|
||||
dateRange: {
|
||||
get() {
|
||||
|
@ -127,3 +142,7 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import 'vue3-daterange-picker/src/assets/daterangepicker';
|
||||
</style>
|
||||
|
|
|
@ -1,72 +1,69 @@
|
|||
<template>
|
||||
<div class="flow-upload">
|
||||
<div class="upload-progress">
|
||||
<template v-for="(file, key) in files.value" :key="key">
|
||||
<div v-if="file.isVisible" class="uploading-file pt-1" :id="'file_upload_' + file.uniqueIdentifier"
|
||||
:class="{ 'text-success': file.isCompleted, 'text-danger': file.error }">
|
||||
<h6 class="fileuploadname m-0">{{ file.name }}</h6>
|
||||
<div v-if="!file.isCompleted" class="progress h-15 my-1">
|
||||
<div class="progress-bar h-15" role="progressbar" :style="{width: file.progressPercent+'%'}"
|
||||
:aria-valuenow="file.progressPercent" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<template
|
||||
v-for="(file, key) in files.value"
|
||||
:key="key"
|
||||
>
|
||||
<div
|
||||
v-if="file.isVisible"
|
||||
:id="'file_upload_' + file.uniqueIdentifier"
|
||||
class="uploading-file pt-1"
|
||||
:class="{ 'text-success': file.isCompleted, 'text-danger': file.error }"
|
||||
>
|
||||
<h6 class="fileuploadname m-0">
|
||||
{{ file.name }}
|
||||
</h6>
|
||||
<div
|
||||
v-if="!file.isCompleted"
|
||||
class="progress h-15 my-1"
|
||||
>
|
||||
<div
|
||||
class="progress-bar h-15"
|
||||
role="progressbar"
|
||||
:style="{width: file.progressPercent+'%'}"
|
||||
:aria-valuenow="file.progressPercent"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="upload-status" v-if="file.error">
|
||||
<div
|
||||
v-if="file.error"
|
||||
class="upload-status"
|
||||
>
|
||||
{{ file.error }}
|
||||
</div>
|
||||
<div class="size">{{ file.size }}</div>
|
||||
<div class="size">
|
||||
{{ file.size }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="file-drop-target" ref="$fileDropTarget">
|
||||
<div
|
||||
ref="$fileDropTarget"
|
||||
class="file-drop-target"
|
||||
>
|
||||
{{ $gettext('Drag file(s) here to upload or') }}
|
||||
<button ref="$fileBrowseTarget" class="file-upload btn btn-primary text-center ml-1" type="button">
|
||||
<icon icon="cloud_upload"></icon>
|
||||
<button
|
||||
ref="$fileBrowseTarget"
|
||||
class="file-upload btn btn-primary text-center ml-1"
|
||||
type="button"
|
||||
>
|
||||
<icon icon="cloud_upload" />
|
||||
{{ $gettext('Select File') }}
|
||||
</button>
|
||||
<small class="file-name"></small>
|
||||
<input type="file" :accept="validMimeTypesList" :multiple="allowMultiple"
|
||||
style="visibility: hidden; position: absolute;"/>
|
||||
<small class="file-name" />
|
||||
<input
|
||||
type="file"
|
||||
:accept="validMimeTypesList"
|
||||
:multiple="allowMultiple"
|
||||
style="visibility: hidden; position: absolute;"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
div.flow-upload {
|
||||
div.upload-progress {
|
||||
padding: 4px 0;
|
||||
|
||||
& > div {
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #a00;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.progress-bar {
|
||||
border-bottom-width: 10px;
|
||||
|
||||
&::after {
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.file-drop-target {
|
||||
padding: 25px 0;
|
||||
text-align: center;
|
||||
|
||||
input {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import formatFileSize from '~/functions/formatFileSize.js';
|
||||
import Icon from './Icon.vue';
|
||||
|
@ -216,3 +213,40 @@ onUnmounted(() => {
|
|||
files.reset();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
div.flow-upload {
|
||||
div.upload-progress {
|
||||
padding: 4px 0;
|
||||
|
||||
& > div {
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #a00;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.progress-bar {
|
||||
border-bottom-width: 10px;
|
||||
|
||||
&::after {
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.file-drop-target {
|
||||
padding: 25px 0;
|
||||
text-align: center;
|
||||
|
||||
input {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<i :class="iconClass" aria-hidden="true">{{ icon }}</i>
|
||||
<i
|
||||
:class="iconClass"
|
||||
aria-hidden="true"
|
||||
>{{ icon }}</i>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
<template>
|
||||
<div class="card-body alert-info d-flex align-items-center" role="alert">
|
||||
<div
|
||||
class="card-body alert-info d-flex align-items-center"
|
||||
role="alert"
|
||||
>
|
||||
<div class="flex-shrink-0 mr-2">
|
||||
<icon icon="info" />
|
||||
</div>
|
||||
<div class="flex-fill">
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
<template>
|
||||
<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;" tabindex="-1" aria-hidden="true"/>
|
||||
<input
|
||||
type="submit"
|
||||
style="position: absolute; left: -9999px; width: 1px; height: 1px;"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
>
|
||||
</template>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<template>
|
||||
<div class="list-group list-group-flush">
|
||||
<a v-for="log in logs" :key="log.key" class="list-group-item list-group-item-action log-item"
|
||||
href="#" @click.prevent="viewLog(log.links.self)">
|
||||
<a
|
||||
v-for="log in logs"
|
||||
:key="log.key"
|
||||
class="list-group-item list-group-item-action log-item"
|
||||
href="#"
|
||||
@click.prevent="viewLog(log.links.self)"
|
||||
>
|
||||
<span class="log-name">{{ log.name }}</span><br>
|
||||
<small class="text-secondary">{{ log.path }}</small>
|
||||
</a>
|
||||
|
@ -11,10 +16,10 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'LogList',
|
||||
emits: ['view'],
|
||||
props: {
|
||||
url: String,
|
||||
},
|
||||
emits: ['view'],
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
|
|
|
@ -1,13 +1,35 @@
|
|||
<template>
|
||||
<b-modal :size="size" :centered="centered" :id="id" ref="modal" :title="title" :busy="loading" @shown="onShown"
|
||||
@hidden="onHidden" :no-enforce-focus="noEnforceFocus">
|
||||
<b-modal
|
||||
:id="id"
|
||||
ref="modal"
|
||||
:size="size"
|
||||
:centered="centered"
|
||||
:title="title"
|
||||
:busy="loading"
|
||||
:no-enforce-focus="noEnforceFocus"
|
||||
@shown="onShown"
|
||||
@hidden="onHidden"
|
||||
>
|
||||
<template #default="slotProps">
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-alert variant="danger" :show="error != null">{{ error }}</b-alert>
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<b-alert
|
||||
variant="danger"
|
||||
:show="error != null"
|
||||
>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
|
||||
<b-form class="form vue-form" @submit.prevent="doSubmit">
|
||||
<slot name="default" v-bind="slotProps">
|
||||
</slot>
|
||||
<b-form
|
||||
class="form vue-form"
|
||||
@submit.prevent="doSubmit"
|
||||
>
|
||||
<slot
|
||||
name="default"
|
||||
v-bind="slotProps"
|
||||
/>
|
||||
|
||||
<invisible-submit-button />
|
||||
</b-form>
|
||||
|
@ -15,11 +37,22 @@
|
|||
</template>
|
||||
|
||||
<template #modal-footer="slotProps">
|
||||
<slot name="modal-footer" v-bind="slotProps">
|
||||
<b-button variant="default" type="button" @click="close">
|
||||
<slot
|
||||
name="modal-footer"
|
||||
v-bind="slotProps"
|
||||
>
|
||||
<b-button
|
||||
variant="default"
|
||||
type="button"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
<b-button :variant="(disableSaveButton) ? 'danger' : 'primary'" type="submit" @click="doSubmit">
|
||||
<b-button
|
||||
:variant="(disableSaveButton) ? 'danger' : 'primary'"
|
||||
type="submit"
|
||||
@click="doSubmit"
|
||||
>
|
||||
<slot name="save-button-name">
|
||||
{{ $gettext('Save Changes') }}
|
||||
</slot>
|
||||
|
@ -27,8 +60,14 @@
|
|||
</slot>
|
||||
</template>
|
||||
|
||||
<template v-for="(_, slot) of filteredScopedSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
<template
|
||||
v-for="(_, slot) of filteredScopedSlots"
|
||||
#[slot]="scope"
|
||||
>
|
||||
<slot
|
||||
:name="slot"
|
||||
v-bind="scope"
|
||||
/>
|
||||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
@ -40,7 +79,6 @@ import _ from "lodash";
|
|||
|
||||
export default defineComponent({
|
||||
components: {InvisibleSubmitButton},
|
||||
emits: ['submit', 'shown', 'hidden'],
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
|
@ -74,6 +112,7 @@ export default defineComponent({
|
|||
type: String
|
||||
}
|
||||
},
|
||||
emits: ['submit', 'shown', 'hidden'],
|
||||
computed: {
|
||||
filteredScopedSlots() {
|
||||
return _.filter(this.$slots, (slot, name) => {
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
<template>
|
||||
<a href="#" @click.prevent="toggle" :title="langTitle">
|
||||
<icon :class="iconClass" :icon="iconText"></icon>
|
||||
<a
|
||||
href="#"
|
||||
:title="langTitle"
|
||||
@click.prevent="toggle"
|
||||
>
|
||||
<icon
|
||||
:class="iconClass"
|
||||
:icon="iconText"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<full-calendar ref="calendar" :options="calendarOptions"></full-calendar>
|
||||
<full-calendar
|
||||
ref="calendar"
|
||||
:options="calendarOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
<template>
|
||||
<b-modal id="logs_modal" size="lg" ref="$modal" @hidden="clearContents"
|
||||
:title="$gettext('Log Viewer')" no-enforce-focus>
|
||||
<streaming-log-view ref="$logView" :log-url="logUrl"></streaming-log-view>
|
||||
<b-modal
|
||||
id="logs_modal"
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
:title="$gettext('Log Viewer')"
|
||||
no-enforce-focus
|
||||
@hidden="clearContents"
|
||||
>
|
||||
<streaming-log-view
|
||||
ref="$logView"
|
||||
:log-url="logUrl"
|
||||
/>
|
||||
|
||||
<template #modal-footer>
|
||||
<b-button variant="default" type="button" @click="close">
|
||||
<b-button
|
||||
variant="default"
|
||||
type="button"
|
||||
@click="close"
|
||||
>
|
||||
{{ $gettext('Close') }}
|
||||
</b-button>
|
||||
<b-button variant="primary" class="btn_copy" @click.prevent="doCopy" type="button">
|
||||
<b-button
|
||||
variant="primary"
|
||||
class="btn_copy"
|
||||
type="button"
|
||||
@click.prevent="doCopy"
|
||||
>
|
||||
{{ $gettext('Copy to Clipboard') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
<template>
|
||||
<b-overlay variant="card" :show="loading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="loading"
|
||||
>
|
||||
<b-form-group label-for="modal_scroll_to_bottom">
|
||||
<b-form-checkbox id="modal_scroll_to_bottom" v-model="scrollToBottom">
|
||||
<b-form-checkbox
|
||||
id="modal_scroll_to_bottom"
|
||||
v-model="scrollToBottom"
|
||||
>
|
||||
{{ $gettext('Automatically Scroll to Bottom') }}
|
||||
</b-form-checkbox>
|
||||
</b-form-group>
|
||||
|
||||
<textarea class="form-control log-viewer" ref="textarea" id="log-view-contents" spellcheck="false"
|
||||
readonly>{{ logs }}</textarea>
|
||||
<textarea
|
||||
id="log-view-contents"
|
||||
ref="textarea"
|
||||
class="form-control log-viewer"
|
||||
spellcheck="false"
|
||||
readonly
|
||||
>{{ logs }}</textarea>
|
||||
</b-overlay>
|
||||
</template>
|
||||
|
||||
|
@ -56,7 +67,7 @@ export default {
|
|||
this.loading = false;
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
clearTimeout(this.timeoutUpdateLog);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
<template>
|
||||
<b-input v-bind="$attrs" type="time" v-model="timeCode" pattern="[0-9]{2}:[0-9]{2}" placeholder="13:45"></b-input>
|
||||
<b-input
|
||||
v-bind="$attrs"
|
||||
v-model="timeCode"
|
||||
type="time"
|
||||
pattern="[0-9]{2}:[0-9]{2}"
|
||||
placeholder="13:45"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<b-row>
|
||||
<b-form-group class="col-md-12">
|
||||
<div class="waveform__container">
|
||||
<div id="waveform-timeline"></div>
|
||||
<div id="waveform"></div>
|
||||
<div id="waveform-timeline" />
|
||||
<div id="waveform" />
|
||||
</div>
|
||||
</b-form-group>
|
||||
</b-row>
|
||||
|
@ -17,27 +17,48 @@
|
|||
</label>
|
||||
</div>
|
||||
<div class="flex-fill mx-3">
|
||||
<b-form-input id="waveform-zoom" v-model.number="zoom" type="range" min="0" max="256"
|
||||
class="w-100"></b-form-input>
|
||||
<b-form-input
|
||||
id="waveform-zoom"
|
||||
v-model.number="zoom"
|
||||
type="range"
|
||||
min="0"
|
||||
max="256"
|
||||
class="w-100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col md="5">
|
||||
<div class="inline-volume-controls d-flex align-items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<a class="btn btn-sm btn-outline-inverse" href="#" @click.prevent="volume = 0"
|
||||
:title="$gettext('Mute')">
|
||||
<icon icon="volume_mute"></icon>
|
||||
<a
|
||||
class="btn btn-sm btn-outline-inverse"
|
||||
href="#"
|
||||
:title="$gettext('Mute')"
|
||||
@click.prevent="volume = 0"
|
||||
>
|
||||
<icon icon="volume_mute" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex-fill mx-1">
|
||||
<input type="range" :title="$gettext('Volume')" class="player-volume-range custom-range w-100"
|
||||
min="0" max="100" step="1" v-model.number="volume">
|
||||
<input
|
||||
v-model.number="volume"
|
||||
type="range"
|
||||
:title="$gettext('Volume')"
|
||||
class="player-volume-range custom-range w-100"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<a class="btn btn-sm btn-outline-inverse" href="#" @click.prevent="volume = 100"
|
||||
:title="$gettext('Full Volume')">
|
||||
<icon icon="volume_up"></icon>
|
||||
<a
|
||||
class="btn btn-sm btn-outline-inverse"
|
||||
href="#"
|
||||
:title="$gettext('Full Volume')"
|
||||
@click.prevent="volume = 100"
|
||||
>
|
||||
<icon icon="volume_up" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,42 +1,90 @@
|
|||
<template>
|
||||
<div id="dashboard">
|
||||
<section class="card mb-4" role="region">
|
||||
<section
|
||||
class="card mb-4"
|
||||
role="region"
|
||||
>
|
||||
<div class="card-header bg-primary-dark d-flex flex-wrap align-items-center">
|
||||
<avatar class="flex-shrink-0 mr-3" v-if="user.avatar.url" :url="user.avatar.url"
|
||||
:service="user.avatar.service" :service-url="user.avatar.serviceUrl"></avatar>
|
||||
<avatar
|
||||
v-if="user.avatar.url"
|
||||
class="flex-shrink-0 mr-3"
|
||||
:url="user.avatar.url"
|
||||
:service="user.avatar.service"
|
||||
:service-url="user.avatar.serviceUrl"
|
||||
/>
|
||||
|
||||
<div class="flex-fill">
|
||||
<h2 class="card-title mt-0">{{ user.name }}</h2>
|
||||
<h3 class="card-subtitle">{{ user.email }}</h3>
|
||||
<h2 class="card-title mt-0">
|
||||
{{ user.name }}
|
||||
</h2>
|
||||
<h3 class="card-subtitle">
|
||||
{{ user.email }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="flex-md-shrink-0 mt-3 mt-md-0 buttons">
|
||||
<a class="btn btn-bg" role="button" :href="profileUrl">
|
||||
<icon icon="account_circle"></icon>
|
||||
<a
|
||||
class="btn btn-bg"
|
||||
role="button"
|
||||
:href="profileUrl"
|
||||
>
|
||||
<icon icon="account_circle" />
|
||||
{{ $gettext('My Account') }}
|
||||
</a>
|
||||
<a v-if="showAdmin" class="btn btn-bg" role="button" :href="adminUrl">
|
||||
<icon icon="settings"></icon>
|
||||
<a
|
||||
v-if="showAdmin"
|
||||
class="btn btn-bg"
|
||||
role="button"
|
||||
:href="adminUrl"
|
||||
>
|
||||
<icon icon="settings" />
|
||||
{{ $gettext('Administration') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="!notificationsLoading && notifications.length > 0">
|
||||
<div v-for="notification in notifications" class="card-body d-flex align-items-center"
|
||||
:class="'alert-'+notification.type" role="alert">
|
||||
<div class="flex-shrink-0 mr-3" v-if="'info' === notification.type">
|
||||
<icon class="lg" icon="info"></icon>
|
||||
<div
|
||||
v-for="notification in notifications"
|
||||
class="card-body d-flex align-items-center"
|
||||
:class="'alert-'+notification.type"
|
||||
role="alert"
|
||||
>
|
||||
<div
|
||||
v-if="'info' === notification.type"
|
||||
class="flex-shrink-0 mr-3"
|
||||
>
|
||||
<icon
|
||||
class="lg"
|
||||
icon="info"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-shrink-0 mr-3" v-else>
|
||||
<icon class="lg" icon="warning"></icon>
|
||||
<div
|
||||
v-else
|
||||
class="flex-shrink-0 mr-3"
|
||||
>
|
||||
<icon
|
||||
class="lg"
|
||||
icon="warning"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-fill">
|
||||
<h4>{{ notification.title }}</h4>
|
||||
<p class="card-text" v-html="notification.body"></p>
|
||||
<p
|
||||
class="card-text"
|
||||
v-html="notification.body"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="notification.actionLabel && notification.actionUrl" class="flex-shrink-0 ml-3">
|
||||
<b-button :href="notification.actionUrl" target="_blank" size="sm" variant="light">
|
||||
<div
|
||||
v-if="notification.actionLabel && notification.actionUrl"
|
||||
class="flex-shrink-0 ml-3"
|
||||
>
|
||||
<b-button
|
||||
:href="notification.actionUrl"
|
||||
target="_blank"
|
||||
size="sm"
|
||||
variant="light"
|
||||
>
|
||||
{{ notification.actionLabel }}
|
||||
</b-button>
|
||||
</div>
|
||||
|
@ -44,31 +92,60 @@
|
|||
</template>
|
||||
</section>
|
||||
|
||||
<section class="card mb-4" role="region" v-if="showCharts">
|
||||
<section
|
||||
v-if="showCharts"
|
||||
class="card mb-4"
|
||||
role="region"
|
||||
>
|
||||
<div class="card-header bg-primary-dark d-flex align-items-center">
|
||||
<div class="flex-fill">
|
||||
<h3 class="card-title">{{ $gettext('Listeners Per Station') }}</h3>
|
||||
<h3 class="card-title">
|
||||
{{ $gettext('Listeners Per Station') }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<b-button variant="outline-light" size="sm" class="py-2" @click="toggleCharts">{{
|
||||
<b-button
|
||||
variant="outline-light"
|
||||
size="sm"
|
||||
class="py-2"
|
||||
@click="toggleCharts"
|
||||
>
|
||||
{{
|
||||
langShowHideCharts
|
||||
}}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
<b-collapse id="charts" v-model="chartsVisible">
|
||||
<b-overlay variant="card" :show="chartsLoading">
|
||||
<div class="card-body py-5" v-if="chartsLoading">
|
||||
<b-collapse
|
||||
id="charts"
|
||||
v-model="chartsVisible"
|
||||
>
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="chartsLoading"
|
||||
>
|
||||
<div
|
||||
v-if="chartsLoading"
|
||||
class="card-body py-5"
|
||||
>
|
||||
|
||||
</div>
|
||||
<b-tabs pills card lazy v-else>
|
||||
<b-tabs
|
||||
v-else
|
||||
pills
|
||||
card
|
||||
lazy
|
||||
>
|
||||
<b-tab active>
|
||||
<template #title>
|
||||
{{ $gettext('Average Listeners') }}
|
||||
</template>
|
||||
|
||||
<time-series-chart style="width: 100%;" :data="chartsData.average.metrics">
|
||||
<span v-html="chartsData.average.alt"></span>
|
||||
<time-series-chart
|
||||
style="width: 100%;"
|
||||
:data="chartsData.average.metrics"
|
||||
>
|
||||
<span v-html="chartsData.average.alt" />
|
||||
</time-series-chart>
|
||||
</b-tab>
|
||||
<b-tab>
|
||||
|
@ -76,8 +153,11 @@
|
|||
{{ $gettext('Unique Listeners') }}
|
||||
</template>
|
||||
|
||||
<time-series-chart style="width: 100%;" :data="chartsData.unique.metrics">
|
||||
<span v-html="chartsData.unique.alt"></span>
|
||||
<time-series-chart
|
||||
style="width: 100%;"
|
||||
:data="chartsData.unique.metrics"
|
||||
>
|
||||
<span v-html="chartsData.unique.alt" />
|
||||
</time-series-chart>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
|
@ -85,24 +165,47 @@
|
|||
</b-collapse>
|
||||
</section>
|
||||
|
||||
<section class="card" role="region">
|
||||
<section
|
||||
class="card"
|
||||
role="region"
|
||||
>
|
||||
<div class="card-header bg-primary-dark d-flex flex-wrap align-items-center">
|
||||
<div class="flex-fill">
|
||||
<h2 class="card-title">{{ $gettext('Station Overview') }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ $gettext('Station Overview') }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="flex-shrink-0" v-if="showAdmin">
|
||||
<b-button variant="outline-light" size="sm" class="py-2" :href="manageStationsUrl">
|
||||
<icon icon="settings"></icon>
|
||||
<div
|
||||
v-if="showAdmin"
|
||||
class="flex-shrink-0"
|
||||
>
|
||||
<b-button
|
||||
variant="outline-light"
|
||||
size="sm"
|
||||
class="py-2"
|
||||
:href="manageStationsUrl"
|
||||
>
|
||||
<icon icon="settings" />
|
||||
{{ $gettext('Manage Stations') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b-overlay variant="card" :show="stationsLoading">
|
||||
<div class="card-body py-3" v-if="stationsLoading">
|
||||
<b-overlay
|
||||
variant="card"
|
||||
:show="stationsLoading"
|
||||
>
|
||||
<div
|
||||
v-if="stationsLoading"
|
||||
class="card-body py-3"
|
||||
>
|
||||
|
||||
</div>
|
||||
<table class="table table-striped table-responsive mb-0" id="station_dashboard" v-else>
|
||||
<table
|
||||
v-else
|
||||
id="station_dashboard"
|
||||
class="table table-striped table-responsive mb-0"
|
||||
>
|
||||
<colgroup>
|
||||
<col width="5%">
|
||||
<col width="30%">
|
||||
|
@ -112,30 +215,52 @@
|
|||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="pr-3"> </th>
|
||||
<th class="pl-2">{{ $gettext('Station Name') }}</th>
|
||||
<th class="text-center">{{ $gettext('Listeners') }}</th>
|
||||
<th class="pr-3">
|
||||
|
||||
</th>
|
||||
<th class="pl-2">
|
||||
{{ $gettext('Station Name') }}
|
||||
</th>
|
||||
<th class="text-center">
|
||||
{{ $gettext('Listeners') }}
|
||||
</th>
|
||||
<th>{{ $gettext('Now Playing') }}</th>
|
||||
<th class="text-right"></th>
|
||||
<th class="text-right" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="align-middle" v-for="item in stations" :key="item.station.id">
|
||||
<tr
|
||||
v-for="item in stations"
|
||||
:key="item.station.id"
|
||||
class="align-middle"
|
||||
>
|
||||
<td class="text-center pr-3">
|
||||
<play-button class="file-icon" icon-class="lg outlined align-middle"
|
||||
:url="item.station.listen_url" is-stream></play-button>
|
||||
<play-button
|
||||
class="file-icon"
|
||||
icon-class="lg outlined align-middle"
|
||||
:url="item.station.listen_url"
|
||||
is-stream
|
||||
/>
|
||||
</td>
|
||||
<td class="pl-2">
|
||||
<div class="typography-subheading">{{ item.station.name }}</div>
|
||||
<div class="typography-subheading">
|
||||
{{ item.station.name }}
|
||||
</div>
|
||||
<div v-if="item.station.is_public">
|
||||
<a :href="item.links.public" target="_blank">
|
||||
<a
|
||||
:href="item.links.public"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $gettext('Public Page') }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="pr-1">
|
||||
<icon class="sm align-middle" icon="headset"></icon>
|
||||
<icon
|
||||
class="sm align-middle"
|
||||
icon="headset"
|
||||
/>
|
||||
</span>
|
||||
<template v-if="item.links.listeners">
|
||||
<a :href="item.links.listeners">
|
||||
|
@ -148,19 +273,31 @@
|
|||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<album-art v-if="showAlbumArt" :src="item.now_playing.song.art"
|
||||
class="flex-shrink-0 pr-3"></album-art>
|
||||
<album-art
|
||||
v-if="showAlbumArt"
|
||||
:src="item.now_playing.song.art"
|
||||
class="flex-shrink-0 pr-3"
|
||||
/>
|
||||
|
||||
<div v-if="!item.is_online" class="flex-fill text-muted">
|
||||
<div
|
||||
v-if="!item.is_online"
|
||||
class="flex-fill text-muted"
|
||||
>
|
||||
{{ $gettext('Station Offline') }}
|
||||
</div>
|
||||
<div v-else-if="item.now_playing.song.title !== ''" class="flex-fill">
|
||||
<div
|
||||
v-else-if="item.now_playing.song.title !== ''"
|
||||
class="flex-fill"
|
||||
>
|
||||
<strong><span class="nowplaying-title">
|
||||
{{ item.now_playing.song.title }}
|
||||
</span></strong><br>
|
||||
<span class="nowplaying-artist">{{ item.now_playing.song.artist }}</span>
|
||||
</div>
|
||||
<div v-else class="flex-fill">
|
||||
<div
|
||||
v-else
|
||||
class="flex-fill"
|
||||
>
|
||||
<strong><span class="nowplaying-title">
|
||||
{{ item.now_playing.song.text }}
|
||||
</span></strong>
|
||||
|
@ -168,7 +305,10 @@
|
|||
</div>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-primary" v-bind:href="item.links.manage">
|
||||
<a
|
||||
class="btn btn-primary"
|
||||
:href="item.links.manage"
|
||||
>
|
||||
{{ $gettext('Manage') }}
|
||||
</a>
|
||||
</td>
|
||||
|
|
|
@ -1,20 +1,38 @@
|
|||
<template>
|
||||
<b-form-group v-bind="$attrs" :label-for="id">
|
||||
<b-form-group
|
||||
v-bind="$attrs"
|
||||
:label-for="id"
|
||||
>
|
||||
<template #default="slotProps">
|
||||
<div :id="id">
|
||||
<slot name="default" v-bind="slotProps"></slot>
|
||||
<slot
|
||||
name="default"
|
||||
v-bind="slotProps"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #label="slotProps">
|
||||
<slot name="label" v-bind="slotProps"></slot>
|
||||
<slot
|
||||
name="label"
|
||||
v-bind="slotProps"
|
||||
/>
|
||||
</template>
|
||||
<template #description="slotProps">
|
||||
<slot name="description" v-bind="slotProps"></slot>
|
||||
<slot
|
||||
name="description"
|
||||
v-bind="slotProps"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-for="(_, slot) of filteredSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
<template
|
||||
v-for="(_, slot) of filteredSlots"
|
||||
#[slot]="scope"
|
||||
>
|
||||
<slot
|
||||
:name="slot"
|
||||
v-bind="scope"
|
||||
/>
|
||||
</template>
|
||||
</b-form-group>
|
||||
</template>
|
||||
|
|
|
@ -1,30 +1,57 @@
|
|||
<template>
|
||||
<b-form-group v-bind="$attrs" :label-for="id" :state="fieldState">
|
||||
<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 v-bind="inputAttrs" v-model="field.$model" :id="id" :name="name">
|
||||
<slot name="label"></slot>
|
||||
<span v-if="isRequired" class="text-danger">
|
||||
<slot
|
||||
name="default"
|
||||
v-bind="{ id, field, state: fieldState }"
|
||||
>
|
||||
<b-form-checkbox
|
||||
v-bind="inputAttrs"
|
||||
:id="id"
|
||||
v-model="field.$model"
|
||||
:name="name"
|
||||
>
|
||||
<slot name="label" />
|
||||
<span
|
||||
v-if="isRequired"
|
||||
class="text-danger"
|
||||
>
|
||||
<span aria-hidden="true">*</span>
|
||||
<span class="sr-only">Required</span>
|
||||
</span>
|
||||
<span v-if="advanced" class="badge small badge-primary">
|
||||
<span
|
||||
v-if="advanced"
|
||||
class="badge small badge-primary"
|
||||
>
|
||||
{{ $gettext('Advanced') }}
|
||||
</span>
|
||||
</b-form-checkbox>
|
||||
|
||||
<b-form-invalid-feedback :state="fieldState">
|
||||
<vuelidate-error :field="field"></vuelidate-error>
|
||||
<vuelidate-error :field="field" />
|
||||
</b-form-invalid-feedback>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<template #description="slotProps">
|
||||
<slot name="description" v-bind="slotProps"></slot>
|
||||
<slot
|
||||
name="description"
|
||||
v-bind="slotProps"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-for="(_, slot) of filteredSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
<template
|
||||
v-for="(_, slot) of filteredSlots"
|
||||
#[slot]="scope"
|
||||
>
|
||||
<slot
|
||||
:name="slot"
|
||||
v-bind="scope"
|
||||
/>
|
||||
</template>
|
||||
</b-form-group>
|
||||
</template>
|
||||
|
|
|
@ -1,36 +1,82 @@
|
|||
<template>
|
||||
<b-form-group v-bind="$attrs" :label-for="id" :state="fieldState">
|
||||
<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-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-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
|
||||
name="default"
|
||||
v-bind="{ id, field, state: fieldState }"
|
||||
>
|
||||
<b-form-textarea
|
||||
v-if="inputType === 'textarea'"
|
||||
v-bind="inputAttrs"
|
||||
:id="id"
|
||||
ref="$input"
|
||||
v-model="modelValue"
|
||||
:name="name"
|
||||
:required="isRequired"
|
||||
:number="isNumeric"
|
||||
:trim="inputTrim"
|
||||
:autofocus="autofocus"
|
||||
:state="fieldState"
|
||||
/>
|
||||
<b-form-input
|
||||
v-else
|
||||
v-bind="inputAttrs"
|
||||
:id="id"
|
||||
ref="$input"
|
||||
v-model="modelValue"
|
||||
:type="inputType"
|
||||
:name="name"
|
||||
:required="isRequired"
|
||||
:number="isNumeric"
|
||||
:trim="inputTrim"
|
||||
:autofocus="autofocus"
|
||||
:state="fieldState"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
<b-form-invalid-feedback :state="fieldState">
|
||||
<vuelidate-error :field="field"></vuelidate-error>
|
||||
<vuelidate-error :field="field" />
|
||||
</b-form-invalid-feedback>
|
||||
</template>
|
||||
|
||||
<template #label="slotProps">
|
||||
<slot v-bind="slotProps" name="label"></slot>
|
||||
<span v-if="isRequired" class="text-danger">
|
||||
<slot
|
||||
v-bind="slotProps"
|
||||
name="label"
|
||||
/>
|
||||
<span
|
||||
v-if="isRequired"
|
||||
class="text-danger"
|
||||
>
|
||||
<span aria-hidden="true">*</span>
|
||||
<span class="sr-only">Required</span>
|
||||
</span>
|
||||
<span v-if="advanced" class="badge small badge-primary ml-2">
|
||||
<span
|
||||
v-if="advanced"
|
||||
class="badge small badge-primary ml-2"
|
||||
>
|
||||
{{ $gettext('Advanced') }}
|
||||
</span>
|
||||
</template>
|
||||
<template #description="slotProps">
|
||||
<slot v-bind="slotProps" name="description"></slot>
|
||||
<slot
|
||||
v-bind="slotProps"
|
||||
name="description"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-for="(_, slot) of filteredSlots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"></slot>
|
||||
<template
|
||||
v-for="(_, slot) of filteredSlots"
|
||||
#[slot]="scope"
|
||||
>
|
||||
<slot
|
||||
:name="slot"
|
||||
v-bind="scope"
|
||||
/>
|
||||
</template>
|
||||
</b-form-group>
|
||||
</template>
|
||||
|
|
|
@ -1,69 +1,81 @@
|
|||
<template>
|
||||
<audio-player ref="$player" :volume="volume" :is-muted="isMuted"></audio-player>
|
||||
<audio-player
|
||||
ref="$player"
|
||||
:volume="volume"
|
||||
:is-muted="isMuted"
|
||||
/>
|
||||
|
||||
<div class="ml-3 player-inline" v-if="isPlaying">
|
||||
<div class="inline-seek d-inline-flex align-items-center ml-1" v-if="!current.isStream && duration !== 0">
|
||||
<div
|
||||
v-if="isPlaying"
|
||||
class="ml-3 player-inline"
|
||||
>
|
||||
<div
|
||||
v-if="!current.isStream && duration !== 0"
|
||||
class="inline-seek d-inline-flex align-items-center ml-1"
|
||||
>
|
||||
<div class="flex-shrink-0 mx-1 text-white-50 time-display">
|
||||
{{ currentTimeText }}
|
||||
</div>
|
||||
<div class="flex-fill mx-2">
|
||||
<input type="range" :title="$gettext('Seek')" class="player-seek-range custom-range" min="0"
|
||||
<input
|
||||
v-model="progress"
|
||||
type="range"
|
||||
:title="$gettext('Seek')"
|
||||
class="player-seek-range custom-range"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1" v-model="progress">
|
||||
step="1"
|
||||
>
|
||||
</div>
|
||||
<div class="flex-shrink-0 mx-1 text-white-50 time-display">
|
||||
{{ durationText }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="btn btn-sm btn-outline-light px-2 ml-1" href="#" @click.prevent="stop()"
|
||||
:aria-label="$gettext('Stop')">
|
||||
<icon icon="stop"></icon>
|
||||
<a
|
||||
class="btn btn-sm btn-outline-light px-2 ml-1"
|
||||
href="#"
|
||||
:aria-label="$gettext('Stop')"
|
||||
@click.prevent="stop()"
|
||||
>
|
||||
<icon icon="stop" />
|
||||
</a>
|
||||
<div class="inline-volume-controls d-inline-flex align-items-center ml-1">
|
||||
<div class="flex-shrink-0">
|
||||
<a class="btn btn-sm btn-outline-light px-2" href="#" @click.prevent="mute"
|
||||
:aria-label="$gettext('Mute')">
|
||||
<icon icon="volume_mute"></icon>
|
||||
<a
|
||||
class="btn btn-sm btn-outline-light px-2"
|
||||
href="#"
|
||||
:aria-label="$gettext('Mute')"
|
||||
@click.prevent="mute"
|
||||
>
|
||||
<icon icon="volume_mute" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex-fill mx-1">
|
||||
<input type="range" :title="$gettext('Volume')" class="player-volume-range custom-range" min="0"
|
||||
<input
|
||||
v-model="volume"
|
||||
type="range"
|
||||
:title="$gettext('Volume')"
|
||||
class="player-volume-range custom-range"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1" v-model="volume">
|
||||
step="1"
|
||||
>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<a class="btn btn-sm btn-outline-light px-2" href="#" @click.prevent="fullVolume"
|
||||
:aria-label="$gettext('Full Volume')">
|
||||
<icon icon="volume_up"></icon>
|
||||
<a
|
||||
class="btn btn-sm btn-outline-light px-2"
|
||||
href="#"
|
||||
:aria-label="$gettext('Full Volume')"
|
||||
@click.prevent="fullVolume"
|
||||
>
|
||||
<icon icon="volume_up" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.player-inline {
|
||||
.inline-seek {
|
||||
width: 300px;
|
||||
|
||||
div.time-display {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.inline-volume-controls {
|
||||
width: 175px;
|
||||
}
|
||||
|
||||
input.player-volume-range,
|
||||
input.player-seek-range {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import AudioPlayer from '~/components/Common/AudioPlayer.vue';
|
||||
import formatTime from '~/functions/formatTime.js';
|
||||
|
@ -122,3 +134,25 @@ const fullVolume = () => {
|
|||
volume.value = 100;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.player-inline {
|
||||
.inline-seek {
|
||||
width: 300px;
|
||||
|
||||
div.time-display {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.inline-volume-controls {
|
||||
width: 175px;
|
||||
}
|
||||
|
||||
input.player-volume-range,
|
||||
input.player-seek-range {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,33 +2,54 @@
|
|||
<div class="public-page">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">{{ stationName }}</h2>
|
||||
<h2 class="card-title">
|
||||
{{ stationName }}
|
||||
</h2>
|
||||
|
||||
<div class="stations nowplaying">
|
||||
<radio-player v-bind="$props" @np_updated="onNowPlayingUpdate"></radio-player>
|
||||
<radio-player
|
||||
v-bind="$props"
|
||||
@np_updated="onNowPlayingUpdate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<a class="btn btn-sm btn-outline-secondary" v-b-modal.song_history_modal>
|
||||
<icon icon="history"></icon>
|
||||
<a
|
||||
v-b-modal.song_history_modal
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
>
|
||||
<icon icon="history" />
|
||||
{{ $gettext('Song History') }}
|
||||
</a>
|
||||
<a class="btn btn-sm btn-outline-secondary" v-if="enableRequests" v-b-modal.request_modal>
|
||||
<icon icon="help_outline"></icon>
|
||||
<a
|
||||
v-if="enableRequests"
|
||||
v-b-modal.request_modal
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
>
|
||||
<icon icon="help_outline" />
|
||||
{{ $gettext('Request Song') }}
|
||||
</a>
|
||||
<a class="btn btn-sm btn-outline-secondary" :href="downloadPlaylistUri">
|
||||
<icon icon="file_download"></icon>
|
||||
<a
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
:href="downloadPlaylistUri"
|
||||
>
|
||||
<icon icon="file_download" />
|
||||
{{ $gettext('Playlist') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<song-history-modal :show-album-art="showAlbumArt" :history="history"></song-history-modal>
|
||||
<request-modal :show-album-art="showAlbumArt" :request-list-uri="requestListUri"
|
||||
:custom-fields="customFields"></request-modal>
|
||||
<song-history-modal
|
||||
:show-album-art="showAlbumArt"
|
||||
:history="history"
|
||||
/>
|
||||
<request-modal
|
||||
:show-album-art="showAlbumArt"
|
||||
:request-list-uri="requestListUri"
|
||||
:custom-fields="customFields"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
<template>
|
||||
<b-modal size="lg" id="request_modal" ref="$modal" :title="$gettext('Request a Song')" hide-footer>
|
||||
<song-request :show-album-art="showAlbumArt" :request-list-uri="requestListUri" :custom-fields="customFields"
|
||||
@submitted="doClose"></song-request>
|
||||
<b-modal
|
||||
id="request_modal"
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
:title="$gettext('Request a Song')"
|
||||
hide-footer
|
||||
>
|
||||
<song-request
|
||||
:show-album-art="showAlbumArt"
|
||||
:request-list-uri="requestListUri"
|
||||
:custom-fields="customFields"
|
||||
@submitted="doClose"
|
||||
/>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,21 +1,54 @@
|
|||
<template>
|
||||
<div id="station-history">
|
||||
<p v-if="history.length <= 0">{{ $gettext('No records to display.') }}</p>
|
||||
<div class="song" v-for="(row, index) in history">
|
||||
<p v-if="history.length <= 0">
|
||||
{{ $gettext('No records to display.') }}
|
||||
</p>
|
||||
<div
|
||||
v-for="(row, index) in history"
|
||||
class="song"
|
||||
>
|
||||
<strong class="order">{{ history.length - index }}</strong>
|
||||
<img v-if="showAlbumArt" class="art" :src="row.song.art">
|
||||
<img
|
||||
v-if="showAlbumArt"
|
||||
class="art"
|
||||
:src="row.song.art"
|
||||
>
|
||||
<div class="name">
|
||||
<strong v-html="row.song.title"></strong>
|
||||
<span v-html="albumAndArtist(row.song)"></span>
|
||||
<strong v-html="row.song.title" />
|
||||
<span v-html="albumAndArtist(row.song)" />
|
||||
</div>
|
||||
<div class="break"></div>
|
||||
<div class="break" />
|
||||
<small class="date-played text-muted">
|
||||
<span v-html="unixTimestampToDate(row.played_at)"></span>
|
||||
<span v-html="unixTimestampToDate(row.played_at)" />
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {DateTime} from "luxon";
|
||||
|
||||
const props = defineProps({
|
||||
history: Array,
|
||||
showAlbumArt: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
});
|
||||
|
||||
const unixTimestampToDate = (timestamp) => {
|
||||
if (!timestamp) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return DateTime.fromSeconds(timestamp).toRelative();
|
||||
};
|
||||
|
||||
const albumAndArtist = (song) => {
|
||||
return [song.artist, song.album].filter(str => !!str).join(', ');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#station-history {
|
||||
.song {
|
||||
|
@ -76,27 +109,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import {DateTime} from "luxon";
|
||||
|
||||
const props = defineProps({
|
||||
history: Array,
|
||||
showAlbumArt: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
});
|
||||
|
||||
const unixTimestampToDate = (timestamp) => {
|
||||
if (!timestamp) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return DateTime.fromSeconds(timestamp).toRelative();
|
||||
};
|
||||
|
||||
const albumAndArtist = (song) => {
|
||||
return [song.artist, song.album].filter(str => !!str).join(', ');
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
<template>
|
||||
<b-modal size="md" id="song_history_modal" ref="modal" :title="$gettext('Song History')" centered hide-footer>
|
||||
<song-history :show-album-art="showAlbumArt" :history="history"></song-history>
|
||||
<b-modal
|
||||
id="song_history_modal"
|
||||
ref="modal"
|
||||
size="md"
|
||||
:title="$gettext('Song History')"
|
||||
centered
|
||||
hide-footer
|
||||
>
|
||||
<song-history
|
||||
:show-album-art="showAlbumArt"
|
||||
:history="history"
|
||||
/>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<template>
|
||||
<div id="song_history">
|
||||
<song-history :show-album-art="showAlbumArt" :history="history"></song-history>
|
||||
<song-history
|
||||
:show-album-art="showAlbumArt"
|
||||
:history="history"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
<template>
|
||||
<section id="content" role="main" class="d-flex align-items-stretch" style="height: 100vh;">
|
||||
<div class="container pt-5 pb-5 h-100" style="flex: 1;">
|
||||
<div class="card" style="height: 100%;">
|
||||
<section
|
||||
id="content"
|
||||
role="main"
|
||||
class="d-flex align-items-stretch"
|
||||
style="height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="container pt-5 pb-5 h-100"
|
||||
style="flex: 1;"
|
||||
>
|
||||
<div
|
||||
class="card"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-shrink">
|
||||
|
@ -15,31 +26,56 @@
|
|||
</h2>
|
||||
</div>
|
||||
<div class="flex-fill text-right">
|
||||
<inline-player ref="player"></inline-player>
|
||||
<inline-player ref="player" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<data-table ref="datatable" id="station_on_demand_table" paginated select-fields
|
||||
:fields="fields" :api-url="listUrl">
|
||||
<data-table
|
||||
id="station_on_demand_table"
|
||||
ref="datatable"
|
||||
paginated
|
||||
select-fields
|
||||
:fields="fields"
|
||||
:api-url="listUrl"
|
||||
>
|
||||
<template #cell(download_url)="row">
|
||||
<play-button class="file-icon" icon-class="outlined" :url="row.item.download_url"
|
||||
:is-stream="false"></play-button>
|
||||
<play-button
|
||||
class="file-icon"
|
||||
icon-class="outlined"
|
||||
:url="row.item.download_url"
|
||||
:is-stream="false"
|
||||
/>
|
||||
<template v-if="showDownloadButton">
|
||||
|
||||
<a class="name" :href="row.item.download_url" target="_blank" :title="$gettext('Download')">
|
||||
<icon icon="cloud_download"></icon>
|
||||
<a
|
||||
class="name"
|
||||
:href="row.item.download_url"
|
||||
target="_blank"
|
||||
:title="$gettext('Download')"
|
||||
>
|
||||
<icon icon="cloud_download" />
|
||||
</a>
|
||||
</template>
|
||||
</template>
|
||||
<template #cell(media_art)="row">
|
||||
<a :href="row.item.media_art" class="album-art" target="_blank"
|
||||
data-fancybox="gallery">
|
||||
<img class="media_manager_album_art" :alt="$gettext('Album Art')" :src="row.item.media_art">
|
||||
<a
|
||||
:href="row.item.media_art"
|
||||
class="album-art"
|
||||
target="_blank"
|
||||
data-fancybox="gallery"
|
||||
>
|
||||
<img
|
||||
class="media_manager_album_art"
|
||||
:alt="$gettext('Album Art')"
|
||||
:src="row.item.media_art"
|
||||
>
|
||||
</a>
|
||||
</template>
|
||||
<template #cell(size)="row">
|
||||
<template v-if="!row.item.size"> </template>
|
||||
<template v-if="!row.item.size">
|
||||
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formatFileSize(row.item.size) }}
|
||||
</template>
|
||||
|
@ -50,6 +86,43 @@
|
|||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import InlinePlayer from '../InlinePlayer';
|
||||
import DataTable from '~/components/Common/DataTable';
|
||||
import {forEach} from 'lodash';
|
||||
import Icon from '~/components/Common/Icon';
|
||||
import PlayButton from "~/components/Common/PlayButton";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
|
||||
const props = defineProps({
|
||||
listUrl: String,
|
||||
stationName: String,
|
||||
customFields: Array,
|
||||
showDownloadButton: Boolean
|
||||
});
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
let fields = [
|
||||
{key: 'download_url', label: ' '},
|
||||
{key: 'media_art', label: $gettext('Art')},
|
||||
{key: 'media_title', label: $gettext('Title'), sortable: true, selectable: true},
|
||||
{key: 'media_artist', label: $gettext('Artist'), sortable: true, selectable: true},
|
||||
{key: 'media_album', label: $gettext('Album'), sortable: true, selectable: true, visible: false},
|
||||
{key: 'playlist', label: $gettext('Playlist'), sortable: true, selectable: true, visible: false}
|
||||
];
|
||||
|
||||
forEach(props.customFields.slice(), (field) => {
|
||||
fields.push({
|
||||
key: field.display_key,
|
||||
label: field.label,
|
||||
sortable: true,
|
||||
selectable: true,
|
||||
visible: false
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ondemand.embed {
|
||||
.container {
|
||||
|
@ -91,40 +164,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import InlinePlayer from '../InlinePlayer';
|
||||
import DataTable from '~/components/Common/DataTable';
|
||||
import {forEach} from 'lodash';
|
||||
import Icon from '~/components/Common/Icon';
|
||||
import PlayButton from "~/components/Common/PlayButton";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
|
||||
const props = defineProps({
|
||||
listUrl: String,
|
||||
stationName: String,
|
||||
customFields: Array,
|
||||
showDownloadButton: Boolean
|
||||
});
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
let fields = [
|
||||
{key: 'download_url', label: ' '},
|
||||
{key: 'media_art', label: $gettext('Art')},
|
||||
{key: 'media_title', label: $gettext('Title'), sortable: true, selectable: true},
|
||||
{key: 'media_artist', label: $gettext('Artist'), sortable: true, selectable: true},
|
||||
{key: 'media_album', label: $gettext('Album'), sortable: true, selectable: true, visible: false},
|
||||
{key: 'playlist', label: $gettext('Playlist'), sortable: true, selectable: true, visible: false}
|
||||
];
|
||||
|
||||
forEach(props.customFields.slice(), (field) => {
|
||||
fields.push({
|
||||
key: field.display_key,
|
||||
label: field.label,
|
||||
sortable: true,
|
||||
selectable: true,
|
||||
visible: false
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,16 +1,33 @@
|
|||
<template>
|
||||
<div class="radio-player-widget">
|
||||
<audio-player ref="$player" :title="np.now_playing.song.text" :volume="volume"
|
||||
:is-muted="isMuted"></audio-player>
|
||||
<audio-player
|
||||
ref="$player"
|
||||
:title="np.now_playing.song.text"
|
||||
:volume="volume"
|
||||
:is-muted="isMuted"
|
||||
/>
|
||||
|
||||
<div class="now-playing-details">
|
||||
<div class="now-playing-art" v-if="showAlbumArt && np.now_playing.song.art">
|
||||
<a :href="np.now_playing.song.art" data-fancybox target="_blank">
|
||||
<img :src="np.now_playing.song.art" :alt="$gettext('Album Art')">
|
||||
<div
|
||||
v-if="showAlbumArt && np.now_playing.song.art"
|
||||
class="now-playing-art"
|
||||
>
|
||||
<a
|
||||
:href="np.now_playing.song.art"
|
||||
data-fancybox
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
:src="np.now_playing.song.art"
|
||||
:alt="$gettext('Album Art')"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
<div class="now-playing-main">
|
||||
<h6 class="now-playing-live" v-if="np.live.is_live">
|
||||
<h6
|
||||
v-if="np.live.is_live"
|
||||
class="now-playing-live"
|
||||
>
|
||||
{{ $gettext('Live') }}
|
||||
{{ np.live.streamer_name }}
|
||||
</h6>
|
||||
|
@ -21,21 +38,33 @@
|
|||
</h4>
|
||||
</div>
|
||||
<div v-else-if="np.now_playing.song.title !== ''">
|
||||
<h4 class="now-playing-title">{{ np.now_playing.song.title }}</h4>
|
||||
<h5 class="now-playing-artist">{{ np.now_playing.song.artist }}</h5>
|
||||
<h4 class="now-playing-title">
|
||||
{{ np.now_playing.song.title }}
|
||||
</h4>
|
||||
<h5 class="now-playing-artist">
|
||||
{{ np.now_playing.song.artist }}
|
||||
</h5>
|
||||
</div>
|
||||
<div v-else>
|
||||
<h4 class="now-playing-title">{{ np.now_playing.song.text }}</h4>
|
||||
<h4 class="now-playing-title">
|
||||
{{ np.now_playing.song.text }}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="time-display" v-if="currentTimeElapsedDisplay != null">
|
||||
<div
|
||||
v-if="currentTimeElapsedDisplay != null"
|
||||
class="time-display"
|
||||
>
|
||||
<div class="time-display-played text-secondary">
|
||||
{{ currentTimeElapsedDisplay }}
|
||||
</div>
|
||||
<div class="time-display-progress">
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-secondary" role="progressbar"
|
||||
:style="{ width: currentTrackPercent+'%' }"></div>
|
||||
<div
|
||||
class="progress-bar bg-secondary"
|
||||
role="progressbar"
|
||||
:style="{ width: currentTrackPercent+'%' }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="time-display-total text-secondary">
|
||||
|
@ -48,18 +77,39 @@
|
|||
<hr>
|
||||
|
||||
<div class="radio-controls">
|
||||
<play-button class="radio-control-play-button" icon-class="outlined lg" :url="currentStream.url"
|
||||
:is-hls="currentStream.hls" is-stream></play-button>
|
||||
<play-button
|
||||
class="radio-control-play-button"
|
||||
icon-class="outlined lg"
|
||||
:url="currentStream.url"
|
||||
:is-hls="currentStream.hls"
|
||||
is-stream
|
||||
/>
|
||||
|
||||
<div class="radio-control-select-stream">
|
||||
<div v-if="streams.length > 1" class="dropdown">
|
||||
<button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" id="btn-select-stream"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<div
|
||||
v-if="streams.length > 1"
|
||||
class="dropdown"
|
||||
>
|
||||
<button
|
||||
id="btn-select-stream"
|
||||
class="btn btn-sm btn-outline-primary dropdown-toggle"
|
||||
type="button"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
{{ currentStream.name }}
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="btn-select-stream">
|
||||
<a class="dropdown-item" v-for="stream in streams" href="javascript:"
|
||||
@click.prevent="switchStream(stream)">
|
||||
<div
|
||||
class="dropdown-menu"
|
||||
aria-labelledby="btn-select-stream"
|
||||
>
|
||||
<a
|
||||
v-for="stream in streams"
|
||||
class="dropdown-item"
|
||||
href="javascript:"
|
||||
@click.prevent="switchStream(stream)"
|
||||
>
|
||||
{{ stream.name }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -67,146 +117,41 @@
|
|||
</div>
|
||||
|
||||
<div class="radio-control-mute-button">
|
||||
<a href="#" class="text-secondary" :title="$gettext('Mute')" @click.prevent="toggleMute">
|
||||
<icon icon="volume_mute"></icon>
|
||||
<a
|
||||
href="#"
|
||||
class="text-secondary"
|
||||
:title="$gettext('Mute')"
|
||||
@click.prevent="toggleMute"
|
||||
>
|
||||
<icon icon="volume_mute" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="radio-control-volume-slider">
|
||||
<input type="range" :title="$gettext('Volume')" class="custom-range" min="0" max="100" step="1"
|
||||
:disabled="isMuted" v-model.number="volume">
|
||||
<input
|
||||
v-model.number="volume"
|
||||
type="range"
|
||||
:title="$gettext('Volume')"
|
||||
class="custom-range"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:disabled="isMuted"
|
||||
>
|
||||
</div>
|
||||
<div class="radio-control-max-volume-button">
|
||||
<a href="#" class="text-secondary" :title="$gettext('Full Volume')" @click.prevent="fullVolume">
|
||||
<icon icon="volume_up"></icon>
|
||||
<a
|
||||
href="#"
|
||||
class="text-secondary"
|
||||
:title="$gettext('Full Volume')"
|
||||
@click.prevent="fullVolume"
|
||||
>
|
||||
<icon icon="volume_up" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.radio-player-widget {
|
||||
.now-playing-details {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.now-playing-art {
|
||||
padding-right: .5rem;
|
||||
|
||||
img {
|
||||
width: 75px;
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
|
||||
@media (max-width: 575px) {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.now-playing-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.now-playing-title,
|
||||
.now-playing-artist {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
text-overflow: clip;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.time-display {
|
||||
font-size: 10px;
|
||||
margin-top: .25rem;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.time-display-played {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.time-display-progress {
|
||||
flex: 1 1 auto;
|
||||
|
||||
.progress-bar {
|
||||
-webkit-transition: width 1s; /* Safari */
|
||||
transition: width 1s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
}
|
||||
|
||||
.time-display-total {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: .5rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
i.material-icons {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.radio-controls {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.radio-control-play-button {
|
||||
margin-right: .25rem;
|
||||
}
|
||||
|
||||
.radio-control-select-stream {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.radio-control-mute-button,
|
||||
.radio-control-max-volume-button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.radio-control-volume-slider {
|
||||
flex: 1 1 auto;
|
||||
max-width: 30%;
|
||||
|
||||
input {
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import AudioPlayer from '~/components/Common/AudioPlayer';
|
||||
import Icon from '~/components/Common/Icon';
|
||||
|
@ -362,3 +307,126 @@ const onNowPlayingUpdated = (np_new) => {
|
|||
|
||||
watch(np, onNowPlayingUpdated, {immediate: true});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.radio-player-widget {
|
||||
.now-playing-details {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.now-playing-art {
|
||||
padding-right: .5rem;
|
||||
|
||||
img {
|
||||
width: 75px;
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
|
||||
@media (max-width: 575px) {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.now-playing-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.now-playing-title,
|
||||
.now-playing-artist {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
text-overflow: clip;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.time-display {
|
||||
font-size: 10px;
|
||||
margin-top: .25rem;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.time-display-played {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.time-display-progress {
|
||||
flex: 1 1 auto;
|
||||
|
||||
.progress-bar {
|
||||
-webkit-transition: width 1s; /* Safari */
|
||||
transition: width 1s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
}
|
||||
|
||||
.time-display-total {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: .5rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
i.material-icons {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.radio-controls {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.radio-control-play-button {
|
||||
margin-right: .25rem;
|
||||
}
|
||||
|
||||
.radio-control-select-stream {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.radio-control-mute-button,
|
||||
.radio-control-max-volume-button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.radio-control-volume-slider {
|
||||
flex: 1 1 auto;
|
||||
max-width: 30%;
|
||||
|
||||
input {
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,12 +1,23 @@
|
|||
<template>
|
||||
<div style="overflow-x: hidden">
|
||||
<data-table ref="datatable" id="song_requests" paginated select-fields :page-options="pageOptions"
|
||||
<data-table
|
||||
id="song_requests"
|
||||
ref="datatable"
|
||||
paginated
|
||||
select-fields
|
||||
:page-options="pageOptions"
|
||||
:fields="fields"
|
||||
:responsive="false" :api-url="requestListUri">
|
||||
:responsive="false"
|
||||
:api-url="requestListUri"
|
||||
>
|
||||
<template #cell(name)="row">
|
||||
<div class="d-flex align-items-center">
|
||||
<album-art v-if="showAlbumArt" :src="row.item.song.art" :width="40"
|
||||
class="flex-shrink-1 pr-3"></album-art>
|
||||
<album-art
|
||||
v-if="showAlbumArt"
|
||||
:src="row.item.song.art"
|
||||
:width="40"
|
||||
class="flex-shrink-1 pr-3"
|
||||
/>
|
||||
<div class="flex-fill">
|
||||
{{ row.item.song.title }}<br>
|
||||
<small>{{ row.item.song.artist }}</small>
|
||||
|
@ -15,7 +26,11 @@
|
|||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="primary" @click.prevent="doSubmitRequest(row.item.request_url)">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
@click.prevent="doSubmitRequest(row.item.request_url)"
|
||||
>
|
||||
{{ $gettext('Request') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
@ -24,14 +39,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
img.album_art {
|
||||
width: 40px;
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import DataTable from '~/components/Common/DataTable';
|
||||
import _ from 'lodash';
|
||||
|
@ -39,7 +46,6 @@ import AlbumArt from '~/components/Common/AlbumArt';
|
|||
|
||||
export default {
|
||||
components: {AlbumArt, DataTable},
|
||||
emits: ['submitted'],
|
||||
props: {
|
||||
requestListUri: {
|
||||
type: String,
|
||||
|
@ -55,6 +61,7 @@ export default {
|
|||
default: () => []
|
||||
}
|
||||
},
|
||||
emits: ['submitted'],
|
||||
data () {
|
||||
let fields = [
|
||||
{key: 'name', isRowHeader: true, label: this.$gettext('Name'), sortable: true, selectable: true},
|
||||
|
@ -121,3 +128,11 @@ export default {
|
|||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
img.album_art {
|
||||
width: 40px;
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
<template>
|
||||
<section id="content" role="main" class="d-flex align-items-stretch" style="height: 100vh;">
|
||||
<div class="container pt-5 pb-5 h-100" style="flex: 1;">
|
||||
<div class="card" style="height: 100%;">
|
||||
<section
|
||||
id="content"
|
||||
role="main"
|
||||
class="d-flex align-items-stretch"
|
||||
style="height: 100vh;"
|
||||
>
|
||||
<div
|
||||
class="container pt-5 pb-5 h-100"
|
||||
style="flex: 1;"
|
||||
>
|
||||
<div
|
||||
class="card"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<div class="card-header bg-primary-dark">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-shrink">
|
||||
|
@ -18,14 +29,27 @@
|
|||
</div>
|
||||
|
||||
<div id="station-schedule-calendar">
|
||||
<schedule ref="schedule" :schedule-url="scheduleUrl"
|
||||
:station-time-zone="stationTimeZone"></schedule>
|
||||
<schedule
|
||||
ref="schedule"
|
||||
:schedule-url="scheduleUrl"
|
||||
:station-time-zone="stationTimeZone"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Schedule from '~/components/Common/ScheduleView';
|
||||
|
||||
const props = defineProps({
|
||||
scheduleUrl: String,
|
||||
stationName: String,
|
||||
stationTimeZone: String
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.schedule.embed {
|
||||
.container {
|
||||
|
@ -38,13 +62,3 @@
|
|||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import Schedule from '~/components/Common/ScheduleView';
|
||||
|
||||
const props = defineProps({
|
||||
scheduleUrl: String,
|
||||
stationName: String,
|
||||
stationTimeZone: String
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,29 +1,33 @@
|
|||
<template>
|
||||
<section id="content" role="main" style="height: 100vh;">
|
||||
<section
|
||||
id="content"
|
||||
role="main"
|
||||
style="height: 100vh;"
|
||||
>
|
||||
<div class="container pt-5">
|
||||
<div class="form-row">
|
||||
<div class="col-md-4 mb-sm-4">
|
||||
<settings-panel v-bind="{ stationName, baseUri, libUrls }"></settings-panel>
|
||||
<settings-panel v-bind="{ stationName, baseUri, libUrls }" />
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="form-row mb-3">
|
||||
<div class="col-md-12">
|
||||
<microphone-panel></microphone-panel>
|
||||
<microphone-panel />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row mb-3">
|
||||
<div class="col-md-12">
|
||||
<mixer-panel></mixer-panel>
|
||||
<mixer-panel />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row mb-4">
|
||||
<div class="col-md-6 mb-sm-4">
|
||||
<playlist-panel id="playlist_1"></playlist-panel>
|
||||
<playlist-panel id="playlist_1" />
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<playlist-panel id="playlist_2"></playlist-panel>
|
||||
<playlist-panel id="playlist_2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,26 +45,26 @@ import SettingsPanel from './WebDJ/SettingsPanel.vue';
|
|||
import Stream from './WebDJ/Stream.js';
|
||||
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
'stream': Stream
|
||||
};
|
||||
},
|
||||
components: {
|
||||
MixerPanel,
|
||||
MicrophonePanel,
|
||||
PlaylistPanel,
|
||||
SettingsPanel
|
||||
},
|
||||
provide: function () {
|
||||
return {
|
||||
getStream: this.getStream,
|
||||
resumeStream: this.resumeStream
|
||||
};
|
||||
},
|
||||
props: {
|
||||
stationName: String,
|
||||
libUrls: Array,
|
||||
baseUri: String
|
||||
},
|
||||
provide: function () {
|
||||
data: function () {
|
||||
return {
|
||||
getStream: this.getStream,
|
||||
resumeStream: this.resumeStream
|
||||
'stream': Stream
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
</h5>
|
||||
</div>
|
||||
<div class="flex-shrink-0 pl-3">
|
||||
<volume-slider v-model.number="volume"></volume-slider>
|
||||
<volume-slider v-model.number="volume" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,11 +18,18 @@
|
|||
<div class="d-flex-shrink-0">
|
||||
<div class="control-group">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-danger" v-on:click="toggleRecording"
|
||||
v-bind:class="{ active: playing }">
|
||||
<icon icon="mic"></icon>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
:class="{ active: playing }"
|
||||
@click="toggleRecording"
|
||||
>
|
||||
<icon icon="mic" />
|
||||
</button>
|
||||
<button class="btn" v-on:click="cue" v-bind:class="{ 'btn-primary': passThrough }">
|
||||
<button
|
||||
class="btn"
|
||||
:class="{ 'btn-primary': passThrough }"
|
||||
@click="cue"
|
||||
>
|
||||
{{ $gettext('Cue') }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -30,12 +37,22 @@
|
|||
</div>
|
||||
<div class="flex-fill pl-3">
|
||||
<div class="form-group microphone-entry mb-0">
|
||||
<label for="select_microphone_source" class="mb-2">
|
||||
<label
|
||||
for="select_microphone_source"
|
||||
class="mb-2"
|
||||
>
|
||||
{{ $gettext('Microphone Source') }}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select id="select_microphone_source" v-model="device" class="form-control">
|
||||
<option v-for="device_row in devices" v-bind:value="device_row.deviceId">
|
||||
<select
|
||||
id="select_microphone_source"
|
||||
v-model="device"
|
||||
class="form-control"
|
||||
>
|
||||
<option
|
||||
v-for="device_row in devices"
|
||||
:value="device_row.deviceId"
|
||||
>
|
||||
{{ device_row.label }}
|
||||
</option>
|
||||
</select>
|
||||
|
@ -44,12 +61,21 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="playing" class="mt-3">
|
||||
<div
|
||||
v-if="playing"
|
||||
class="mt-3"
|
||||
>
|
||||
<div class="progress mb-1">
|
||||
<div class="progress-bar" v-bind:style="{ width: volumeLeft+'%' }"></div>
|
||||
<div
|
||||
class="progress-bar"
|
||||
:style="{ width: volumeLeft+'%' }"
|
||||
/>
|
||||
</div>
|
||||
<div class="progress mb-2">
|
||||
<div class="progress-bar" v-bind:style="{ width: volumeRight+'%' }"></div>
|
||||
<div
|
||||
class="progress-bar"
|
||||
:style="{ width: volumeRight+'%' }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,9 +13,16 @@
|
|||
{{ $gettext('Playlist 1') }}
|
||||
</div>
|
||||
<div class="flex-fill px-2">
|
||||
<input type="range" min="0" max="1" step="0.01" class="custom-range slider"
|
||||
v-model="position" @click.right.prevent="position = 0.5"
|
||||
style="width: 200px; height: 10px;">
|
||||
<input
|
||||
v-model="position"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
class="custom-range slider"
|
||||
style="width: 200px; height: 10px;"
|
||||
@click.right.prevent="position = 0.5"
|
||||
>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
{{ $gettext('Playlist 2') }}
|
||||
|
|
|
@ -3,64 +3,114 @@
|
|||
<div class="card-header bg-primary-dark">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-fill text-nowrap">
|
||||
<h5 class="card-title">{{ lang_header }}</h5>
|
||||
<h5 class="card-title">
|
||||
{{ lang_header }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="flex-shrink-0 pl-3">
|
||||
<volume-slider v-model.number="volume"></volume-slider>
|
||||
<volume-slider v-model.number="volume" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="control-group d-flex justify-content-center">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-sm btn-success" v-if="!playing || paused" v-on:click="play">
|
||||
<icon icon="play_arrow"></icon>
|
||||
<button
|
||||
v-if="!playing || paused"
|
||||
class="btn btn-sm btn-success"
|
||||
@click="play"
|
||||
>
|
||||
<icon icon="play_arrow" />
|
||||
</button>
|
||||
<button class="btn btn-sm btn-warning" v-if="playing && !paused" v-on:click="togglePause()">
|
||||
<icon icon="pause"></icon>
|
||||
<button
|
||||
v-if="playing && !paused"
|
||||
class="btn btn-sm btn-warning"
|
||||
@click="togglePause()"
|
||||
>
|
||||
<icon icon="pause" />
|
||||
</button>
|
||||
<button class="btn btn-sm" v-on:click="previous()">
|
||||
<icon icon="fast_rewind"></icon>
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
@click="previous()"
|
||||
>
|
||||
<icon icon="fast_rewind" />
|
||||
</button>
|
||||
<button class="btn btn-sm" v-on:click="next()">
|
||||
<icon icon="fast_forward"></icon>
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
@click="next()"
|
||||
>
|
||||
<icon icon="fast_forward" />
|
||||
</button>
|
||||
<button class="btn btn-sm btn-danger" v-on:click="stop()">
|
||||
<icon icon="stop"></icon>
|
||||
<button
|
||||
class="btn btn-sm btn-danger"
|
||||
@click="stop()"
|
||||
>
|
||||
<icon icon="stop" />
|
||||
</button>
|
||||
<button class="btn btn-sm" v-on:click="cue()" v-bind:class="{ 'btn-primary': passThrough }">
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
:class="{ 'btn-primary': passThrough }"
|
||||
@click="cue()"
|
||||
>
|
||||
{{ $gettext('Cue') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3" v-if="playing">
|
||||
|
||||
<div
|
||||
v-if="playing"
|
||||
class="mt-3"
|
||||
>
|
||||
<div class="d-flex flex-row mb-2">
|
||||
<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"
|
||||
v-on:mousedown="isSeeking = true"
|
||||
v-on:mousemove="doSeek($event)"
|
||||
v-on:mouseup="isSeeking = false">
|
||||
<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"
|
||||
:value="seekingPosition"
|
||||
@mousedown="isSeeking = true"
|
||||
@mousemove="doSeek($event)"
|
||||
@mouseup="isSeeking = false"
|
||||
>
|
||||
</div>
|
||||
<div class="flex-shrink-0 pt-1 pl-2">
|
||||
{{ prettifyTime(duration) }}
|
||||
</div>
|
||||
<div class="flex-shrink-0 pt-1 pl-2">{{ prettifyTime(duration) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="progress mb-1">
|
||||
<div class="progress-bar" v-bind:style="{ width: volumeLeft+'%' }"></div>
|
||||
<div
|
||||
class="progress-bar"
|
||||
:style="{ width: volumeLeft+'%' }"
|
||||
/>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" v-bind:style="{ width: volumeRight+'%' }"></div>
|
||||
<div
|
||||
class="progress-bar"
|
||||
:style="{ width: volumeRight+'%' }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<div class="custom-file">
|
||||
<input v-bind:id="id + '_files'" type="file" class="custom-file-input files" accept="audio/*"
|
||||
multiple="multiple" v-on:change="addNewFiles($event.target.files)">
|
||||
<label v-bind:for="id + '_files'" class="custom-file-label">
|
||||
<input
|
||||
:id="id + '_files'"
|
||||
type="file"
|
||||
class="custom-file-input files"
|
||||
accept="audio/*"
|
||||
multiple="multiple"
|
||||
@change="addNewFiles($event.target.files)"
|
||||
>
|
||||
<label
|
||||
:for="id + '_files'"
|
||||
class="custom-file-label"
|
||||
>
|
||||
{{ $gettext('Add Files to Playlist') }}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -69,15 +119,30 @@
|
|||
<div class="form-group mb-0">
|
||||
<div class="controls">
|
||||
<div class="custom-control custom-checkbox custom-control-inline">
|
||||
<input v-bind:id="id + '_playthrough'" type="checkbox" class="custom-control-input"
|
||||
v-model="playThrough">
|
||||
<label v-bind:for="id + '_playthrough'" class="custom-control-label">
|
||||
<input
|
||||
:id="id + '_playthrough'"
|
||||
v-model="playThrough"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label
|
||||
:for="id + '_playthrough'"
|
||||
class="custom-control-label"
|
||||
>
|
||||
{{ $gettext('Continuous Play') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="custom-control custom-checkbox custom-control-inline">
|
||||
<input v-bind:id="id + '_loop'" type="checkbox" class="custom-control-input" v-model="loop">
|
||||
<label v-bind:for="id + '_loop'" class="custom-control-label">
|
||||
<input
|
||||
:id="id + '_loop'"
|
||||
v-model="loop"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label
|
||||
:for="id + '_loop'"
|
||||
class="custom-control-label"
|
||||
>
|
||||
{{ $gettext('Repeat') }}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -85,10 +150,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-group list-group-flush" v-if="files.length > 0">
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start"
|
||||
v-for="(rowFile, rowIndex) in files" v-bind:class="{ active: rowIndex === fileIndex }"
|
||||
v-on:click.prevent="play({ fileIndex: rowIndex })">
|
||||
<div
|
||||
v-if="files.length > 0"
|
||||
class="list-group list-group-flush"
|
||||
>
|
||||
<a
|
||||
v-for="(rowFile, rowIndex) in files"
|
||||
href="#"
|
||||
class="list-group-item list-group-item-action flex-column align-items-start"
|
||||
:class="{ active: rowIndex === fileIndex }"
|
||||
@click.prevent="play({ fileIndex: rowIndex })"
|
||||
>
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-0">{{
|
||||
rowFile.metadata.title ? rowFile.metadata.title : lang_unknown_title
|
||||
|
@ -110,6 +182,9 @@ import VolumeSlider from "~/components/Public/WebDJ/VolumeSlider";
|
|||
export default {
|
||||
components: {VolumeSlider, Icon},
|
||||
extends: track,
|
||||
props: {
|
||||
id: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
'fileIndex': -1,
|
||||
|
@ -144,9 +219,6 @@ export default {
|
|||
return (this.isSeeking) ? this.seekPosition : this.positionPercent;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
id: String
|
||||
},
|
||||
mounted () {
|
||||
this.mixGainObj = this.getStream().context.createGain();
|
||||
this.mixGainObj.connect(this.getStream().webcast);
|
||||
|
|
|
@ -12,12 +12,20 @@
|
|||
<div class="col-sm-12">
|
||||
<ul class="nav nav-tabs card-header-tabs mt-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#settings" data-toggle="tab">
|
||||
<a
|
||||
class="nav-link active"
|
||||
href="#settings"
|
||||
data-toggle="tab"
|
||||
>
|
||||
{{ $gettext('Settings') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#metadata" data-toggle="tab">
|
||||
<a
|
||||
class="nav-link"
|
||||
href="#metadata"
|
||||
data-toggle="tab"
|
||||
>
|
||||
{{ $gettext('Metadata') }}
|
||||
</a>
|
||||
</li>
|
||||
|
@ -27,70 +35,157 @@
|
|||
<div class="form-row">
|
||||
<div class="col-sm-12">
|
||||
<div class="tab-content mt-1">
|
||||
<div class="tab-pane active" id="settings">
|
||||
<div
|
||||
id="settings"
|
||||
class="tab-pane active"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label class="mb-2">
|
||||
{{ $gettext('Encoder') }}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<div class="custom-control custom-radio custom-control-inline">
|
||||
<input id="encoder_mp3" type="radio" v-model="encoder" value="mp3"
|
||||
class="custom-control-input">
|
||||
<label for="encoder_mp3" class="custom-control-label">
|
||||
<input
|
||||
id="encoder_mp3"
|
||||
v-model="encoder"
|
||||
type="radio"
|
||||
value="mp3"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label
|
||||
for="encoder_mp3"
|
||||
class="custom-control-label"
|
||||
>
|
||||
{{ $gettext('MP3') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="custom-control custom-radio custom-control-inline">
|
||||
<input id="encoder_raw" type="radio" v-model="encoder" value="raw"
|
||||
class="custom-control-input">
|
||||
<label for="encoder_raw" class="custom-control-label">
|
||||
<input
|
||||
id="encoder_raw"
|
||||
v-model="encoder"
|
||||
type="radio"
|
||||
value="raw"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label
|
||||
for="encoder_raw"
|
||||
class="custom-control-label"
|
||||
>
|
||||
{{ $gettext('Raw') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="select_samplerate" class="mb-2">
|
||||
<label
|
||||
for="select_samplerate"
|
||||
class="mb-2"
|
||||
>
|
||||
{{ $gettext('Sample Rate') }}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select id="select_samplerate" class="form-control" v-model.number="samplerate">
|
||||
<option value="8000">8 kHz</option>
|
||||
<option value="11025">11.025 kHz</option>
|
||||
<option value="12000">12 kHz</option>
|
||||
<option value="16000">16 kHz</option>
|
||||
<option value="22050">22.05 kHz</option>
|
||||
<option value="24000">24 kHz</option>
|
||||
<option value="32000">32 kHz</option>
|
||||
<option value="44100">44.1 kHz</option>
|
||||
<option value="48000">48 kHz</option>
|
||||
<select
|
||||
id="select_samplerate"
|
||||
v-model.number="samplerate"
|
||||
class="form-control"
|
||||
>
|
||||
<option value="8000">
|
||||
8 kHz
|
||||
</option>
|
||||
<option value="11025">
|
||||
11.025 kHz
|
||||
</option>
|
||||
<option value="12000">
|
||||
12 kHz
|
||||
</option>
|
||||
<option value="16000">
|
||||
16 kHz
|
||||
</option>
|
||||
<option value="22050">
|
||||
22.05 kHz
|
||||
</option>
|
||||
<option value="24000">
|
||||
24 kHz
|
||||
</option>
|
||||
<option value="32000">
|
||||
32 kHz
|
||||
</option>
|
||||
<option value="44100">
|
||||
44.1 kHz
|
||||
</option>
|
||||
<option value="48000">
|
||||
48 kHz
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="select_bitrate" class="mb-2">
|
||||
<label
|
||||
for="select_bitrate"
|
||||
class="mb-2"
|
||||
>
|
||||
{{ $gettext('Bit Rate') }}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select id="select_bitrate" class="form-control" v-model.number="bitrate">
|
||||
<option value="8">8 kbps</option>
|
||||
<option value="16">16 kbps</option>
|
||||
<option value="24">24 kbps</option>
|
||||
<option value="32">32 kbps</option>
|
||||
<option value="40">40 kbps</option>
|
||||
<option value="48">48 kbps</option>
|
||||
<option value="56">56 kbps</option>
|
||||
<option value="64">64 kbps</option>
|
||||
<option value="80">80 kbps</option>
|
||||
<option value="96">96 kbps</option>
|
||||
<option value="112">112 kbps</option>
|
||||
<option value="128">128 kbps</option>
|
||||
<option value="144">144 kbps</option>
|
||||
<option value="160">160 kbps</option>
|
||||
<option value="192">192 kbps</option>
|
||||
<option value="224">224 kbps</option>
|
||||
<option value="256">256 kbps</option>
|
||||
<option value="320">320 kbps</option>
|
||||
<select
|
||||
id="select_bitrate"
|
||||
v-model.number="bitrate"
|
||||
class="form-control"
|
||||
>
|
||||
<option value="8">
|
||||
8 kbps
|
||||
</option>
|
||||
<option value="16">
|
||||
16 kbps
|
||||
</option>
|
||||
<option value="24">
|
||||
24 kbps
|
||||
</option>
|
||||
<option value="32">
|
||||
32 kbps
|
||||
</option>
|
||||
<option value="40">
|
||||
40 kbps
|
||||
</option>
|
||||
<option value="48">
|
||||
48 kbps
|
||||
</option>
|
||||
<option value="56">
|
||||
56 kbps
|
||||
</option>
|
||||
<option value="64">
|
||||
64 kbps
|
||||
</option>
|
||||
<option value="80">
|
||||
80 kbps
|
||||
</option>
|
||||
<option value="96">
|
||||
96 kbps
|
||||
</option>
|
||||
<option value="112">
|
||||
112 kbps
|
||||
</option>
|
||||
<option value="128">
|
||||
128 kbps
|
||||
</option>
|
||||
<option value="144">
|
||||
144 kbps
|
||||
</option>
|
||||
<option value="160">
|
||||
160 kbps
|
||||
</option>
|
||||
<option value="192">
|
||||
192 kbps
|
||||
</option>
|
||||
<option value="224">
|
||||
224 kbps
|
||||
</option>
|
||||
<option value="256">
|
||||
256 kbps
|
||||
</option>
|
||||
<option value="320">
|
||||
320 kbps
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -101,47 +196,84 @@
|
|||
|
||||
<div class="form-row">
|
||||
<div class="col-6">
|
||||
<input type="text" v-model="djUsername" class="form-control"
|
||||
v-bind:placeholder="langDjUsername">
|
||||
<input
|
||||
v-model="djUsername"
|
||||
type="text"
|
||||
class="form-control"
|
||||
:placeholder="langDjUsername"
|
||||
>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input type="password" v-model="djPassword" class="form-control"
|
||||
v-bind:placeholder="langDjPassword">
|
||||
<input
|
||||
v-model="djPassword"
|
||||
type="password"
|
||||
class="form-control"
|
||||
:placeholder="langDjPassword"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input id="use_async_worker" type="checkbox" v-model="asynchronous"
|
||||
class="custom-control-input">
|
||||
<label for="use_async_worker" class="custom-control-label">
|
||||
<input
|
||||
id="use_async_worker"
|
||||
v-model="asynchronous"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label
|
||||
for="use_async_worker"
|
||||
class="custom-control-label"
|
||||
>
|
||||
{{ $gettext('Use Asynchronous Worker') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="metadata">
|
||||
<div
|
||||
id="metadata"
|
||||
class="tab-pane"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label for="metadata_title" class="mb-2">
|
||||
<label
|
||||
for="metadata_title"
|
||||
class="mb-2"
|
||||
>
|
||||
{{ $gettext('Title') }}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input id="metadata_title" class="form-control" type="text" v-model="metadata.title"
|
||||
v-bind:disabled="!isStreaming">
|
||||
<input
|
||||
id="metadata_title"
|
||||
v-model="metadata.title"
|
||||
class="form-control"
|
||||
type="text"
|
||||
:disabled="!isStreaming"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="metadata_artist" class="mb-2">
|
||||
<label
|
||||
for="metadata_artist"
|
||||
class="mb-2"
|
||||
>
|
||||
{{ $gettext('Artist') }}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input id="metadata_artist" class="form-control" type="text"
|
||||
v-model="metadata.artist" v-bind:disabled="!isStreaming">
|
||||
<input
|
||||
id="metadata_artist"
|
||||
v-model="metadata.artist"
|
||||
class="form-control"
|
||||
type="text"
|
||||
:disabled="!isStreaming"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary" v-on:click="updateMetadata"
|
||||
v-bind:disabled="!isStreaming">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
:disabled="!isStreaming"
|
||||
@click="updateMetadata"
|
||||
>
|
||||
{{ $gettext('Update Metadata') }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -152,13 +284,25 @@
|
|||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<button class="btn btn-success" v-on:click="startStreaming" v-if="!isStreaming">
|
||||
<button
|
||||
v-if="!isStreaming"
|
||||
class="btn btn-success"
|
||||
@click="startStreaming"
|
||||
>
|
||||
{{ langStreamButton }}
|
||||
</button>
|
||||
<button class="btn btn-danger" v-on:click="stopStreaming" v-if="isStreaming">
|
||||
<button
|
||||
v-if="isStreaming"
|
||||
class="btn btn-danger"
|
||||
@click="stopStreaming"
|
||||
>
|
||||
{{ langStreamButton }}
|
||||
</button>
|
||||
<button class="btn" v-on:click="cue" v-bind:class="{ 'btn-primary': passThrough }">
|
||||
<button
|
||||
class="btn"
|
||||
:class="{ 'btn-primary': passThrough }"
|
||||
@click="cue"
|
||||
>
|
||||
{{ $gettext('Cue') }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -168,6 +312,11 @@
|
|||
<script>
|
||||
export default {
|
||||
inject: ['getStream', 'resumeStream'],
|
||||
props: {
|
||||
stationName: String,
|
||||
libUrls: Array,
|
||||
baseUri: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
'isStreaming': false,
|
||||
|
@ -200,11 +349,6 @@ export default {
|
|||
return 'wss://' + this.djUsername + ':' + this.djPassword + '@' + this.baseUri;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
stationName: String,
|
||||
libUrls: Array,
|
||||
baseUri: String
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('new-cue', this.onNewCue);
|
||||
this.$root.$on('metadata-update', this.onMetadataUpdate);
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
<template>
|
||||
<div class="d-flex flex-row align-items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<icon icon="volume_mute"></icon>
|
||||
<icon icon="volume_mute" />
|
||||
</div>
|
||||
<div class="flex-fill px-2">
|
||||
<input type="range" min="0" max="100" class="custom-range slider"
|
||||
v-model.number="volume" @click.right.prevent="reset" style="height: 10px; width: 100px;">
|
||||
<input
|
||||
v-model.number="volume"
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
class="custom-range slider"
|
||||
style="height: 10px; width: 100px;"
|
||||
@click.right.prevent="reset"
|
||||
>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<icon icon="volume_up"></icon>
|
||||
<icon icon="volume_up" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -13,21 +13,49 @@
|
|||
</h3>
|
||||
</div>
|
||||
|
||||
<b-alert variant="danger" :show="error != null">{{ error }}</b-alert>
|
||||
<b-alert
|
||||
variant="danger"
|
||||
:show="error != null"
|
||||
>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
|
||||
<form id="recover-form" class="form vue-form" action="" method="post">
|
||||
<input type="hidden" name="csrf" :value="csrf"/>
|
||||
<form
|
||||
id="recover-form"
|
||||
class="form vue-form"
|
||||
action=""
|
||||
method="post"
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
name="csrf"
|
||||
:value="csrf"
|
||||
>
|
||||
|
||||
<b-wrapped-form-group id="password" name="password" label-class="mb-2" :field="v$.password"
|
||||
input-type="password">
|
||||
<b-wrapped-form-group
|
||||
id="password"
|
||||
name="password"
|
||||
label-class="mb-2"
|
||||
:field="v$.password"
|
||||
input-type="password"
|
||||
>
|
||||
<template #label>
|
||||
<icon icon="vpn_key" class="mr-1"></icon>
|
||||
<icon
|
||||
icon="vpn_key"
|
||||
class="mr-1"
|
||||
/>
|
||||
{{ $gettext('Password') }}
|
||||
</template>
|
||||
</b-wrapped-form-group>
|
||||
|
||||
<b-button type="submit" size="lg" block variant="primary" :disabled="v$.$invalid"
|
||||
class="mt-2">
|
||||
<b-button
|
||||
type="submit"
|
||||
size="lg"
|
||||
block
|
||||
variant="primary"
|
||||
:disabled="v$.$invalid"
|
||||
class="mt-2"
|
||||
>
|
||||
{{ $gettext('Recover Account') }}
|
||||
</b-button>
|
||||
</form>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user