Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,34 @@ jobs:

steps:
- uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
working-directory: ./mapswipe_workers
run: |
python -m pip install --upgrade pip
pip install flake8 black==22.3.0 isort

- name: Code style
working-directory: ./mapswipe_workers
run: |
black --check mapswipe_workers ../django
flake8 --count --config setup.cfg mapswipe_workers/ ../django/
isort --check --settings-file setup.cfg mapswipe_workers/ ../django/

- name: Assert check
run: |
cmp --silent ./postgres/initdb.sql ./mapswipe_workers/tests/integration/set_up_db.sql || {
echo 'The set_up_db.sql is not same as initdb.sql. Please sync this files and push';
diff ./postgres/initdb.sql ./mapswipe_workers/tests/integration/set_up_db.sql;
exit 1;
}
- name: Setup Postgres Database Container

- name: Setup Postgres Database Container
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
Expand All @@ -44,12 +49,14 @@ jobs:
touch postgres/serviceAccountKey.json
docker-compose up --build --detach postgres
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)

- name: Deploy Firebase Rules and Functions
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
FIREBASE_DB: ${{ secrets.FIREBASE_DB }}
run: |
docker-compose run --rm firebase_deploy sh -c "firebase use $FIREBASE_DB && firebase deploy --token $FIREBASE_TOKEN --only database"

- name: Decrypt Service Account Key File
working-directory: ./
run: |
Expand All @@ -58,6 +65,7 @@ jobs:
OPENSSL_PASSPHRASE: ${{ secrets.OPENSSL_PASSPHRASE }}
OPENSSL_KEY: ${{ secrets.OPENSSL_KEY }}
OPENSSL_IV: ${{ secrets.OPENSSL_IV }}

- name: Run Tests
working-directory: ./mapswipe_workers
env:
Expand All @@ -73,3 +81,27 @@ jobs:
docker-compose run --rm mapswipe_workers_creation python -m unittest discover --verbose --start-directory tests/unittests/
docker-compose run --rm mapswipe_workers_creation bash -c 'pip install pytest && pytest -ra -v --durations=10 tests/integration/'
docker-compose run --rm django pytest -ra -v --durations=10

- name: Django Graphql Schema Check
env:
SOURCE_SCHEMA: './django/schema.graphql'
LATEST_SCHEMA: './django-data/schema-latest.graphql'
run: |
docker-compose run --rm django bash -c 'wait-for-it postgres:5432 && ./manage.py graphql_schema --out /django-data/schema-latest.graphql' &&
cmp --silent $SOURCE_SCHEMA $LATEST_SCHEMA || {
echo 'The schema.graphql is not up to date with the latest changes. Please update and push latest';
diff $SOURCE_SCHEMA $LATEST_SCHEMA;
exit 1;
}

- name: Django Database Migration Check
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: postgres
DJANGO_SECRET_KEY: test-django-secret-key
run: |
docker-compose run --rm django bash -c 'wait-for-it postgres:5432 && ./manage.py makemigrations --check --dry-run' || {
echo 'There are some changes to be reflected in the migration. Make sure to run makemigrations';
exit 1;
}
7 changes: 4 additions & 3 deletions community-dashboard/app/Base/configs/apollo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const GRAPHQL_ENDPOINT = process.env.REACT_APP_GRAPHQL_ENDPOINT as string;

const link = new HttpLink({
uri: GRAPHQL_ENDPOINT,
credentials: 'include',
credentials: 'omit',
}) as unknown as ApolloLinkFromClient;

/*
Expand Down Expand Up @@ -39,8 +39,9 @@ const apolloOptions: ApolloClientOptions<NormalizedCacheObject> = {
errorPolicy: 'all',
},
watchQuery: {
fetchPolicy: 'cache-and-network',
nextFetchPolicy: 'cache-and-network',
// NOTE: setting nextFetchPolicy to cache-and-network is risky
fetchPolicy: 'network-only',
nextFetchPolicy: 'cache-only',
errorPolicy: 'all',
},
},
Expand Down
95 changes: 82 additions & 13 deletions community-dashboard/app/components/ItemSelectInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,35 @@ export type SearchItemType = {
isArchived?: boolean,
};

const LIMIT = 5;

const USERS = gql`
query UserOptions($search: String) {
users(filters: { search: $search }, pagination: { limit: 5, offset: 0 }) {
query UserOptions($search: String, $offset: Int!, $limit: Int!) {
users(filters: { search: $search }, pagination: { limit: $limit, offset: $offset }) {
items {
id
userId
username
}
count
offset
limit
}
}
`;

const USER_GROUPS = gql`
query UserGroupOptions($search: String) {
userGroups(filters: { search: $search }, pagination: { limit: 5, offset: 0 }) {
query UserGroupOptions($search: String, $offset: Int!, $limit: Int!) {
userGroups(filters: { search: $search }, pagination: { limit: $limit, offset: $offset }) {
items {
id
isArchived
userGroupId
name
}
count
offset
limit
}
}
`;
Expand Down Expand Up @@ -135,17 +143,19 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)

const [opened, setOpened] = useState(false);
const [searchText, setSearchText] = useState<string>('');

const debouncedSearchText = useDebouncedValue(searchText);

const variables = useMemo(() => ({
search: debouncedSearchText,
offset: 0,
limit: LIMIT,
}), [debouncedSearchText]);

const {
previousData: previousUserData,
data: userData = previousUserData,
loading: userDataLoading,
fetchMore: fetchMoreUser,
} = useQuery<UserOptionsQuery, UserOptionsQueryVariables>(
USERS,
{
Expand All @@ -158,6 +168,7 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
previousData: previousUserGroupData,
data: userGroupData = previousUserGroupData,
loading: userGroupDataLoading,
fetchMore: fetchMoreUserGroup,
} = useQuery<UserGroupOptionsQuery, UserGroupOptionsQueryVariables>(
USER_GROUPS,
{
Expand All @@ -168,8 +179,14 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)

const loading = userDataLoading || userGroupDataLoading;
const count = (userData?.users.count ?? 0) + (userGroupData?.userGroups.count ?? 0);
const usersData = userData?.users.items;
const userGroupsData = userGroupData?.userGroups.items;
const usersData = useMemo(
() => userData?.users.items,
[userData?.users.items],
);
const userGroupsData = useMemo(
() => userGroupData?.userGroups.items,
[userGroupData?.userGroups.items],
);

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

const optionRendererParams = useCallback(
(_: number | string, option: SearchItemType) => {
// const isActive = key === selectedItem;
const isActive = false;

return {
Expand All @@ -209,32 +225,85 @@ function ItemSelectInput<Name extends string>(props: ItemSelectInputProps<Name>)
};
},
[],
// [selectedItem],
);

const handleShowMoreClick = useCallback(
() => {
fetchMoreUser({
variables: {
offset: (userData?.users.offset ?? 0) + LIMIT,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
const oldUsers = previousResult;
const newUsers = fetchMoreResult;

if (!newUsers) {
return previousResult;
}

return ({
users: {
...newUsers.users,
items: [
...oldUsers.users?.items ?? [],
...newUsers.users?.items ?? [],
],
},
});
},
});
fetchMoreUserGroup({
variables: {
offset: (userGroupData?.userGroups.offset ?? 0) + LIMIT,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
const oldUserGroups = previousResult;
const newUserGroups = fetchMoreResult;

if (!newUserGroups) {
return previousResult;
}

return ({
userGroups: {
...newUserGroups.userGroups,
items: [
...oldUserGroups.userGroups.items ?? [],
...newUserGroups.userGroups.items ?? [],
],
},
});
},
});
}, [
fetchMoreUser,
fetchMoreUserGroup,
userData?.users.offset,
userGroupData?.userGroups.offset,
],
);

return (
<SearchSelectInput
{...otherProps}
className={className}
name="item-select-input"
icons={(
<IoSearch />
)}
optionRendererParams={optionRendererParams}
optionRenderer={Option}
options={[]}
// onOptionsChange={setItemOptions}
// value={selectedItem}
value={undefined}
onChange={handleSelectItem}
// Other props
className={className}
keySelector={keySelector}
labelSelector={titleSelector}
onSearchValueChange={setSearchText}
onShowDropdownChange={setOpened}
searchOptions={data}
optionsPending={loading}
totalOptionsCount={count}
handleShowMoreClick={handleShowMoreClick}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,17 @@ export type SearchSelectInputProps<
| 'optionRendererParams'
>
) & (
{ nonClearable: true; onChange: (newValue: T, name: K) => void }
| { nonClearable?: false; onChange: (newValue: T | undefined, name: K) => void }
);
{
nonClearable: true;
onChange: (newValue: T, name: K) => void
}
| {
nonClearable?: false;
onChange: (newValue: T | undefined, name: K) => void
}
) & {
handleShowMoreClick?: () => void;
};

const emptyList: unknown[] = [];

Expand All @@ -113,6 +121,7 @@ function SearchSelectInput<
onShowDropdownChange,
optionRendererParams,
optionRenderer,
handleShowMoreClick,
...otherProps
} = props;

Expand Down Expand Up @@ -288,6 +297,7 @@ function SearchSelectInput<
onFocusedKeyChange={setFocusedKey}
hasValue={isDefined(value)}
persistentOptionPopup={false}
handleShowMoreClick={handleShowMoreClick}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import { IoChevronForward } from 'react-icons/io5';
import Button from '#components/Button';

import styles from './styles.css';

Expand All @@ -9,6 +11,7 @@ interface DefaultEmptyComponentProps {
totalOptionsCount: number | undefined;
emptyMessage?: React.ReactNode;
emptyFilteredMessage?: React.ReactNode;
handleShowMoreClick?: () => void;
}

function EmptyOptions(props: DefaultEmptyComponentProps) {
Expand All @@ -19,6 +22,7 @@ function EmptyOptions(props: DefaultEmptyComponentProps) {
totalOptionsCount = 0,
emptyMessage = 'No options available',
emptyFilteredMessage = 'No matching options available',
handleShowMoreClick,
} = props;

if (pending) {
Expand Down Expand Up @@ -49,8 +53,21 @@ function EmptyOptions(props: DefaultEmptyComponentProps) {
const hiddenOptions = totalOptionsCount - optionsCount;
if (hiddenOptions > 0) {
return (
<div className={styles.empty}>
{`and ${hiddenOptions} more`}
<div className={styles.hiddenOptionsCount}>
<span className={styles.hiddenCountMessage}>
{`and ${hiddenOptions} more`}
</span>
{handleShowMoreClick && (
<Button
className={styles.button}
name={undefined}
onClick={handleShowMoreClick}
actions={<IoChevronForward />}
variant="transparent"
>
Show more
</Button>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
.empty {
padding: var(--spacing-small) var(--spacing-large);
min-height: 2em;
color: var(--color-text-watermark);
}
.hidden-options-count {
display: flex;
align-items: baseline;
padding: var(--spacing-small) var(--spacing-large);
}
.hidden-count-message {
display: flex;
flex-grow: 1;
justify-content: flex-start;
color: var(--color-text-watermark);
}
.button {
flex-shrink: 0;
padding: 0;
}
Loading