-
Notifications
You must be signed in to change notification settings - Fork 46
feat(registry/ui): filters #607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This middleware is used to enable strongly typed filters in the request. Additionally, the filters object is guaranteed to be valid, otherwise 400 is returned.
Also, add domainId filter parameter to /api/v1/app route.
Also, add domainId filter parameter to /api/v1/template route.
ListBulkActions, | ||
ListActionsToolbar, | ||
} from '../components'; | ||
import { Datagrid, List, SimpleList, TextField, EditButton, FunctionField } from 'react-admin'; // eslint-disable-line import/no-unresolved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please avoid import/no-unresolved looks scary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done. ✅
BTW, i don't see any eslint-related checks in the repo 🤔
@@ -23,6 +39,24 @@ const getApps = async (req: Request, res: Response): Promise<void> => { | |||
if (filters.q) { | |||
query.where('name', 'like', `%${filters.q}%`); | |||
} | |||
if (filters.domainId) { | |||
if (filters.domainId === 'null') { | |||
query.whereNotExists(function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please move the code to the service because it is hard to read it.
@@ -23,6 +39,24 @@ const getApps = async (req: Request, res: Response): Promise<void> => { | |||
if (filters.q) { | |||
query.where('name', 'like', `%${filters.q}%`); | |||
} | |||
if (filters.domainId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a test involving these queries (if it's not exits yet).
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done ✅
`${Tables.Templates}.*`, | ||
]); | ||
|
||
if (req.filters?.domainId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a test involving these queries (if it's not exits yet).
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done ✅
const query = db | ||
.selectVersionedRows(Tables.SharedLibs, 'name', EntityTypes.shared_libs, [`${Tables.SharedLibs}.*`]) | ||
.from(Tables.SharedLibs); | ||
|
||
if (req.filters?.name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a test involving these queries (if it's not exits yet).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
try { | ||
// create apps | ||
for (const app of example.appsList) { | ||
await req.post(example.url).send(app).expect(200); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh I'm not a big fan of having manual creation explicitly in tests where its required, in this way we reduce test quality by
- testing things that are not the part of the case - creation, deletion, instead of filtering
- reducing tests speed which is a metric by itself.
I'm ok with approach for now cause there where no tests at all for this part of functionality, but I'd prefer fixtures preloading for filters instead.
empty={<Empty />} | ||
> | ||
{isSmall ? ( | ||
<SimpleList | ||
primaryText={record => `@sharedLibrary/${record.name}`} | ||
secondaryText={record => record.spaBundle} | ||
primaryText={(record) => `@sharedLibrary/${record.name}`} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest isolating this part into some function, its used multiple times
/@sharedLibrary/${record.name}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I am new to this project, I don't know the purpose of this prefixing, so I have no better idea than calling it getPrefixedSharedLibName(name: string): string
or smth like this.
|
||
useEffect(() => { | ||
dataProvider | ||
.getList('router_domains', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(minor) introduce new method inside dataProvider in order to simplify call with these parameters? getFullList or smth
pagination: false,
sort: false,
filter: false,
const query = db | ||
.selectVersionedRows(Tables.SharedLibs, 'name', EntityTypes.shared_libs, [`${Tables.SharedLibs}.*`]) | ||
.from(Tables.SharedLibs); | ||
|
||
if (req.filters?.name) { | ||
query.whereILike('name', `%${req.filters.name}%`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just double-checking, does it correctly partially matches with the beginning of the string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From MySQL docs:
SQL pattern matching enables you to use _ to match any single character and % to match an arbitrary number of characters (including zero characters).
PostgreSQL and SQLite docs describe the same behavior.
Covered with tests too.
if (req.filters?.id || req.filters?.name) { | ||
const name = req.filters?.name ?? req.filters?.id; | ||
ok(name); | ||
const normalizedNames = Array.isArray(name) ? name : [name]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(nit) slightly simpler
const normalizedNames = [].concat(name);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In TS it becomes:
const normalizedName = ([] as string[]).concat(name)
But I still prefer the more literal way over the shorter one for its readability.
query.whereIn('name', normalizedNames); | ||
} | ||
|
||
if (req.filters?.domainId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
matching for template500 seems to happen multiple times, utilize some constant for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a field name, just like "name" or "domainId". If we put it into constant, we will need to do the same for the rest of the fields, just like we do for tables.
Also: - fix(registry/client): unhardcode `@sharedLibrary/` prefix
…ository Also: - refactor: convert the templatesRepository to a class - refactor: pre-initialize all my repositories in the bootstrap phase - feat: introduce normalizeArray utility function
res.status(200).send(itemsWithId); | ||
const getTemplates = async (req: RequestWithFilters<TemplatesGetListFilters>, res: Response): Promise<void> => { | ||
const { data, pagination } = await templatesRepository.getList(req.filters ?? {}); | ||
res.setHeader('Content-Range', pagination.total); //Stub for future pagination capabilities |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not add that until it is required to be present
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left it from the implementation made by previous developer. The client-side code relies on it
}); | ||
|
||
res.setHeader('Content-Range', sharedLibs.pagination.total); | ||
res.status(200).send(preProcessResponse(itemsWithId)); | ||
res.setHeader('Content-Range', pagination.total); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
Coverage ReportIlc/serverCommit SHA:ae871d79ec415ac4de89a9479b1d642da7bb04d1 Test coverage results 🧪
File details
Ilc/clientCommit SHA:ae871d79ec415ac4de89a9479b1d642da7bb04d1 Test coverage results 🧪
File details
RegistryCommit SHA:ae871d79ec415ac4de89a9479b1d642da7bb04d1 Test coverage results 🧪
File details
|
No description provided.