Skip to content
Merged

Next #177

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
29 changes: 22 additions & 7 deletions adapters/install-adapters.sh
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
ADAPTERS="adminforth-completion-adapter-open-ai-chat-gpt adminforth-email-adapter-aws-ses adminforth-google-oauth-adapter adminforth-github-oauth-adapter"
#!/usr/bin/env bash
ADAPTERS="adminforth-completion-adapter-open-ai-chat-gpt adminforth-email-adapter-aws-ses adminforth-google-oauth-adapter adminforth-github-oauth-adapter adminforth-facebook-oauth-adapter adminforth-keycloak-oauth-adapter adminforth-microsoft-oauth-adapter"

# for each plugin
for adapter in $ADAPTERS; do
# for each
install_adapter() {
adapter=$1

if [ -d "$adapter/.git" ]; then
echo "Repository for $adapter exists. Pulling latest changes..."
cd "$adapter"
git pull
else
echo "Repository for $adapter does not exist. Cloning..."
git clone git@github.com:devforth/$adapter.git
cd $adapter
git clone git@github.com:devforth/$adapter.git "$adapter"
cd "$adapter"
fi


cd ..
}

do_npm_ci() {
adapter=$1
cd "$adapter"
npm ci
cd ..
done
}

export -f install_adapter
export -f do_npm_ci

echo $ADAPTERS | tr ' ' '\n' | xargs -P 0 -I {} bash -c 'install_adapter "$@"' _ {}

echo $ADAPTERS | tr ' ' '\n' | while read adapter; do
do_npm_ci "$adapter"
done
21 changes: 21 additions & 0 deletions adminforth/dataConnectors/baseConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
return data.length > 0 ? data[0] : null;
}

validateAndNormalizeInputFilters(filter: IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter> | undefined): IAdminForthAndOrFilter {
if (!filter) {
// if no filter, return empty "and" filter
return { operator: AdminForthFilterOperators.AND, subFilters: [] };
}
if (typeof filter !== 'object') {
throw new Error(`Filter should be an array or an object`);
}
if (Array.isArray(filter)) {
// if filter is an array, combine them using "and" operator
return { operator: AdminForthFilterOperators.AND, subFilters: filter };
}
if ((filter as IAdminForthAndOrFilter).subFilters) {
// if filter is already AndOr filter - return as is
return filter as IAdminForthAndOrFilter;
}

// by default, assume filter is Single filter, turn it into AndOr filter
return { operator: AdminForthFilterOperators.AND, subFilters: [filter] };
}

validateAndNormalizeFilters(filters: IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter>, resource: AdminForthResource): { ok: boolean, error: string } {
if (Array.isArray(filters)) {
// go through all filters in array and call validation+normalization for each
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ columns: [
...
]
```

This way, when admin selects, for example, "Luxury" option for "Apartment Type" filter, it will be replace with a more complex "or" filter.

### Custom SQL queries with `insecureRawSQL`
Expand Down
28 changes: 3 additions & 25 deletions adminforth/modules/operationalResource.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,6 @@
import { IAdminForthSingleFilter, IAdminForthAndOrFilter, IAdminForthSort, IOperationalResource, IAdminForthDataSourceConnectorBase, AdminForthResource } from '../types/Back.js';
import { AdminForthFilterOperators } from '../types/Common.js';


function filtersIfFilter(filter: IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter> | undefined): IAdminForthAndOrFilter {
if (!filter) {
// if no filter, return empty "and" filter
return { operator: AdminForthFilterOperators.AND, subFilters: [] };
}
if (typeof filter !== 'object') {
throw new Error(`Filter should be an array or an object`);
}
if (Array.isArray(filter)) {
// if filter is an array, combine them using "and" operator
return { operator: AdminForthFilterOperators.AND, subFilters: filter };
}
if ((filter as IAdminForthAndOrFilter).subFilters) {
// if filter is already AndOr filter - return as is
return filter as IAdminForthAndOrFilter;
}

// by default, assume filter is Single filter, turn it into AndOr filter
return { operator: AdminForthFilterOperators.AND, subFilters: [filter] };
}

function sortsIfSort(sort: IAdminForthSort | IAdminForthSort[]): IAdminForthSort[] {
return (Array.isArray(sort) ? sort : [sort]) as IAdminForthSort[];
}
Expand All @@ -40,7 +18,7 @@ export default class OperationalResource implements IOperationalResource {
return (
await this.dataConnector.getData({
resource: this.resourceConfig,
filters: filtersIfFilter(filter),
filters: this.dataConnector.validateAndNormalizeInputFilters(filter),
limit: 1,
offset: 0,
sort: [],
Expand Down Expand Up @@ -73,7 +51,7 @@ export default class OperationalResource implements IOperationalResource {

const { data } = await this.dataConnector.getData({
resource: this.resourceConfig,
filters: filtersIfFilter(filter),
filters: this.dataConnector.validateAndNormalizeInputFilters(filter),
limit: appliedLimit,
offset: appliedOffset,
sort: sortsIfSort(sort),
Expand All @@ -86,7 +64,7 @@ export default class OperationalResource implements IOperationalResource {
async count(filter: IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter> | undefined): Promise<number> {
return await this.dataConnector.getCount({
resource: this.resourceConfig,
filters: filtersIfFilter(filter),
filters: this.dataConnector.validateAndNormalizeInputFilters(filter),
});
}

Expand Down
4 changes: 2 additions & 2 deletions adminforth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"docs": "typedoc",
"--comment_postinstall": "postinstall executed after package installed in other project package and when we do npm ci in the package",
"postinstall": "if test -d ./dist/spa/; then cd ./dist/spa/ && npm ci && echo 'installed spa dependencies'; fi",
"install-plugins": "cd ../plugins && sh install-plugins.sh",
"install-adapters": "cd ../adapters && sh install-adapters.sh"
"install-plugins": "cd ../plugins && bash install-plugins.sh",
"install-adapters": "cd ../adapters && bash install-adapters.sh"
},
"release": {
"plugins": [
Expand Down
6 changes: 5 additions & 1 deletion adminforth/types/Adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export interface EmailAdapter {
text: string,
html: string,
subject: string
): Promise<void>;
): Promise<{
error?: string;
ok?: boolean;
}>;
}

export interface CompletionAdapter {
Expand All @@ -29,4 +32,5 @@ export interface OAuth2Adapter {
getAuthUrl(): string;
getTokenFromCode(code: string, redirect_uri: string): Promise<{ email: string }>;
getIcon(): string;
getButtonText?(): string;
}
2 changes: 2 additions & 0 deletions adminforth/types/Back.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ export interface IAdminForthDataSourceConnector {
*/
export interface IAdminForthDataSourceConnectorBase extends IAdminForthDataSourceConnector {

validateAndNormalizeInputFilters(filter: IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter> | undefined): IAdminForthAndOrFilter;

getPrimaryKey(resource: AdminForthResource): string;

getData({ resource, limit, offset, sort, filters }: {
Expand Down
6 changes: 6 additions & 0 deletions dev-demo/.env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
KEYCLOAK_URL=http://localhost:8080

ADMINFORTH_SECRET=123
NODE_ENV=development
DATABASE_URL=sqlite://.db.sqlite
PRISMA_DATABASE_URL=file:.db.sqlite
Loading