Upgrade Webpack and JS dependencies

This commit is contained in:
Michael Mayer 2019-05-07 15:41:33 +02:00
parent 53a5d84653
commit 940e2a69f9
32 changed files with 5514 additions and 5829 deletions

View file

@ -1,4 +1,4 @@
FROM photoprism/development:20190506
FROM photoprism/development:20190507
# Set up project directory
WORKDIR "/go/src/github.com/photoprism/photoprism"

View file

@ -24,6 +24,8 @@ build:
js:
(cd frontend && npm install --production)
(cd frontend && env NODE_ENV=production npm run build)
test-js:
(cd frontend && env NODE_ENV=development npm run test)
start:
go run cmd/photoprism/photoprism.go start
migrate:

View file

@ -25,6 +25,7 @@ services:
PHOTOPRISM_SQL_PORT: 4000
PHOTOPRISM_SQL_PASSWORD: "photoprism"
PHOTOPRISM_DARKTABLE_CLI: "/usr/bin/darktable-cli"
TF_CPP_MIN_LOG_LEVEL: 1
database:
image: mysql:8.0.16

View file

@ -5,5 +5,8 @@ RUN mkdir -p /srv/photoprism/photos/import && \
RUN photoprism import
# Hide TensorFlow warnings
ENV TF_CPP_MIN_LOG_LEVEL 2
# Start PhotoPrism server
CMD photoprism start
CMD photoprism start

View file

@ -16,7 +16,13 @@ RUN apt-get update && apt-get upgrade && \
apt-get install \
build-essential \
curl \
chrpath \
libssl-dev \
libxft-dev \
libfreetype6 \
libfreetype6-dev \
libfontconfig1 \
libfontconfig1-dev \
libhdf5-serial-dev \
libpng-dev \
libzmq3-dev \
@ -35,7 +41,11 @@ RUN apt-get update && apt-get upgrade && \
git \
mysql-client \
libgtk-3-bin \
tzdata
tzdata \
gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libgcc1 \
libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 \
libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 \
libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils
# Install darktable (RAW to JPEG converter)
RUN add-apt-repository ppa:pmjdebruijn/darktable-release && \
@ -50,15 +60,18 @@ RUN curl -L \
tar -C "/usr/local" -xz
RUN ldconfig
# Hide some warnings
ENV TF_CPP_MIN_LOG_LEVEL 2
# Show TensorFlow debug log
ENV TF_CPP_MIN_LOG_LEVEL 0
# Install NPM (NodeJS)
# Install NodeJS
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN apt-get update && \
apt-get install nodejs && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install and configure NodeJS Package Manager (npm)
ENV NODE_ENV production
RUN npm install -g npm
RUN npm config set cache ~/.cache/npm
@ -91,10 +104,6 @@ RUN wget "https://dl.photoprism.org/fixtures/testdata.zip?$BUILD_DATE" -O /tmp/p
# Install goimports
RUN env GO111MODULE=off /usr/local/go/bin/go get golang.org/x/tools/cmd/goimports
# Configure JS environment for building
ENV NODE_ENV production
ENV YARN_CACHE_FOLDER /root/.cache/yarn
# Configure broadwayd (HTML5 display server)
# Command: broadwayd -p 8080 -a 0.0.0.0 :5
ENV GDK_BACKEND broadway

View file

@ -1,4 +1,4 @@
FROM photoprism/development:20190506 as build
FROM photoprism/development:20190507 as build
# Set up project directory
WORKDIR "/go/src/github.com/photoprism/photoprism"
@ -45,6 +45,9 @@ RUN apt-get update && \
# Show photoprism version
RUN photoprism -v
# Hide TensorFlow warnings
ENV TF_CPP_MIN_LOG_LEVEL 2
# Expose HTTP & TiDB port
EXPOSE 80
EXPOSE 4000

View file

@ -1,4 +1,4 @@
FROM photoprism/development:20190506
FROM photoprism/development:20190507
# Install Python and TensorFlow
RUN apt-get update && apt-get install -y --no-install-recommends \

View file

@ -36,6 +36,10 @@ main {
margin: 0;
}
#app main a {
color: #00B8D4;
}
.v-badge__badge {
font-size: 12px;
height: 19px;

View file

@ -1,20 +1,19 @@
const path = require('path');
// See https://github.com/webpack/loader-utils/issues/56
process.noDeprecation = true;
process.env.CHROME_BIN = require('puppeteer').executablePath()
module.exports = (config) => {
const tests = 'tests/*/*.test.js';
config.set({
frameworks: ['mocha'],
phantomjsLauncher: {
// Have phantomjs exit if a ResourceError is encountered (useful if karma exits without killing phantom)
exitOnResourceError: true
},
browsers: ['PhotoPrism'],
browsers: ['PhantomJS'],
customLaunchers: {
PhotoPrism: {
base: 'ChromeHeadless',
flags: ['--disable-translate', '--disable-extensions', '--no-sandbox', '--disable-web-security'],
}
},
files: [
{pattern: 'tests/**/*_test.js', watched: false}
@ -32,6 +31,8 @@ module.exports = (config) => {
},
webpack: {
mode: 'development',
resolve: {
modules: [
path.join(__dirname, 'src'),
@ -47,8 +48,12 @@ module.exports = (config) => {
{
test: /\.js$/,
loader: 'babel-loader',
exclude: file => (
/node_modules/.test(file)
),
query: {
presets: ['es2015']
presets: ['@babel/preset-env'],
compact: false
},
},
]
@ -57,4 +62,4 @@ module.exports = (config) => {
singleRun: true,
});
};
};

10130
frontend/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -10,83 +10,100 @@
"lint": "eslint app/ webpack.*.js --cache",
"test": "karma start"
},
"babel": {
"presets": [
"@babel/preset-env"
]
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.2.0",
"@babel/cli": "^7.4.4",
"@babel/core": "^7.4.4",
"@babel/plugin-transform-runtime": "^7.4.4",
"@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.4.4",
"@babel/register": "^7.4.4",
"@fortawesome/fontawesome-free": "^5.8.1",
"@types/leaflet": "^1.4.4",
"autoprefixer": "^6.7.2",
"axios": "^0.16.1",
"axios-mock-adapter": "^1.8.1",
"babel-core": "^6.22.1",
"babel-eslint": "^7.1.1",
"babel-loader": "^7.1.5",
"babel-plugin-istanbul": "^3.1.2",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.2.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.22.0",
"babel-register": "^6.22.0",
"chai": "^3.5.0",
"acorn": "^6.1.1",
"ajv": "^6.10.0",
"autoprefixer": "^9.5.1",
"axios": "^0.18.0",
"axios-mock-adapter": "^1.16.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.5",
"browserslist": "^4.5.6",
"chai": "^4.2.0",
"chalk": "^1.1.3",
"chart.js": "^2.5.0",
"clean-webpack-plugin": "^2.0.2",
"connect-history-api-fallback": "^1.3.0",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^3.1.4",
"css-loader": "^0.28.11",
"eslint": "^3.14.1",
"eslint-config-standard": "^6.2.1",
"eslint-friendly-formatter": "^2.0.7",
"eslint-loader": "^1.6.1",
"eslint-plugin-html": "^2.0.0",
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-standard": "^2.0.1",
"copy-webpack-plugin": "^4.6.0",
"cross-env": "^5.2.0",
"css-loader": "^2.1.1",
"cssnano": "^4.1.10",
"eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.1.2",
"eslint-plugin-html": "^2.0.3",
"eslint-plugin-import": "^2.17.2",
"eslint-plugin-node": "^9.0.1",
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0",
"eventsource-polyfill": "^0.9.6",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^0.10.0",
"friendly-errors-webpack-plugin": "^1.1.3",
"html-webpack-plugin": "^2.28.0",
"http-proxy-middleware": "^0.17.3",
"inject-loader": "^2.0.1",
"justified-gallery": "^0.1.0",
"karma": "^1.7.0",
"karma-chrome-launcher": "^2.1.1",
"karma-firefox-launcher": "^1.0.1",
"karma-htmlfile-reporter": "^0.3.5",
"file-loader": "^3.0.1",
"friendly-errors-webpack-plugin": "^1.7.0",
"html-webpack-plugin": "^3.2.0",
"http-proxy-middleware": "^0.19.1",
"inject-loader": "^4.0.1",
"karma": "^4.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.1.0",
"karma-htmlfile-reporter": "^0.3.8",
"karma-mocha": "^1.3.0",
"karma-phantomjs-launcher": "^1.0.4",
"karma-webdriver-launcher": "^1.0.5",
"karma-webpack": "^2.0.3",
"karma-webpack": "^4.0.0-rc.6",
"leaflet": "^1.4.0",
"material-design-icons-iconfont": "^3.0.3",
"mocha": "^3.3.0",
"node-sass": "^4.9.2",
"optimize-css-assets-webpack-plugin": "^1.3.0",
"ora": "^1.1.0",
"phantomjs-prebuilt": "^2.1.14",
"mini-css-extract-plugin": "^0.6.0",
"mocha": "^6.1.4",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"ora": "^1.4.0",
"photoswipe": "^4.1.3",
"pluralize": "^4.0.0",
"pubsub-js": "^1.5.6",
"sass-loader": "^7.0.3",
"style-loader": "^0.16.1",
"svg-url-loader": "^2.0.2",
"url-loader": "^0.5.8",
"vue": "^2.4.4",
"vue-fullscreen": "^2.1.3",
"pluralize": "^7.0.0",
"postcss": "^7.0.16",
"postcss-browser-reporter": "^0.6.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.6.0",
"postcss-reporter": "^6.0.1",
"postcss-url": "^8.0.0",
"pubsub-js": "^1.7.0",
"puppeteer": "^1.15.0",
"resolve-url-loader": "^3.1.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"sugarss": "^2.0.0",
"svg-url-loader": "^2.3.2",
"tar": "^4.4.8",
"url-loader": "^1.1.2",
"vue": "^2.6.10",
"vue-fullscreen": "^2.1.5",
"vue-infinite-scroll": "^2.0.2",
"vue-justified-layout": "^0.1.0",
"vue-loader": "^11.1.4",
"vue-loader": "^14.2.4",
"vue-moment": "^4.0.0",
"vue-router": "^2.7.0",
"vue-style-loader": "^2.0.0",
"vue-template-compiler": "^2.4.4",
"vue-router": "^3.0.6",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"vue-truncate-filter": "^1.1.7",
"vue2-leaflet": "^2.1.1",
"vuelidate": "^0.4.3",
"vuetify": "^1.2.3",
"webpack": "^3.12.0",
"webpack-bundle-analyzer": "^2.13.1",
"webpack-dev-middleware": "^2.0.0",
"webpack-hot-middleware": "^2.22.3",
"vuelidate": "^0.7.4",
"vuetify": "^1.5.14",
"webpack": "^4.30.0",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^3.3.2",
"webpack-hot-middleware": "^2.24.4",
"webpack-md5-hash": "0.0.6",
"webpack-merge": "^4.1.3"
},
"engines": {
@ -95,7 +112,7 @@
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
"not ie <= 9",
"last 3 versions"
]
}

View file

@ -0,0 +1,7 @@
module.exports = ({ file, options, env }) => ({
plugins: {
"postcss-import": {},
"postcss-preset-env": true,
"cssnano": env === "production",
}
});

View file

@ -568,19 +568,3 @@
},
};
</script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -547,19 +547,3 @@
},
};
</script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -88,23 +88,3 @@
methods: {}
};
</script>
<style scoped>
a {
color: #00B8D4;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -27,23 +27,3 @@
methods: {}
};
</script>
<style scoped>
a {
color: #00B8D4;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -12,7 +12,7 @@
Additionally duplicates are removed and images get tagged and metadata (like location, camera model etc.) will be extracted. In case you have not supported file types
(e.g. videos) within the folder you import --> those are ignored. </p>
<v-btn color="success" @click="$refs.inputUpload.click()" type="file" class="importbtn">Import & Index</v-btn>
<input v-show="false" ref="inputUpload" type="file" @change="inputFileExcel" >
<input v-show="false" ref="inputUpload" type="file" >
</v-form>
</v-container>
<v-container fluid>
@ -28,233 +28,11 @@
</template>
<script>
import Photo from 'model/photo';
export default {
name: 'import',
props: {},
data() {
const query = this.$route.query;
const order = query['order'] ? query['order'] : 'newest';
const camera = query['camera'] ? parseInt(query['camera']) : 0;
const q = query['q'] ? query['q'] : '';
const country = query['country'] ? query['country'] : '';
const view = query['view'] ? query['view'] : 'details';
const cameras = [{ID: 0, CameraModel: 'All Cameras'}].concat(this.$config.getValue('cameras'));
const countries = [{
LocCountryCode: '',
LocCountry: 'All Countries'
}].concat(this.$config.getValue('countries'));
return {
'snackbarVisible': false,
'snackbarText': '',
'advandedSearch': false,
'window': {
width: 0,
height: 0
},
'results': [],
'query': {
view: view,
country: country,
camera: camera,
order: order,
q: q,
},
'options': {
'categories': [
{value: '', text: 'All Categories'},
{value: 'airport', text: 'Airport'},
{value: 'amenity', text: 'Amenity'},
{value: 'building', text: 'Building'},
{value: 'historic', text: 'Historic'},
{value: 'shop', text: 'Shop'},
{value: 'tourism', text: 'Tourism'},
],
'views': [
{value: 'details', text: 'Details'},
{value: 'list', text: 'List'},
{value: 'tiles', text: 'Tiles'},
],
'countries': countries,
'cameras': cameras,
'sorting': [
{value: 'newest', text: 'Newest first'},
{value: 'oldest', text: 'Oldest first'},
{value: 'imported', text: 'Recently imported'},
],
},
'listColumns': [
{text: 'Title', value: 'PhotoTitle'},
{text: 'Description', value: 'PhotoFavorite'},
{text: 'Taken At', value: 'TakenAt'},
{text: 'City', value: 'LocCity'},
{text: 'Country', value: 'LocCountry'},
{text: 'Camera', value: 'CameraModel'},
],
'view': view,
'loadMoreDisabled': true,
'pageSize': 60,
'offset': 0,
'lastQuery': {},
'submitTimeout': false,
'selected': [],
'dialog': false,
};
},
destroyed() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
this.window.width = window.innerWidth;
this.window.height = window.innerHeight;
},
clearSelection() {
for (let i = 0; i < this.selected.length; i++) {
this.selected[i].selected = false;
}
this.selected = [];
this.updateSnackbar();
},
updateSnackbar(text) {
if (!text) text = "";
this.snackbarText = text;
this.snackbarVisible = this.snackbarText !== "";
},
showSnackbar() {
this.snackbarVisible = this.snackbarText !== "";
},
hideSnackbar() {
this.snackbarVisible = false;
},
selectPhoto(photo, ev) {
if (photo.selected) {
for (let i = 0; i < this.selected.length; i++) {
if (this.selected[i].id === photo.id) {
this.selected.splice(i, 1);
break;
}
}
photo.selected = false;
} else {
this.selected.push(photo);
photo.selected = true;
}
if (this.selected.length > 0) {
if (this.selected.length === 1) {
this.snackbarText = 'One photo selected';
} else {
this.snackbarText = this.selected.length + ' photos selected';
}
this.snackbarVisible = true;
} else {
this.snackbarText = '';
this.snackbarVisible = false;
}
},
likePhoto(photo) {
photo.PhotoFavorite = !photo.PhotoFavorite;
photo.like(photo.PhotoFavorite);
},
deletePhoto(photo) {
this.$alert.success('Photo deleted');
},
formChange(event) {
this.refreshList();
},
clearQuery() {
this.query.q = '';
this.refreshList();
},
openPhoto(index) {
this.$refs.gallery.openPhoto(index)
},
loadMore() {
if (this.loadMoreDisabled) return;
this.loadMoreDisabled = true;
this.offset += this.pageSize;
const params = {
count: this.pageSize,
offset: this.offset,
};
Object.assign(params, this.lastQuery);
Photo.search(params).then(response => {
console.log(response);
this.results = this.results.concat(response.models);
this.loadMoreDisabled = (response.models.length < this.pageSize);
if (this.loadMoreDisabled) {
this.$alert.info('All ' + this.results.length + ' photos loaded');
}
});
},
refreshList() {
this.loadMoreDisabled = true;
// Don't query the same data more than once:197
if (JSON.stringify(this.lastQuery) === JSON.stringify(this.query)) return;
Object.assign(this.lastQuery, this.query);
this.offset = 0;
this.$router.replace({query: this.query});
const params = {
count: this.pageSize,
offset: this.offset,
};
Object.assign(params, this.query);
Photo.search(params).then(response => {
this.results = response.models;
this.loadMoreDisabled = (response.models.length < this.pageSize);
if (this.loadMoreDisabled) {
this.$alert.info(this.results.length + ' photos found');
} else {
this.$alert.info('More than 50 photos found');
}
});
}
},
beforeRouteLeave(to, from, next) {
next()
},
created() {
window.addEventListener('resize', this.handleResize);
this.handleResize();
this.refreshList();
return {}
},
};
</script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -12,7 +12,7 @@
Additionally duplicates are removed and images get tagged and metadata (like location, camera model etc.) will be extracted. In case you have not supported file types
(e.g. videos) within the folder you import --> those are ignored. </p>
<v-btn color="success" @click="$refs.inputUpload.click()" type="file" class="importbtn" disabled>Import & Index</v-btn>
<input v-show="false" ref="inputUpload" type="file" @change="inputFileExcel" >
<input v-show="false" ref="inputUpload" type="file">
<v-flex xs12 sm6 offset-sm3>
<v-card class="card">
<v-card-title primary-title>
@ -42,233 +42,11 @@
</template>
<script>
import Photo from 'model/photo';
export default {
name: 'import',
props: {},
data() {
const query = this.$route.query;
const order = query['order'] ? query['order'] : 'newest';
const camera = query['camera'] ? parseInt(query['camera']) : 0;
const q = query['q'] ? query['q'] : '';
const country = query['country'] ? query['country'] : '';
const view = query['view'] ? query['view'] : 'details';
const cameras = [{ID: 0, CameraModel: 'All Cameras'}].concat(this.$config.getValue('cameras'));
const countries = [{
LocCountryCode: '',
LocCountry: 'All Countries'
}].concat(this.$config.getValue('countries'));
return {
'snackbarVisible': false,
'snackbarText': '',
'advandedSearch': false,
'window': {
width: 0,
height: 0
},
'results': [],
'query': {
view: view,
country: country,
camera: camera,
order: order,
q: q,
},
'options': {
'categories': [
{value: '', text: 'All Categories'},
{value: 'airport', text: 'Airport'},
{value: 'amenity', text: 'Amenity'},
{value: 'building', text: 'Building'},
{value: 'historic', text: 'Historic'},
{value: 'shop', text: 'Shop'},
{value: 'tourism', text: 'Tourism'},
],
'views': [
{value: 'details', text: 'Details'},
{value: 'list', text: 'List'},
{value: 'tiles', text: 'Tiles'},
],
'countries': countries,
'cameras': cameras,
'sorting': [
{value: 'newest', text: 'Newest first'},
{value: 'oldest', text: 'Oldest first'},
{value: 'imported', text: 'Recently imported'},
],
},
'listColumns': [
{text: 'Title', value: 'PhotoTitle'},
{text: 'Description', value: 'PhotoFavorite'},
{text: 'Taken At', value: 'TakenAt'},
{text: 'City', value: 'LocCity'},
{text: 'Country', value: 'LocCountry'},
{text: 'Camera', value: 'CameraModel'},
],
'view': view,
'loadMoreDisabled': true,
'pageSize': 60,
'offset': 0,
'lastQuery': {},
'submitTimeout': false,
'selected': [],
'dialog': false,
};
},
destroyed() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
this.window.width = window.innerWidth;
this.window.height = window.innerHeight;
},
clearSelection() {
for (let i = 0; i < this.selected.length; i++) {
this.selected[i].selected = false;
}
this.selected = [];
this.updateSnackbar();
},
updateSnackbar(text) {
if (!text) text = "";
this.snackbarText = text;
this.snackbarVisible = this.snackbarText !== "";
},
showSnackbar() {
this.snackbarVisible = this.snackbarText !== "";
},
hideSnackbar() {
this.snackbarVisible = false;
},
selectPhoto(photo, ev) {
if (photo.selected) {
for (let i = 0; i < this.selected.length; i++) {
if (this.selected[i].id === photo.id) {
this.selected.splice(i, 1);
break;
}
}
photo.selected = false;
} else {
this.selected.push(photo);
photo.selected = true;
}
if (this.selected.length > 0) {
if (this.selected.length === 1) {
this.snackbarText = 'One photo selected';
} else {
this.snackbarText = this.selected.length + ' photos selected';
}
this.snackbarVisible = true;
} else {
this.snackbarText = '';
this.snackbarVisible = false;
}
},
likePhoto(photo) {
photo.PhotoFavorite = !photo.PhotoFavorite;
photo.like(photo.PhotoFavorite);
},
deletePhoto(photo) {
this.$alert.success('Photo deleted');
},
formChange(event) {
this.refreshList();
},
clearQuery() {
this.query.q = '';
this.refreshList();
},
openPhoto(index) {
this.$refs.gallery.openPhoto(index)
},
loadMore() {
if (this.loadMoreDisabled) return;
this.loadMoreDisabled = true;
this.offset += this.pageSize;
const params = {
count: this.pageSize,
offset: this.offset,
};
Object.assign(params, this.lastQuery);
Photo.search(params).then(response => {
console.log(response);
this.results = this.results.concat(response.models);
this.loadMoreDisabled = (response.models.length < this.pageSize);
if (this.loadMoreDisabled) {
this.$alert.info('All ' + this.results.length + ' photos loaded');
}
});
},
refreshList() {
this.loadMoreDisabled = true;
// Don't query the same data more than once:197
if (JSON.stringify(this.lastQuery) === JSON.stringify(this.query)) return;
Object.assign(this.lastQuery, this.query);
this.offset = 0;
this.$router.replace({query: this.query});
const params = {
count: this.pageSize,
offset: this.offset,
};
Object.assign(params, this.query);
Photo.search(params).then(response => {
this.results = response.models;
this.loadMoreDisabled = (response.models.length < this.pageSize);
if (this.loadMoreDisabled) {
this.$alert.info(this.results.length + ' photos found');
} else {
this.$alert.info('More than 50 photos found');
}
});
}
},
beforeRouteLeave(to, from, next) {
next()
},
created() {
window.addEventListener('resize', this.handleResize);
this.handleResize();
this.refreshList();
return {}
},
};
</script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -12,7 +12,7 @@
Additionally duplicates are removed and images get tagged and metadata (like location, camera model etc.) will be extracted. In case you have not supported file types
(e.g. videos) within the folder you import --> those are ignored. </p>
<v-btn color="success" @click="$refs.inputUpload.click()" type="file" class="importbtn" disabled>Import & Index</v-btn>
<input v-show="false" ref="inputUpload" type="file" @change="inputFileExcel" >
<input v-show="false" ref="inputUpload" type="file">
<v-flex xs12 sm6 offset-sm3>
<v-card class="card">
<v-card-title primary-title>
@ -47,233 +47,11 @@
</template>
<script>
import Photo from 'model/photo';
export default {
name: 'import',
props: {},
data() {
const query = this.$route.query;
const order = query['order'] ? query['order'] : 'newest';
const camera = query['camera'] ? parseInt(query['camera']) : 0;
const q = query['q'] ? query['q'] : '';
const country = query['country'] ? query['country'] : '';
const view = query['view'] ? query['view'] : 'details';
const cameras = [{ID: 0, CameraModel: 'All Cameras'}].concat(this.$config.getValue('cameras'));
const countries = [{
LocCountryCode: '',
LocCountry: 'All Countries'
}].concat(this.$config.getValue('countries'));
return {
'snackbarVisible': false,
'snackbarText': '',
'advandedSearch': false,
'window': {
width: 0,
height: 0
},
'results': [],
'query': {
view: view,
country: country,
camera: camera,
order: order,
q: q,
},
'options': {
'categories': [
{value: '', text: 'All Categories'},
{value: 'airport', text: 'Airport'},
{value: 'amenity', text: 'Amenity'},
{value: 'building', text: 'Building'},
{value: 'historic', text: 'Historic'},
{value: 'shop', text: 'Shop'},
{value: 'tourism', text: 'Tourism'},
],
'views': [
{value: 'details', text: 'Details'},
{value: 'list', text: 'List'},
{value: 'tiles', text: 'Tiles'},
],
'countries': countries,
'cameras': cameras,
'sorting': [
{value: 'newest', text: 'Newest first'},
{value: 'oldest', text: 'Oldest first'},
{value: 'imported', text: 'Recently imported'},
],
},
'listColumns': [
{text: 'Title', value: 'PhotoTitle'},
{text: 'Description', value: 'PhotoFavorite'},
{text: 'Taken At', value: 'TakenAt'},
{text: 'City', value: 'LocCity'},
{text: 'Country', value: 'LocCountry'},
{text: 'Camera', value: 'CameraModel'},
],
'view': view,
'loadMoreDisabled': true,
'pageSize': 60,
'offset': 0,
'lastQuery': {},
'submitTimeout': false,
'selected': [],
'dialog': false,
};
},
destroyed() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
this.window.width = window.innerWidth;
this.window.height = window.innerHeight;
},
clearSelection() {
for (let i = 0; i < this.selected.length; i++) {
this.selected[i].selected = false;
}
this.selected = [];
this.updateSnackbar();
},
updateSnackbar(text) {
if (!text) text = "";
this.snackbarText = text;
this.snackbarVisible = this.snackbarText !== "";
},
showSnackbar() {
this.snackbarVisible = this.snackbarText !== "";
},
hideSnackbar() {
this.snackbarVisible = false;
},
selectPhoto(photo, ev) {
if (photo.selected) {
for (let i = 0; i < this.selected.length; i++) {
if (this.selected[i].id === photo.id) {
this.selected.splice(i, 1);
break;
}
}
photo.selected = false;
} else {
this.selected.push(photo);
photo.selected = true;
}
if (this.selected.length > 0) {
if (this.selected.length === 1) {
this.snackbarText = 'One photo selected';
} else {
this.snackbarText = this.selected.length + ' photos selected';
}
this.snackbarVisible = true;
} else {
this.snackbarText = '';
this.snackbarVisible = false;
}
},
likePhoto(photo) {
photo.PhotoFavorite = !photo.PhotoFavorite;
photo.like(photo.PhotoFavorite);
},
deletePhoto(photo) {
this.$alert.success('Photo deleted');
},
formChange(event) {
this.refreshList();
},
clearQuery() {
this.query.q = '';
this.refreshList();
},
openPhoto(index) {
this.$refs.gallery.openPhoto(index)
},
loadMore() {
if (this.loadMoreDisabled) return;
this.loadMoreDisabled = true;
this.offset += this.pageSize;
const params = {
count: this.pageSize,
offset: this.offset,
};
Object.assign(params, this.lastQuery);
Photo.search(params).then(response => {
console.log(response);
this.results = this.results.concat(response.models);
this.loadMoreDisabled = (response.models.length < this.pageSize);
if (this.loadMoreDisabled) {
this.$alert.info('All ' + this.results.length + ' photos loaded');
}
});
},
refreshList() {
this.loadMoreDisabled = true;
// Don't query the same data more than once:197
if (JSON.stringify(this.lastQuery) === JSON.stringify(this.query)) return;
Object.assign(this.lastQuery, this.query);
this.offset = 0;
this.$router.replace({query: this.query});
const params = {
count: this.pageSize,
offset: this.offset,
};
Object.assign(params, this.query);
Photo.search(params).then(response => {
this.results = response.models;
this.loadMoreDisabled = (response.models.length < this.pageSize);
if (this.loadMoreDisabled) {
this.$alert.info(this.results.length + ' photos found');
} else {
this.$alert.info('More than 50 photos found');
}
});
}
},
beforeRouteLeave(to, from, next) {
next()
},
created() {
window.addEventListener('resize', this.handleResize);
this.handleResize();
this.refreshList();
return {}
},
};
</script>
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -12,7 +12,7 @@
v-model="query.q"
@keyup.enter.native="formChange"
></v-text-field>
<!-- v-btn @click="formChange" color="secondary">Create Filter</v-btn -->
<v-spacer></v-spacer>
<v-btn icon @click="advandedSearch = !advandedSearch">
@ -324,7 +324,6 @@
<v-spacer></v-spacer>
<v-combobox
v-model="model"
:filter="filter"
:hide-no-data="!search"
:items="items"
:search-input.sync="search"
@ -390,7 +389,6 @@
<h4>Remove tags</h4>
<v-combobox
v-model="model"
:filter="filter"
:hide-no-data="!search"
:items="items"
:search-input.sync="search"
@ -722,7 +720,7 @@
this.$alert.info('More than 50 photos found');
}
});
}
},
},
beforeRouteLeave(to, from, next) {
next()
@ -734,6 +732,3 @@
},
};
</script>
<style scoped>
</style>

View file

@ -398,6 +398,3 @@
},
};
</script>
<style scoped>
</style>

View file

@ -22,24 +22,3 @@
methods: {},
};
</script>
<style scoped>
.map {
width: 100%;
height: 100%;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -39,23 +39,3 @@
}
};
</script>
<style scoped>
a {
color: #00B8D4;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -461,6 +461,9 @@
this.$alert.info('More than 50 photos found');
}
});
},
translation() {
return ''
}
},
beforeRouteLeave(to, from, next) {
@ -473,6 +476,3 @@
},
};
</script>
<style scoped>
</style>

View file

@ -27,23 +27,3 @@
methods: {}
};
</script>
<style scoped>
a {
color: #00B8D4;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
</style>

View file

@ -1,6 +1,6 @@
import axios from 'axios';
import Event from 'pubsub-js';
import 'babel-polyfill';
import '@babel/polyfill';
const Api = axios.create({
baseURL: '/api/v1',

View file

@ -117,6 +117,3 @@
},
};
</script>
<style scoped>
</style>

View file

@ -293,6 +293,3 @@
}
}
</script>
<style scoped>
</style>

View file

@ -223,6 +223,3 @@
}
};
</script>
<style scoped>
</style>

View file

@ -113,6 +113,9 @@
}
},
openGallery: function () {
},
openPhoto: function (index = 0) {
if (this.$props.images.length === 0) {
return
@ -170,7 +173,3 @@
}
}
</script>
<style scoped>
</style>

View file

@ -1,6 +1,6 @@
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
@ -10,15 +10,11 @@ const PATHS = {
build: path.join(__dirname, '../assets/server/public/build'),
};
const cssPlugin = new ExtractTextPlugin({
filename: '[name].css',
});
// See https://github.com/webpack/loader-utils/issues/56
process.noDeprecation = true;
const isDev = process.env.NODE_ENV !== 'production';
const config = {
devtool: false,
mode: 'production',
devtool: isDev ? 'inline-source-map' : false,
entry: {
app: PATHS.app,
},
@ -36,11 +32,18 @@ const config = {
},
},
plugins: [
cssPlugin
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
node: {
fs: 'empty',
},
performance: {
hints: 'warning',
maxEntrypointSize: 1512000,
maxAssetSize: 1512000
},
module: {
rules: [
{
@ -50,46 +53,120 @@ const config = {
loader: 'eslint-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['es2015'],
test: /\.vue$/,
loader: "vue-loader",
options: {
loaders: {
js: 'babel-loader',
css: 'css-loader',
}
},
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
js: 'babel-loader?presets[]=es2015',
},
test: /\.js$/,
loader: 'babel-loader',
exclude: file => (
/node_modules/.test(file)
),
query: {
presets: ['@babel/preset-env'],
compact: false
},
},
{
test: /\.css$/,
include: PATHS.css,
exclude: /node_modules/,
use: cssPlugin.extract({
use: 'css-loader',
fallback: 'style-loader',
}),
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: false,
fallback: 'vue-style-loader',
use: [
// "vue-style-loader",
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
sourceMap: isDev
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: isDev,
config: {
path: path.resolve(__dirname, './postcss.config.js'),
},
},
},
'resolve-url-loader',
],
publicPath: PATHS.build,
},
},
"css-loader",
]
},
{
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', 'css-loader']
loaders: [
"vue-style-loader",
'style-loader',
{
loader: 'css-loader',
options: { importLoaders: 1, sourceMap: isDev },
},
{
loader: 'postcss-loader',
options: {
sourceMap: isDev,
config: {
path: path.resolve(__dirname, './postcss.config.js'),
},
},
},
'resolve-url-loader'
]
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
test: /\.s[c|a]ss$/,
use: [
"vue-style-loader",
'style-loader',
{
loader: 'css-loader',
options: { importLoaders: 2, sourceMap: isDev },
},
{
loader: 'postcss-loader',
options: {
sourceMap: isDev,
config: {
path: path.resolve(__dirname, './postcss.config.js'),
},
},
},
'resolve-url-loader',
'sass-loader'
]
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
test: /\.(png|jpg|jpeg|gif)$/,
loader: 'url-loader',
},
{
test: /\.(wav|mp3|eot|ttf)$/,
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
options: {
name: '[hash].[ext]',
publicPath: '/assets/build/fonts',
outputPath: 'fonts',
}
},
{
test: /\.svg/,
@ -103,7 +180,7 @@ const config = {
};
// No sourcemap for production
if (process.env.NODE_ENV !== "production") {
if (isDev) {
const devToolPlugin = new webpack.SourceMapDevToolPlugin({
filename: '[name].map',
});
@ -111,4 +188,4 @@ if (process.env.NODE_ENV !== "production") {
config.plugins.push(devToolPlugin);
}
module.exports = config;
module.exports = config;

View file

@ -6,7 +6,7 @@ if [[ -z $TRAVIS_BRANCH ]]; then
fi
if [[ $TRAVIS_BRANCH == "develop" ]]; then
docker-compose -f docker-compose.travis.yml exec photoprism make all install migrate test-codecov;
docker-compose -f docker-compose.travis.yml exec photoprism make all test-js install migrate test-codecov;
else
docker-compose -f docker-compose.travis.yml exec photoprism make all install migrate test;
docker-compose -f docker-compose.travis.yml exec photoprism make all test-js install migrate test;
fi