Skip to content
Merged

Next #460

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
4 changes: 2 additions & 2 deletions adminforth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ getClientIp(headers: object) {
decoded = jwt.verify(jwtToken, secret);
} catch (err) {
if (err.name === 'TokenExpiredError') {
afLogger.error(`Token expired: ${err.message}`);
afLogger.info(`Token expired: ${err.message}`);
} else if (err.name === 'JsonWebTokenError') {
afLogger.error(`Token error: ${err.message}`);
afLogger.info(`Token error: ${err.message}, JWT secret changed?`);
} else {
afLogger.error(`Failed to verify JWT token: ${err}`);
}
Expand Down
3 changes: 3 additions & 0 deletions adminforth/dataConnectors/baseConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon

client: any;

/**
* @deprecated Since 1.2.9. Will be removed in 2.0.0. Use .client instead.
*/
get db() {
afLogger.warn('.db is deprecated, use .client instead');
return this.client;
Expand Down
2 changes: 1 addition & 1 deletion adminforth/documentation/blog/2024-08-05-chatgpt/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Today LLM is already a must tool to speed-up writing, brainstorming, or generati

Here is how it looks in action:

![alt text](../../docs/tutorial/07-Plugins/demoChatGpt.gif)
![alt text](../../docs/tutorial/08-Plugins/demoChatGpt.gif)

<!-- truncate -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ For example we can prevent the user to see Apartments created by other users. Su
}

// this function will skip existing realtor_id filter if it supplied already from UI or previous hook, and will add new one for realtor_id
query.filterTools.replaceOrAddTopFilter(Filters.EQ('realtor_id', adminUser.dbUser.id)
query.filterTools.replaceOrAddTopFilter(Filters.EQ('realtor_id', adminUser.dbUser.id))

return { ok: true };
},
Expand Down
24 changes: 24 additions & 0 deletions adminforth/documentation/docs/tutorial/03-Customization/15-afcl.md
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,30 @@ const tableState = ref("loading");

</div>


### Making header and pagination sticky

If you want to make table header or pagination, you can add `makeHeaderSticky`, `makePaginationSticky`

```
<Table
class="min-h-[200px] max-h-[250px]"
makeHeaderSticky
makePaginationSticky
:columns="[
{ label: 'Name', fieldName: 'name' },
{ label: 'Age', fieldName: 'age' },
{ label: 'Country', fieldName: 'country' },
]"
:data="[
{ name: 'John', age: 30, country: 'US' },
{ name: 'Rick', age: 25, country: 'CA' },
{ name: 'Alice', age: 35, country: 'UK' },
{ name: 'Colin', age: 40, country: 'AU' },
]"
></Table>
```

## ProgressBar

<div class="split-screen" >
Expand Down
60 changes: 60 additions & 0 deletions adminforth/documentation/docs/tutorial/07-UsageOfLogger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Usage of the logger

There are cases when you might want to debug an Adminforth app or add custom logs.

## Adding custom logs

> These logs are used only on the backend.

> ❗️Do not combine them with `console.log()` because it can cause an unpredictable order of logs.

To add a custom log, import the logger and use the desired level:

```ts
import { logger } from 'adminforth';

logger.trace("This is trace log");
logger.debug("This is debug log");
logger.info("This is info log");
logger.warn("This is warn log");
logger.error("This is error log");
```

Depending on the active log level, some messages will be filtered out.


## Changing logging level and debugging the Adminforth SPA

There are three types of logs: user logs, Adminforth logs, and database logs.
Use separate environment variables to control each type.

Logger has 5 debug levels:

```ts
"trace"
"debug"
"info"
"warn"
"error"
```

By default, the logger uses the `info` level.

To change it, set the environment variable for the logger you want to see:

- `DEBUG_LEVEL=trace` - user logs at `trace` level
- `AF_DEBUG_LEVEL=debug` - Adminforth logs at `debug` level
- `DB_DEBUG_LEVEL=trace` - database logs at `trace` level

Or run the Adminforth app like this:

```bash
DB_DEBUG_LEVEL=trace npm start
```

And the logs will be visible as well.





Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ And finally add this callback:
//diff-add
if (adminUser.dbUser.avatar === null || adminUser.dbUser.avatar === undefined || adminUser.dbUser.avatar === '') {
//diff-add
return '';
return undefined;
//diff-add
}
//diff-add
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ And finally add this callback:
//diff-add
if (adminUser.dbUser.avatar === null || adminUser.dbUser.avatar === undefined || adminUser.dbUser.avatar === '') {
//diff-add
return '';
return undefined;
//diff-add
}
//diff-add
Expand Down
43 changes: 29 additions & 14 deletions adminforth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import {
AdminForthResource,
IAdminForthDataSourceConnectorBase,
IWebSocketBroker,
HttpExtra,
BeforeCreateSaveFunction,
AdminForthInputConfig,
IAdminForthHttpResponse,
CreateResourceRecordParams,
UpdateResourceRecordParams,
DeleteResourceRecordParams,
CreateResourceRecordResult,
UpdateResourceRecordResult,
DeleteResourceRecordResult,
} from './types/Back.js';

import {
AdminForthFilterOperators,
AdminForthDataTypes,
Expand Down Expand Up @@ -538,10 +540,15 @@ class AdminForth implements IAdminForth {
return users.data[0] || null;
}

/**
* Create record and execute hooks
* @param params - Parameters for record creation. See CreateResourceRecordParams.
* @returns Result of record creation. See CreateResourceRecordResult.
*/
async createResourceRecord(
{ resource, record, adminUser, extra, response }:
{ resource: AdminForthResource, record: any, adminUser: AdminUser, extra?: HttpExtra, response: IAdminForthHttpResponse }
): Promise<{ error?: string, createdRecord?: any, newRecordId?: any }> {
params: CreateResourceRecordParams,
): Promise<CreateResourceRecordResult> {
const { resource, record, adminUser, extra, response } = params;

const err = this.validateRecordValues(resource, record, 'create');
if (err) {
Expand Down Expand Up @@ -622,12 +629,15 @@ class AdminForth implements IAdminForth {

/**
* record is partial record with only changed fields
*
* Update record by id and execute hooks
* @param params - Parameters for record update. See UpdateResourceRecordParams.
* @returns Result of record update. See UpdateResourceRecordResult.
*/
async updateResourceRecord(
{ resource, recordId, record, oldRecord, adminUser, response, extra, updates }:
| { resource: AdminForthResource, recordId: any, record: any, oldRecord: any, adminUser: AdminUser, response: IAdminForthHttpResponse, extra?: HttpExtra, updates?: never }
| { resource: AdminForthResource, recordId: any, record?: never, oldRecord: any, adminUser: AdminUser, response: IAdminForthHttpResponse, extra?: HttpExtra, updates: any }
): Promise<{ error?: string }> {
params: UpdateResourceRecordParams,
): Promise<UpdateResourceRecordResult> {
const { resource, recordId, record, oldRecord, adminUser, response, extra, updates } = params;
const dataToUse = updates || record;
const err = this.validateRecordValues(resource, dataToUse, 'edit');
if (err) {
Expand Down Expand Up @@ -713,10 +723,15 @@ class AdminForth implements IAdminForth {
return { error: null };
}

/**
* Delete record by id and execute hooks
* @param params - Parameters for record deletion. See DeleteResourceRecordParams.
* @returns Result of record deletion. See DeleteResourceRecordResult.
*/
async deleteResourceRecord(
{ resource, recordId, adminUser, record, response, extra }:
{ resource: AdminForthResource, recordId: any, adminUser: AdminUser, record: any, response: IAdminForthHttpResponse, extra?: HttpExtra }
): Promise<{ error?: string }> {
params: DeleteResourceRecordParams,
): Promise<DeleteResourceRecordResult> {
const { resource, recordId, adminUser, record, response, extra } = params;
// execute hook if needed
for (const hook of listify(resource.hooks?.delete?.beforeSave)) {
const resp = await hook({
Expand Down
17 changes: 13 additions & 4 deletions adminforth/modules/restApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
: '1d';

await this.processLoginCallbacks(adminUser, toReturn, response, {
body, headers, query, cookies, requestUrl,
body, headers, query, cookies, requestUrl, response
}, expireInDuration);

if (toReturn.allowedLogin) {
Expand Down Expand Up @@ -1275,7 +1275,10 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
}
}

const createRecordResponse = await this.adminforth.createResourceRecord({ resource, record, adminUser, response, extra: { body, query, headers, cookies, requestUrl } });
const createRecordResponse = await this.adminforth.createResourceRecord({
resource, record, adminUser, response,
extra: { body, query, headers, cookies, requestUrl, response }
});
if (createRecordResponse.error) {
return { error: createRecordResponse.error, ok: false, newRecordId: createRecordResponse.newRecordId };
}
Expand Down Expand Up @@ -1395,7 +1398,10 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
}
}

const { error } = await this.adminforth.updateResourceRecord({ resource, record, adminUser, oldRecord, recordId, response, extra: { body, query, headers, cookies, requestUrl} });
const { error } = await this.adminforth.updateResourceRecord({
resource, record, adminUser, oldRecord, recordId, response,
extra: { body, query, headers, cookies, requestUrl, response }
});
if (error) {
return { error };
}
Expand Down Expand Up @@ -1434,7 +1440,10 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
return { error };
}

const { error: deleteError } = await this.adminforth.deleteResourceRecord({ resource, record, adminUser, recordId: body['primaryKey'], response, extra: { body, query, headers, cookies, requestUrl } });
const { error: deleteError } = await this.adminforth.deleteResourceRecord({
resource, record, adminUser, recordId: body['primaryKey'], response,
extra: { body, query, headers, cookies, requestUrl, response }
});
if (deleteError) {
return { error: deleteError };
}
Expand Down
2 changes: 1 addition & 1 deletion adminforth/spa/src/afcl/Dialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<!-- Confirmation Modal -->
<div
v-if="showConfirmationOnClose"
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-60"
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-[60]"
>
<div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-lg max-w-sm w-full">
<h2 class="text-lg font-semibold mb-4 text-lightDialogHeaderText dark:text-darkDialogHeaderText">Confirm Close</h2>
Expand Down
2 changes: 1 addition & 1 deletion adminforth/spa/src/afcl/Select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</div>
</div>
<teleport to="body" v-if="(teleportToBody || teleportToTop) && showDropdown">
<div ref="dropdownEl" :style="getDropdownPosition" :class="{'shadow-none': isTop, 'z-10': teleportToBody, 'z-[1000]': teleportToTop}"
<div ref="dropdownEl" :style="getDropdownPosition" :class="{'shadow-none': isTop, 'z-30': teleportToBody, 'z-[1000]': teleportToTop}"
class="fixed w-full bg-lightDropdownOptionsBackground shadow-lg dark:shadow-black dark:bg-darkDropdownOptionsBackground
dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-48"
@scroll="handleDropdownScroll">
Expand Down
12 changes: 7 additions & 5 deletions adminforth/spa/src/afcl/Table.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<template>
<div class="afcl-table-container relative overflow-x-auto shadow-md rounded-lg">
<div class="overflow-x-auto w-full">
<div class="afcl-table-container relative overflow-x-auto overflow-y-auto shadow-md rounded-lg">
<table class="afcl-table w-full text-sm text-left rtl:text-right text-lightTableText dark:text-darkTableText overflow-x-auto">
<thead class="afcl-table-thread text-xs text-lightTableHeadingText uppercase bg-lightTableHeadingBackground dark:bg-darkTableHeadingBackground dark:text-darkTableHeadingText">
<thead class="afcl-table-thread z-40 text-xs text-lightTableHeadingText uppercase bg-lightTableHeadingBackground dark:bg-darkTableHeadingBackground dark:text-darkTableHeadingText" :class="makeHeaderSticky ? 'sticky top-0' : ''">
<tr>
<th
scope="col"
Expand Down Expand Up @@ -79,10 +78,11 @@
</tr>
</tbody>
</table>
</div>
<nav class="afcl-table-pagination-container bg-lightTableBackground dark:bg-darkTableBackground mt-2 flex flex-col gap-2 items-center sm:flex-row justify-center sm:justify-between px-4 pb-4"
v-if="totalPages > 1"
:aria-label="$t('Table navigation')">
:aria-label="$t('Table navigation')"
:class="makePaginationSticky ? 'sticky bottom-0 pt-4' : ''"
>
<i18n-t
keypath="Showing {from} to {to} of {total}" tag="span" class="afcl-table-pagination-text text-sm font-normal text-center text-lightTablePaginationText dark:text-darkTablePaginationText sm:mb-4 md:mb-0 block w-full md:inline md:w-auto"
>
Expand Down Expand Up @@ -169,6 +169,8 @@
isLoading?: boolean,
defaultSortField?: string,
defaultSortDirection?: 'asc' | 'desc',
makeHeaderSticky?: boolean,
makePaginationSticky?: boolean,
}>(), {
evenHighlights: true,
pageSize: 5,
Expand Down
Loading