Skip to content

Commit 2ca90a1

Browse files
authored
Merge pull request #226 from pawelmalak/feature
Version 2.1.0
2 parents f963c19 + fcf2b87 commit 2ca90a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1223
-674
lines changed

.env

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
PORT=5005
22
NODE_ENV=development
3-
VERSION=2.0.1
3+
VERSION=2.1.0
44
PASSWORD=flame_password
55
SECRET=e02eb43d69953658c6d07311d6313f2d4467672cb881f96b29368ba1f3f4da4b

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
### v2.1.0 (2021-11-26)
2+
- Added option to set custom order for bookmarks ([#43](https://github.com/pawelmalak/flame/issues/43)) and ([#187](https://github.com/pawelmalak/flame/issues/187))
3+
- Added support for .ico files for custom icons ([#209](https://github.com/pawelmalak/flame/issues/209))
4+
- Empty apps and categories sections will now be hidden from guests ([#210](https://github.com/pawelmalak/flame/issues/210))
5+
- Fixed bug with fahrenheit degrees being displayed as float ([#221](https://github.com/pawelmalak/flame/issues/221))
6+
- Fixed bug with alphabetical order not working for bookmarks until the page was refreshed ([#224](https://github.com/pawelmalak/flame/issues/224))
7+
- Added option to change visibilty of apps, categories and bookmarks directly from table view
8+
- Password input will now autofocus when visiting /settings/app
9+
110
### v2.0.1 (2021-11-19)
211
- Added option to display humidity in the weather widget ([#136](https://github.com/pawelmalak/flame/issues/136))
312
- Added option to set default theme for all new users ([#165](https://github.com/pawelmalak/flame/issues/165))

client/.env

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
REACT_APP_VERSION=2.0.1
1+
REACT_APP_VERSION=2.1.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.TableActions {
2+
display: flex;
3+
align-items: center;
4+
}
5+
6+
.TableAction {
7+
width: 22px;
8+
}
9+
10+
.TableAction:hover {
11+
cursor: pointer;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { Icon } from '../UI';
2+
import classes from './TableActions.module.css';
3+
4+
interface Entity {
5+
id: number;
6+
name: string;
7+
isPinned?: boolean;
8+
isPublic: boolean;
9+
}
10+
11+
interface Props {
12+
entity: Entity;
13+
deleteHandler: (id: number, name: string) => void;
14+
updateHandler: (id: number) => void;
15+
pinHanlder?: (id: number) => void;
16+
changeVisibilty: (id: number) => void;
17+
showPin?: boolean;
18+
}
19+
20+
export const TableActions = (props: Props): JSX.Element => {
21+
const {
22+
entity,
23+
deleteHandler,
24+
updateHandler,
25+
pinHanlder,
26+
changeVisibilty,
27+
showPin = true,
28+
} = props;
29+
30+
const _pinHandler = pinHanlder || function () {};
31+
32+
return (
33+
<td className={classes.TableActions}>
34+
{/* DELETE */}
35+
<div
36+
className={classes.TableAction}
37+
onClick={() => deleteHandler(entity.id, entity.name)}
38+
tabIndex={0}
39+
>
40+
<Icon icon="mdiDelete" />
41+
</div>
42+
43+
{/* UPDATE */}
44+
<div
45+
className={classes.TableAction}
46+
onClick={() => updateHandler(entity.id)}
47+
tabIndex={0}
48+
>
49+
<Icon icon="mdiPencil" />
50+
</div>
51+
52+
{/* PIN */}
53+
{showPin && (
54+
<div
55+
className={classes.TableAction}
56+
onClick={() => _pinHandler(entity.id)}
57+
tabIndex={0}
58+
>
59+
{entity.isPinned ? (
60+
<Icon icon="mdiPinOff" color="var(--color-accent)" />
61+
) : (
62+
<Icon icon="mdiPin" />
63+
)}
64+
</div>
65+
)}
66+
67+
{/* VISIBILITY */}
68+
<div
69+
className={classes.TableAction}
70+
onClick={() => changeVisibilty(entity.id)}
71+
tabIndex={0}
72+
>
73+
{entity.isPublic ? (
74+
<Icon icon="mdiEyeOff" color="var(--color-accent)" />
75+
) : (
76+
<Icon icon="mdiEye" />
77+
)}
78+
</div>
79+
</td>
80+
);
81+
};

client/src/components/Apps/AppForm/AppForm.tsx

+19-13
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,41 @@
11
import { useState, useEffect, ChangeEvent, SyntheticEvent } from 'react';
2-
import { useDispatch } from 'react-redux';
3-
import { App, NewApp } from '../../../interfaces';
2+
import { useDispatch, useSelector } from 'react-redux';
3+
import { NewApp } from '../../../interfaces';
44

55
import classes from './AppForm.module.css';
66

77
import { ModalForm, InputGroup, Button } from '../../UI';
88
import { inputHandler, newAppTemplate } from '../../../utility';
99
import { bindActionCreators } from 'redux';
1010
import { actionCreators } from '../../../store';
11+
import { State } from '../../../store/reducers';
1112

1213
interface Props {
1314
modalHandler: () => void;
14-
app?: App;
1515
}
1616

17-
export const AppForm = ({ app, modalHandler }: Props): JSX.Element => {
17+
export const AppForm = ({ modalHandler }: Props): JSX.Element => {
18+
const { appInUpdate } = useSelector((state: State) => state.apps);
19+
1820
const dispatch = useDispatch();
19-
const { addApp, updateApp } = bindActionCreators(actionCreators, dispatch);
21+
const { addApp, updateApp, setEditApp } = bindActionCreators(
22+
actionCreators,
23+
dispatch
24+
);
2025

2126
const [useCustomIcon, toggleUseCustomIcon] = useState<boolean>(false);
2227
const [customIcon, setCustomIcon] = useState<File | null>(null);
2328
const [formData, setFormData] = useState<NewApp>(newAppTemplate);
2429

2530
useEffect(() => {
26-
if (app) {
31+
if (appInUpdate) {
2732
setFormData({
28-
...app,
33+
...appInUpdate,
2934
});
3035
} else {
3136
setFormData(newAppTemplate);
3237
}
33-
}, [app]);
38+
}, [appInUpdate]);
3439

3540
const inputChangeHandler = (
3641
e: ChangeEvent<HTMLInputElement | HTMLSelectElement>,
@@ -66,7 +71,7 @@ export const AppForm = ({ app, modalHandler }: Props): JSX.Element => {
6671
return data;
6772
};
6873

69-
if (!app) {
74+
if (!appInUpdate) {
7075
if (customIcon) {
7176
const data = createFormData();
7277
addApp(data);
@@ -76,14 +81,15 @@ export const AppForm = ({ app, modalHandler }: Props): JSX.Element => {
7681
} else {
7782
if (customIcon) {
7883
const data = createFormData();
79-
updateApp(app.id, data);
84+
updateApp(appInUpdate.id, data);
8085
} else {
81-
updateApp(app.id, formData);
86+
updateApp(appInUpdate.id, formData);
8287
modalHandler();
8388
}
8489
}
8590

8691
setFormData(newAppTemplate);
92+
setEditApp(null);
8793
};
8894

8995
return (
@@ -154,7 +160,7 @@ export const AppForm = ({ app, modalHandler }: Props): JSX.Element => {
154160
id="icon"
155161
required
156162
onChange={(e) => fileChangeHandler(e)}
157-
accept=".jpg,.jpeg,.png,.svg"
163+
accept=".jpg,.jpeg,.png,.svg,.ico"
158164
/>
159165
<span
160166
onClick={() => {
@@ -182,7 +188,7 @@ export const AppForm = ({ app, modalHandler }: Props): JSX.Element => {
182188
</select>
183189
</InputGroup>
184190

185-
{!app ? (
191+
{!appInUpdate ? (
186192
<Button>Add new application</Button>
187193
) : (
188194
<Button>Update application</Button>

client/src/components/Apps/AppGrid/AppGrid.module.css

-18
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,3 @@
2020
grid-template-columns: repeat(4, 1fr);
2121
}
2222
}
23-
24-
.GridMessage {
25-
color: var(--color-primary);
26-
}
27-
28-
.GridMessage a {
29-
color: var(--color-accent);
30-
font-weight: 600;
31-
}
32-
33-
.AppsMessage {
34-
color: var(--color-primary);
35-
}
36-
37-
.AppsMessage a {
38-
color: var(--color-accent);
39-
font-weight: 600;
40-
}

client/src/components/Apps/AppGrid/AppGrid.tsx

+21-24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
33
import { App } from '../../../interfaces/App';
44

55
import { AppCard } from '../AppCard/AppCard';
6+
import { Message } from '../../UI';
67

78
interface Props {
89
apps: App[];
@@ -13,36 +14,32 @@ interface Props {
1314
export const AppGrid = (props: Props): JSX.Element => {
1415
let apps: JSX.Element;
1516

16-
if (props.apps.length > 0) {
17-
apps = (
18-
<div className={classes.AppGrid}>
19-
{props.apps.map((app: App): JSX.Element => {
20-
return <AppCard key={app.id} app={app} />;
21-
})}
22-
</div>
23-
);
17+
if (props.searching || props.apps.length) {
18+
if (!props.apps.length) {
19+
apps = <Message>No apps match your search criteria</Message>;
20+
} else {
21+
apps = (
22+
<div className={classes.AppGrid}>
23+
{props.apps.map((app: App): JSX.Element => {
24+
return <AppCard key={app.id} app={app} />;
25+
})}
26+
</div>
27+
);
28+
}
2429
} else {
2530
if (props.totalApps) {
26-
if (props.searching) {
27-
apps = (
28-
<p className={classes.AppsMessage}>
29-
No apps match your search criteria
30-
</p>
31-
);
32-
} else {
33-
apps = (
34-
<p className={classes.AppsMessage}>
35-
There are no pinned applications. You can pin them from the{' '}
36-
<Link to="/applications">/applications</Link> menu
37-
</p>
38-
);
39-
}
31+
apps = (
32+
<Message>
33+
There are no pinned applications. You can pin them from the{' '}
34+
<Link to="/applications">/applications</Link> menu
35+
</Message>
36+
);
4037
} else {
4138
apps = (
42-
<p className={classes.AppsMessage}>
39+
<Message>
4340
You don't have any applications. You can add a new one from{' '}
4441
<Link to="/applications">/applications</Link> menu
45-
</p>
42+
</Message>
4643
);
4744
}
4845
}

0 commit comments

Comments
 (0)