Fix ESLint rules once and for all

This commit is contained in:
Pitu 2020-12-24 23:45:16 +09:00
parent 2412a60bd4
commit fb2c27086f
51 changed files with 297 additions and 16953 deletions

View File

@ -1,11 +0,0 @@
{
"trailingComma": "none",
"tabWidth": 4,
"semi": true,
"singleQuote": true,
"endOfLine": "lf",
"bracketSpacing": true,
"useTabs": true,
"printWidth": 120,
"jsxBracketSameLine": false
}

View File

@ -1,11 +1,9 @@
{
"discord.enabled": true,
"editor.detectIndentation": false,
"editor.insertSpaces": false,
"files.insertFinalNewline": true,
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"vetur.validation.template": false,
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
@ -15,11 +13,6 @@
"prettier.disableLanguages": ["vue"],
"vetur.format.enable": true,
"files.eol": "\n",
"vetur.format.defaultFormatter.html": "js-beautify-html",
"vetur.format.defaultFormatter.js": "prettier",
"vetur.format.defaultFormatter.scss": "prettier",
"vetur.format.defaultFormatter.stylus": "stylus-supremacy",
"vetur.format.defaultFormatter.ts": "vscode-typescript",
"eslint.alwaysShowStatus": true,
"eslint.format.enable": true,
"editor.codeActionsOnSave": {

15734
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -44,8 +44,6 @@
"cors": "^2.8.5",
"dotenv": "^6.2.0",
"dumper.js": "^1.3.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"express": "^4.17.1",
"express-rate-limit": "^3.4.0",
"ffmpeg-generate-video-preview": "^1.0.3",
@ -89,98 +87,24 @@
"babel-eslint": "^10.0.1",
"cross-env": "^5.2.0",
"eslint": "^5.13.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-config-aqua": "^4.4.1",
"eslint-config-aqua": "^7.3.0",
"eslint-import-resolver-nuxt": "^1.0.1",
"eslint-plugin-vue": "^5.2.1",
"node-sass": "^4.11.0",
"nodemon": "^1.19.3",
"postcss-css-variables": "^0.11.0",
"postcss-nested": "^3.0.0",
"prettier": "adamjlev/prettier",
"sass-loader": "^7.1.0"
},
"eslintConfig": {
"extends": [
"airbnb-base",
"plugin:eslint-plugin-vue/recommended"
"aqua/node",
"aqua/vue"
],
"parserOptions": {
"parser": "babel-eslint",
"sourceType": "module"
},
"rules": {
"max-len": [
"error",
{
"code": 120,
"ignoreUrls": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true,
"ignoreRegExpLiterals": true
}
],
"class-methods-use-this": "off",
"no-param-reassign": "off",
"no-plusplus": [
"error",
{
"allowForLoopAfterthoughts": true
}
],
"no-underscore-dangle": [
"error",
{
"allow": [
"_id"
]
}
],
"import/extensions": [
"error",
"always",
{
"js": "never",
"ts": "never"
}
],
"vue/attribute-hyphenation": 0,
"vue/html-closing-bracket-newline": [
"error",
{
"singleline": "never",
"multiline": "never"
}
],
"vue/max-attributes-per-line": [
"error",
{
"singleline": 5,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}
],
"quote-props": 0,
"indent": [
"error",
"tab"
],
"no-tabs": "off",
"vue/html-indent": [
"error",
"tab"
],
"import/no-extraneous-dependencies": "off",
"no-restricted-syntax": "off",
"no-continue": "off",
"no-await-in-loop": "off",
"comma-dangle": [
"error",
"never"
]
},
"settings": {
"import/resolver": {
"nuxt": {

View File

@ -1,5 +1,5 @@
exports.up = async (knex) => {
await knex.schema.createTable('users', (table) => {
exports.up = async knex => {
await knex.schema.createTable('users', table => {
table.increments();
table.string('username').unique();
table.text('password');
@ -12,7 +12,7 @@ exports.up = async (knex) => {
table.timestamp('editedAt');
});
await knex.schema.createTable('albums', (table) => {
await knex.schema.createTable('albums', table => {
table.increments();
table.integer('userId');
table.string('name');
@ -24,7 +24,7 @@ exports.up = async (knex) => {
table.unique(['userId', 'name']);
});
await knex.schema.createTable('files', (table) => {
await knex.schema.createTable('files', table => {
table.increments();
table.integer('userId');
table.string('name');
@ -38,7 +38,7 @@ exports.up = async (knex) => {
table.timestamp('editedAt');
});
await knex.schema.createTable('links', (table) => {
await knex.schema.createTable('links', table => {
table.increments();
table.integer('userId');
table.integer('albumId');
@ -53,7 +53,7 @@ exports.up = async (knex) => {
table.unique(['userId', 'albumId', 'identifier']);
});
await knex.schema.createTable('albumsFiles', (table) => {
await knex.schema.createTable('albumsFiles', table => {
table.increments();
table.integer('albumId');
table.integer('fileId');
@ -61,13 +61,13 @@ exports.up = async (knex) => {
table.unique(['albumId', 'fileId']);
});
await knex.schema.createTable('albumsLinks', (table) => {
await knex.schema.createTable('albumsLinks', table => {
table.increments();
table.integer('albumId');
table.integer('linkId').unique();
});
await knex.schema.createTable('tags', (table) => {
await knex.schema.createTable('tags', table => {
table.increments();
table.string('uuid');
table.integer('userId');
@ -78,7 +78,7 @@ exports.up = async (knex) => {
table.unique(['userId', 'name']);
});
await knex.schema.createTable('fileTags', (table) => {
await knex.schema.createTable('fileTags', table => {
table.increments();
table.integer('fileId');
table.integer('tagId');
@ -86,13 +86,13 @@ exports.up = async (knex) => {
table.unique(['fileId', 'tagId']);
});
await knex.schema.createTable('bans', (table) => {
await knex.schema.createTable('bans', table => {
table.increments();
table.string('ip');
table.timestamp('createdAt');
});
};
exports.down = async (knex) => {
exports.down = async knex => {
await knex.schema.dropTableIfExists('users');
await knex.schema.dropTableIfExists('albums');
await knex.schema.dropTableIfExists('files');

View File

@ -2,7 +2,7 @@
const bcrypt = require('bcrypt');
const moment = require('moment');
exports.seed = async (db) => {
exports.seed = async db => {
const now = moment.utc().toDate();
const user = await db.table('users').where({ username: process.env.ADMIN_ACCOUNT }).first();
if (user) return;

View File

@ -27,7 +27,7 @@ const generateThumbnailForImage = async (filename, output) => {
}
};
const generateThumbnailForVideo = (filename) => {
const generateThumbnailForVideo = filename => {
try {
ffmpeg(nodePath.join(__dirname, '../../uploads', filename))
.thumbnail({
@ -36,7 +36,7 @@ const generateThumbnailForVideo = (filename) => {
folder: nodePath.join(__dirname, '../../uploads/thumbs/square'),
size: '64x64'
})
.on('error', (error) => console.error(error.message));
.on('error', error => console.error(error.message));
ffmpeg(nodePath.join(__dirname, '../../uploads', filename))
.thumbnail({
timestamps: [0],
@ -44,7 +44,7 @@ const generateThumbnailForVideo = (filename) => {
folder: nodePath.join(__dirname, '../../uploads/thumbs'),
size: '150x?'
})
.on('error', (error) => console.error(error.message));
.on('error', error => console.error(error.message));
console.log('finished', filename);
} catch (error) {
console.log('error', filename);
@ -64,15 +64,15 @@ const newDb = require('knex')({
connection: {
filename: nodePath.join(__dirname, '../../', 'database.sqlite')
},
postProcessResponse: (result) => {
postProcessResponse: result => {
const booleanFields = [
'enabled',
'enableDownload',
'isAdmin'
];
const processResponse = (row) => {
Object.keys(row).forEach((key) => {
const processResponse = row => {
Object.keys(row).forEach(key => {
if (booleanFields.includes(key)) {
if (row[key] === 0) row[key] = false;
else if (row[key] === 1) row[key] = true;
@ -81,7 +81,7 @@ const newDb = require('knex')({
return row;
};
if (Array.isArray(result)) return result.map((row) => processResponse(row));
if (Array.isArray(result)) return result.map(row => processResponse(row));
if (typeof result === 'object') return processResponse(result);
return result;
},

View File

@ -64,11 +64,11 @@ class albumGET extends Route {
/*
Get the actual files
*/
const fileIds = fileList.map((el) => el.fileId);
const fileIds = fileList.map(el => el.fileId);
const files = await db.table('files')
.whereIn('id', fileIds)
.select('name');
const filesToZip = files.map((el) => el.name);
const filesToZip = files.map(el => el.name);
try {
Util.createZip(filesToZip, album);

View File

@ -18,7 +18,7 @@ class filesGET extends Route {
.select('albumId');
if (albumFiles.length) {
albumFiles = albumFiles.map((a) => a.albumId);
albumFiles = albumFiles.map(a => a.albumId);
albums = await db.table('albums')
.whereIn('id', albumFiles)
.select('id', 'name');

View File

@ -56,7 +56,7 @@ class uploadPOST extends Route {
if (!album) return res.status(401).json({ message: 'Album doesn\'t exist or it doesn\'t belong to the user' });
}
return upload(req, res, async (err) => {
return upload(req, res, async err => {
if (err) console.error(err.message);
let uploadedFile = {};
@ -142,7 +142,7 @@ class uploadPOST extends Route {
async checkIfFileExists(db, user, hash) {
const exists = await db.table('files')
.where(function () { // eslint-disable-line func-names
.where(function() { // eslint-disable-line func-names
if (user) this.where('userId', user.id);
else this.whereNull('userId');
})

View File

@ -9,7 +9,7 @@ const db = require('knex')({
database: process.env.DB_DATABASE,
filename: nodePath.join(__dirname, '../../../database.sqlite')
},
postProcessResponse: (result) => {
postProcessResponse: result => {
/*
Fun fact: Depending on the database used by the user and given that I don't want
to force a specific database for everyone because of the nature of this project,
@ -18,8 +18,8 @@ const db = require('knex')({
*/
const booleanFields = ['enabled', 'enableDownload', 'isAdmin'];
const processResponse = (row) => {
Object.keys(row).forEach((key) => {
const processResponse = row => {
Object.keys(row).forEach(key => {
if (booleanFields.includes(key)) {
if (row[key] === 0) row[key] = false;
else if (row[key] === 1) row[key] = true;
@ -28,7 +28,7 @@ const db = require('knex')({
return row;
};
if (Array.isArray(result)) return result.map((row) => processResponse(row));
if (Array.isArray(result)) return result.map(row => processResponse(row));
if (typeof result === 'object') return processResponse(result);
return result;
},

View File

@ -42,16 +42,16 @@ class Server {
if (ext) { ext = `.${ext.toLowerCase()}`; }
if (
ThumbUtil.imageExtensions.indexOf(ext) > -1
|| ThumbUtil.videoExtensions.indexOf(ext) > -1
|| req.path.indexOf('_nuxt') > -1
|| req.path.indexOf('favicon.ico') > -1
ThumbUtil.imageExtensions.indexOf(ext) > -1 ||
ThumbUtil.videoExtensions.indexOf(ext) > -1 ||
req.path.indexOf('_nuxt') > -1 ||
req.path.indexOf('favicon.ico') > -1
) {
return true;
}
return false;
},
'stream': {
stream: {
write(str) { log.debug(str); }
}
}));
@ -64,7 +64,7 @@ class Server {
}
registerAllTheRoutes() {
jetpack.find(this.routesFolder, { matching: '*.js' }).forEach((routeFile) => {
jetpack.find(this.routesFolder, { matching: '*.js' }).forEach(routeFile => {
// eslint-disable-next-line import/no-dynamic-require, global-require
const RouteClass = require(path.join('../../../', routeFile));
let routes = [RouteClass];

View File

@ -2,16 +2,16 @@ const chrono = require('chrono-node');
class QueryHelper {
static parsers = {
before: (val) => QueryHelper.parseChronoList(val),
after: (val) => QueryHelper.parseChronoList(val),
tag: (val) => QueryHelper.sanitizeTags(val)
before: val => QueryHelper.parseChronoList(val),
after: val => QueryHelper.parseChronoList(val),
tag: val => QueryHelper.sanitizeTags(val)
};
static requirementHandlers = {
album: (knex) => knex
album: knex => knex
.join('albumsFiles', 'files.id', '=', 'albumsFiles.fileId')
.join('albums', 'albumsFiles.albumId', '=', 'album.id'),
tag: (knex) => knex
tag: knex => knex
.join('fileTags', 'files.id', '=', 'fileTags.fileId')
.join('tags', 'fileTags.tagId', '=', 'tags.id')
}
@ -93,11 +93,11 @@ class QueryHelper {
}
static parseChronoList(list) {
return list.map((e) => chrono.parse(e));
return list.map(e => chrono.parse(e));
}
static sanitizeTags(list) {
return list.map((e) => e.replace(/\s/g, '_'));
return list.map(e => e.replace(/\s/g, '_'));
}
static generateInclusionForTags(db, knex, list) {

View File

@ -53,7 +53,7 @@ class ThumbUtil {
folder: ThumbUtil.squareThumbPath,
size: '64x64'
})
.on('error', (error) => log.error(error.message));
.on('error', error => log.error(error.message));
ffmpeg(filePath)
.thumbnail({
@ -62,7 +62,7 @@ class ThumbUtil {
folder: ThumbUtil.thumbPath,
size: '150x?'
})
.on('error', (error) => log.error(error.message));
.on('error', error => log.error(error.message));
try {
await previewUtil({

View File

@ -25,7 +25,7 @@ const getStartTime = (vDuration, fDuration, ignoreBeforePercent, ignoreAfterPerc
return getRandomInt(ignoreBeforePercent * safeVDuration, ignoreAfterPercent * safeVDuration);
};
module.exports = async (opts) => {
module.exports = async opts => {
const {
log = noop,
@ -78,7 +78,7 @@ module.exports = async (opts) => {
.outputOptions([`-t ${fragmentDurationSecond}`])
.noAudio()
.output(output)
.on('start', (cmd) => log && log({ cmd }))
.on('start', cmd => log && log({ cmd }))
.on('end', resolve)
.on('error', reject)
.run();

View File

@ -4,7 +4,7 @@ const probe = require('ffmpeg-probe');
const noop = () => {};
module.exports = async (opts) => {
module.exports = async opts => {
const {
log = noop,
@ -22,7 +22,7 @@ module.exports = async (opts) => {
const info = await probe(input);
// const numFramesTotal = parseInt(info.streams[0].nb_frames, 10);
const { avg_frame_rate: avgFrameRate, duration } = info.streams[0];
const [frames, time] = avgFrameRate.split('/').map((e) => parseInt(e, 10));
const [frames, time] = avgFrameRate.split('/').map(e => parseInt(e, 10));
const numFramesTotal = (frames / time) * duration;
@ -63,9 +63,9 @@ module.exports = async (opts) => {
.noAudio()
.outputFormat('webm')
.output(output)
.on('start', (cmd) => log && log({ cmd }))
.on('start', cmd => log && log({ cmd }))
.on('end', () => resolve())
.on('error', (err) => reject(err))
.on('error', err => reject(err))
.run();
});

View File

@ -119,12 +119,12 @@ import { mapState, mapActions } from 'vuex';
export default {
props: {
albumId: {
type: Number,
default: 0
'type': Number,
'default': 0
},
details: {
type: Object,
default: () => ({})
'type': Object,
'default': () => ({})
}
},
data() {
@ -175,7 +175,7 @@ export default {
} catch (e) {
this.alert({ text: e.message, error: true });
} finally {
this.isDeletingLinks = this.isDeletingLinks.filter((e) => e !== identifier);
this.isDeletingLinks = this.isDeletingLinks.filter(e => e !== identifier);
}
},
async createLink(albumId) {
@ -207,7 +207,7 @@ export default {
maxlength: 10
},
trapFocus: true,
onConfirm: (value) => this.$handler.executeAction('albums/createCustomLink', { albumId, value })
onConfirm: value => this.$handler.executeAction('albums/createCustomLink', { albumId, value })
});
},
isDeleting(identifier) {

View File

@ -53,7 +53,7 @@
<AlbumDetails
v-if="isExpanded"
:details="getDetails(album.id)"
:albumId="album.id" />
:album-id="album.id" />
</div>
</template>
@ -67,8 +67,8 @@ export default {
},
props: {
album: {
type: Object,
default: () => ({})
'type': Object,
'default': () => ({})
}
},
computed: {

View File

@ -54,6 +54,8 @@
</div>
<div class="column">
<a href="https://github.com/weebdev/lolisafe">GitHub</a>
<a href="https://patreon.com/pitu">Patreon</a>
<a href="https://discord.gg/5g6vgwn">Discord</a>
</div>
<div class="column">
<a
@ -79,9 +81,9 @@ export default {
computed: {
...mapGetters({ loggedIn: 'auth/isLoggedIn' }),
...mapState({
version: (state) => state.config.version,
serviceName: (state) => state.config.serviceName,
token: (state) => state.auth.token
version: state => state.config.version,
serviceName: state => state.config.serviceName,
token: state => state.auth.token
})
},
methods: {

View File

@ -23,10 +23,10 @@
<template v-if="!images.showList">
<Waterfall
:gutterWidth="10"
:gutterHeight="4"
:gutter-width="10"
:gutter-height="4"
:options="{fitWidth: true}"
:itemWidth="width"
:item-width="width"
:items="gridFiles">
<template v-slot="{item}">
<template v-if="isPublic">
@ -165,32 +165,32 @@ export default {
},
props: {
files: {
type: Array,
default: () => []
'type': Array,
'default': () => []
},
total: {
type: Number,
default: 0
'type': Number,
'default': 0
},
fixed: {
type: Boolean,
default: false
'type': Boolean,
'default': false
},
isPublic: {
type: Boolean,
default: false
'type': Boolean,
'default': false
},
width: {
type: Number,
default: 150
'type': Number,
'default': 150
},
enableSearch: {
type: Boolean,
default: true
'type': Boolean,
'default': true
},
enableToolbar: {
type: Boolean,
default: true
'type': Boolean,
'default': true
}
},
data() {
@ -212,16 +212,16 @@ export default {
},
computed: {
...mapState({
user: (state) => state.auth.user,
albums: (state) => state.albums.tinyDetails,
images: (state) => state.images
user: state => state.auth.user,
albums: state => state.albums.tinyDetails,
images: state => state.images
}),
blank() {
// eslint-disable-next-line global-require, import/no-unresolved
return require('@/assets/images/blank.png');
},
gridFiles() {
return (this.files || []).filter((v) => !v.hideFromList);
return (this.files || []).filter(v => !v.hideFromList);
}
},
watch: {
@ -259,8 +259,8 @@ export default {
},
isAlbumSelected(id) {
if (!this.showingModalForFile) return false;
const found = this.showingModalForFile.albums.find((el) => el.id === id);
return !!(found && found.id);
const found = this.showingModalForFile.albums.find(el => el.id === id);
return Boolean(found && found.id);
},
async openAlbumModal(file) {
const { id } = file;

View File

@ -24,24 +24,24 @@ export default {
},
props: {
options: {
type: Object,
default: () => {}
'type': Object,
'default': () => {}
},
items: {
type: Array,
default: () => []
'type': Array,
'default': () => []
},
itemWidth: {
type: Number,
default: 150
'type': Number,
'default': 150
},
gutterWidth: {
type: Number,
default: 10
'type': Number,
'default': 10
},
gutterHeight: {
type: Number,
default: 4
'type': Number,
'default': 4
}
},
mounted() {
@ -84,20 +84,20 @@ export default {
this.masonry.layout();
},
diffDomChildren() {
const oldChildren = this.domChildren.filter((element) => !!element.parentNode);
const oldChildren = this.domChildren.filter(element => Boolean(element.parentNode));
const newChildren = this.getNewDomChildren();
const removed = oldChildren.filter((oldChild) => !newChildren.includes(oldChild));
const domDiff = newChildren.filter((newChild) => !oldChildren.includes(newChild));
const removed = oldChildren.filter(oldChild => !newChildren.includes(oldChild));
const domDiff = newChildren.filter(newChild => !oldChildren.includes(newChild));
const prepended = domDiff.filter((newChild, index) => newChildren[index] === newChild);
const appended = domDiff.filter((el) => !prepended.includes(el));
const appended = domDiff.filter(el => !prepended.includes(el));
let moved = [];
if (removed.length === 0) {
moved = oldChildren.filter((child, index) => index !== newChildren.indexOf(child));
}
this.domChildren = newChildren;
return {
old: oldChildren,
new: newChildren,
'old': oldChildren,
'new': newChildren,
removed,
appended,
prepended,
@ -120,15 +120,10 @@ export default {
getNewDomChildren() {
const node = this.$refs.waterfall;
const children = this.options && this.options.itemSelector
? node.querySelectorAll(this.options.itemSelector) : node.children;
? node.querySelectorAll(this.options.itemSelector)
: node.children;
return Array.prototype.slice.call(children);
}
}
};
</script>
<style lang="scss" scoped>
.wfi {
}
</style>

View File

@ -24,22 +24,20 @@
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'Albuminfo',
props: {
imageId: {
type: Number,
default: 0
'type': Number,
'default': 0
},
imageAlbums: {
type: Array,
default: () => []
'type': Array,
'default': () => []
},
albums: {
type: Array,
default: () => []
'type': Array,
'default': () => []
}
},
data() {
@ -52,7 +50,7 @@ export default {
this.orderedAlbums = this.getOrderedAlbums();
// we're sorting here instead of computed because we want sort on creation
// then the array's values should be frozen
this.selectedOptions = this.imageAlbums.map((e) => e.id);
this.selectedOptions = this.imageAlbums.map(e => e.id);
},
methods: {
getOrderedAlbums() {
@ -70,8 +68,8 @@ export default {
},
isAlbumSelected(id) {
if (!this.showingModalForFile) return false;
const found = this.showingModalForFile.albums.find((el) => el.id === id);
return !!(found && found.id);
const found = this.showingModalForFile.albums.find(el => el.id === id);
return Boolean(found && found.id);
},
async handleClick(id) {
// here the album should be already removed from the selected list

View File

@ -97,12 +97,12 @@
<div class="divider is-lolisafe has-text-light">
Tags
</div>
<Taginfo :imageId="file.id" :imageTags="tags" />
<Taginfo :image-id="file.id" :image-tags="tags" />
<div class="divider is-lolisafe has-text-light">
Albums
</div>
<Albuminfo :imageId="file.id" :imageAlbums="albums" :albums="tinyDetails" />
<Albuminfo :image-id="file.id" :image-albums="albums" :albums="tinyDetails" />
</div>
</div>
</div>
@ -122,21 +122,21 @@ export default {
},
props: {
file: {
type: Object,
default: () => ({})
'type': Object,
'default': () => ({})
},
albums: {
type: Array,
default: () => ([])
'type': Array,
'default': () => ([])
},
tags: {
type: Array,
default: () => ([])
'type': Array,
'default': () => ([])
}
},
computed: mapState({
images: (state) => state.images,
tinyDetails: (state) => state.albums.tinyDetails
images: state => state.images,
tinyDetails: state => state.albums.tinyDetails
}),
methods: {
formatBytes(bytes, decimals = 2) {
@ -148,6 +148,7 @@ export default {
const i = Math.floor(Math.log(bytes) / Math.log(k));
// eslint-disable-next-line no-mixed-operators
return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
},
isVideo(type) {

View File

@ -22,12 +22,12 @@ export default {
name: 'Taginfo',
props: {
imageId: {
type: Number,
default: 0
'type': Number,
'default': 0
},
imageTags: {
type: Array,
default: () => []
'type': Array,
'default': () => []
}
},
data() {
@ -37,14 +37,14 @@ export default {
},
computed: {
...mapState({
tags: (state) => state.tags.tagsList
tags: state => state.tags.tagsList
}),
selectedTags() { return this.imageTags.map((e) => e.name); },
lowercaseTags() { return this.imageTags.map((e) => e.name.toLowerCase()); }
selectedTags() { return this.imageTags.map(e => e.name); },
lowercaseTags() { return this.imageTags.map(e => e.name.toLowerCase()); }
},
methods: {
getFilteredTags(str) {
this.filteredTags = this.tags.map((e) => e.name).filter((e) => {
this.filteredTags = this.tags.map(e => e.name).filter(e => {
// check if the search string matches any of the tags
const sanitezedTag = e.toString().toLowerCase();
const matches = sanitezedTag.indexOf(str.toLowerCase()) >= 0;

View File

@ -8,16 +8,16 @@
export default {
props: {
size: {
type: String,
default: '60px'
'type': String,
'default': '60px'
},
background: {
type: String,
default: '#9C27B0'
'type': String,
'default': '#9C27B0'
},
duration: {
type: String,
default: '1.8s'
'type': String,
'default': '1.8s'
}
},
computed: {

View File

@ -19,8 +19,8 @@
export default {
props: {
size: {
type: String,
default: '40px'
'type': String,
'default': '40px'
}
},
computed: {

View File

@ -18,8 +18,8 @@
export default {
props: {
size: {
type: String,
default: '60px'
'type': String,
'default': '60px'
}
},
computed: {

View File

@ -8,8 +8,8 @@
export default {
props: {
size: {
type: String,
default: '40px'
'type': String,
'default': '40px'
}
},
computed: {

View File

@ -72,8 +72,8 @@ import { mapState, mapGetters } from 'vuex';
export default {
props: {
isWhite: {
type: Boolean,
default: false
'type': Boolean,
'default': false
}
},
data() {

View File

@ -89,12 +89,12 @@ export default {
props: {
value: [Number, String],
data: {
type: Array,
default: () => []
'type': Array,
'default': () => []
},
field: {
type: String,
default: 'value'
'type': String,
'default': 'value'
},
keepFirst: Boolean,
clearOnSelect: Boolean,
@ -105,8 +105,8 @@ export default {
clearable: Boolean,
maxHeight: [String, Number],
dropdownPosition: {
type: String,
default: 'auto'
'type': String,
'default': 'auto'
},
iconRight: String,
iconRightClickable: Boolean,
@ -159,25 +159,25 @@ export default {
* Check if exists default slot
*/
hasDefaultSlot() {
return !!this.$scopedSlots.default;
return Boolean(this.$scopedSlots.default);
},
/**
* Check if exists "empty" slot
*/
hasEmptySlot() {
return !!this.$slots.empty;
return Boolean(this.$slots.empty);
},
/**
* Check if exists "header" slot
*/
hasHeaderSlot() {
return !!this.$slots.header;
return Boolean(this.$slots.header);
},
/**
* Check if exists "footer" slot
*/
hasFooterSlot() {
return !!this.$slots.footer;
return Boolean(this.$slots.footer);
},
/**
* Apply dropdownPosition property
@ -202,7 +202,8 @@ export default {
// eslint-disable-next-line no-nested-ternary
maxHeight: this.maxHeight === undefined
// eslint-disable-next-line no-restricted-globals
? null : (isNaN(this.maxHeight) ? this.maxHeight : `${this.maxHeight}px`)
? null
: (isNaN(this.maxHeight) ? this.maxHeight : `${this.maxHeight}px`)
};
}
},
@ -239,7 +240,7 @@ export default {
}
// Close dropdown if input is clear or else open it
if (this.hasFocus && (!this.openOnFocus || value)) {
this.isActive = !!value;
this.isActive = Boolean(value);
}
},
/**
@ -378,8 +379,8 @@ export default {
* reached it's end.
*/
checkIfReachedTheEndOfScroll(list) {
if (list.clientHeight !== list.scrollHeight
&& list.scrollTop + list.clientHeight >= list.scrollHeight) {
if (list.clientHeight !== list.scrollHeight &&
list.scrollTop + list.clientHeight >= list.scrollHeight) {
this.$emit('infinite-scroll');
}
},
@ -396,9 +397,9 @@ export default {
if (this.$refs.dropdown === undefined) return;
const rect = this.$refs.dropdown.getBoundingClientRect();
this.isListInViewportVertically = (
rect.top >= 0
&& rect.bottom <= (window.innerHeight
|| document.documentElement.clientHeight)
rect.top >= 0 &&
rect.bottom <= (window.innerHeight ||
document.documentElement.clientHeight)
);
if (this.appendToBody) {
this.updateAppendToBody();
@ -425,9 +426,9 @@ export default {
list.scrollTop = element.offsetTop;
} else if (element.offsetTop >= visMax) {
list.scrollTop = (
element.offsetTop
- list.clientHeight
+ element.clientHeight
element.offsetTop -
list.clientHeight +
element.clientHeight
);
}
} else {
@ -487,7 +488,7 @@ export default {
if (dropdownMenu && trigger) {
// update wrapper dropdown
const root = this.$data._bodyEl;
root.classList.forEach((item) => root.classList.remove(item));
root.classList.forEach(item => root.classList.remove(item));
root.classList.add('autocomplete');
root.classList.add('control');
if (this.expandend) {
@ -496,10 +497,10 @@ export default {
const rect = trigger.getBoundingClientRect();
let top = rect.top + window.scrollY;
const left = rect.left + window.scrollX;
if (!this.isOpenedTop) {
top += trigger.clientHeight;
} else {
if (this.isOpenedTop) {
top -= dropdownMenu.clientHeight;
} else {
top += trigger.clientHeight;
}
this.style = {
position: 'absolute',

View File

@ -6,7 +6,7 @@
ref="autocomplete"
v-model="query"
:data="filteredHints"
:customSelector="handleSelect"
:custom-selector="handleSelect"
field="name"
class="lolisafe-input search"
placeholder="Search"
@ -40,8 +40,8 @@ export default {
},
props: {
hiddenHints: {
type: Array,
default: () => []
'type': Array,
'default': () => []
}
},
data() {
@ -49,34 +49,34 @@ export default {
query: '',
hints: [
{
'name': 'tag',
'valueFormat': 'name',
'hint': ''
name: 'tag',
valueFormat: 'name',
hint: ''
},
{
'name': 'album',
'valueFormat': 'name',
'hint': ''
name: 'album',
valueFormat: 'name',
hint: ''
},
{
'name': 'before',
'valueFormat': 'specific date',
'hint': ''
name: 'before',
valueFormat: 'specific date',
hint: ''
},
{
'name': 'during',
'valueFormat': 'specific date',
'hint': ''
name: 'during',
valueFormat: 'specific date',
hint: ''
},
{
'name': 'after',
'valueFormat': 'specific date',
'hint': ''
name: 'after',
valueFormat: 'specific date',
hint: ''
},
{
'name': 'file',
'valueFormat': 'generated name',
'hint': ''
name: 'file',
valueFormat: 'generated name',
hint: ''
}
],
filteredHints: []
@ -98,13 +98,22 @@ export default {
// get the last word or group of words
let lastWord = (qry.match(/("[^"]*")|[^\s]+/g) || ['']).pop().toLowerCase();
// if there's an open/unbalanced quote, don't autosuggest
if (/^[^"]*("[^"]*"[^"]*)*(")[^"]*$/.test(qry)) { this.filteredHints = []; return; }
if (/^[^"]*("[^"]*"[^"]*)*(")[^"]*$/.test(qry)) {
this.filteredHints = [];
return;
}
// don't autosuggest if we have an open query but no text yet
if (/:\s+$/gi.test(qry)) { this.filteredHints = []; return; }
if (/:\s+$/gi.test(qry)) {
this.filteredHints = [];
return;
}
// if the above query didn't match (all quotes are balanced
// and the previous tag has value
// check if we're about to start a new tag
if (/\s+$/gi.test(qry)) { this.filteredHints = this.hints; return; }
if (/\s+$/gi.test(qry)) {
this.filteredHints = this.hints;
return;
}
// ignore starting `-` from lastword, because - is used to
// exclude something, so -alb should autosuggest album
@ -112,7 +121,7 @@ export default {
// if we got here, then we handled all special cases
// now take last word, and check if we can autosuggest a tag
this.filteredHints = this.hints.filter((hint) => hint.name
this.filteredHints = this.hints.filter(hint => hint.name
.toString()
.toLowerCase()
.indexOf(lastWord) === 0);

View File

@ -48,7 +48,7 @@ import { mapState } from 'vuex';
export default {
computed: mapState({
user: (state) => state.auth.user
user: state => state.auth.user
}),
methods: {
isRouteActive(id) {

View File

@ -93,8 +93,8 @@ export default {
},
computed: {
...mapState({
config: (state) => state.config,
albums: (state) => state.albums.tinyDetails
config: state => state.config,
albums: state => state.albums.tinyDetails
}),
...mapGetters({ loggedIn: 'auth/isLoggedIn', token: 'auth/getToken' })
},

View File

@ -3,7 +3,7 @@
v-bar
class="scroll-area">
<div class="default-body">
<Navbar :isWhite="true" />
<Navbar :is-white="true" />
<nuxt-child
id="app"
class="nuxt-app is-height-max-content" />
@ -23,7 +23,7 @@ export default {
},
computed: mapState(['config', 'alert']),
created() {
this.$store.watch((state) => state.alert.message, () => {
this.$store.watch(state => state.alert.message, () => {
const { message, type, snackbar } = this.alert;
if (!message) return;

View File

@ -10,7 +10,7 @@
<template>
<section class="hero is-fullheight">
<Navbar :isWhite="true" />
<Navbar :is-white="true" />
<div class="hero-body">
<div class="container">
<h2>404エラ</h2>

View File

@ -1,4 +1,4 @@
export default function ({ store, redirect }) {
export default function({ store, redirect }) {
// If the user is not authenticated
if (!store.state.auth.user) return redirect('/login');
if (!store.state.auth.user.isAdmin) return redirect('/dashboard');

View File

@ -1,4 +1,4 @@
export default function ({ store, redirect }) {
export default function({ store, redirect }) {
// If the user is not authenticated
if (!store.state.auth.loggedIn) {
return redirect('/login');

View File

@ -36,10 +36,10 @@
<Grid
v-if="files && files.length"
:files="files"
:isPublic="true"
:is-public="true"
:width="200"
:enableSearch="false"
:enableToolbar="false" />
:enable-search="false"
:enable-toolbar="false" />
</div>
</template>
<template v-else>

View File

@ -115,9 +115,9 @@ export default {
};
},
computed: {
...mapGetters({ 'apiKey': 'auth/getApiKey' }),
...mapGetters({ apiKey: 'auth/getApiKey' }),
...mapState({
user: (state) => state.auth.user
user: state => state.auth.user
})
},
metaInfo() {

View File

@ -168,6 +168,7 @@ export default {
const i = Math.floor(Math.log(bytes) / Math.log(k));
// eslint-disable-next-line no-mixed-operators
return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
}
}

View File

@ -145,7 +145,7 @@ export default {
return { title: 'Settings' };
},
computed: mapState({
settings: (state) => state.admin.settings
settings: state => state.admin.settings
}),
methods: {
promptRestartService() {

View File

@ -92,7 +92,7 @@ export default {
};
},
computed: mapState({
user: (state) => state.admin.user
user: state => state.admin.user
}),
methods: {
promptDisableUser() {

View File

@ -102,8 +102,8 @@ export default {
}
}],
computed: mapState({
users: (state) => state.admin.users,
config: (state) => state.config
users: state => state.admin.users,
config: state => state.config
}),
metaInfo() {
return { title: 'Uploads' };

View File

@ -74,7 +74,7 @@ export default {
},
methods: {
...mapActions({
'alert': 'alert/set'
alert: 'alert/set'
}),
async createAlbum() {
if (!this.newAlbumName || this.newAlbumName === '') return;

View File

@ -27,7 +27,7 @@
<Grid
v-if="totalFiles && !isLoading"
:files="images.files"
:enableSearch="false"
:enable-search="false"
class="grid">
<template v-slot:pagination>
<b-pagination
@ -112,6 +112,7 @@ export default {
this.search = query;
const sanitizedQ = this.sanitizeQuery(query);
// eslint-disable-next-line no-negated-condition
if (!sanitizedQ.length) {
this.current = 1;
await this.fetch(this.current);

View File

@ -1,13 +1,13 @@
export default function ({ $axios, store }) {
export default function({ $axios, store }) {
$axios.setHeader('accept', 'application/vnd.lolisafe.json');
$axios.onRequest((config) => {
$axios.onRequest(config => {
if (store.state.auth.token) {
config.headers.common.Authorization = `bearer ${store.state.auth.token}`;
}
});
$axios.onError((error) => {
$axios.onError(error => {
if (process.env.NODE_ENV !== 'production') console.error('[AXIOS Error]', error);
if (process.browser) {
if (process.env.NODE_ENV !== 'production') {

View File

@ -6,11 +6,11 @@ const search = new FlexSearch('speed');
// https://github.com/nextapps-de/flexsearch
Vue.prototype.$search = {
items: async (items) => {
'items': async items => {
await search.clear();
await search.add(items);
},
do: async (term, field) => {
'do': async (term, field) => {
const results = await search.search(term, { field });
return results;
}

View File

@ -1,3 +1,3 @@
export default async (ctx) => {
export default async ctx => {
await ctx.store.dispatch('nuxtClientInit', ctx);
};

View File

@ -9,8 +9,8 @@ export const state = () => ({
});
export const getters = {
isExpanded: (state) => (id) => state.expandedAlbums.indexOf(id) > -1,
getDetails: (state) => (id) => state.albumDetails[id] || {}
isExpanded: state => id => state.expandedAlbums.indexOf(id) > -1,
getDetails: state => id => state.albumDetails[id] || {}
};
export const actions = {

View File

@ -11,9 +11,9 @@ const getDefaultState = () => ({
export const state = getDefaultState;
export const getters = {
isLoggedIn: (state) => state.loggedIn,
getApiKey: (state) => state.user?.apiKey,
getToken: (state) => state.token
isLoggedIn: state => state.loggedIn,
getApiKey: state => state.user?.apiKey,
getToken: state => state.token
};
export const actions = {

950
yarn.lock

File diff suppressed because it is too large Load Diff