Skip to content

Commit 308f8b4

Browse files
authored
Merge pull request #934 from mapswipe/dev
Release - 2024-May
2 parents ae33b71 + 9cc1914 commit 308f8b4

File tree

20 files changed

+1050
-476
lines changed

20 files changed

+1050
-476
lines changed

.github/workflows/actions.yml

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,34 @@ jobs:
1212

1313
steps:
1414
- uses: actions/checkout@v2
15+
1516
- name: Set up Python ${{ matrix.python-version }}
1617
uses: actions/setup-python@v2
1718
with:
1819
python-version: ${{ matrix.python-version }}
20+
1921
- name: Install dependencies
2022
working-directory: ./mapswipe_workers
2123
run: |
2224
python -m pip install --upgrade pip
2325
pip install flake8 black==22.3.0 isort
26+
2427
- name: Code style
2528
working-directory: ./mapswipe_workers
2629
run: |
2730
black --check mapswipe_workers ../django
2831
flake8 --count --config setup.cfg mapswipe_workers/ ../django/
2932
isort --check --settings-file setup.cfg mapswipe_workers/ ../django/
33+
3034
- name: Assert check
3135
run: |
3236
cmp --silent ./postgres/initdb.sql ./mapswipe_workers/tests/integration/set_up_db.sql || {
3337
echo 'The set_up_db.sql is not same as initdb.sql. Please sync this files and push';
3438
diff ./postgres/initdb.sql ./mapswipe_workers/tests/integration/set_up_db.sql;
3539
exit 1;
3640
}
37-
- name: Setup Postgres Database Container
41+
42+
- name: Setup Postgres Database Container
3843
env:
3944
POSTGRES_PASSWORD: postgres
4045
POSTGRES_USER: postgres
@@ -44,12 +49,14 @@ jobs:
4449
touch postgres/serviceAccountKey.json
4550
docker-compose up --build --detach postgres
4651
for i in {1..5}; do docker-compose exec -T postgres pg_isready && s=0 && break || s=$? && sleep 5; done; (docker-compose logs postgres && exit $s)
52+
4753
- name: Deploy Firebase Rules and Functions
4854
env:
4955
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
5056
FIREBASE_DB: ${{ secrets.FIREBASE_DB }}
5157
run: |
5258
docker-compose run --rm firebase_deploy sh -c "firebase use $FIREBASE_DB && firebase deploy --token $FIREBASE_TOKEN --only database"
59+
5360
- name: Decrypt Service Account Key File
5461
working-directory: ./
5562
run: |
@@ -58,6 +65,7 @@ jobs:
5865
OPENSSL_PASSPHRASE: ${{ secrets.OPENSSL_PASSPHRASE }}
5966
OPENSSL_KEY: ${{ secrets.OPENSSL_KEY }}
6067
OPENSSL_IV: ${{ secrets.OPENSSL_IV }}
68+
6169
- name: Run Tests
6270
working-directory: ./mapswipe_workers
6371
env:
@@ -73,3 +81,27 @@ jobs:
7381
docker-compose run --rm mapswipe_workers_creation python -m unittest discover --verbose --start-directory tests/unittests/
7482
docker-compose run --rm mapswipe_workers_creation bash -c 'pip install pytest && pytest -ra -v --durations=10 tests/integration/'
7583
docker-compose run --rm django pytest -ra -v --durations=10
84+
85+
- name: Django Graphql Schema Check
86+
env:
87+
SOURCE_SCHEMA: './django/schema.graphql'
88+
LATEST_SCHEMA: './django-data/schema-latest.graphql'
89+
run: |
90+
docker-compose run --rm django bash -c 'wait-for-it postgres:5432 && ./manage.py graphql_schema --out /django-data/schema-latest.graphql' &&
91+
cmp --silent $SOURCE_SCHEMA $LATEST_SCHEMA || {
92+
echo 'The schema.graphql is not up to date with the latest changes. Please update and push latest';
93+
diff $SOURCE_SCHEMA $LATEST_SCHEMA;
94+
exit 1;
95+
}
96+
97+
- name: Django Database Migration Check
98+
env:
99+
POSTGRES_PASSWORD: postgres
100+
POSTGRES_USER: postgres
101+
POSTGRES_DB: postgres
102+
DJANGO_SECRET_KEY: test-django-secret-key
103+
run: |
104+
docker-compose run --rm django bash -c 'wait-for-it postgres:5432 && ./manage.py makemigrations --check --dry-run' || {
105+
echo 'There are some changes to be reflected in the migration. Make sure to run makemigrations';
106+
exit 1;
107+
}

community-dashboard/app/Base/configs/apollo.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const GRAPHQL_ENDPOINT = process.env.REACT_APP_GRAPHQL_ENDPOINT as string;
44

55
const link = new HttpLink({
66
uri: GRAPHQL_ENDPOINT,
7-
credentials: 'include',
7+
credentials: 'omit',
88
}) as unknown as ApolloLinkFromClient;
99

1010
/*
@@ -39,8 +39,9 @@ const apolloOptions: ApolloClientOptions<NormalizedCacheObject> = {
3939
errorPolicy: 'all',
4040
},
4141
watchQuery: {
42-
fetchPolicy: 'cache-and-network',
43-
nextFetchPolicy: 'cache-and-network',
42+
// NOTE: setting nextFetchPolicy to cache-and-network is risky
43+
fetchPolicy: 'network-only',
44+
nextFetchPolicy: 'cache-only',
4445
errorPolicy: 'all',
4546
},
4647
},

community-dashboard/app/components/ItemSelectInput/index.tsx

Lines changed: 82 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,35 @@ export type SearchItemType = {
3030
isArchived?: boolean,
3131
};
3232

33+
const LIMIT = 5;
34+
3335
const USERS = gql`
34-
query UserOptions($search: String) {
35-
users(filters: { search: $search }, pagination: { limit: 5, offset: 0 }) {
36+
query UserOptions($search: String, $offset: Int!, $limit: Int!) {
37+
users(filters: { search: $search }, pagination: { limit: $limit, offset: $offset }) {
3638
items {
39+
id
3740
userId
3841
username
3942
}
4043
count
44+
offset
45+
limit
4146
}
4247
}
4348
`;
4449

4550
const USER_GROUPS = gql`
46-
query UserGroupOptions($search: String) {
47-
userGroups(filters: { search: $search }, pagination: { limit: 5, offset: 0 }) {
51+
query UserGroupOptions($search: String, $offset: Int!, $limit: Int!) {
52+
userGroups(filters: { search: $search }, pagination: { limit: $limit, offset: $offset }) {
4853
items {
54+
id
4955
isArchived
5056
userGroupId
5157
name
5258
}
5359
count
60+
offset
61+
limit
5462
}
5563
}
5664
`;
@@ -135,17 +143,19 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
135143

136144
const [opened, setOpened] = useState(false);
137145
const [searchText, setSearchText] = useState<string>('');
138-
139146
const debouncedSearchText = useDebouncedValue(searchText);
140147

141148
const variables = useMemo(() => ({
142149
search: debouncedSearchText,
150+
offset: 0,
151+
limit: LIMIT,
143152
}), [debouncedSearchText]);
144153

145154
const {
146155
previousData: previousUserData,
147156
data: userData = previousUserData,
148157
loading: userDataLoading,
158+
fetchMore: fetchMoreUser,
149159
} = useQuery<UserOptionsQuery, UserOptionsQueryVariables>(
150160
USERS,
151161
{
@@ -158,6 +168,7 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
158168
previousData: previousUserGroupData,
159169
data: userGroupData = previousUserGroupData,
160170
loading: userGroupDataLoading,
171+
fetchMore: fetchMoreUserGroup,
161172
} = useQuery<UserGroupOptionsQuery, UserGroupOptionsQueryVariables>(
162173
USER_GROUPS,
163174
{
@@ -168,8 +179,14 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
168179

169180
const loading = userDataLoading || userGroupDataLoading;
170181
const count = (userData?.users.count ?? 0) + (userGroupData?.userGroups.count ?? 0);
171-
const usersData = userData?.users.items;
172-
const userGroupsData = userGroupData?.userGroups.items;
182+
const usersData = useMemo(
183+
() => userData?.users.items,
184+
[userData?.users.items],
185+
);
186+
const userGroupsData = useMemo(
187+
() => userGroupData?.userGroups.items,
188+
[userGroupData?.userGroups.items],
189+
);
173190

174191
const data: SearchItemType[] = useMemo(
175192
() => ([
@@ -198,7 +215,6 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
198215

199216
const optionRendererParams = useCallback(
200217
(_: number | string, option: SearchItemType) => {
201-
// const isActive = key === selectedItem;
202218
const isActive = false;
203219

204220
return {
@@ -209,32 +225,85 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
209225
};
210226
},
211227
[],
212-
// [selectedItem],
228+
);
229+
230+
const handleShowMoreClick = useCallback(
231+
() => {
232+
fetchMoreUser({
233+
variables: {
234+
offset: (userData?.users.offset ?? 0) + LIMIT,
235+
},
236+
updateQuery: (previousResult, { fetchMoreResult }) => {
237+
const oldUsers = previousResult;
238+
const newUsers = fetchMoreResult;
239+
240+
if (!newUsers) {
241+
return previousResult;
242+
}
243+
244+
return ({
245+
users: {
246+
...newUsers.users,
247+
items: [
248+
...oldUsers.users?.items ?? [],
249+
...newUsers.users?.items ?? [],
250+
],
251+
},
252+
});
253+
},
254+
});
255+
fetchMoreUserGroup({
256+
variables: {
257+
offset: (userGroupData?.userGroups.offset ?? 0) + LIMIT,
258+
},
259+
updateQuery: (previousResult, { fetchMoreResult }) => {
260+
const oldUserGroups = previousResult;
261+
const newUserGroups = fetchMoreResult;
262+
263+
if (!newUserGroups) {
264+
return previousResult;
265+
}
266+
267+
return ({
268+
userGroups: {
269+
...newUserGroups.userGroups,
270+
items: [
271+
...oldUserGroups.userGroups.items ?? [],
272+
...newUserGroups.userGroups.items ?? [],
273+
],
274+
},
275+
});
276+
},
277+
});
278+
}, [
279+
fetchMoreUser,
280+
fetchMoreUserGroup,
281+
userData?.users.offset,
282+
userGroupData?.userGroups.offset,
283+
],
213284
);
214285

215286
return (
216287
<SearchSelectInput
217288
{...otherProps}
289+
className={className}
218290
name="item-select-input"
219291
icons={(
220292
<IoSearch />
221293
)}
222294
optionRendererParams={optionRendererParams}
223295
optionRenderer={Option}
224296
options={[]}
225-
// onOptionsChange={setItemOptions}
226-
// value={selectedItem}
227297
value={undefined}
228298
onChange={handleSelectItem}
229-
// Other props
230-
className={className}
231299
keySelector={keySelector}
232300
labelSelector={titleSelector}
233301
onSearchValueChange={setSearchText}
234302
onShowDropdownChange={setOpened}
235303
searchOptions={data}
236304
optionsPending={loading}
237305
totalOptionsCount={count}
306+
handleShowMoreClick={handleShowMoreClick}
238307
/>
239308
);
240309
}

community-dashboard/app/components/SelectInput/SearchSelectInput.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,17 @@ export type SearchSelectInputProps<
8484
| 'optionRendererParams'
8585
>
8686
) & (
87-
{ nonClearable: true; onChange: (newValue: T, name: K) => void }
88-
| { nonClearable?: false; onChange: (newValue: T | undefined, name: K) => void }
89-
);
87+
{
88+
nonClearable: true;
89+
onChange: (newValue: T, name: K) => void
90+
}
91+
| {
92+
nonClearable?: false;
93+
onChange: (newValue: T | undefined, name: K) => void
94+
}
95+
) & {
96+
handleShowMoreClick?: () => void;
97+
};
9098

9199
const emptyList: unknown[] = [];
92100

@@ -113,6 +121,7 @@ function SearchSelectInput<
113121
onShowDropdownChange,
114122
optionRendererParams,
115123
optionRenderer,
124+
handleShowMoreClick,
116125
...otherProps
117126
} = props;
118127

@@ -288,6 +297,7 @@ function SearchSelectInput<
288297
onFocusedKeyChange={setFocusedKey}
289298
hasValue={isDefined(value)}
290299
persistentOptionPopup={false}
300+
handleShowMoreClick={handleShowMoreClick}
291301
/>
292302
);
293303
}

community-dashboard/app/components/SelectInputContainer/EmptyOptions/index.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import React from 'react';
2+
import { IoChevronForward } from 'react-icons/io5';
3+
import Button from '#components/Button';
24

35
import styles from './styles.css';
46

@@ -9,6 +11,7 @@ interface DefaultEmptyComponentProps {
911
totalOptionsCount: number | undefined;
1012
emptyMessage?: React.ReactNode;
1113
emptyFilteredMessage?: React.ReactNode;
14+
handleShowMoreClick?: () => void;
1215
}
1316

1417
function EmptyOptions(props: DefaultEmptyComponentProps) {
@@ -19,6 +22,7 @@ function EmptyOptions(props: DefaultEmptyComponentProps) {
1922
totalOptionsCount = 0,
2023
emptyMessage = 'No options available',
2124
emptyFilteredMessage = 'No matching options available',
25+
handleShowMoreClick,
2226
} = props;
2327

2428
if (pending) {
@@ -49,8 +53,21 @@ function EmptyOptions(props: DefaultEmptyComponentProps) {
4953
const hiddenOptions = totalOptionsCount - optionsCount;
5054
if (hiddenOptions > 0) {
5155
return (
52-
<div className={styles.empty}>
53-
{`and ${hiddenOptions} more`}
56+
<div className={styles.hiddenOptionsCount}>
57+
<span className={styles.hiddenCountMessage}>
58+
{`and ${hiddenOptions} more`}
59+
</span>
60+
{handleShowMoreClick && (
61+
<Button
62+
className={styles.button}
63+
name={undefined}
64+
onClick={handleShowMoreClick}
65+
actions={<IoChevronForward />}
66+
variant="transparent"
67+
>
68+
Show more
69+
</Button>
70+
)}
5471
</div>
5572
);
5673
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
11
.empty {
22
padding: var(--spacing-small) var(--spacing-large);
3+
min-height: 2em;
34
color: var(--color-text-watermark);
45
}
6+
.hidden-options-count {
7+
display: flex;
8+
align-items: baseline;
9+
padding: var(--spacing-small) var(--spacing-large);
10+
}
11+
.hidden-count-message {
12+
display: flex;
13+
flex-grow: 1;
14+
justify-content: flex-start;
15+
color: var(--color-text-watermark);
16+
}
17+
.button {
18+
flex-shrink: 0;
19+
padding: 0;
20+
}

0 commit comments

Comments
 (0)