Skip to content

Commit 32c7518

Browse files
authored
Listing improvements (#222)
* upgrading dependencies, fixing image placeholder * improving processing times label and hide when screen width is too low * aligning run now button * renaming settings -> general settings * smaller security and memory improvements * improving footer
1 parent db3702e commit 32c7518

File tree

6 files changed

+409
-256
lines changed

6 files changed

+409
-256
lines changed

package.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fredy",
3-
"version": "14.3.1",
3+
"version": "14.3.2",
44
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
55
"scripts": {
66
"prepare": "husky",
@@ -56,13 +56,13 @@
5656
"Firefox ESR"
5757
],
5858
"dependencies": {
59-
"@douyinfe/semi-icons": "^2.86.0",
60-
"@douyinfe/semi-ui": "2.86.0",
59+
"@douyinfe/semi-icons": "^2.87.1",
60+
"@douyinfe/semi-ui": "2.87.1",
6161
"@sendgrid/mail": "8.1.6",
6262
"@visactor/react-vchart": "^2.0.5",
6363
"@visactor/vchart": "^2.0.5",
6464
"@visactor/vchart-semi-theme": "^1.12.2",
65-
"@vitejs/plugin-react": "5.0.4",
65+
"@vitejs/plugin-react": "5.1.0",
6666
"better-sqlite3": "^12.4.1",
6767
"body-parser": "2.2.0",
6868
"cheerio": "^1.1.2",
@@ -72,39 +72,39 @@
7272
"nanoid": "5.1.6",
7373
"node-cron": "^4.2.1",
7474
"node-fetch": "3.3.2",
75-
"node-mailjet": "6.0.9",
75+
"node-mailjet": "6.0.11",
7676
"p-throttle": "^8.0.0",
7777
"package-up": "^5.0.0",
78-
"puppeteer": "^24.24.0",
78+
"puppeteer": "^24.27.0",
7979
"puppeteer-extra": "^3.3.6",
8080
"puppeteer-extra-plugin-stealth": "^2.11.2",
8181
"query-string": "9.3.1",
8282
"react": "18.3.1",
8383
"react-dom": "18.3.1",
84-
"react-router": "7.9.4",
85-
"react-router-dom": "7.9.4",
84+
"react-router": "7.9.5",
85+
"react-router-dom": "7.9.5",
8686
"restana": "5.1.0",
8787
"semver": "^7.7.3",
8888
"serve-static": "2.2.0",
8989
"slack": "11.0.2",
90-
"vite": "7.1.9",
90+
"vite": "7.1.12",
9191
"x-var": "^3.0.1",
9292
"zustand": "^5.0.8"
9393
},
9494
"devDependencies": {
95-
"@babel/core": "7.28.4",
96-
"@babel/eslint-parser": "7.28.4",
97-
"@babel/preset-env": "7.28.3",
98-
"@babel/preset-react": "7.27.1",
95+
"@babel/core": "7.28.5",
96+
"@babel/eslint-parser": "7.28.5",
97+
"@babel/preset-env": "7.28.5",
98+
"@babel/preset-react": "7.28.5",
9999
"chai": "6.2.0",
100-
"eslint": "9.37.0",
100+
"eslint": "9.39.0",
101101
"eslint-config-prettier": "10.1.8",
102102
"eslint-plugin-react": "7.37.5",
103103
"esmock": "2.7.3",
104104
"history": "5.3.0",
105105
"husky": "9.1.7",
106106
"less": "4.4.2",
107-
"lint-staged": "16.2.4",
107+
"lint-staged": "16.2.6",
108108
"mocha": "11.7.4",
109109
"nodemon": "^3.1.10",
110110
"prettier": "3.6.2"

ui/src/components/footer/FredyFooter.less

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
justify-content: space-between;
66
align-items: center;
77
height: 1.7rem;
8+
border-radius: .3rem;
9+
border-top: 1px solid #45464b;
810

911
&__version {
1012
padding-left: .5rem;

ui/src/components/navigation/Navigation.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default function Navigation({ isAdmin }) {
2222

2323
if (isAdmin) {
2424
items.push({ itemKey: '/users', text: 'User Management', icon: <IconUser /> });
25-
items.push({ itemKey: '/generalSettings', text: 'Settings', icon: <IconSetting /> });
25+
items.push({ itemKey: '/generalSettings', text: 'General Settings', icon: <IconSetting /> });
2626
}
2727

2828
function parsePathName(name) {

ui/src/components/table/listings/ListingsTable.jsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import ListingsFilter from './ListingsFilter.jsx';
1414

1515
const columns = [
1616
{
17-
title: '#',
18-
width: 100,
17+
title: 'Watchlist',
18+
width: 110,
1919
dataIndex: 'isWatched',
2020
sorter: true,
2121
render: (id, row) => {
@@ -180,6 +180,7 @@ export default function ListingsTable() {
180180
const [activityFilter, setActivityFilter] = useState(null);
181181
const [providerFilter, setProviderFilter] = useState(null);
182182

183+
const [imageWidth, setImageWidth] = useState('100%');
183184
const handlePageChange = (_page) => {
184185
setPage(_page);
185186
};
@@ -208,14 +209,29 @@ export default function ListingsTable() {
208209

209210
const handleFilterChange = useMemo(() => debounce((value) => setFreeTextFilter(value), 500), []);
210211

212+
useEffect(() => {
213+
return () => {
214+
// cleanup debounced handler to avoid memory leaks
215+
handleFilterChange.cancel && handleFilterChange.cancel();
216+
};
217+
}, [handleFilterChange]);
218+
211219
const expandRowRender = (record) => {
212220
return (
213221
<div className="listingsTable__expanded">
214222
<div>
215223
{record.image_url == null ? (
216-
<Image height={200} src={no_image} />
224+
<Image height={200} width={180} src={no_image} />
217225
) : (
218-
<Image height={200} src={record.image_url} />
226+
<Image
227+
height={200}
228+
width={imageWidth}
229+
src={record.image_url}
230+
onError={() => {
231+
setImageWidth('180px');
232+
}}
233+
fallback={<Image height={200} src={no_image} />}
234+
/>
219235
)}
220236
</div>
221237
<div>
@@ -226,7 +242,7 @@ export default function ListingsTable() {
226242
</Tag>
227243
</Descriptions.Item>
228244
<Descriptions.Item itemKey="Link">
229-
<a href={record.link} target="_blank" rel="noreferrer">
245+
<a href={record.link} target="_blank" rel="noopener noreferrer">
230246
Link to Listing
231247
</a>
232248
</Descriptions.Item>

ui/src/views/jobs/ProcessingTimes.jsx

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,90 @@
11
import React from 'react';
22
import { format } from '../../services/time/timeService';
33
import { Button, Card, Col, Row, Toast } from '@douyinfe/semi-ui';
4-
import { IconPlayCircle } from '@douyinfe/semi-icons';
4+
import {
5+
IconClock,
6+
IconDoubleChevronLeft,
7+
IconDoubleChevronRight,
8+
IconPlayCircle,
9+
IconSearch,
10+
} from '@douyinfe/semi-icons';
511
import { xhrPost } from '../../services/xhr.js';
612

713
import './ProsessingTimes.less';
14+
import { useScreenWidth } from '../../hooks/screenWidth.js';
815

9-
function InfoCard({ title, value }) {
16+
function InfoCard({ title, value, icon }) {
17+
const { Meta } = Card;
1018
return (
11-
<Card style={{ maxWidth: '13rem', margin: '1rem', background: 'rgb(53, 54, 60)' }} title={title}>
12-
{value}
13-
</Card>
19+
<div
20+
style={{
21+
margin: '1rem',
22+
background: 'rgb(53, 54, 60)',
23+
borderRadius: '.3rem',
24+
padding: '1rem',
25+
minHeight: '3rem',
26+
}}
27+
>
28+
<Meta title={title} description={value} avatar={icon} />
29+
</div>
1430
);
1531
}
1632

1733
export default function ProcessingTimes({ processingTimes = {} }) {
1834
if (Object.keys(processingTimes).length === 0) {
1935
return null;
2036
}
37+
const width = useScreenWidth();
38+
const invisible = width <= 1180;
39+
40+
if (invisible) {
41+
return null;
42+
}
43+
2144
return (
2245
<Row>
2346
<Col span={6}>
24-
<InfoCard title="Processing Interval" value={`${processingTimes.interval} min`} />
47+
<InfoCard
48+
title="Search Interval"
49+
value={`${processingTimes.interval} min`}
50+
icon={<IconClock style={{ color: 'rgba(var(--semi-grey-4), 1)' }} />}
51+
/>
2552
</Col>
2653
{processingTimes.lastRun && (
2754
<>
2855
<Col span={6}>
29-
<InfoCard title="Last run" value={format(processingTimes.lastRun)} />
56+
<InfoCard
57+
title="Last search"
58+
icon={<IconDoubleChevronLeft style={{ color: 'rgba(var(--semi-grey-4), 1)' }} />}
59+
value={format(processingTimes.lastRun)}
60+
/>
3061
</Col>
3162
<Col span={6}>
32-
<InfoCard title="Next run" value={format(processingTimes.lastRun + processingTimes.interval * 60000)} />
63+
<InfoCard
64+
title="Next search"
65+
icon={<IconDoubleChevronRight style={{ color: 'rgba(var(--semi-grey-4), 1)' }} />}
66+
value={format(processingTimes.lastRun + processingTimes.interval * 60000)}
67+
/>
3368
</Col>
3469
</>
3570
)}
3671
<Col span={6}>
3772
<InfoCard
38-
title="Find Listings Now"
73+
title="Search Now"
74+
icon={<IconSearch style={{ color: 'rgba(var(--semi-grey-4), 1)' }} />}
3975
value={
4076
<Button
4177
size="small"
78+
style={{ marginTop: '.2rem' }}
4279
icon={<IconPlayCircle />}
4380
aria-label="Start now"
4481
onClick={async () => {
45-
await xhrPost('/api/jobs/startAll', null);
46-
Toast.success('Successfully triggered Fredy search.');
82+
try {
83+
await xhrPost('/api/jobs/startAll', null);
84+
Toast.success('Successfully triggered Fredy search.');
85+
} catch {
86+
Toast.error('Failed to trigger search');
87+
}
4788
}}
4889
>
4990
Search now

0 commit comments

Comments
 (0)