Upgrade Vue and Buefy UI lib.
- Vue 2.6 introduces "v-slot" which Buefy 0.9.7 uses. - Refactor all `<b-table>` and `<b-column>` instances to work with the new `v-slot` snytax. - Refactor `<b-column>` <td> and class attributes to work wit hthe new syntax. - Fix Buefy scss setup to work with the update. - Fix sidebar responsive view to work with the update.
This commit is contained in:
parent
c593be51c1
commit
dea4d185ae
9 changed files with 386 additions and 426 deletions
2
frontend/package.json
vendored
2
frontend/package.json
vendored
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"buefy": "^0.8.20",
|
||||
"buefy": "^0.9.7",
|
||||
"c3": "^0.7.18",
|
||||
"codeflask": "^1.4.1",
|
||||
"core-js": "^3.6.5",
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
@import "~bulma/sass/base/_all";
|
||||
@import "~bulma/sass/elements/_all";
|
||||
@import "~bulma/sass/components/card";
|
||||
@import "~bulma/sass/components/dropdown";
|
||||
@import "~bulma/sass/components/level";
|
||||
@import "~bulma/sass/components/menu";
|
||||
@import "~bulma/sass/components/message";
|
||||
@import "~bulma/sass/components/modal";
|
||||
@import "~bulma/sass/components/navbar";
|
||||
@import "~bulma/sass/components/pagination";
|
||||
@import "~bulma/sass/components/tabs";
|
||||
@import "~bulma/sass/form/_all";
|
||||
@import "~bulma/sass/grid/columns";
|
||||
@import "~bulma/sass/grid/tiles";
|
||||
@import "~bulma/sass/layout/section";
|
||||
@import "~bulma/sass/layout/footer";
|
||||
|
||||
@import "~buefy/src/scss/utils/_all";
|
||||
@import "~buefy/src/scss/components/_autocomplete";
|
||||
@import "~buefy/src/scss/components/_carousel";
|
||||
@import "~buefy/src/scss/components/_checkbox";
|
||||
@import "~buefy/src/scss/components/_datepicker";
|
||||
@import "~buefy/src/scss/components/_dialog";
|
||||
@import "~buefy/src/scss/components/_dropdown";
|
||||
@import "~buefy/src/scss/components/_form";
|
||||
@import "~buefy/src/scss/components/_icon";
|
||||
@import "~buefy/src/scss/components/_loading";
|
||||
@import "~buefy/src/scss/components/_menu";
|
||||
@import "~buefy/src/scss/components/_message";
|
||||
@import "~buefy/src/scss/components/_modal";
|
||||
@import "~buefy/src/scss/components/_pagination";
|
||||
@import "~buefy/src/scss/components/_notices";
|
||||
@import "~buefy/src/scss/components/_progress";
|
||||
@import "~buefy/src/scss/components/_radio";
|
||||
@import "~buefy/src/scss/components/_select";
|
||||
@import "~buefy/src/scss/components/_sidebar";
|
||||
@import "~buefy/src/scss/components/_switch";
|
||||
@import "~buefy/src/scss/components/_table";
|
||||
@import "~buefy/src/scss/components/_tabs";
|
||||
@import "~buefy/src/scss/components/_tag";
|
||||
@import "~buefy/src/scss/components/_taginput";
|
||||
@import "~buefy/src/scss/components/_timepicker";
|
||||
@import "~buefy/src/scss/components/_tooltip";
|
||||
@import "~buefy/src/scss/components/_upload";
|
|
@ -30,10 +30,11 @@ $modal-background-background-color: rgba(0, 0, 0, .30);
|
|||
$speed-slow: 25ms !default;
|
||||
$speed-slower: 50ms !default;
|
||||
|
||||
/* Import full Bulma and Buefy to override styles. */
|
||||
// @import "~bulma";
|
||||
@import "./buefy";
|
||||
/* Import full Bulma and Buefy */
|
||||
@import "~bulma";
|
||||
@import "~buefy/src/scss/buefy";
|
||||
|
||||
/* Custom style overrides */
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -752,6 +753,7 @@ section.campaign {
|
|||
|
||||
/* Hide sidebar menu captions on mobile */
|
||||
.b-sidebar .sidebar-content.is-mini-mobile {
|
||||
max-width: 90px;
|
||||
.menu-list {
|
||||
li {
|
||||
margin-bottom: 30px;
|
||||
|
@ -773,7 +775,6 @@ section.campaign {
|
|||
|
||||
td .tags {
|
||||
display: block;
|
||||
text-align: right;
|
||||
|
||||
.tag:not(:last-child) {
|
||||
margin-right: 0;
|
||||
|
|
|
@ -118,4 +118,8 @@ export default class Utils {
|
|||
duration: duration || 2000,
|
||||
});
|
||||
};
|
||||
|
||||
// Takes a props.row from a Buefy b-column <td> template and
|
||||
// returns a `data-id` attribute which Buefy then applies to the td.
|
||||
tdID = (row) => ({ 'data-id': row.id.toString() });
|
||||
}
|
||||
|
|
|
@ -29,175 +29,173 @@
|
|||
paginated backend-pagination pagination-position="both" @page-change="onPageChange"
|
||||
:current-page="queryParams.page" :per-page="campaigns.perPage" :total="campaigns.total"
|
||||
hoverable backend-sorting @sort="onSort">
|
||||
<template slot-scope="props">
|
||||
<b-table-column class="status" field="status" :label="$t('globals.fields.status')"
|
||||
width="10%" :id="props.row.id" sortable
|
||||
header-class="cy-status" :data-id="props.row.id">
|
||||
<div>
|
||||
<p>
|
||||
<router-link :to="{ name: 'campaign', params: { 'id': props.row.id }}">
|
||||
<b-tag :class="props.row.status">
|
||||
{{ $t(`campaigns.status.${props.row.status}`) }}
|
||||
</b-tag>
|
||||
<span class="spinner is-tiny" v-if="isRunning(props.row.id)">
|
||||
<b-loading :is-full-page="false" active />
|
||||
</span>
|
||||
</router-link>
|
||||
</p>
|
||||
<p v-if="isSheduled(props.row)">
|
||||
<b-tooltip :label="$t('scheduled')" type="is-dark">
|
||||
<span class="is-size-7 has-text-grey scheduled">
|
||||
<b-icon icon="alarm" size="is-small" />
|
||||
{{ $utils.duration(Date(), props.row.sendAt, true) }}
|
||||
<br />{{ $utils.niceDate(props.row.sendAt, true) }}
|
||||
</span>
|
||||
</b-tooltip>
|
||||
</p>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column field="name" :label="$t('globals.fields.name')" sortable width="25%"
|
||||
header-class="cy-name">
|
||||
<div>
|
||||
<p>
|
||||
<b-tag v-if="props.row.type !== 'regular'" class="is-small">
|
||||
{{ props.row.type }}
|
||||
</b-tag>
|
||||
<router-link :to="{ name: 'campaign', params: { 'id': props.row.id }}">
|
||||
{{ props.row.name }}</router-link>
|
||||
</p>
|
||||
<p class="is-size-7 has-text-grey">{{ props.row.subject }}</p>
|
||||
<b-taglist>
|
||||
<b-tag class="is-small" v-for="t in props.row.tags" :key="t">{{ t }}</b-tag>
|
||||
</b-taglist>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column class="lists" field="lists"
|
||||
:label="$t('globals.terms.lists')" width="15%">
|
||||
<ul class="no">
|
||||
<li v-for="l in props.row.lists" :key="l.id">
|
||||
<router-link :to="{name: 'subscribers_list', params: { listID: l.id }}">
|
||||
{{ l.name }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</b-table-column>
|
||||
<b-table-column field="created_at" :label="$t('campaigns.timestamps')"
|
||||
width="19%" sortable header-class="cy-timestamp">
|
||||
<div class="fields timestamps" :set="stats = getCampaignStats(props.row)">
|
||||
<p>
|
||||
<label>{{ $t('globals.fields.createdAt') }}</label>
|
||||
{{ $utils.niceDate(props.row.createdAt, true) }}
|
||||
</p>
|
||||
<p v-if="stats.startedAt">
|
||||
<label>{{ $t('campaigns.startedAt') }}</label>
|
||||
{{ $utils.niceDate(stats.startedAt, true) }}
|
||||
</p>
|
||||
<p v-if="isDone(props.row)">
|
||||
<label>{{ $t('campaigns.ended') }}</label>
|
||||
{{ $utils.niceDate(stats.updatedAt, true) }}
|
||||
</p>
|
||||
<p v-if="stats.startedAt && stats.updatedAt"
|
||||
class="is-capitalized" title="Duration">
|
||||
<label><b-icon icon="alarm" size="is-small" /></label>
|
||||
{{ $utils.duration(stats.startedAt, stats.updatedAt) }}
|
||||
</p>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" class="status" field="status"
|
||||
:label="$t('globals.fields.status')" width="10%" sortable
|
||||
:td-attrs="$utils.tdID" header-class="cy-status">
|
||||
<div>
|
||||
<p>
|
||||
<router-link :to="{ name: 'campaign', params: { 'id': props.row.id }}">
|
||||
<b-tag :class="props.row.status">
|
||||
{{ $t(`campaigns.status.${props.row.status}`) }}
|
||||
</b-tag>
|
||||
<span class="spinner is-tiny" v-if="isRunning(props.row.id)">
|
||||
<b-loading :is-full-page="false" active />
|
||||
</span>
|
||||
</router-link>
|
||||
</p>
|
||||
<p v-if="isSheduled(props.row)">
|
||||
<b-tooltip :label="$t('scheduled')" type="is-dark">
|
||||
<span class="is-size-7 has-text-grey scheduled">
|
||||
<b-icon icon="alarm" size="is-small" />
|
||||
{{ $utils.duration(Date(), props.row.sendAt, true) }}
|
||||
<br />{{ $utils.niceDate(props.row.sendAt, true) }}
|
||||
</span>
|
||||
</b-tooltip>
|
||||
</p>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="name" :label="$t('globals.fields.name')" width="25%"
|
||||
sortable header-class="cy-name">
|
||||
<div>
|
||||
<p>
|
||||
<b-tag v-if="props.row.type !== 'regular'" class="is-small">
|
||||
{{ props.row.type }}
|
||||
</b-tag>
|
||||
<router-link :to="{ name: 'campaign', params: { 'id': props.row.id }}">
|
||||
{{ props.row.name }}</router-link>
|
||||
</p>
|
||||
<p class="is-size-7 has-text-grey">{{ props.row.subject }}</p>
|
||||
<b-taglist>
|
||||
<b-tag class="is-small" v-for="t in props.row.tags" :key="t">{{ t }}</b-tag>
|
||||
</b-taglist>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" class="lists" field="lists"
|
||||
:label="$t('globals.terms.lists')" width="15%">
|
||||
<ul class="no">
|
||||
<li v-for="l in props.row.lists" :key="l.id">
|
||||
<router-link :to="{name: 'subscribers_list', params: { listID: l.id }}">
|
||||
{{ l.name }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="created_at" :label="$t('campaigns.timestamps')"
|
||||
width="19%" sortable header-class="cy-timestamp">
|
||||
<div class="fields timestamps" :set="stats = getCampaignStats(props.row)">
|
||||
<p>
|
||||
<label>{{ $t('globals.fields.createdAt') }}</label>
|
||||
{{ $utils.niceDate(props.row.createdAt, true) }}
|
||||
</p>
|
||||
<p v-if="stats.startedAt">
|
||||
<label>{{ $t('campaigns.startedAt') }}</label>
|
||||
{{ $utils.niceDate(stats.startedAt, true) }}
|
||||
</p>
|
||||
<p v-if="isDone(props.row)">
|
||||
<label>{{ $t('campaigns.ended') }}</label>
|
||||
{{ $utils.niceDate(stats.updatedAt, true) }}
|
||||
</p>
|
||||
<p v-if="stats.startedAt && stats.updatedAt"
|
||||
class="is-capitalized" title="Duration">
|
||||
<label><b-icon icon="alarm" size="is-small" /></label>
|
||||
{{ $utils.duration(stats.startedAt, stats.updatedAt) }}
|
||||
</p>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="stats" :class="props.row.status"
|
||||
:label="$t('campaigns.stats')" width="18%">
|
||||
<div class="fields stats" :set="stats = getCampaignStats(props.row)">
|
||||
<p>
|
||||
<label>{{ $t('campaigns.views') }}</label>
|
||||
{{ props.row.views }}
|
||||
</p>
|
||||
<p>
|
||||
<label>{{ $t('campaigns.clicks') }}</label>
|
||||
{{ props.row.clicks }}
|
||||
</p>
|
||||
<p>
|
||||
<label>{{ $t('campaigns.sent') }}</label>
|
||||
{{ stats.sent }} / {{ stats.toSend }}
|
||||
</p>
|
||||
<p title="Speed" v-if="stats.rate">
|
||||
<label><b-icon icon="speedometer" size="is-small"></b-icon></label>
|
||||
<span class="send-rate">
|
||||
{{ stats.rate.toFixed(0) }} / min
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="isRunning(props.row.id)">
|
||||
<label>{{ $t('campaigns.progress') }}
|
||||
<span class="spinner is-tiny">
|
||||
<b-loading :is-full-page="false" active />
|
||||
</span>
|
||||
</label>
|
||||
<b-progress :value="stats.sent / stats.toSend * 100" size="is-small" />
|
||||
</p>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="stats" :label="$t('campaigns.stats')" width="18%">
|
||||
<div class="fields stats" :set="stats = getCampaignStats(props.row)">
|
||||
<p>
|
||||
<label>{{ $t('campaigns.views') }}</label>
|
||||
{{ props.row.views }}
|
||||
</p>
|
||||
<p>
|
||||
<label>{{ $t('campaigns.clicks') }}</label>
|
||||
{{ props.row.clicks }}
|
||||
</p>
|
||||
<p>
|
||||
<label>{{ $t('campaigns.sent') }}</label>
|
||||
{{ stats.sent }} / {{ stats.toSend }}
|
||||
</p>
|
||||
<p title="Speed" v-if="stats.rate">
|
||||
<label><b-icon icon="speedometer" size="is-small"></b-icon></label>
|
||||
<span class="send-rate">
|
||||
{{ stats.rate.toFixed(0) }} / min
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="isRunning(props.row.id)">
|
||||
<label>{{ $t('campaigns.progress') }}
|
||||
<span class="spinner is-tiny">
|
||||
<b-loading :is-full-page="false" active />
|
||||
</span>
|
||||
</label>
|
||||
<b-progress :value="stats.sent / stats.toSend * 100" size="is-small" />
|
||||
</p>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column class="actions" width="13%" align="right">
|
||||
<div>
|
||||
<a href="" v-if="canStart(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'running'))" data-cy="btn-start">
|
||||
<b-tooltip :label="$t('campaigns.start')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canPause(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'paused'))" data-cy="btn-pause">
|
||||
<b-tooltip :label="$t('campaigns.pause')" type="is-dark">
|
||||
<b-icon icon="pause-circle-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canResume(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'running'))" data-cy="btn-resume">
|
||||
<b-tooltip :label="$t('campaigns.send')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canSchedule(props.row)"
|
||||
@click.prevent="$utils.confirm($t('campaigns.confirmSchedule'),
|
||||
() => changeCampaignStatus(props.row, 'scheduled'))" data-cy="btn-schedule">
|
||||
<b-tooltip :label="$t('campaigns.schedule')" type="is-dark">
|
||||
<b-icon icon="clock-start" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="previewCampaign(props.row)" data-cy="btn-preview">
|
||||
<b-tooltip :label="$t('campaigns.preview')" type="is-dark">
|
||||
<b-icon icon="file-find-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="$utils.prompt($t('globals.buttons.clone'),
|
||||
{ placeholder: $t('globals.fields.name'),
|
||||
value: $t('campaigns.copyOf', { name: props.row.name }) },
|
||||
(name) => cloneCampaign(name, props.row))"
|
||||
data-cy="btn-clone">
|
||||
<b-tooltip :label="$t('globals.buttons.clone')" type="is-dark">
|
||||
<b-icon icon="file-multiple-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canCancel(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'cancelled'))"
|
||||
data-cy="btn-cancel">
|
||||
<b-tooltip :label="$t('globals.buttons.cancel')" type="is-dark">
|
||||
<b-icon icon="cancel" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="$utils.confirm($tc('campaigns.confirmDelete'),
|
||||
() => deleteCampaign(props.row))" data-cy="btn-delete">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
</template>
|
||||
<template slot="empty" v-if="!loading.campaigns">
|
||||
<empty-placeholder />
|
||||
</template>
|
||||
<b-table-column v-slot="props" cell-class="actions" width="13%" align="right">
|
||||
<div>
|
||||
<a href="" v-if="canStart(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'running'))" data-cy="btn-start">
|
||||
<b-tooltip :label="$t('campaigns.start')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canPause(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'paused'))" data-cy="btn-pause">
|
||||
<b-tooltip :label="$t('campaigns.pause')" type="is-dark">
|
||||
<b-icon icon="pause-circle-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canResume(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'running'))" data-cy="btn-resume">
|
||||
<b-tooltip :label="$t('campaigns.send')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canSchedule(props.row)"
|
||||
@click.prevent="$utils.confirm($t('campaigns.confirmSchedule'),
|
||||
() => changeCampaignStatus(props.row, 'scheduled'))" data-cy="btn-schedule">
|
||||
<b-tooltip :label="$t('campaigns.schedule')" type="is-dark">
|
||||
<b-icon icon="clock-start" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="previewCampaign(props.row)" data-cy="btn-preview">
|
||||
<b-tooltip :label="$t('campaigns.preview')" type="is-dark">
|
||||
<b-icon icon="file-find-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="$utils.prompt($t('globals.buttons.clone'),
|
||||
{ placeholder: $t('globals.fields.name'),
|
||||
value: $t('campaigns.copyOf', { name: props.row.name }) },
|
||||
(name) => cloneCampaign(name, props.row))"
|
||||
data-cy="btn-clone">
|
||||
<b-tooltip :label="$t('globals.buttons.clone')" type="is-dark">
|
||||
<b-icon icon="file-multiple-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" v-if="canCancel(props.row)"
|
||||
@click.prevent="$utils.confirm(null,
|
||||
() => changeCampaignStatus(props.row, 'cancelled'))"
|
||||
data-cy="btn-cancel">
|
||||
<b-tooltip :label="$t('globals.buttons.cancel')" type="is-dark">
|
||||
<b-icon icon="cancel" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="$utils.confirm($tc('campaigns.confirmDelete'),
|
||||
() => deleteCampaign(props.row))" data-cy="btn-delete">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<template #empty v-if="!loading.campaigns">
|
||||
<empty-placeholder />
|
||||
</template>
|
||||
</b-table>
|
||||
|
||||
<campaign-preview v-if="previewItem"
|
||||
|
|
|
@ -22,84 +22,85 @@
|
|||
:current-page="queryParams.page" :per-page="lists.perPage" :total="lists.total"
|
||||
backend-sorting @sort="onSort"
|
||||
>
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="name" :label="$t('globals.fields.name')" header-class="cy-name"
|
||||
sortable width="25%" paginated backend-pagination pagination-position="both"
|
||||
@page-change="onPageChange" :data-id="props.row.id">
|
||||
<div>
|
||||
<router-link :to="{name: 'subscribers_list', params: { listID: props.row.id }}">
|
||||
{{ props.row.name }}
|
||||
</router-link>
|
||||
<b-taglist>
|
||||
<b-tag class="is-small" v-for="t in props.row.tags" :key="t">{{ t }}</b-tag>
|
||||
</b-taglist>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="name" :label="$t('globals.fields.name')"
|
||||
header-class="cy-name" sortable width="25%"
|
||||
paginated backend-pagination pagination-position="both"
|
||||
:td-attrs="$utils.tdID"
|
||||
@page-change="onPageChange">
|
||||
<div>
|
||||
<router-link :to="{name: 'subscribers_list', params: { listID: props.row.id }}">
|
||||
{{ props.row.name }}
|
||||
</router-link>
|
||||
<b-taglist>
|
||||
<b-tag class="is-small" v-for="t in props.row.tags" :key="t">{{ t }}</b-tag>
|
||||
</b-taglist>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="type" :label="$t('globals.fields.type')" header-class="cy-type"
|
||||
sortable>
|
||||
<div>
|
||||
<b-tag :class="props.row.type" :data-cy="`type-${props.row.type}`">
|
||||
{{ $t('lists.types.' + props.row.type) }}
|
||||
</b-tag>
|
||||
{{ ' ' }}
|
||||
<b-tag :data-cy="`optin-${props.row.optin}`">
|
||||
<b-icon :icon="props.row.optin === 'double' ?
|
||||
'account-check-outline' : 'account-off-outline'" size="is-small" />
|
||||
{{ ' ' }}
|
||||
{{ $t('lists.optins.' + props.row.optin) }}
|
||||
</b-tag>{{ ' ' }}
|
||||
<a v-if="props.row.optin === 'double'" class="is-size-7 send-optin"
|
||||
href="#" @click="$utils.confirm(null, () => createOptinCampaign(props.row))"
|
||||
data-cy="btn-send-optin-campaign">
|
||||
<b-tooltip :label="$t('lists.sendOptinCampaign')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
{{ $t('lists.sendOptinCampaign') }}
|
||||
</b-tooltip>
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="type" :label="$t('globals.fields.type')"
|
||||
header-class="cy-type" sortable>
|
||||
<div>
|
||||
<b-tag :class="props.row.type" :data-cy="`type-${props.row.type}`">
|
||||
{{ $t('lists.types.' + props.row.type) }}
|
||||
</b-tag>
|
||||
{{ ' ' }}
|
||||
<b-tag :data-cy="`optin-${props.row.optin}`">
|
||||
<b-icon :icon="props.row.optin === 'double' ?
|
||||
'account-check-outline' : 'account-off-outline'" size="is-small" />
|
||||
{{ ' ' }}
|
||||
{{ $t('lists.optins.' + props.row.optin) }}
|
||||
</b-tag>{{ ' ' }}
|
||||
<a v-if="props.row.optin === 'double'" class="is-size-7 send-optin"
|
||||
href="#" @click="$utils.confirm(null, () => createOptinCampaign(props.row))"
|
||||
data-cy="btn-send-optin-campaign">
|
||||
<b-tooltip :label="$t('lists.sendOptinCampaign')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
{{ $t('lists.sendOptinCampaign') }}
|
||||
</b-tooltip>
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="subscriber_count" :label="$t('globals.terms.subscribers')"
|
||||
header-class="cy-subscribers" numeric sortable centered>
|
||||
<router-link :to="`/subscribers/lists/${props.row.id}`">
|
||||
{{ props.row.subscriberCount }}
|
||||
</router-link>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="subscriber_count"
|
||||
:label="$t('globals.terms.subscribers')" header-class="cy-subscribers"
|
||||
numeric sortable centered>
|
||||
<router-link :to="`/subscribers/lists/${props.row.id}`">
|
||||
{{ props.row.subscriberCount }}
|
||||
</router-link>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="created_at" :label="$t('globals.fields.createdAt')"
|
||||
header-class="cy-created_at" sortable>
|
||||
{{ $utils.niceDate(props.row.createdAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column field="updated_at" :label="$t('globals.fields.updatedAt')"
|
||||
header-class="cy-updated_at" sortable>
|
||||
{{ $utils.niceDate(props.row.updatedAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="created_at" :label="$t('globals.fields.createdAt')"
|
||||
header-class="cy-created_at" sortable>
|
||||
{{ $utils.niceDate(props.row.createdAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="updated_at" :label="$t('globals.fields.updatedAt')"
|
||||
header-class="cy-updated_at" sortable>
|
||||
{{ $utils.niceDate(props.row.updatedAt) }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column class="actions" align="right">
|
||||
<div>
|
||||
<router-link :to="`/campaigns/new?list_id=${props.row.id}`" data-cy="btn-campaign">
|
||||
<b-tooltip :label="$t('lists.sendCampaign')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</router-link>
|
||||
<a href="" @click.prevent="showEditForm(props.row)" data-cy="btn-edit">
|
||||
<b-tooltip :label="$t('globals.buttons.edit')" type="is-dark">
|
||||
<b-icon icon="pencil-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="deleteList(props.row)" data-cy="btn-delete">
|
||||
<b-tooltip :label="$t('globals.buttons.delete')" type="is-dark">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
</template>
|
||||
<b-table-column v-slot="props" cell-class="actions" align="right">
|
||||
<div>
|
||||
<router-link :to="`/campaigns/new?list_id=${props.row.id}`" data-cy="btn-campaign">
|
||||
<b-tooltip :label="$t('lists.sendCampaign')" type="is-dark">
|
||||
<b-icon icon="rocket-launch-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</router-link>
|
||||
<a href="" @click.prevent="showEditForm(props.row)" data-cy="btn-edit">
|
||||
<b-tooltip :label="$t('globals.buttons.edit')" type="is-dark">
|
||||
<b-icon icon="pencil-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="deleteList(props.row)" data-cy="btn-delete">
|
||||
<b-tooltip :label="$t('globals.buttons.delete')" type="is-dark">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<template slot="empty" v-if="!loading.lists">
|
||||
<empty-placeholder />
|
||||
</template>
|
||||
<template #empty v-if="!loading.lists">
|
||||
<empty-placeholder />
|
||||
</template>
|
||||
</b-table>
|
||||
|
||||
<!-- Add / edit form modal -->
|
||||
|
|
|
@ -108,86 +108,85 @@
|
|||
paginated backend-pagination pagination-position="both" @page-change="onPageChange"
|
||||
:current-page="queryParams.page" :per-page="subscribers.perPage" :total="subscribers.total"
|
||||
hoverable checkable backend-sorting @sort="onSort">
|
||||
<template slot="top-left">
|
||||
<template #top-left>
|
||||
<a href='' @click.prevent="exportSubscribers">
|
||||
<b-icon icon="cloud-download-outline" size="is-small" /> {{ $t('subscribers.export') }}
|
||||
</a>
|
||||
</template>
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="status" :label="$t('globals.fields.status')"
|
||||
header-class="cy-status" :data-id="props.row.id" sortable>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)">
|
||||
<b-tag :class="props.row.status">
|
||||
{{ $t('subscribers.status.'+ props.row.status) }}
|
||||
<b-table-column v-slot="props" field="status" :label="$t('globals.fields.status')"
|
||||
header-class="cy-status" :td-attrs="$utils.tdID" sortable>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)">
|
||||
<b-tag :class="props.row.status">
|
||||
{{ $t('subscribers.status.'+ props.row.status) }}
|
||||
</b-tag>
|
||||
</a>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column v-slot="props" field="email" :label="$t('subscribers.email')"
|
||||
header-class="cy-email" sortable>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)">
|
||||
{{ props.row.email }}
|
||||
</a>
|
||||
<b-taglist>
|
||||
<template v-for="l in props.row.lists">
|
||||
<router-link :to="`/subscribers/lists/${l.id}`"
|
||||
v-bind:key="l.id" style="padding-right:0.5em;">
|
||||
<b-tag :class="l.subscriptionStatus" size="is-small" :key="l.id">
|
||||
{{ l.name }}
|
||||
<sup>{{ $t('subscribers.status.'+ l.subscriptionStatus) }}</sup>
|
||||
</b-tag>
|
||||
</a>
|
||||
</b-table-column>
|
||||
</router-link>
|
||||
</template>
|
||||
</b-taglist>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="email" :label="$t('subscribers.email')"
|
||||
header-class="cy-email" sortable>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)">
|
||||
{{ props.row.email }}
|
||||
</a>
|
||||
<b-taglist>
|
||||
<template v-for="l in props.row.lists">
|
||||
<router-link :to="`/subscribers/lists/${l.id}`"
|
||||
v-bind:key="l.id" style="padding-right:0.5em;">
|
||||
<b-tag :class="l.subscriptionStatus" size="is-small" :key="l.id">
|
||||
{{ l.name }}
|
||||
<sup>{{ $t('subscribers.status.'+ l.subscriptionStatus) }}</sup>
|
||||
</b-tag>
|
||||
</router-link>
|
||||
</template>
|
||||
</b-taglist>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="name" :label="$t('globals.fields.name')"
|
||||
header-class="cy-name" sortable>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)">
|
||||
{{ props.row.name }}
|
||||
</a>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="name" :label="$t('globals.fields.name')"
|
||||
header-class="cy-name" sortable>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)">
|
||||
{{ props.row.name }}
|
||||
</a>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="lists" :label="$t('globals.terms.lists')"
|
||||
header-class="cy-lists" centered>
|
||||
{{ listCount(props.row.lists) }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="lists" :label="$t('globals.terms.lists')"
|
||||
header-class="cy-lists" numeric centered>
|
||||
{{ listCount(props.row.lists) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="created_at" :label="$t('globals.fields.createdAt')"
|
||||
header-class="cy-created_at" sortable>
|
||||
{{ $utils.niceDate(props.row.createdAt) }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="created_at" :label="$t('globals.fields.createdAt')"
|
||||
header-class="cy-created_at" sortable>
|
||||
{{ $utils.niceDate(props.row.createdAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="updated_at" :label="$t('globals.fields.updatedAt')"
|
||||
header-class="cy-updated_at" sortable>
|
||||
{{ $utils.niceDate(props.row.updatedAt) }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="updated_at" :label="$t('globals.fields.updatedAt')"
|
||||
header-class="cy-updated_at" sortable>
|
||||
{{ $utils.niceDate(props.row.updatedAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" label="Actions" cell-class="actions" align="right">
|
||||
<div>
|
||||
<a :href="`/api/subscribers/${props.row.id}/export`" data-cy="btn-download">
|
||||
<b-tooltip :label="$t('subscribers.downloadData')" type="is-dark">
|
||||
<b-icon icon="cloud-download-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)" data-cy="btn-edit">
|
||||
<b-tooltip :label="$t('globals.buttons.edit')" type="is-dark">
|
||||
<b-icon icon="pencil-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href='' @click.prevent="deleteSubscriber(props.row)" data-cy="btn-delete">
|
||||
<b-tooltip :label="$t('globals.buttons.delete')" type="is-dark">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column class="actions" align="right">
|
||||
<div>
|
||||
<a :href="`/api/subscribers/${props.row.id}/export`" data-cy="btn-download">
|
||||
<b-tooltip :label="$t('subscribers.downloadData')" type="is-dark">
|
||||
<b-icon icon="cloud-download-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a :href="`/subscribers/${props.row.id}`"
|
||||
@click.prevent="showEditForm(props.row)" data-cy="btn-edit">
|
||||
<b-tooltip :label="$t('globals.buttons.edit')" type="is-dark">
|
||||
<b-icon icon="pencil-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href='' @click.prevent="deleteSubscriber(props.row)" data-cy="btn-delete">
|
||||
<b-tooltip :label="$t('globals.buttons.delete')" type="is-dark">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
</div>
|
||||
</b-table-column>
|
||||
</template>
|
||||
<template slot="empty" v-if="!loading.subscribers">
|
||||
<template #empty v-if="!loading.subscribers">
|
||||
<empty-placeholder />
|
||||
</template>
|
||||
</b-table>
|
||||
|
|
|
@ -14,70 +14,71 @@
|
|||
|
||||
<b-table :data="templates" :hoverable="true" :loading="loading.templates"
|
||||
default-sort="createdAt">
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="name" :label="$t('globals.fields.name')" sortable>
|
||||
<a :href="props.row.id" @click.prevent="showEditForm(props.row)">
|
||||
{{ props.row.name }}
|
||||
</a>
|
||||
<b-tag v-if="props.row.isDefault">{{ $t('templates.default') }}</b-tag>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="name" :label="$t('globals.fields.name')"
|
||||
:td-attrs="$utils.tdID" sortable>
|
||||
<a :href="props.row.id" @click.prevent="showEditForm(props.row)">
|
||||
{{ props.row.name }}
|
||||
</a>
|
||||
<b-tag v-if="props.row.isDefault">{{ $t('templates.default') }}</b-tag>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="createdAt" :label="$t('globals.fields.createdAt')" sortable>
|
||||
{{ $utils.niceDate(props.row.createdAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="createdAt"
|
||||
:label="$t('globals.fields.createdAt')" sortable>
|
||||
{{ $utils.niceDate(props.row.createdAt) }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="updatedAt" :label="$t('globals.fields.updatedAt')" sortable>
|
||||
{{ $utils.niceDate(props.row.updatedAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="updatedAt"
|
||||
:label="$t('globals.fields.updatedAt')" sortable>
|
||||
{{ $utils.niceDate(props.row.updatedAt) }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column class="actions" align="right">
|
||||
<div>
|
||||
<a href="#" @click.prevent="previewTemplate(props.row)" data-cy="btn-preview">
|
||||
<b-tooltip :label="$t('templates.preview')" type="is-dark">
|
||||
<b-icon icon="file-find-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="#" @click.prevent="showEditForm(props.row)" data-cy="btn-edit">
|
||||
<b-tooltip :label="$t('globals.buttons.edit')" type="is-dark">
|
||||
<b-icon icon="pencil-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="$utils.prompt(`Clone template`,
|
||||
{ placeholder: 'Name', value: `Copy of ${props.row.name}`},
|
||||
(name) => cloneTemplate(name, props.row))"
|
||||
data-cy="btn-clone">
|
||||
<b-tooltip :label="$t('globals.buttons.clone')" type="is-dark">
|
||||
<b-icon icon="file-multiple-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a v-if="!props.row.isDefault" href="#"
|
||||
@click.prevent="$utils.confirm(null, () => makeTemplateDefault(props.row))"
|
||||
data-cy="btn-set-default">
|
||||
<b-tooltip :label="$t('templates.makeDefault')" type="is-dark">
|
||||
<b-icon icon="check-circle-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<span v-else class="a has-text-grey-light">
|
||||
<b-icon icon="check-circle-outline" size="is-small" />
|
||||
</span>
|
||||
<b-table-column v-slot="props" cell-class="actions" align="right">
|
||||
<div>
|
||||
<a href="#" @click.prevent="previewTemplate(props.row)" data-cy="btn-preview">
|
||||
<b-tooltip :label="$t('templates.preview')" type="is-dark">
|
||||
<b-icon icon="file-find-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="#" @click.prevent="showEditForm(props.row)" data-cy="btn-edit">
|
||||
<b-tooltip :label="$t('globals.buttons.edit')" type="is-dark">
|
||||
<b-icon icon="pencil-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a href="" @click.prevent="$utils.prompt(`Clone template`,
|
||||
{ placeholder: 'Name', value: `Copy of ${props.row.name}`},
|
||||
(name) => cloneTemplate(name, props.row))"
|
||||
data-cy="btn-clone">
|
||||
<b-tooltip :label="$t('globals.buttons.clone')" type="is-dark">
|
||||
<b-icon icon="file-multiple-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<a v-if="!props.row.isDefault" href="#"
|
||||
@click.prevent="$utils.confirm(null, () => makeTemplateDefault(props.row))"
|
||||
data-cy="btn-set-default">
|
||||
<b-tooltip :label="$t('templates.makeDefault')" type="is-dark">
|
||||
<b-icon icon="check-circle-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<span v-else class="a has-text-grey-light">
|
||||
<b-icon icon="check-circle-outline" size="is-small" />
|
||||
</span>
|
||||
|
||||
<a v-if="!props.row.isDefault" href="#"
|
||||
@click.prevent="$utils.confirm(null, () => deleteTemplate(props.row))"
|
||||
data-cy="btn-delete">
|
||||
<b-tooltip :label="$t('globals.buttons.delete')" type="is-dark">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<span v-else class="a has-text-grey-light">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</span>
|
||||
</div>
|
||||
</b-table-column>
|
||||
</template>
|
||||
<a v-if="!props.row.isDefault" href="#"
|
||||
@click.prevent="$utils.confirm(null, () => deleteTemplate(props.row))"
|
||||
data-cy="btn-delete">
|
||||
<b-tooltip :label="$t('globals.buttons.delete')" type="is-dark">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</b-tooltip>
|
||||
</a>
|
||||
<span v-else class="a has-text-grey-light">
|
||||
<b-icon icon="trash-can-outline" size="is-small" />
|
||||
</span>
|
||||
</div>
|
||||
</b-table-column>
|
||||
|
||||
<template slot="empty" v-if="!loading.templates">
|
||||
<empty-placeholder />
|
||||
</template>
|
||||
<template #empty v-if="!loading.templates">
|
||||
<empty-placeholder />
|
||||
</template>
|
||||
</b-table>
|
||||
|
||||
<!-- Add / edit form modal -->
|
||||
|
|
18
frontend/yarn.lock
vendored
18
frontend/yarn.lock
vendored
|
@ -2606,12 +2606,12 @@ browserslist@^4.14.5, browserslist@^4.16.6:
|
|||
escalade "^3.1.1"
|
||||
node-releases "^1.1.71"
|
||||
|
||||
buefy@^0.8.20:
|
||||
version "0.8.20"
|
||||
resolved "https://registry.yarnpkg.com/buefy/-/buefy-0.8.20.tgz#75708800548220654575903d031a81fc8575b7f3"
|
||||
integrity sha512-pg8Cn0m9cjqp2/vaKT4VIfU8KIumuX/gAT1GtearXRs56+kKqAPx3j9O8cm9W6P4jPUCHajKX6H8AqD0ram2Bg==
|
||||
buefy@^0.9.7:
|
||||
version "0.9.7"
|
||||
resolved "https://registry.yarnpkg.com/buefy/-/buefy-0.9.7.tgz#694e73fe0b32632a53d94c5ba9cfa4468363badd"
|
||||
integrity sha512-Fli0ZjNDgtFtHm0LItWmfhNJ1oLjDwPzUWccvwXXoo2mADXaH8JQxyhY+drUuUV5/GMu5PtwqQSqPgZy942VZg==
|
||||
dependencies:
|
||||
bulma "0.7.5"
|
||||
bulma "0.9.2"
|
||||
|
||||
buffer-crc32@~0.2.3:
|
||||
version "0.2.13"
|
||||
|
@ -2652,10 +2652,10 @@ builtin-status-codes@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
||||
|
||||
bulma@0.7.5:
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.7.5.tgz#35066c37f82c088b68f94450be758fc00a967208"
|
||||
integrity sha512-cX98TIn0I6sKba/DhW0FBjtaDpxTelU166pf7ICXpCCuplHWyu6C9LYZmL5PEsnePIeJaiorsTEzzNk3Tsm1hw==
|
||||
bulma@0.9.2:
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.2.tgz#340011e119c605f19b8ca886bfea595f1deaf23c"
|
||||
integrity sha512-e14EF+3VSZ488yL/lJH0tR8mFWiEQVCMi/BQUMi2TGMBOk+zrDg4wryuwm/+dRSHJw0gMawp2tsW7X1JYUCE3A==
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
|
|
Loading…
Reference in a new issue