Merge branch 'webpack-tweaking' into 'develop'

Improve front-end performance

See merge request funkwhale/funkwhale!499
merge-requests/552/head
Eliot Berriot 2018-12-20 13:50:05 +01:00
commit e1450d28b8
68 zmienionych plików z 3856 dodań i 42770 usunięć

1
.gitignore vendored
Wyświetl plik

@ -93,5 +93,6 @@ po/*.po
docs/swagger
_build
front/src/translations.json
front/src/translations/*.json
front/locales/en_US/LC_MESSAGES/app.po
*.prof

Wyświetl plik

@ -58,15 +58,6 @@ class RavenDSN(types.StringPreference):
field_kwargs = {"required": False}
@global_preferences_registry.register
class RavenEnabled(types.BooleanPreference):
show_in_api = True
section = raven
name = "front_enabled"
default = False
verbose_name = "Report front-end errors with Raven"
@global_preferences_registry.register
class InstanceNodeinfoEnabled(types.BooleanPreference):
show_in_api = False

Wyświetl plik

@ -0,0 +1,51 @@
Improved front-end performance by stripping unused dependencies, reducing bundle size
and enabling gzip compression
Enable gzip compression [manual action suggested]
-------------------------------------------------
Gzip compression will be enabled on new instances by default
and will reduce the amount of bandwidth consumed by your instance.
If you with to benefit from gzip compression on your instance,
edit your reverse proxy virtualhost file (located at ``/etc/nginx/sites-available/funkwhale.conf``) and add the following snippet
in the server block, then reload your nginx server::
server {
# ... exiting configuration
# compression settings
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/activity+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
# end of compression settings
}

Wyświetl plik

@ -29,6 +29,40 @@ server {
# HSTS
add_header Strict-Transport-Security "max-age=31536000";
# compression settings
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/activity+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
location / {
include /etc/nginx/funkwhale_proxy.conf;
proxy_pass http://fw/;

Wyświetl plik

@ -43,6 +43,41 @@ server {
root ${FUNKWHALE_FRONTEND_PATH};
# compression settings
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/activity+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
# end of compression settings
location / {
include /etc/nginx/funkwhale_proxy.conf;
# this is needed if you have file import via upload enabled

Wyświetl plik

@ -43,6 +43,39 @@ http {
charset utf-8;
client_max_body_size 30M;
include /etc/nginx/funkwhale_proxy.conf;
# compression settings
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/activity+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
location /front/ {
proxy_pass http://funkwhale-front/front/;

Wyświetl plik

@ -182,7 +182,7 @@ work. We will store the necessary files in the ``/srv/funkwhale/custom`` directo
mkdir custom
cat <<EOF > custom/settings.json
{
"additionalStylesheets": ["/custom/custom.css"]
"additionalStylesheets": ["/front/custom/custom.css"]
}
EOF
cat <<EOF > custom/custom.css
@ -194,7 +194,7 @@ work. We will store the necessary files in the ``/srv/funkwhale/custom`` directo
By executing the previous commands, you will end up with two files in your ``/srv/funkwhale/custom``
directory:
- ``settings.json`` will tell the front-end what stylesheets you want to load (``/custom/custom.css`` in this example)
- ``settings.json`` will tell the front-end what stylesheets you want to load (``/front/custom/custom.css`` in this example)
- ``custom.css`` will hold your custom CSS
The last step to make this work is to ensure both files are served by the reverse proxy.

Wyświetl plik

@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "scripts/i18n-compile.sh && vue-cli-service serve --port ${VUE_PORT:-8000} --host ${VUE_HOST:-0.0.0.0}",
"serve": "vue-cli-service serve --port ${VUE_PORT:-8000} --host ${VUE_HOST:-0.0.0.0}",
"build": "scripts/i18n-compile.sh && vue-cli-service build",
"lint": "vue-cli-service lint",
"i18n-extract": "scripts/i18n-extract.sh",
@ -20,8 +20,7 @@
"lodash": "^4.17.10",
"masonry-layout": "^4.2.2",
"moment": "^2.22.2",
"raven-js": "^3.26.4",
"semantic-ui-css": "^2.3.3",
"semantic-ui-css": "^2.4.1",
"showdown": "^1.8.6",
"vue": "^2.5.17",
"vue-gettext": "^2.1.0",
@ -49,7 +48,8 @@
"node-sass": "^4.9.3",
"sass-loader": "^7.1.0",
"sinon": "^6.1.5",
"vue-template-compiler": "^2.5.17"
"vue-template-compiler": "^2.5.17",
"webpack-bundle-size-analyzer": "^3.0.0"
},
"eslintConfig": {
"root": true,

Wyświetl plik

@ -1,3 +1,5 @@
{
"additionalStylesheets": ["/custom.css"]
"additionalStylesheets": [
"/front/custom.css"
]
}

Wyświetl plik

@ -1,3 +1,7 @@
#!/bin/bash -eux
locales=$(tail -n +2 src/locales.js | sed -e 's/export default //' | jq '.locales[].code' | xargs echo)
find locales -name '*.po' | xargs $(yarn bin)/gettext-compile --output src/translations.json
locales=$(tail -n +2 src/locales.js | sed -e 's/export default //' | jq '.locales[].code' | grep -v 'en_US' | xargs echo)
for locale in $locales; do
find "locales/$locale" -name '*.po' | $(yarn bin)/gettext-compile locales/$locale/LC_MESSAGES/app.po --output src/translations/$locale.json
done
# find locales -name '*.po' | xargs $(yarn bin)/gettext-compile --output src/translations.json

Wyświetl plik

@ -43,10 +43,6 @@
:version="version"
@show:shortcuts-modal="showShortcutsModal = !showShortcutsModal"
></app-footer>
<raven
v-if="$store.state.instance.settings.raven.front_enabled.value"
:dsn="$store.state.instance.settings.raven.front_dsn.value"
></raven>
<playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal>
<shortcuts-modal @update:show="showShortcutsModal = $event" :show="showShortcutsModal"></shortcuts-modal>
<GlobalEvents @keydown.h.exact="showShortcutsModal = !showShortcutsModal"/>
@ -56,18 +52,16 @@
<script>
import axios from 'axios'
import _ from 'lodash'
import _ from '@/lodash'
import {mapState} from 'vuex'
import { WebSocketBridge } from 'django-channels'
import GlobalEvents from '@/components/utils/global-events'
import translations from '@/translations'
import Sidebar from '@/components/Sidebar'
import AppFooter from '@/components/Footer'
import Raven from '@/components/Raven'
import ServiceMessages from '@/components/ServiceMessages'
import locales from './locales'
import PlaylistModal from '@/components/playlists/PlaylistModal'
import ShortcutsModal from '@/components/ShortcutsModal'
@ -76,7 +70,6 @@ export default {
components: {
Sidebar,
AppFooter,
Raven,
PlaylistModal,
ShortcutsModal,
GlobalEvents,
@ -139,7 +132,7 @@ export default {
},
autodetectLanguage () {
let userLanguage = navigator.language || navigator.userLanguage
let available = _.keys(translations)
let available = locales.locales.map(e => { return e.code })
let matching = available.filter((a) => {
return userLanguage.replace('-', '_') === a
})
@ -223,181 +216,5 @@ export default {
</script>
<style lang="scss">
// we do the import here instead in main.js
// as resolve order is not deterministric in webpack
// and we end up with CSS rules not applied,
// see https://github.com/webpack/webpack/issues/215
@import "semantic/semantic.css";
@import "style/vendor/media";
html,
body {
@include media("<desktop") {
font-size: 90%;
}
}
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.instance-chooser {
margin-top: 2em;
}
.main.pusher,
.footer {
@include media(">desktop") {
margin-left: 350px !important;
margin-top: 50px;
}
transform: none !important;
}
.main.pusher > .ui.secondary.menu {
margin-left: 0;
margin-right: 0;
border: none;
box-shadow: inset 0px -2px 0px 0px rgba(34, 36, 38, 0.15);
.ui.item {
border: none;
border-bottom-style: none;
margin-bottom: 0px;
&.active {
box-shadow: inset 0px -2px 0px 0px #000;
}
}
@include media(">tablet") {
padding: 0 2.5rem;
}
@include media(">desktop") {
position: fixed;
left: 350px;
right: 0px;
top: 0px;
z-index: 99;
}
background-color: white;
.item {
padding-top: 1.5em;
padding-bottom: 1.5em;
}
}
.service-messages {
position: fixed;
bottom: 1em;
left: 1em;
@include media(">desktop") {
left: 350px;
}
}
.main-pusher {
padding: 1.5rem 0;
}
.ui.stripe.segment,
#footer {
padding: 2em;
@include media(">tablet") {
padding: 4em;
}
}
.ellipsis {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.ui.small.text.container {
max-width: 500px !important;
}
.button.icon.tiny {
padding: 0.5em !important;
}
.sidebar {
.logo {
path {
fill: white;
}
}
}
.discrete {
color: rgba(0, 0, 0, 0.87);
}
.link {
cursor: pointer;
}
.ui.really.basic.button {
&:not(:focus) {
box-shadow: none !important;
background-color: none !important;
}
}
.floated.buttons .button ~ .dropdown {
border-left: none;
}
.ui.icon.header .circular.icon {
display: flex;
justify-content: center;
}
.segment-content .button {
margin: 0.5em;
}
a {
cursor: pointer;
}
.segment.hidden {
display: none;
}
button.reset {
border: none;
margin: 0;
padding: 0;
width: auto;
overflow: visible;
background: transparent;
/* inherit font & color from ancestor */
color: inherit;
font: inherit;
/* Normalize `line-height`. Cannot be changed from `normal` in Firefox 4+. */
line-height: normal;
/* Corrects font smoothing for webkit */
-webkit-font-smoothing: inherit;
-moz-osx-font-smoothing: inherit;
/* Corrects inability to style clickable `input` types in iOS */
-webkit-appearance: none;
text-align: inherit;
}
.ui.table > caption {
font-weight: bold;
padding: 0.5em;
text-align: left;
}
[role="button"] {
cursor: pointer;
}
.left.floated {
float: left;
}
.right.floated {
float: right;
}
@import "style/_main";
</style>

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 67 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 21 KiB

Wyświetl plik

@ -27,9 +27,9 @@
<p>{{ instance.short_description.value }}</p>
</div>
<div
v-if="instance.long_description.value"
v-if="markdown && instance.long_description.value"
class="ui middle aligned stackable text container"
v-html="$options.filters.markdown(instance.long_description.value)">
v-html="markdown.makeHtml(instance.long_description.value)">
</div>
</section>
</main>
@ -43,8 +43,17 @@ export default {
components: {
Stats
},
created() {
data () {
return {
markdown: null
}
},
created () {
this.$store.dispatch("instance/fetchSettings")
let self = this
import('showdown').then(module => {
self.markdown = new module.default.Converter()
})
},
computed: {
...mapState({

Wyświetl plik

@ -20,7 +20,7 @@
<div class="ui form">
<div class="ui field">
<label><translate>Change language</translate></label>
<select class="ui dropdown" v-model="$language.current">
<select class="ui dropdown" :value="$language.current" @change="updateLanguage($event.target.value)">
<option v-for="(language, key) in $language.available" :key="key" :value="key">{{ language }}</option>
</select>
</div>
@ -60,7 +60,9 @@
</template>
<script>
import Vue from "vue"
import { mapState } from "vuex"
import axios from 'axios'
export default {
props: ["version"],
@ -74,6 +76,13 @@ export default {
if (confirm) {
this.$store.commit("instance/instanceUrl", null)
}
},
updateLanguage(value) {
let self = this
import(`../translations/${value}.json`).then((response) =>{
Vue.$translations[value] = response.default[value]
self.$language.current = value
})
}
},
computed: {

Wyświetl plik

@ -24,7 +24,7 @@
</template>
<script>
import _ from "lodash"
import _ from "@/lodash"
export default {
props: {

Wyświetl plik

@ -1,40 +0,0 @@
<template>
<div class="raven"></div>
</template>
<script>
import Raven from 'raven-js'
import RavenVue from 'raven-js/plugins/vue'
import Vue from 'vue'
import logger from '@/logging'
export default {
props: ['dsn'],
created () {
Raven.uninstall()
this.setUp()
},
destroyed () {
Raven.uninstall()
},
methods: {
setUp () {
Raven.uninstall()
logger.default.info('Installing raven...')
Raven.config(this.dsn).addPlugin(RavenVue, Vue).install()
}
},
watch: {
dsn: function () {
this.setUp()
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped >
.raven {
display: none;
}
</style>

Wyświetl plik

@ -16,8 +16,8 @@
<div class="menu-area">
<div class="ui compact fluid two item inverted menu">
<a class="active item" role="button" @click.prevent.stop="selectedTab = 'library'" data-tab="library"><translate>Browse</translate></a>
<a class="item" role="button" @click.prevent.stop="selectedTab = 'queue'" data-tab="queue">
<a :class="[{active: selectedTab === 'library'}, 'item']" role="button" @click.prevent.stop="selectedTab = 'library'" data-tab="library"><translate>Browse</translate></a>
<a :class="[{active: selectedTab === 'queue'}, 'item']" role="button" @click.prevent.stop="selectedTab = 'queue'" data-tab="queue">
<translate>Queue</translate>&nbsp;
<template v-if="queue.tracks.length === 0">
<translate>(empty)</translate>
@ -29,7 +29,7 @@
</div>
</div>
<div class="tabs">
<section class="ui bottom attached active tab" data-tab="library" :aria-label="labels.mainMenu">
<section :class="['ui', 'bottom', 'attached', {active: selectedTab === 'library'}, 'tab']" :aria-label="labels.mainMenu">
<nav class="ui inverted vertical large fluid menu" role="navigation" :aria-label="labels.mainMenu">
<div class="item">
<header class="header"><translate>My account</translate></header>
@ -39,7 +39,7 @@
<translate :translate-params="{username: $store.state.auth.username}">
Logged in as %{ username }
</translate>
<img class="ui right floated circular tiny avatar image" v-if="$store.state.auth.profile.avatar.square_crop" :src="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.square_crop)" />
<img class="ui right floated circular tiny avatar image" v-if="$store.state.auth.profile.avatar.square_crop" v-lazy="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.square_crop)" />
</router-link>
<router-link class="item" v-if="$store.state.auth.authenticated" :to="{path: '/settings'}"><i class="setting icon"></i><translate>Settings</translate></router-link>
<router-link class="item" v-if="$store.state.auth.authenticated" :to="{name: 'notifications'}">
@ -113,7 +113,7 @@
</div>
</div>
</div>
<section class="ui bottom attached tab" data-tab="queue">
<section :class="['ui', 'bottom', 'attached', {active: selectedTab === 'queue'}, 'tab']">
<table class="ui compact inverted very basic fixed single line unstackable table">
<draggable v-model="tracks" element="tbody" @update="reorder">
<tr
@ -188,11 +188,6 @@ export default {
fetchInterval: null
}
},
mounted() {
$(this.$el)
.find(".menu .item")
.tab()
},
destroy() {
if (this.fetchInterval) {
clearInterval(this.fetchInterval)
@ -206,10 +201,8 @@ export default {
labels() {
let mainMenu = this.$gettext("Main menu")
let selectTrack = this.$gettext("Play this track")
let pendingRequests = this.$gettext("Pending import requests")
let pendingFollows = this.$gettext("Pending follow requests")
return {
pendingRequests,
pendingFollows,
mainMenu,
selectTrack

Wyświetl plik

@ -29,7 +29,7 @@
</template>
<script>
import _ from 'lodash'
import _ from '@/lodash'
import axios from 'axios'
import logger from '@/logging'
import AlbumCard from '@/components/audio/album/Card'

Wyświetl plik

@ -4,7 +4,7 @@
<script>
import {mapState} from 'vuex'
import _ from 'lodash'
import _ from '@/lodash'
import url from '@/utils/url'
import {Howl} from 'howler'

Wyświetl plik

@ -11,7 +11,7 @@
<div class="ui loader"></div>
</div>
<div class="card" v-for="album in albums" :key="album.id">
<div :class="['ui', 'image', 'with-overlay', {'default-cover': !album.cover.original}]" :style="getImageStyle(album)">
<div :class="['ui', 'image', 'with-overlay', {'default-cover': !album.cover.original}]" v-lazy:background-image="getImageUrl(album)">
<play-button class="play-overlay" :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :album="album.id"></play-button>
</div>
<div class="content">
@ -36,7 +36,7 @@
</template>
<script>
import _ from 'lodash'
import _ from '@/lodash'
import axios from 'axios'
import PlayButton from '@/components/audio/PlayButton'
@ -87,17 +87,15 @@ export default {
this.offset = Math.max(this.offset - this.limit, 0)
}
},
getImageStyle (album) {
getImageUrl (album) {
let url = '../../../assets/audio/default-cover.png'
if (album.cover.original) {
url = this.$store.getters['instance/absoluteUrl'](album.cover.medium_square_crop)
} else {
return {}
}
return {
'background-image': `url("${url}")`
return null
}
return url
}
},
watch: {
@ -108,10 +106,10 @@ export default {
}
</script>
<style scoped lang="scss">
@import '../../../style/vendor/media';
@import "../../../style/vendor/media";
.default-cover {
background-image: url('../../../assets/audio/default-cover.png') !important;
background-image: url("../../../assets/audio/default-cover.png") !important;
}
.wrapper {

Wyświetl plik

@ -11,7 +11,7 @@
<tbody>
<tr v-for="album in albums">
<td>
<img class="ui mini image" v-if="album.cover.original" :src="$store.getters['instance/absoluteUrl'](album.cover.small_square_crop)">
<img class="ui mini image" v-if="album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](album.cover.small_square_crop)">
<img class="ui mini image" v-else src="../../../assets/audio/default-cover.png">
</td>
<td colspan="4">
@ -82,5 +82,4 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -47,7 +47,7 @@
</template>
<script>
import _ from 'lodash'
import _ from '@/lodash'
import axios from 'axios'
import PlayButton from '@/components/audio/PlayButton'
@ -109,7 +109,7 @@ export default {
</script>
<style scoped lang="scss">
@import '../../../style/vendor/media';
@import "../../../style/vendor/media";
.play-overlay {
position: absolute;

Wyświetl plik

@ -7,7 +7,7 @@
<div :class="['ui', 'head', 'vertical', 'center', 'aligned', 'stripe', 'segment']">
<h2 class="ui center aligned icon header">
<i v-if="!profile.avatar.square_crop" class="circular inverted user green icon"></i>
<img class="ui big circular image" v-else :src="$store.getters['instance/absoluteUrl'](profile.avatar.square_crop)" />
<img class="ui big circular image" v-else v-lazy="$store.getters['instance/absoluteUrl'](profile.avatar.square_crop)" />
<div class="content">
{{ profile.username }}
<div class="sub header" v-translate="{date: signupDate}">Registered since %{ date }</div>

Wyświetl plik

@ -53,7 +53,7 @@
</div>
<div class="ui six wide column">
<h3 class="ui header"><translate>Current avatar</translate></h3>
<img class="ui circular image" v-if="currentAvatar && currentAvatar.square_crop" :src="$store.getters['instance/absoluteUrl'](currentAvatar.medium_square_crop)" />
<img class="ui circular image" v-if="currentAvatar && currentAvatar.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](currentAvatar.medium_square_crop)" />
<div class="ui hidden divider"></div>
<button @click="removeAvatar" v-if="currentAvatar && currentAvatar.square_crop" :class="['ui', {'loading': isLoadingAvatar}, ,'yellow', 'button']">
<translate>Remove avatar</translate>

Wyświetl plik

@ -3,7 +3,7 @@
<img
class="ui tiny circular avatar"
v-if="user.avatar && user.avatar.small_square_crop"
:src="$store.getters['instance/absoluteUrl'](user.avatar.small_square_crop)" />
v-lazy="$store.getters['instance/absoluteUrl'](user.avatar.small_square_crop)" />
<span v-else :style="defaultAvatarStyle" class="ui circular label">{{ user.username[0]}}</span>
&nbsp;@{{ user.username }}
</span>

Wyświetl plik

@ -1,53 +0,0 @@
<template>
<div class="comment">
<div class="content">
<a class="author">{{ user.username }}</a>
<div class="metadata">
<div class="date"><human-date :date="date"></human-date></div>
</div>
<div class="text" v-html="comment"></div>
</div>
<div class="actions">
<span
@click="collapsed = false"
v-if="truncated && collapsed"
class="expand">
<translate>Expand</translate>
</span>
<span
@click="collapsed = true"
v-if="truncated && !collapsed"
class="collapse">
<translate>Collapse</translate>
</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
user: {type: Object, required: true},
date: {required: true},
content: {type: String, required: true}
},
data () {
return {
collapsed: true,
length: 50
}
},
computed: {
comment () {
let text = this.content
if (this.collapsed) {
text = this.$options.filters.truncate(text, this.length)
}
return this.$options.filters.markdown(text)
},
truncated () {
return this.content.length > this.length
}
}
}
</script>

Wyświetl plik

@ -26,7 +26,7 @@
</template>
<script>
import _ from 'lodash'
import _ from '@/lodash'
import axios from 'axios'
import LibraryCard from '@/views/content/remote/Card'

Wyświetl plik

@ -61,7 +61,7 @@
</template>
<script>
import _ from 'lodash'
import _ from '@/lodash'
import axios from 'axios'
import logger from '@/logging'

Wyświetl plik

@ -69,7 +69,7 @@
</template>
<script>
import _ from "lodash"
import _ from "@/lodash"
import axios from "axios"
import logger from "@/logging"
import backend from "@/audio/backend"

Wyświetl plik

@ -70,7 +70,7 @@
<script>
import axios from "axios"
import _ from "lodash"
import _ from "@/lodash"
import $ from "jquery"
import logger from "@/logging"

Wyświetl plik

@ -123,6 +123,7 @@
</template>
<script>
import _ from "@/lodash"
import $ from "jquery";
import axios from "axios";
import logger from "@/logging";

Wyświetl plik

@ -92,7 +92,7 @@
<script>
import axios from "axios"
import _ from "lodash"
import _ from "@/lodash"
import $ from "jquery"
import logger from "@/logging"

Wyświetl plik

@ -94,7 +94,7 @@
<script>
import axios from "axios"
import $ from "jquery"
import _ from "lodash"
import _ from "@/lodash"
import BuilderFilter from "./Filter"
import TrackTable from "@/components/audio/track/Table"
import RadioButton from "@/components/radios/Button"

Wyświetl plik

@ -64,7 +64,7 @@
<script>
import axios from 'axios'
import $ from 'jquery'
import _ from 'lodash'
import _ from '@/lodash'
import Modal from '@/components/semantic/Modal'
import TrackTable from '@/components/audio/track/Table'

Wyświetl plik

@ -106,7 +106,7 @@
<script>
import axios from 'axios'
import _ from 'lodash'
import _ from '@/lodash'
import time from '@/utils/time'
import Pagination from '@/components/Pagination'
import ActionTable from '@/components/common/ActionTable'

Wyświetl plik

@ -86,7 +86,7 @@
<script>
import axios from 'axios'
import moment from 'moment'
import _ from 'lodash'
import _ from '@/lodash'
import Pagination from '@/components/Pagination'
import ActionTable from '@/components/common/ActionTable'
import OrderingMixin from '@/components/mixins/Ordering'

Wyświetl plik

@ -96,7 +96,7 @@
<script>
import axios from 'axios'
import _ from 'lodash'
import _ from '@/lodash'
import time from '@/utils/time'
import Pagination from '@/components/Pagination'
import ActionTable from '@/components/common/ActionTable'

Wyświetl plik

@ -67,7 +67,7 @@
</template>
<script>
import _ from 'lodash'
import _ from '@/lodash'
import axios from 'axios'
import {mapState} from 'vuex'

Wyświetl plik

@ -15,7 +15,7 @@
</template>
<script>
import _ from 'lodash'
import _ from '@/lodash'
import axios from 'axios'
import PlaylistCard from '@/components/playlists/Card'

Wyświetl plik

@ -1,61 +0,0 @@
<template>
<div :class="['ui', {collapsed: collapsed}, 'card']">
<div class="content">
<div class="header">{{ request.artist_name }}</div>
<div class="description">
<div
v-if="request.albums" v-html="$options.filters.markdown(request.albums)"></div>
<div class="ui comments">
<comment
:user="request.user"
:content="request.comment || ''"
:date="request.creation_date"></comment>
</div>
</div>
</div>
<div class="extra content">
<span >
<i v-if="request.status === 'pending'" class="hourglass start icon"></i>
<i v-if="request.status === 'accepted'" class="hourglass half icon"></i>
<i v-if="request.status === 'imported'" class="check icon"></i>
{{ request.status | capitalize }}
</span>
<button
@click="createImport"
v-if="request.status === 'pending' && importAction && $store.state.auth.availablePermissions['library']"
class="ui mini basic green right floated button"><translate>Create import</translate></button>
</div>
</div>
</template>
<script>
import Comment from '@/components/discussion/Comment'
export default {
props: {
request: {type: Object, required: true},
importAction: {type: Boolean, default: true}
},
components: {
Comment
},
data () {
return {
collapsed: true
}
},
methods: {
createImport () {
this.$router.push({
name: 'library.import.launch',
query: {request: this.request.id}})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -1,127 +0,0 @@
<template>
<div>
<form v-if="!over" class="ui form" @submit.prevent="submit">
<p><translate>Something's missing in the library? Let us know what you would like to listen!</translate></p>
<div class="required field">
<label><translate>Artist name</translate></label>
<input v-model="currentArtistName" :placeholder="labels.artistNamePlaceholder" required maxlength="200">
</div>
<div class="field">
<label><translate>Albums</translate></label>
<p><translate>Leave this field empty if you're requesting the whole discography.</translate></p>
<input v-model="currentAlbums" :placeholder="labels.albumTitlePlaceholder" maxlength="2000">
</div>
<div class="field">
<label><translate>Comment</translate></label>
<textarea v-model="currentComment" rows="3" :placeholder="labels.commentPlaceholder" maxlength="2000"></textarea>
</div>
<button class="ui submit button" type="submit"><translate>Submit</translate></button>
</form>
<div v-else class="ui success message">
<div class="header"><translate>Request submitted!</translate></div>
<p><translate>We've received your request, you'll get some groove soon ;)</translate></p>
<button @click="reset" class="ui button"><translate>Submit another request</translate></button>
</div>
<div v-if="requests.length > 0">
<div class="ui divider"></div>
<h3 class="ui header"><translate>Pending requests</translate></h3>
<div class="ui list">
<div v-for="request in requests" class="item">
<div class="content">
<div class="header">{{ request.artist_name }}</div>
<div v-if="request.albums" class="description">
{{ request.albums|truncate }}</div>
<div v-if="request.comment" class="description">
{{ request.comment|truncate }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import $ from 'jquery'
import axios from 'axios'
import logger from '@/logging'
export default {
props: {
defaultArtistName: {type: String, default: ''},
defaultAlbums: {type: String, default: ''},
defaultComment: {type: String, default: ''}
},
created () {
this.fetchRequests()
},
mounted () {
$('.ui.radio.checkbox').checkbox()
},
data () {
return {
currentArtistName: this.defaultArtistName,
currentAlbums: this.defaultAlbums,
currentComment: this.defaultComment,
isLoading: false,
over: false,
requests: []
}
},
computed: {
labels () {
let artistNamePlaceholder = this.$gettext('The Beatles, Mickael Jackson…')
let albumTitlePlaceholder = this.$gettext('The White Album, Thriller…')
let commentPlaceholder = this.$gettext('Use this comment box to add details to your request if needed')
return {
artistNamePlaceholder,
albumTitlePlaceholder,
commentPlaceholder
}
}
},
methods: {
fetchRequests () {
let self = this
let url = 'requests/import-requests/'
axios.get(url, {}).then((response) => {
self.requests = response.data.results
})
},
submit () {
let self = this
this.isLoading = true
let url = 'requests/import-requests/'
let payload = {
artist_name: this.currentArtistName,
albums: this.currentAlbums,
comment: this.currentComment
}
axios.post(url, payload).then((response) => {
logger.default.info('Submitted request!')
self.isLoading = false
self.over = true
self.requests.unshift(response.data)
}, (response) => {
logger.default.error('error while submitting request')
self.isLoading = false
})
},
reset () {
this.over = false
this.currentArtistName = ''
this.currentAlbums = ''
this.currentComment = ''
},
truncate (string, length) {
if (string.length > length) {
return string.substring(0, length) + '…'
}
return string
}
}
}
</script>
<style scoped>
</style>

Wyświetl plik

@ -1,7 +1,6 @@
import Vue from 'vue'
import Embed from './Embed'
import axios from 'axios'
import VuePlyr from 'vue-plyr'
Vue.use(VuePlyr)

Wyświetl plik

@ -1,7 +1,6 @@
import Vue from 'vue'
import moment from 'moment'
import showdown from 'showdown'
export function truncate (str, max, ellipsis) {
max = max || 100
@ -14,13 +13,6 @@ export function truncate (str, max, ellipsis) {
Vue.filter('truncate', truncate)
export function markdown (str) {
const converter = new showdown.Converter()
return converter.makeHtml(str)
}
Vue.filter('markdown', markdown)
export function ago (date) {
const m = moment(date)
return m.fromNow()

Wyświetl plik

@ -0,0 +1,13 @@
// cherry-pick specific lodash methods here to reduce bundle size
export default {
clone: require('lodash/clone'),
debounce: require('lodash/debounce'),
get: require('lodash/get'),
merge: require('lodash/merge'),
range: require('lodash/range'),
shuffle: require('lodash/shuffle'),
sortBy: require('lodash/sortBy'),
throttle: require('lodash/throttle'),
uniq: require('lodash/uniq'),
}

Wyświetl plik

@ -14,7 +14,6 @@ import VueLazyload from 'vue-lazyload'
import store from './store'
import GetTextPlugin from 'vue-gettext'
import { sync } from 'vuex-router-sync'
import translations from './translations.json'
import locales from '@/locales'
import filters from '@/filters' // eslint-disable-line
@ -23,12 +22,9 @@ import globals from '@/components/globals' // eslint-disable-line
sync(store, router)
window.$ = window.jQuery = require('jquery')
// this is absolutely dirty but at the moment, semantic UI does not
// play really nice with webpack and I want to get rid of Google Fonts
// require('./semantic/semantic.css')
require('semantic-ui-css/semantic.js')
require('./semantic.js')
require('masonry-layout')
let availableLanguages = (function () {
let l = {}
locales.locales.forEach(c => {
@ -54,7 +50,7 @@ Vue.use(GetTextPlugin, {
}
}
},
translations: translations,
translations: {},
silent: true
})

Wyświetl plik

@ -0,0 +1,24 @@
// require('semantic-ui-css/components/accordion.min.js')
require('semantic-ui-css/components/api.min.js')
require('semantic-ui-css/components/checkbox.min.js')
// require('semantic-ui-css/components/colorize.min.js')
require('semantic-ui-css/components/dimmer.min.js')
require('semantic-ui-css/components/dropdown.min.js')
// require('semantic-ui-css/components/embed.min.js')
// require('semantic-ui-css/components/form.min.js')
require('semantic-ui-css/components/modal.min.js')
// require('semantic-ui-css/components/nag.min.js')
// require('semantic-ui-css/components/popup.min.js')
require('semantic-ui-css/components/progress.min.js')
// require('semantic-ui-css/components/rating.min.js')
require('semantic-ui-css/components/search.min.js')
// require('semantic-ui-css/components/shape.min.js')
// require('semantic-ui-css/components/sidebar.min.js')
require('semantic-ui-css/components/site.min.js')
require('semantic-ui-css/components/state.min.js')
require('semantic-ui-css/components/sticky.min.js')
// require('semantic-ui-css/components/tab.min.js')
require('semantic-ui-css/components/transition.min.js')
// require('semantic-ui-css/components/video.min.js')
require('semantic-ui-css/components/visibility.min.js')
// require('semantic-ui-css/components/visit.min.js')

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 957 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 28 KiB

Wyświetl plik

@ -1,6 +1,6 @@
import axios from 'axios'
import logger from '@/logging'
import _ from 'lodash'
import _ from '@/lodash'
function getDefaultUrl () {
return (
@ -40,14 +40,6 @@ export default {
enabled: {
value: true
}
},
raven: {
front_enabled: {
value: false
},
front_dsn: {
value: null
}
}
}
},
@ -131,7 +123,7 @@ export default {
})
},
fetchFrontSettings ({commit}) {
return axios.get('/settings.json').then(response => {
return axios.get('/front/settings.json').then(response => {
commit('frontSettings', response.data)
}, response => {
logger.default.error('Error when fetching front-end configuration (or no customization available)')

Wyświetl plik

@ -1,5 +1,5 @@
import logger from '@/logging'
import _ from 'lodash'
import _ from '@/lodash'
export default {
namespaced: true,
@ -86,7 +86,7 @@ export default {
if (callback && i + 1 === total) {
p.then(callback)
}
if (shouldPlay && p) {
if (shouldPlay && p && i + 1 === total) {
p.then(() => {
dispatch('next')
})

Wyświetl plik

@ -0,0 +1,250 @@
/*
Import this file into your LESS project to use Semantic UI without build tools
*/
/* Global */
@import "~semantic-ui-css/components/reset.css";
// we use our custom site css here to avoid loading google font
@import "./site";
/* Elements */
@import "~semantic-ui-css/components/button.css";
@import "~semantic-ui-css/components/container.css";
@import "~semantic-ui-css/components/divider.css";
// @import "~semantic-ui-css/components/flag.css";
@import "~semantic-ui-css/components/header.css";
@import "~semantic-ui-css/components/icon.css";
@import "~semantic-ui-css/components/image.css";
@import "~semantic-ui-css/components/input.css";
@import "~semantic-ui-css/components/label.css";
@import "~semantic-ui-css/components/list.css";
@import "~semantic-ui-css/components/loader.css";
// @import "~semantic-ui-css/components/placeholder.css";
// @import "~semantic-ui-css/components/rail.css";
// @import "~semantic-ui-css/components/reveal.css";
@import "~semantic-ui-css/components/segment.css";
@import "~semantic-ui-css/components/step.css";
/* Collections */
// @import "~semantic-ui-css/components/breadcrumb.css";
@import "~semantic-ui-css/components/form.css";
@import "~semantic-ui-css/components/grid.css";
@import "~semantic-ui-css/components/menu.css";
@import "~semantic-ui-css/components/message.css";
@import "~semantic-ui-css/components/table.css";
/* Views */
// @import "~semantic-ui-css/components/ad.css";
@import "~semantic-ui-css/components/card.css";
// @import "~semantic-ui-css/components/comment.css";
// @import "~semantic-ui-css/components/feed.css";
@import "~semantic-ui-css/components/item.css";
@import "~semantic-ui-css/components/statistic.css";
/* Modules */
// @import "~semantic-ui-css/components/accordion.css";
@import "~semantic-ui-css/components/checkbox.css";
@import "~semantic-ui-css/components/dimmer.css";
@import "~semantic-ui-css/components/dropdown.css";
// @import "~semantic-ui-css/components/embed.css";
@import "~semantic-ui-css/components/modal.css";
// @import "~semantic-ui-css/components/nag.css";
@import "~semantic-ui-css/components/popup.css";
@import "~semantic-ui-css/components/progress.css";
// @import "~semantic-ui-css/components/rating.css";
@import "~semantic-ui-css/components/search.css";
// @import "~semantic-ui-css/components/shape.css";
@import "~semantic-ui-css/components/sidebar.css";
@import "~semantic-ui-css/components/sticky.css";
@import "~semantic-ui-css/components/tab.css";
@import "~semantic-ui-css/components/transition.css";
// we do the import here instead in main.js
// as resolve order is not deterministric in webpack
// and we end up with CSS rules not applied,
// see https://github.com/webpack/webpack/issues/215
@import "./vendor/media";
html,
body {
@include media("<desktop") {
font-size: 90%;
}
}
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.instance-chooser {
margin-top: 2em;
}
.main.pusher,
.footer {
@include media(">desktop") {
margin-left: 350px !important;
margin-top: 50px;
}
transform: none !important;
}
.main.pusher > .ui.secondary.menu {
margin-left: 0;
margin-right: 0;
border: none;
box-shadow: inset 0px -2px 0px 0px rgba(34, 36, 38, 0.15);
.ui.item {
border: none;
border-bottom-style: none;
margin-bottom: 0px;
&.active {
box-shadow: inset 0px -2px 0px 0px #000;
}
}
@include media(">tablet") {
padding: 0 2.5rem;
}
@include media(">desktop") {
position: fixed;
left: 350px;
right: 0px;
top: 0px;
z-index: 99;
}
background-color: white;
.item {
padding-top: 1.5em;
padding-bottom: 1.5em;
}
}
.service-messages {
position: fixed;
bottom: 1em;
left: 1em;
@include media(">desktop") {
left: 350px;
}
}
.main-pusher {
padding: 1.5rem 0;
}
.ui.stripe.segment,
#footer {
padding: 2em;
@include media(">tablet") {
padding: 4em;
}
}
.ellipsis {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.ui.small.text.container {
max-width: 500px !important;
}
.button.icon.tiny {
padding: 0.5em !important;
}
.sidebar {
.logo {
&.bordered.icon {
padding: .5em .41em !important;
}
path {
fill: white;
}
}
}
.discrete {
color: rgba(0, 0, 0, 0.87);
}
.link {
cursor: pointer;
}
.ui.really.basic.button {
&:not(:focus) {
box-shadow: none !important;
background-color: none !important;
}
}
.floated.buttons .button ~ .dropdown {
border-left: none;
}
.ui.icon.header .circular.icon {
display: flex;
justify-content: center;
}
.segment-content .button {
margin: 0.5em;
}
a {
cursor: pointer;
}
.segment.hidden {
display: none;
}
button.reset {
border: none;
margin: 0;
padding: 0;
width: auto;
overflow: visible;
background: transparent;
/* inherit font & color from ancestor */
color: inherit;
font: inherit;
/* Normalize `line-height`. Cannot be changed from `normal` in Firefox 4+. */
line-height: normal;
/* Corrects font smoothing for webkit */
-webkit-font-smoothing: inherit;
-moz-osx-font-smoothing: inherit;
/* Corrects inability to style clickable `input` types in iOS */
-webkit-appearance: none;
text-align: inherit;
}
.ui.table > caption {
font-weight: bold;
padding: 0.5em;
text-align: left;
}
[role="button"] {
cursor: pointer;
}
.left.floated {
float: left;
}
.right.floated {
float: right;
}

Wyświetl plik

@ -0,0 +1,202 @@
/*!
* # Semantic UI 2.4.1 - Site
* http://github.com/semantic-org/semantic-ui/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
/*******************************
Page
*******************************/
html,
body {
height: 100%;
}
html {
font-size: 14px;
}
body {
margin: 0px;
padding: 0px;
overflow-x: hidden;
min-width: 320px;
background: #FFFFFF;
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
font-size: 14px;
line-height: 1.4285em;
color: rgba(0, 0, 0, 0.87);
font-smoothing: antialiased;
}
/*******************************
Headers
*******************************/
h1,
h2,
h3,
h4,
h5 {
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
line-height: 1.28571429em;
margin: calc(2rem - 0.14285714em ) 0em 1rem;
font-weight: bold;
padding: 0em;
}
h1 {
min-height: 1rem;
font-size: 2rem;
}
h2 {
font-size: 1.71428571rem;
}
h3 {
font-size: 1.28571429rem;
}
h4 {
font-size: 1.07142857rem;
}
h5 {
font-size: 1rem;
}
h1:first-child,
h2:first-child,
h3:first-child,
h4:first-child,
h5:first-child {
margin-top: 0em;
}
h1:last-child,
h2:last-child,
h3:last-child,
h4:last-child,
h5:last-child {
margin-bottom: 0em;
}
/*******************************
Text
*******************************/
p {
margin: 0em 0em 1em;
line-height: 1.4285em;
}
p:first-child {
margin-top: 0em;
}
p:last-child {
margin-bottom: 0em;
}
/*-------------------
Links
--------------------*/
a {
color: #4183C4;
text-decoration: none;
}
a:hover {
color: #1e70bf;
text-decoration: none;
}
/*******************************
Scrollbars
*******************************/
/*******************************
Highlighting
*******************************/
/* Site */
::-webkit-selection {
background-color: #CCE2FF;
color: rgba(0, 0, 0, 0.87);
}
::-moz-selection {
background-color: #CCE2FF;
color: rgba(0, 0, 0, 0.87);
}
::selection {
background-color: #CCE2FF;
color: rgba(0, 0, 0, 0.87);
}
/* Form */
textarea::-webkit-selection,
input::-webkit-selection {
background-color: rgba(100, 100, 100, 0.4);
color: rgba(0, 0, 0, 0.87);
}
textarea::-moz-selection,
input::-moz-selection {
background-color: rgba(100, 100, 100, 0.4);
color: rgba(0, 0, 0, 0.87);
}
textarea::selection,
input::selection {
background-color: rgba(100, 100, 100, 0.4);
color: rgba(0, 0, 0, 0.87);
}
/* Force Simple Scrollbars */
body ::-webkit-scrollbar {
-webkit-appearance: none;
width: 10px;
height: 10px;
}
body ::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 0px;
}
body ::-webkit-scrollbar-thumb {
cursor: pointer;
border-radius: 5px;
background: rgba(0, 0, 0, 0.25);
-webkit-transition: color 0.2s ease;
transition: color 0.2s ease;
}
body ::-webkit-scrollbar-thumb:window-inactive {
background: rgba(0, 0, 0, 0.15);
}
body ::-webkit-scrollbar-thumb:hover {
background: rgba(128, 135, 139, 0.8);
}
/* Inverted UI */
body .ui.inverted::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
}
body .ui.inverted::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.25);
}
body .ui.inverted::-webkit-scrollbar-thumb:window-inactive {
background: rgba(255, 255, 255, 0.15);
}
body .ui.inverted::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.35);
}
/*******************************
Global Overrides
*******************************/
/*******************************
Site Overrides
*******************************/

Wyświetl plik

@ -16,7 +16,7 @@ export default {
durationFormatted (v) {
let duration = parseInt(v)
if (duration % 1 !== 0) {
return time.parse(0)
return this.parse(0)
}
duration = Math.round(duration)
return this.parse(duration)

Wyświetl plik

@ -142,11 +142,6 @@ export default {
"instance__nodeinfo_stats_enabled",
"instance__nodeinfo_private"
]
},
{
label: errorLabel,
id: "reporting",
settings: ["raven__front_enabled", "raven__front_dsn"]
}
]
}

Wyświetl plik

@ -120,7 +120,7 @@
<script>
import axios from 'axios'
import _ from 'lodash'
import _ from '@/lodash'
import time from '@/utils/time'
import {normalizeQuery, parseTokens, compileTokens} from '@/search'

Wyświetl plik

@ -56,7 +56,7 @@
<script>
import axios from "axios"
import _ from "lodash"
import _ from "@/lodash"
import $ from "jquery"
import OrderingMixin from "@/components/mixins/Ordering"

0
front/stats.json 100644
Wyświetl plik

Wyświetl plik

@ -1,6 +1,6 @@
import {expect} from 'chai'
import {truncate, markdown, ago, capitalize, year} from '@/filters'
import {truncate, ago, capitalize, year} from '@/filters'
describe('filters', () => {
describe('truncate', () => {
@ -20,13 +20,6 @@ describe('filters', () => {
expect(output).to.equal('Hello pouet')
})
})
describe('markdown', () => {
it('renders markdown', () => {
const input = 'Hello world'
let output = markdown(input)
expect(output).to.equal('<p>Hello world</p>')
})
})
describe('ago', () => {
it('works', () => {
const input = new Date()

Wyświetl plik

@ -18,11 +18,11 @@ describe('store/instance', () => {
describe('mutations', () => {
it('settings', () => {
const state = {settings: {raven: {front_dsn: {value: 'test'}}}}
let settings = {raven: {front_enabled: {value: true}}}
const state = {settings: {users: {upload_quota: {value: 1}}}}
let settings = {users: {registration_enabled: {value: true}}}
store.mutations.settings(state, settings)
expect(state.settings).to.deep.equal({
raven: {front_dsn: {value: 'test'}, front_enabled: {value: true}}
users: {upload_quota: {value: 1}, registration_enabled: {value: true}}
})
})
})
@ -32,13 +32,13 @@ describe('store/instance', () => {
status: 200,
response: [
{
section: 'raven',
name: 'front_dsn',
value: 'test'
section: 'users',
name: 'upload_quota',
value: 1
},
{
section: 'raven',
name: 'front_enabled',
section: 'users',
name: 'registration_enabled',
value: false
}
]
@ -50,15 +50,15 @@ describe('store/instance', () => {
{
type: 'settings',
payload: {
raven: {
front_dsn: {
section: 'raven',
name: 'front_dsn',
value: 'test'
users: {
upload_quota: {
section: 'users',
name: 'upload_quota',
value: 1
},
front_enabled: {
section: 'raven',
name: 'front_enabled',
registration_enabled: {
section: 'users',
name: 'registration_enabled',
value: false
}
}

Wyświetl plik

@ -1,7 +1,7 @@
var sinon = require('sinon')
import {expect} from 'chai'
import _ from 'lodash'
import _ from '@/lodash'
import store from '@/store/queue'
import { testAction } from '../../utils'

Wyświetl plik

@ -1,4 +1,14 @@
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const webpack = require('webpack');
let plugins = [
// do not include moment.js locales since it's quite heavy
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
]
if (process.env.BUNDLE_ANALYZE === '1') {
plugins.push(new BundleAnalyzerPlugin())
}
module.exports = {
baseUrl: '/front/',
pages: {
@ -17,6 +27,7 @@ module.exports = {
config.optimization.delete('splitChunks')
},
configureWebpack: {
plugins: plugins,
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'

Plik diff jest za duży Load Diff