Option to open links in the same tab. Api upload icon. Render image icon instead of MDI. Dockerfile client dependencies fix.
This commit is contained in:
parent
e3ed429da1
commit
6c067bee31
18 changed files with 214 additions and 13 deletions
|
@ -12,6 +12,7 @@ COPY . .
|
|||
|
||||
RUN mkdir -p ./public ./data \
|
||||
&& cd ./client \
|
||||
&& npm install --production \
|
||||
&& npm run build \
|
||||
&& cd .. \
|
||||
&& mv ./client/build/* ./public \
|
||||
|
|
|
@ -13,6 +13,7 @@ COPY . .
|
|||
|
||||
RUN mkdir -p ./public ./data \
|
||||
&& cd ./client \
|
||||
&& npm install --production \
|
||||
&& npm run build \
|
||||
&& cd .. \
|
||||
&& mv ./client/build/* ./public \
|
||||
|
|
|
@ -99,6 +99,11 @@ Follow instructions from wiki: [Installation without Docker](https://github.com/
|
|||
- Format: `www.domain.com`, `domain.com`, `sub.domain.com`, `local`, `ip`, `ip:port`
|
||||
- Redirect: `http://{dest}`
|
||||
|
||||
### Custom CSS
|
||||
> This is an experimental feature. Its behaviour might change in the future.
|
||||
>
|
||||
Follow instructions from wiki: [Custom CSS](https://github.com/pawelmalak/flame/wiki/Custom-CSS)
|
||||
|
||||
## Support
|
||||
If you want to support development of Flame and my upcoming self-hosted and open source projects you can use the following link:
|
||||
|
||||
|
|
8
api.js
8
api.js
|
@ -1,15 +1,17 @@
|
|||
const path = require('path');
|
||||
const { join } = require('path');
|
||||
const express = require('express');
|
||||
const errorHandler = require('./middleware/errorHandler');
|
||||
|
||||
const api = express();
|
||||
|
||||
// Static files
|
||||
api.use(express.static(path.join(__dirname, 'public')));
|
||||
api.use(express.static(join(__dirname, 'public')));
|
||||
api.use('/uploads', express.static(join(__dirname, 'data/uploads')));
|
||||
api.get(/^\/(?!api)/, (req, res) => {
|
||||
res.sendFile(path.join(__dirname, 'public/index.html'));
|
||||
res.sendFile(join(__dirname, 'public/index.html'));
|
||||
})
|
||||
|
||||
|
||||
// Body parser
|
||||
api.use(express.json());
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
REACT_APP_VERSION=1.4.2
|
||||
REACT_APP_VERSION=1.4.3
|
|
@ -39,4 +39,12 @@
|
|||
.AppCard:hover {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.CustomIcon {
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
margin-top: 2px;
|
||||
margin-left: 2px;
|
||||
object-fit: contain;
|
||||
}
|
|
@ -3,6 +3,7 @@ import Icon from '../../UI/Icons/Icon/Icon';
|
|||
import { iconParser, urlParser } from '../../../utility';
|
||||
|
||||
import { App } from '../../../interfaces';
|
||||
import { searchConfig } from '../../../utility';
|
||||
|
||||
interface ComponentProps {
|
||||
app: App;
|
||||
|
@ -15,12 +16,19 @@ const AppCard = (props: ComponentProps): JSX.Element => {
|
|||
return (
|
||||
<a
|
||||
href={redirectUrl}
|
||||
target='_blank'
|
||||
target={searchConfig('openSameTab', false) ? '' : '_blank'}
|
||||
rel='noreferrer'
|
||||
className={classes.AppCard}
|
||||
>
|
||||
<div className={classes.AppCardIcon}>
|
||||
<Icon icon={iconParser(props.app.icon)} />
|
||||
{(/.(jpeg|jpg|png)$/).test(props.app.icon)
|
||||
? <img
|
||||
src={`/uploads/${props.app.icon}`}
|
||||
alt={`${props.app.name} icon`}
|
||||
className={classes.CustomIcon}
|
||||
/>
|
||||
: <Icon icon={iconParser(props.app.icon)} />
|
||||
}
|
||||
</div>
|
||||
<div className={classes.AppCardDetails}>
|
||||
<h5>{props.app.name}</h5>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Bookmark, Category } from '../../../interfaces';
|
|||
import classes from './BookmarkCard.module.css';
|
||||
|
||||
import Icon from '../../UI/Icons/Icon/Icon';
|
||||
import { iconParser, urlParser } from '../../../utility';
|
||||
import { iconParser, urlParser, searchConfig } from '../../../utility';
|
||||
|
||||
interface ComponentProps {
|
||||
category: Category;
|
||||
|
@ -19,7 +19,7 @@ const BookmarkCard = (props: ComponentProps): JSX.Element => {
|
|||
return (
|
||||
<a
|
||||
href={redirectUrl}
|
||||
target='_blank'
|
||||
target={searchConfig('openSameTab', false) ? '' : '_blank'}
|
||||
rel='noreferrer'
|
||||
key={`bookmark-${bookmark.id}`}>
|
||||
{bookmark.icon && (
|
||||
|
|
|
@ -29,7 +29,8 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
|||
pinAppsByDefault: 1,
|
||||
pinCategoriesByDefault: 1,
|
||||
hideHeader: 0,
|
||||
useOrdering: 'createdAt'
|
||||
useOrdering: 'createdAt',
|
||||
openSameTab: 0
|
||||
})
|
||||
|
||||
// Get config
|
||||
|
@ -39,7 +40,8 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
|||
pinAppsByDefault: searchConfig('pinAppsByDefault', 1),
|
||||
pinCategoriesByDefault: searchConfig('pinCategoriesByDefault', 1),
|
||||
hideHeader: searchConfig('hideHeader', 0),
|
||||
useOrdering: searchConfig('useOrdering', 'createdAt')
|
||||
useOrdering: searchConfig('useOrdering', 'createdAt'),
|
||||
openSameTab: searchConfig('openSameTab', 0)
|
||||
})
|
||||
}, [props.loading]);
|
||||
|
||||
|
@ -134,6 +136,18 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
|||
<option value='orderId'>Custom order</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor='openSameTab'>Open all links in the same tab</label>
|
||||
<select
|
||||
id='openSameTab'
|
||||
name='openSameTab'
|
||||
value={formData.openSameTab}
|
||||
onChange={(e) => inputChangeHandler(e, true)}
|
||||
>
|
||||
<option value={1}>True</option>
|
||||
<option value={0}>False</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<Button>Save changes</Button>
|
||||
</form>
|
||||
)
|
||||
|
|
|
@ -11,4 +11,5 @@ export interface SettingsForm {
|
|||
pinCategoriesByDefault: number;
|
||||
hideHeader: number;
|
||||
useOrdering: string;
|
||||
openSameTab: number;
|
||||
}
|
|
@ -5,11 +5,16 @@ module.exports = function (app) {
|
|||
target: 'http://localhost:5005'
|
||||
})
|
||||
|
||||
const assetsProxy = createProxyMiddleware('/uploads', {
|
||||
target: 'http://localhost:5005'
|
||||
})
|
||||
|
||||
const wsProxy = createProxyMiddleware('/socket', {
|
||||
target: 'http://localhost:5005',
|
||||
ws: true
|
||||
})
|
||||
|
||||
app.use(apiProxy);
|
||||
app.use(assetsProxy);
|
||||
app.use(wsProxy);
|
||||
};
|
|
@ -14,11 +14,18 @@ exports.createApp = asyncWrapper(async (req, res, next) => {
|
|||
});
|
||||
|
||||
let app;
|
||||
let _body = { ...req.body };
|
||||
|
||||
if (req.file) {
|
||||
console.log(req.file.filename)
|
||||
_body.icon = req.file.filename;
|
||||
}
|
||||
|
||||
|
||||
if (pinApps) {
|
||||
if (parseInt(pinApps.value)) {
|
||||
app = await App.create({
|
||||
...req.body,
|
||||
..._body,
|
||||
isPinned: true
|
||||
})
|
||||
} else {
|
||||
|
|
27
middleware/multer.js
Normal file
27
middleware/multer.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
const fs = require('fs');
|
||||
const { join } = require('path');
|
||||
const multer = require('multer');
|
||||
const uuid = require('uuid');
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, './data/uploads');
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
cb(null, Date.now() + '--' + file.originalname);
|
||||
}
|
||||
})
|
||||
|
||||
const supportedTypes = ['jpg', 'jpeg', 'png'];
|
||||
|
||||
const fileFilter = (req, file, cb) => {
|
||||
if (supportedTypes.includes(file.mimetype.split('/')[1])) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
const upload = multer({ storage, fileFilter });
|
||||
|
||||
module.exports = upload.single('icon');
|
115
package-lock.json
generated
115
package-lock.json
generated
|
@ -224,6 +224,11 @@
|
|||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"append-field": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||
"integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY="
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
|
@ -364,6 +369,43 @@
|
|||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"busboy": {
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
|
||||
"integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
|
||||
"requires": {
|
||||
"dicer": "0.2.5",
|
||||
"readable-stream": "1.1.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||
}
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||
|
@ -553,6 +595,17 @@
|
|||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"concurrently": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.0.2.tgz",
|
||||
|
@ -741,6 +794,38 @@
|
|||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
||||
},
|
||||
"dicer": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
|
||||
"integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
|
||||
"requires": {
|
||||
"readable-stream": "1.1.x",
|
||||
"streamsearch": "0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||
}
|
||||
}
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
|
||||
|
@ -1611,6 +1696,21 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"multer": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz",
|
||||
"integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==",
|
||||
"requires": {
|
||||
"append-field": "^1.0.0",
|
||||
"busboy": "^0.2.11",
|
||||
"concat-stream": "^1.5.2",
|
||||
"mkdirp": "^0.5.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"on-finished": "^2.3.0",
|
||||
"type-is": "^1.6.4",
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"needle": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz",
|
||||
|
@ -2411,6 +2511,11 @@
|
|||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
|
||||
},
|
||||
"streamsearch": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||
|
@ -2577,6 +2682,11 @@
|
|||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||
},
|
||||
"typedarray-to-buffer": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||
|
@ -2804,6 +2914,11 @@
|
|||
"integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
"concurrently": "^6.0.2",
|
||||
"dotenv": "^9.0.0",
|
||||
"express": "^4.17.1",
|
||||
"multer": "^1.4.2",
|
||||
"node-schedule": "^2.0.0",
|
||||
"sequelize": "^6.6.2",
|
||||
"sqlite3": "^5.0.2",
|
||||
"uuid": "^8.3.2",
|
||||
"ws": "^7.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const upload = require('../middleware/multer');
|
||||
|
||||
const {
|
||||
createApp,
|
||||
|
@ -12,7 +13,7 @@ const {
|
|||
|
||||
router
|
||||
.route('/')
|
||||
.post(createApp)
|
||||
.post(upload, createApp)
|
||||
.get(getApps);
|
||||
|
||||
router
|
||||
|
|
|
@ -20,7 +20,7 @@ class Logger {
|
|||
// Timezone
|
||||
const tz = -d.getTimezoneOffset() / 60;
|
||||
|
||||
return `${year}-${month}-${day} ${hour}:${minutes}:${seconds}.${miliseconds} UTC${tz > 0 ? '+' + tz : tz}`;
|
||||
return `${year}-${month}-${day} ${hour}:${minutes}:${seconds}.${miliseconds} UTC${tz >= 0 ? '+' + tz : tz}`;
|
||||
}
|
||||
|
||||
parseDate(date, ms = false) {
|
||||
|
|
|
@ -35,6 +35,10 @@
|
|||
{
|
||||
"key": "useOrdering",
|
||||
"value": "createdAt"
|
||||
},
|
||||
{
|
||||
"key": "openSameTab",
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue