Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
adafce689d Bump url-parse from 1.5.3 to 1.5.10 in /client
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.10.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.10)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-27 20:33:28 +00:00
25 changed files with 200 additions and 229 deletions

View File

@@ -1,2 +0,0 @@
docker build -t pawelmalak/flame -t "pawelmalak/flame:$1" -f .docker/Dockerfile "$2" \
&& docker push pawelmalak/flame && docker push "pawelmalak/flame:$1"

View File

@@ -1,6 +0,0 @@
docker buildx build \
--platform linux/arm/v7,linux/arm64,linux/amd64 \
-f .docker/Dockerfile.multiarch \
-t pawelmalak/flame:multiarch \
-t "pawelmalak/flame:multiarch$1" \
--push "$2"

View File

@@ -27,4 +27,4 @@ EXPOSE 5005
ENV NODE_ENV=production
ENV PASSWORD=flame_password
CMD ["sh", "-c", "chown -R node /app/data && node server.js"]
CMD ["node", "server.js"]

View File

@@ -28,4 +28,4 @@ EXPOSE 5005
ENV NODE_ENV=production
ENV PASSWORD=flame_password
CMD ["sh", "-c", "chown -R node /app/data && node server.js"]
CMD ["node", "server.js"]

2
.env
View File

@@ -1,5 +1,5 @@
PORT=5005
NODE_ENV=development
VERSION=2.2.2
VERSION=2.2.1
PASSWORD=flame_password
SECRET=e02eb43d69953658c6d07311d6313f2d4467672cb881f96b29368ba1f3f4da4b

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
node_modules
data
public
!client/public
!client/public
build.sh

View File

@@ -1,10 +1,3 @@
### v2.2.2 (2022-03-21)
- Added option to get user location directly from the app ([#287](https://github.com/pawelmalak/flame/issues/287))
- Fixed bug with local search not working when using prefix ([#289](https://github.com/pawelmalak/flame/issues/289))
- Fixed bug with app description not updating when using custom icon ([#310](https://github.com/pawelmalak/flame/issues/310))
- Changed permissions to some files and directories created by Flame
- Changed some of the settings tabs
### v2.2.1 (2022-01-08)
- Local search will now include app descriptions ([#266](https://github.com/pawelmalak/flame/issues/266))
- Fixed bug with unsupported characters in local search [#279](https://github.com/pawelmalak/flame/issues/279))

View File

@@ -1 +1 @@
REACT_APP_VERSION=2.2.2
REACT_APP_VERSION=2.2.1

View File

@@ -19621,9 +19621,9 @@
}
},
"node_modules/url-parse": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
@@ -36979,9 +36979,9 @@
}
},
"url-parse": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"requires": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"

View File

@@ -64,9 +64,7 @@ export const AppForm = ({ modalHandler }: Props): JSX.Element => {
if (customIcon) {
data.append('icon', customIcon);
}
data.append('name', formData.name);
data.append('description', formData.description);
data.append('url', formData.url);
data.append('isPublic', `${formData.isPublic ? 1 : 0}`);

View File

@@ -94,7 +94,7 @@ export const AppTable = (props: Props): JSX.Element => {
) : (
<p>
Custom order is disabled. You can change it in the{' '}
<Link to="/settings/general">settings</Link>
<Link to="/settings/interface">settings</Link>
</p>
)}
</Message>

View File

@@ -102,7 +102,7 @@ export const CategoryTable = ({ openFormForUpdating }: Props): JSX.Element => {
) : (
<p>
Custom order is disabled. You can change it in the{' '}
<Link to="/settings/general">settings</Link>
<Link to="/settings/interface">settings</Link>
</p>
)}
</Message>

View File

@@ -69,7 +69,8 @@ export const SearchBar = (props: Props): JSX.Element => {
);
if (isLocal) {
setLocalSearch(search);
// no additional encoding required for local search
setLocalSearch(inputRef.current.value);
}
if (e.code === 'Enter' || e.code === 'NumpadEnter') {

View File

@@ -3,7 +3,7 @@ import { useState, useEffect, FormEvent, ChangeEvent, Fragment } from 'react';
import { useDispatch, useSelector } from 'react-redux';
// Typescript
import { Query, GeneralForm } from '../../../interfaces';
import { Query, SearchForm } from '../../../interfaces';
// Components
import { CustomQueries } from './CustomQueries/CustomQueries';
@@ -12,7 +12,7 @@ import { CustomQueries } from './CustomQueries/CustomQueries';
import { Button, SettingsHeadline, InputGroup } from '../../UI';
// Utils
import { inputHandler, generalSettingsTemplate } from '../../../utility';
import { inputHandler, searchSettingsTemplate } from '../../../utility';
// Data
import { queries } from '../../../utility/searchQueries.json';
@@ -22,20 +22,16 @@ import { State } from '../../../store/reducers';
import { bindActionCreators } from 'redux';
import { actionCreators } from '../../../store';
export const GeneralSettings = (): JSX.Element => {
const {
config: { loading, customQueries, config },
bookmarks: { categories },
} = useSelector((state: State) => state);
export const SearchSettings = (): JSX.Element => {
const { loading, customQueries, config } = useSelector(
(state: State) => state.config
);
const dispatch = useDispatch();
const { updateConfig, sortApps, sortCategories, sortBookmarks } =
bindActionCreators(actionCreators, dispatch);
const { updateConfig } = bindActionCreators(actionCreators, dispatch);
// Initial state
const [formData, setFormData] = useState<GeneralForm>(
generalSettingsTemplate
);
const [formData, setFormData] = useState<SearchForm>(searchSettingsTemplate);
// Get config
useEffect(() => {
@@ -50,16 +46,6 @@ export const GeneralSettings = (): JSX.Element => {
// Save settings
await updateConfig(formData);
// Sort entities with new settings
if (formData.useOrdering !== config.useOrdering) {
sortApps();
sortCategories();
for (let { id } of categories) {
sortBookmarks(id);
}
}
};
// Input handler
@@ -67,7 +53,7 @@ export const GeneralSettings = (): JSX.Element => {
e: ChangeEvent<HTMLInputElement | HTMLSelectElement>,
options?: { isNumber?: boolean; isBool?: boolean }
) => {
inputHandler<GeneralForm>({
inputHandler<SearchForm>({
e,
options,
setStateHandler: setFormData,
@@ -77,95 +63,12 @@ export const GeneralSettings = (): JSX.Element => {
return (
<Fragment>
{/* GENERAL SETTINGS */}
<form
onSubmit={(e) => formSubmitHandler(e)}
style={{ marginBottom: '30px' }}
>
{/* === GENERAL OPTIONS === */}
<SettingsHeadline text="General" />
{/* SORT TYPE */}
<InputGroup>
<label htmlFor="useOrdering">Sorting type</label>
<select
id="useOrdering"
name="useOrdering"
value={formData.useOrdering}
onChange={(e) => inputChangeHandler(e)}
>
<option value="createdAt">By creation date</option>
<option value="name">Alphabetical order</option>
<option value="orderId">Custom order</option>
</select>
</InputGroup>
{/* === APPS OPTIONS === */}
<SettingsHeadline text="Apps" />
{/* PIN APPS */}
<InputGroup>
<label htmlFor="pinAppsByDefault">
Pin new applications by default
</label>
<select
id="pinAppsByDefault"
name="pinAppsByDefault"
value={formData.pinAppsByDefault ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* APPS OPPENING */}
<InputGroup>
<label htmlFor="appsSameTab">Open applications in the same tab</label>
<select
id="appsSameTab"
name="appsSameTab"
value={formData.appsSameTab ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* === BOOKMARKS OPTIONS === */}
<SettingsHeadline text="Bookmarks" />
{/* PIN CATEGORIES */}
<InputGroup>
<label htmlFor="pinCategoriesByDefault">
Pin new categories by default
</label>
<select
id="pinCategoriesByDefault"
name="pinCategoriesByDefault"
value={formData.pinCategoriesByDefault ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* BOOKMARKS OPPENING */}
<InputGroup>
<label htmlFor="bookmarksSameTab">
Open bookmarks in the same tab
</label>
<select
id="bookmarksSameTab"
name="bookmarksSameTab"
value={formData.bookmarksSameTab ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* SEARCH SETTINGS */}
<SettingsHeadline text="Search" />
<InputGroup>
<label htmlFor="defaultSearchProvider">Default search provider</label>
<select
@@ -201,6 +104,32 @@ export const GeneralSettings = (): JSX.Element => {
</select>
</InputGroup>
<InputGroup>
<label htmlFor="hideSearch">Hide search bar</label>
<select
id="hideSearch"
name="hideSearch"
value={formData.hideSearch ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
<InputGroup>
<label htmlFor="disableAutofocus">Disable search bar autofocus</label>
<select
id="disableAutofocus"
name="disableAutofocus"
value={formData.disableAutofocus ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
<Button>Save changes</Button>
</form>

View File

@@ -16,7 +16,7 @@ import { WeatherSettings } from './WeatherSettings/WeatherSettings';
import { UISettings } from './UISettings/UISettings';
import { AppDetails } from './AppDetails/AppDetails';
import { StyleSettings } from './StyleSettings/StyleSettings';
import { GeneralSettings } from './GeneralSettings/GeneralSettings';
import { SearchSettings } from './SearchSettings/SearchSettings';
import { DockerSettings } from './DockerSettings/DockerSettings';
import { ProtectedRoute } from '../Routing/ProtectedRoute';
@@ -59,8 +59,8 @@ export const Settings = (): JSX.Element => {
component={WeatherSettings}
/>
<ProtectedRoute
path="/settings/general"
component={GeneralSettings}
path="/settings/search"
component={SearchSettings}
/>
<ProtectedRoute path="/settings/interface" component={UISettings} />
<ProtectedRoute

View File

@@ -7,22 +7,28 @@ import { bindActionCreators } from 'redux';
import { actionCreators } from '../../../store';
// Typescript
import { UISettingsForm } from '../../../interfaces';
import { OtherSettingsForm } from '../../../interfaces';
// UI
import { InputGroup, Button, SettingsHeadline } from '../../UI';
// Utils
import { uiSettingsTemplate, inputHandler } from '../../../utility';
import { otherSettingsTemplate, inputHandler } from '../../../utility';
export const UISettings = (): JSX.Element => {
const { loading, config } = useSelector((state: State) => state.config);
const {
config: { loading, config },
bookmarks: { categories },
} = useSelector((state: State) => state);
const dispatch = useDispatch();
const { updateConfig } = bindActionCreators(actionCreators, dispatch);
const { updateConfig, sortApps, sortCategories, sortBookmarks } =
bindActionCreators(actionCreators, dispatch);
// Initial state
const [formData, setFormData] = useState<UISettingsForm>(uiSettingsTemplate);
const [formData, setFormData] = useState<OtherSettingsForm>(
otherSettingsTemplate
);
// Get config
useEffect(() => {
@@ -40,6 +46,16 @@ export const UISettings = (): JSX.Element => {
// Update local page title
document.title = formData.customTitle;
// Sort entities with new settings
if (formData.useOrdering !== config.useOrdering) {
sortApps();
sortCategories();
for (let { id } of categories) {
sortBookmarks(id);
}
}
};
// Input handler
@@ -47,7 +63,7 @@ export const UISettings = (): JSX.Element => {
e: ChangeEvent<HTMLInputElement | HTMLSelectElement>,
options?: { isNumber?: boolean; isBool?: boolean }
) => {
inputHandler<UISettingsForm>({
inputHandler<OtherSettingsForm>({
e,
options,
setStateHandler: setFormData,
@@ -72,36 +88,6 @@ export const UISettings = (): JSX.Element => {
/>
</InputGroup>
{/* === SEARCH OPTIONS === */}
<SettingsHeadline text="Search" />
{/* HIDE SEARCHBAR */}
<InputGroup>
<label htmlFor="hideSearch">Hide search bar</label>
<select
id="hideSearch"
name="hideSearch"
value={formData.hideSearch ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* AUTOFOCUS SEARCHBAR */}
<InputGroup>
<label htmlFor="disableAutofocus">Disable search bar autofocus</label>
<select
id="disableAutofocus"
name="disableAutofocus"
value={formData.disableAutofocus ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* === HEADER OPTIONS === */}
<SettingsHeadline text="Header" />
{/* HIDE HEADER */}
@@ -174,8 +160,8 @@ export const UISettings = (): JSX.Element => {
onChange={(e) => inputChangeHandler(e)}
/>
<span>
Greetings must be separated with semicolon. All 4 messages must be
filled, even if they are the same
Greetings must be separated with semicolon. Only 4 messages can be
used
</span>
</InputGroup>
@@ -207,8 +193,85 @@ export const UISettings = (): JSX.Element => {
<span>Names must be separated with semicolon</span>
</InputGroup>
{/* === SECTIONS OPTIONS === */}
<SettingsHeadline text="Sections" />
{/* === BEAHVIOR OPTIONS === */}
<SettingsHeadline text="App Behavior" />
{/* PIN APPS */}
<InputGroup>
<label htmlFor="pinAppsByDefault">
Pin new applications by default
</label>
<select
id="pinAppsByDefault"
name="pinAppsByDefault"
value={formData.pinAppsByDefault ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* PIN CATEGORIES */}
<InputGroup>
<label htmlFor="pinCategoriesByDefault">
Pin new categories by default
</label>
<select
id="pinCategoriesByDefault"
name="pinCategoriesByDefault"
value={formData.pinCategoriesByDefault ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* SORT TYPE */}
<InputGroup>
<label htmlFor="useOrdering">Sorting type</label>
<select
id="useOrdering"
name="useOrdering"
value={formData.useOrdering}
onChange={(e) => inputChangeHandler(e)}
>
<option value="createdAt">By creation date</option>
<option value="name">Alphabetical order</option>
<option value="orderId">Custom order</option>
</select>
</InputGroup>
{/* APPS OPPENING */}
<InputGroup>
<label htmlFor="appsSameTab">Open applications in the same tab</label>
<select
id="appsSameTab"
name="appsSameTab"
value={formData.appsSameTab ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* BOOKMARKS OPPENING */}
<InputGroup>
<label htmlFor="bookmarksSameTab">Open bookmarks in the same tab</label>
<select
id="bookmarksSameTab"
name="bookmarksSameTab"
value={formData.bookmarksSameTab ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
{/* === MODULES OPTIONS === */}
<SettingsHeadline text="Modules" />
{/* HIDE APPS */}
<InputGroup>
<label htmlFor="hideApps">Hide applications</label>

View File

@@ -82,19 +82,6 @@ export const WeatherSettings = (): JSX.Element => {
});
};
// Get user location
const getLocation = () => {
window.navigator.geolocation.getCurrentPosition(
({ coords: { latitude, longitude } }) => {
setFormData({
...formData,
lat: latitude,
long: longitude,
});
}
);
};
return (
<form onSubmit={(e) => formSubmitHandler(e)}>
<SettingsHeadline text="API" />
@@ -133,8 +120,15 @@ export const WeatherSettings = (): JSX.Element => {
step="any"
lang="en-150"
/>
<span onClick={getLocation}>
<a href="#">Click to get current location</a>
<span>
You can use
<a
href="https://www.latlong.net/convert-address-to-lat-long.html"
target="blank"
>
{' '}
latlong.net
</a>
</span>
</InputGroup>

View File

@@ -6,8 +6,13 @@
"authRequired": false
},
{
"name": "General",
"dest": "/settings/general",
"name": "Weather",
"dest": "/settings/weather",
"authRequired": true
},
{
"name": "Search",
"dest": "/settings/search",
"authRequired": true
},
{
@@ -15,11 +20,6 @@
"dest": "/settings/interface",
"authRequired": true
},
{
"name": "Weather",
"dest": "/settings/weather",
"authRequired": true
},
{
"name": "Docker",
"dest": "/settings/docker",

View File

@@ -23,7 +23,7 @@
.InputGroup span {
font-size: 12px;
color: var(--color-primary);
color: var(--color-primary)
}
.InputGroup span a {
@@ -37,4 +37,4 @@
.InputGroup textarea {
resize: none;
height: 50vh;
}
}

View File

@@ -8,29 +8,29 @@ export interface WeatherForm {
weatherData: WeatherData;
}
export interface GeneralForm {
export interface SearchForm {
hideSearch: boolean;
defaultSearchProvider: string;
searchSameTab: boolean;
pinAppsByDefault: boolean;
pinCategoriesByDefault: boolean;
useOrdering: string;
appsSameTab: boolean;
bookmarksSameTab: boolean;
disableAutofocus: boolean;
}
export interface UISettingsForm {
export interface OtherSettingsForm {
customTitle: string;
pinAppsByDefault: boolean;
pinCategoriesByDefault: boolean;
hideHeader: boolean;
hideApps: boolean;
hideCategories: boolean;
useOrdering: string;
appsSameTab: boolean;
bookmarksSameTab: boolean;
useAmericanDate: boolean;
greetingsSchema: string;
daySchema: string;
monthSchema: string;
showTime: boolean;
hideDate: boolean;
hideSearch: boolean;
disableAutofocus: boolean;
}
export interface DockerSettingsForm {

View File

@@ -1,14 +1,14 @@
import {
DockerSettingsForm,
UISettingsForm,
GeneralForm,
OtherSettingsForm,
SearchForm,
ThemeSettingsForm,
WeatherForm,
} from '../interfaces';
export type ConfigFormData =
| WeatherForm
| GeneralForm
| SearchForm
| DockerSettingsForm
| UISettingsForm
| OtherSettingsForm
| ThemeSettingsForm;

View File

@@ -1,16 +1,21 @@
import {
DockerSettingsForm,
UISettingsForm,
GeneralForm,
OtherSettingsForm,
SearchForm,
ThemeSettingsForm,
WeatherForm,
} from '../../interfaces';
export const uiSettingsTemplate: UISettingsForm = {
export const otherSettingsTemplate: OtherSettingsForm = {
customTitle: document.title,
pinAppsByDefault: true,
pinCategoriesByDefault: true,
hideHeader: false,
hideApps: false,
hideCategories: false,
useOrdering: 'createdAt',
appsSameTab: false,
bookmarksSameTab: false,
useAmericanDate: false,
greetingsSchema: 'Good evening!;Good afternoon!;Good morning!;Good night!',
daySchema: 'Sunday;Monday;Tuesday;Wednesday;Thursday;Friday;Saturday',
@@ -18,8 +23,6 @@ export const uiSettingsTemplate: UISettingsForm = {
'January;February;March;April;May;June;July;August;September;October;November;December',
showTime: false,
hideDate: false,
hideSearch: false,
disableAutofocus: false,
};
export const weatherSettingsTemplate: WeatherForm = {
@@ -30,14 +33,11 @@ export const weatherSettingsTemplate: WeatherForm = {
weatherData: 'cloud',
};
export const generalSettingsTemplate: GeneralForm = {
export const searchSettingsTemplate: SearchForm = {
hideSearch: false,
searchSameTab: false,
defaultSearchProvider: 'l',
pinAppsByDefault: true,
pinCategoriesByDefault: true,
useOrdering: 'createdAt',
appsSameTab: false,
bookmarksSameTab: false,
disableAutofocus: false,
};
export const dockerSettingsTemplate: DockerSettingsForm = {