Skip to content

Next #234

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

Open
wants to merge 56 commits into
base: main
Choose a base branch
from
Open

Next #234

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e1d9113
fix: Support both single function and array for beforeLoginConfirmation
SerVitasik Jun 13, 2025
12b1217
feat: add custom filter component for square meters and integrate int…
NoOne7135 Jun 16, 2025
8380ce0
remove vue-suggestion-input dependency
SerVitasik Jun 23, 2025
cbabda7
docs: update RichEditor and Markdown plugin documentation with new re…
NoOne7135 Jun 23, 2025
41855c9
fix: increase limit for column options from 1000 to 1250
SerVitasik Jun 24, 2025
370b536
fix: increase limit for column options from 1250 to 10000
SerVitasik Jun 24, 2025
cc6dd90
Revert "feat: add support for opening list item link in new tab on mi…
SerVitasik Jun 24, 2025
230da5a
fix: revert "feat: add support for opening list item link in new tab …
SerVitasik Jun 24, 2025
3b9c25f
docs: add diff-add comment in markdown plugin tutorial for clarity
NoOne7135 Jun 24, 2025
554a351
feat: refactor square meters filter buttons to use dynamic options an…
NoOne7135 Jun 24, 2025
69a1829
docs: update migration command in getting started tutorial for clarity
Romper9 Jun 25, 2025
5b4aeef
normalize beforeLoginConfirmation to support both single function and…
SerVitasik Jun 27, 2025
3154f1a
fix: cross platform support for postinstall
SerVitasik Jun 30, 2025
d68be08
fix: cross platform support for postinstall
SerVitasik Jun 30, 2025
dbc3eea
fix: cross platform support for postinstall
SerVitasik Jun 30, 2025
0145df2
fix: cross platform support for postinstall
SerVitasik Jun 30, 2025
41f4403
fix: cross platform support for postinstall
SerVitasik Jun 30, 2025
3d9e95b
fix: improve cross-platform compatibility for dependency installation…
SerVitasik Jun 30, 2025
791c3e3
fix: enhance cross-platform compatibility for npm dependency installa…
SerVitasik Jul 1, 2025
3389a2a
fix: update adminforth dependency version to 'next' for improved comp…
SerVitasik Jul 1, 2025
0c5c808
fix: enhance cross-platform compatibility in currentFileDir function
SerVitasik Jul 2, 2025
cfcf80a
fix: enhance cross-platform compatibility for temp directory and comm…
SerVitasik Jul 2, 2025
668417d
fix: add detailed debug logging for AdminForth and CodeInjector initi…
SerVitasik Jul 2, 2025
e449f95
fix: improve cross-platform compatibility for script execution in ind…
SerVitasik Jul 2, 2025
e0e5038
fix: streamline code and enhance cross-platform compatibility in Code…
SerVitasik Jul 2, 2025
3706caf
fix: improve cross-platform compatibility for npm execution in CodeIn…
SerVitasik Jul 2, 2025
6f5a65e
fix: refine cross-platform compatibility for script execution in inde…
SerVitasik Jul 2, 2025
fb0df18
fix: enhance cross-platform command execution in CodeInjector by refi…
SerVitasik Jul 2, 2025
c7b9201
fix: refine i18n extraction command for improved cross-platform compa…
SerVitasik Jul 3, 2025
18b9918
fix: improve npm execution logic for better Windows compatibility in …
SerVitasik Jul 3, 2025
fb5855a
Merge pull request #227 from devforth/custom-filter-component
ivictbor Jul 3, 2025
2ebd9b6
Merge pull request #224 from devforth/beforeLoginConfirmation-fix
ivictbor Jul 3, 2025
448c928
fix: update adminforth dependency version to latest in package.json t…
SerVitasik Jul 3, 2025
41d7f8a
Merge branch 'next' of github.com:devforth/adminforth into next
SerVitasik Jul 3, 2025
259cecc
Merge branch 'main' of github.com:devforth/adminforth into next
ivictbor Jul 3, 2025
ca9ef12
Merge branch 'next' of github.com:devforth/adminforth into next
SerVitasik Jul 3, 2025
25276f5
Merge branch 'main' of github.com:devforth/adminforth into next
SerVitasik Jul 3, 2025
9084bd0
fix: simplify file path comparison in index.ts.hbs
SerVitasik Jul 3, 2025
ca9aa9c
fix: update npm command execution to use node binary and change admin…
SerVitasik Jul 3, 2025
23a215d
fix: add console log for npm command execution path to test on Windows
SerVitasik Jul 3, 2025
9188e21
docs: escape < and > in custom filter example to fix MDX build error
NoOne7135 Jul 3, 2025
4175e6c
fix: quote paths in npm command execution to handle spaces in Windows…
SerVitasik Jul 3, 2025
1472d75
Merge branch 'next' of github.com:devforth/adminforth into next
SerVitasik Jul 3, 2025
478e3ec
fix: refactor npm dependency installation to streamline command execu…
SerVitasik Jul 3, 2025
0368f21
fix: update adminforth dependency version in package.json template fr…
SerVitasik Jul 3, 2025
c73dcb0
docs: update migration command in gettingStarted.md to include local …
SerVitasik Jul 3, 2025
ce84b0f
fix: enhance npm command execution for Windows compatibility by using…
SerVitasik Jul 3, 2025
109ef9b
docs: update migration commands to include local migration execution
NoOne7135 Jul 3, 2025
57df6de
Merge branch 'next' of https://github.com/devforth/adminforth into next
NoOne7135 Jul 3, 2025
c2b6bff
docs: add onMounted lifecycle hook to custom field rendering tutorial
NoOne7135 Jul 3, 2025
f00e37c
fix: adjust Dropzone component styles for better file upload handling…
SerVitasik Jul 3, 2025
5a330c6
Merge branch 'next' of github.com:devforth/adminforth into next
SerVitasik Jul 3, 2025
2890979
docs: add Twitch adapter installation and configuration instructions
NoOne7135 Jul 3, 2025
aaae67e
add Twitch OAuth2 adapter to dev-demo
NoOne7135 Jul 3, 2025
5f23cea
Merge pull request #235 from devforth/twitch-oauth-adapter
ivictbor Jul 3, 2025
9911a67
add Twitch OAuth adapter to the installation script
NoOne7135 Jul 4, 2025
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
2 changes: 1 addition & 1 deletion adapters/install-adapters.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/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 adminforth-image-generation-adapter-openai adminforth-storage-adapter-amazon-s3 adminforth-storage-adapter-local"
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 adminforth-twitch-oauth-adapter adminforth-image-generation-adapter-openai adminforth-storage-adapter-amazon-s3 adminforth-storage-adapter-local"

# for each
install_adapter() {
Expand Down
4 changes: 3 additions & 1 deletion adminforth/commands/createApp/templates/index.ts.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import express from 'express';
import AdminForth from 'adminforth';
import usersResource from "./resources/adminuser.js";
import { fileURLToPath } from 'url';
import path from 'path';

const ADMIN_BASE_URL = '';

Expand Down Expand Up @@ -55,7 +57,7 @@ export const admin = new AdminForth({
],
});

if (import.meta.url === `file://${process.argv[1]}`) {
if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
const app = express();
app.use(express.json());

Expand Down
20 changes: 14 additions & 6 deletions adminforth/commands/createApp/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,22 @@ async function writeTemplateFiles(dirname, cwd, options) {
}

async function installDependencies(ctx, cwd) {
const nodeBinary = process.execPath; // Path to the Node.js binary running this script
const npmPath = path.join(path.dirname(nodeBinary), 'npm'); // Path to the npm executable
const isWindows = process.platform === 'win32';

const nodeBinary = process.execPath;
const npmPath = path.join(path.dirname(nodeBinary), 'npm');
const customDir = ctx.customDir;
const res = await Promise.all([
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
]);
if (isWindows) {
const res = await Promise.all([
await execAsync(`npm install`, { cwd, env: { PATH: process.env.PATH } }),
await execAsync(`npm install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
]);
} else {
const res = await Promise.all([
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
]);
}
// console.log(chalk.dim(`Dependencies installed in ${cwd} and ${customDir}: \n${res[0].stdout}${res[1].stdout}`));
}

Expand Down
1 change: 1 addition & 0 deletions adminforth/commands/createCustomComponent/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ async function handleFieldComponentCreation(config, resources) {
{ name: '📃 show', value: 'show' },
{ name: '✏️ edit', value: 'edit' },
{ name: '➕ create', value: 'create' },
{ name: '🔍 filter', value: 'filter'},
new Separator(),
{ name: '🔙 BACK', value: '__BACK__' },
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<template>
<input
type="text"
:value="localValue"
@input="onInput"
placeholder="Search"
aria-describedby="helper-text-explanation"
class="inline-flex bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-0 focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary focus:border-blue-500 block w-20 p-2.5 dark:bg-gray-700 dark:border-gray-600 placeholder-gray-500 dark:placeholder-gray-400 dark:text-white translate-y-0 rounded-l-md rounded-r-md w-full"
/>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';

const emit = defineEmits(['update:modelValue']);

const props = defineProps<{
column: any;
meta?: any;
modelValue: Array<{ operator: string; value: string }> | null;
}>();

const localValue = ref(props.modelValue?.[0]?.value || '');

watch(() => props.modelValue, (val) => {
localValue.value = val?.[0]?.value || '';
});

function onInput(event: Event) {
const target = event.target as HTMLInputElement;
localValue.value = target.value;
emit('update:modelValue', [{ operator: 'ilike', value: target.value }]);
}
</script>
15 changes: 15 additions & 0 deletions adminforth/commands/postinstall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import fs from 'fs';
import path from 'path';

import { execSync } from 'child_process';
const spaPath = path.join(import.meta.dirname, 'dist', 'spa');


if (fs.existsSync(spaPath)){
console.log('Installing SPA dependencies...');
execSync('npm ci', { cwd: spaPath, stdio: 'inherit' });
console.log('Installed spa dependencies');
} else {
console.log('SPA dependencies not found');
console.log('current directory', import.meta.dirname);
}
2 changes: 1 addition & 1 deletion adminforth/documentation/blog/2024-10-01-ai-blog/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ model ContentImage {
Create a migration:

```bash
npm run makemigration -- --name add-posts
npm run makemigration -- --name add-posts && npm run migrate:local
```


Expand Down
4 changes: 2 additions & 2 deletions adminforth/documentation/docs/tutorial/001-gettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ This will create a migration file in `migrations` and apply it to the database.
In future, when you need to add new resources, you need to modify `schema.prisma` (add models, change fields, etc.). After doing any modification you need to create a new migration using next command:

```bash
npm run makemigration -- --name <name_of_changes>
npm run makemigration -- --name init && npm run migrate:local
```

Other developers need to pull migration and run `npm run migrateLocal` to apply any unapplied migrations.
Expand Down Expand Up @@ -173,7 +173,7 @@ model apartments {
Run the following command to create a new migration:

```bash
npm run makemigration -- --name add-apartments
npm run makemigration -- --name add-apartments && npm run migrate:local
```

### Step3. Create the `apartments` resource
Expand Down
2 changes: 1 addition & 1 deletion adminforth/documentation/docs/tutorial/01-helloWorld.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ model Post {
Create database using `prisma migrate`:

```bash
npm run makemigration --name init
npm run makemigration --name init && npm run migrate:local
```

## Setting up AdminForth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,4 +481,119 @@ list: '@/renderers/ZeroStylesRichText.vue',
//diff-add
```

`ZeroStyleRichText` fits well for tasks like email templates preview fields.
`ZeroStyleRichText` fits well for tasks like email templates preview fields.


### Custom filter component for square meters


Sometimes standard filters are not enough, and you want to make a convenient UI for selecting a range of apartment areas. For example, buttons with options for “Small (&lt;25 m²)”, “Medium (25–90 m²)” and “Large (&gt;90 m²)”.

```ts title='./custom/SquareMetersFilter.vue'
<template>
<div class="flex flex-col gap-2">
<p class="font-medium mb-1 dark:text-white">{{ $t('Square meters filter') }}</p>
<div class="flex gap-2">
<button
v-for="option in options"
:key="option.value"
type="button"
class="flex gap-1 items-center py-1 px-3 text-sm font-medium rounded-default border focus:outline-none focus:z-10 focus:ring-4"
:class="{
'text-white bg-blue-500 border-blue-500 hover:bg-blue-600 focus:ring-blue-200 dark:focus:ring-blue-800': selected === option.value,
'text-gray-900 bg-white border-gray-300 hover:bg-gray-100 hover:text-blue-500 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700': selected !== option.value
}"
@click="select(option.value)"
>
{{ $t(option.label) }}
</button>
</div>
</div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted } from 'vue';

const emit = defineEmits(['update:modelValue']);

const props = defineProps<{
modelValue: Array<{ operator: string; value: number }> | null;
}>();

const selected = ref<string | null>(null);

const options = [
{ value: 'small', label: 'Small' },
{ value: 'medium', label: 'Medium' },
{ value: 'large', label: 'Large' }
];

onMounted(() => {
const val = props.modelValue;
if (!val || val.length === 0) {
selected.value = null;
return;
}

const ops = val.map((v) => `${v.operator}:${v.value}`);

if (ops.includes('lt:25')) selected.value = 'small';
else if (ops.includes('gte:25') && ops.includes('lte:90')) selected.value = 'medium';
else if (ops.includes('gt:90')) selected.value = 'large';
else selected.value = null;
});

watch(selected, (size) => {
if (!size) {
emit('update:modelValue', []);
return;
}

const filters = {
small: [{ operator: 'lt', value: 25 }],
medium: [
{ operator: 'gte', value: 25 },
{ operator: 'lte', value: 90 }
],
large: [{ operator: 'gt', value: 90 }]
};

emit('update:modelValue', filters[size]);
});

function select(size: string) {
selected.value = size;

switch (size) {
case 'small':
emit('update:modelValue', [{ operator: 'lt', value: 25 }]);
break;
case 'medium':
emit('update:modelValue', [
{ operator: 'gte', value: 25 },
{ operator: 'lte', value: 90 }
]);
break;
case 'large':
emit('update:modelValue', [{ operator: 'gt', value: 90 }]);
break;
}
}
</script>
```

```ts title='./resources/apartments.ts'
columns: [
...
{
name: 'square_meter',
label: 'Square',
//diff-add
components: {
//diff-add
filter: '@@/SquareMetersFilter.vue'
//diff-add
}
},
...
]
24 changes: 19 additions & 5 deletions adminforth/documentation/docs/tutorial/05-Plugins/04-RichEditor.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,18 @@ model description_image {
```

```bash
npm run makemigration -- --name add_description_image
npm run makemigration -- --name add_description_image && npm run migrate:local
```

```bash
npm i @adminforth/upload --save
npm i @adminforth/storage-adapter-local --save
```

```typescript title="./resources/description_image.ts"
import AdminForthStorageAdapterLocalFilesystem from "../../adapters/adminforth-storage-adapter-local";
import { AdminForthResourceInput } from "../../adminforth";
import UploadPlugin from "../../plugins/adminforth-upload";
```typescript title="./resources/description_images.ts"
import AdminForthStorageAdapterLocalFilesystem from "@adminforth/storage-adapter-local";
import { AdminForthResourceInput } from "adminforth";
import UploadPlugin from "@adminforth/upload";
import { v1 as uuid } from "uuid";

export default {
Expand Down Expand Up @@ -237,6 +237,20 @@ export default {
],
} as AdminForthResourceInput;
```
Next, add new resource to `index.ts`:

```typescript title="./index.ts"
import descriptionImage from './resources/description_images.js';

...

resources: [
usersResource,
apartments,
// diff-add
descriptionImage
],
```

Next, add attachments to RichEditor plugin:

Expand Down
38 changes: 38 additions & 0 deletions adminforth/documentation/docs/tutorial/05-Plugins/11-oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,44 @@ plugins: [
]
```

### Twitch Adapter

Install Adapter:

```
npm install @adminforth/twitch-oauth-adapter --save
```

1. Go to the [Twitch dashboard](https://dev.twitch.tv/console/)
2. Create a new app or select an existing one
3. In `OAuth Redirect URLs` add `https://your-domain/oauth/callback` (`http://localhost:3500/oauth/callback`)
4. Go to the app and copy `Client ID`, click to `Generate a new client secret`(in Twitch this button can be used only once for some time, becouse of this dont lose it) button and copy secret .
5. Add the credentials to your `.env` file:

```bash
TWITCH_OAUTH_CLIENT_ID=your_twitch_client_id
TWITCH_OAUTH_CLIENT_SECRET=your_twitch_client_secret
```

Add the adapter to your plugin configuration:

```typescript title="./resources/adminuser.ts"
import AdminForthAdapterTwitchOauth2 from '@adminforth/twitch-oauth-adapter';

// ... existing resource configuration ...
plugins: [
new OAuthPlugin({
adapters: [
...
new AdminForthAdapterTwitchOauth2({
clientID: process.env.TWITCH_OAUTH_CLIENT_ID,
clientSecret: process.env.TWITCH_OAUTH_CLIENT_SECRET,
}),
],
}),
]
```

### Need custom provider?

Just fork any existing adapter e.g. [Google](https://github.com/devforth/adminforth-google-oauth-adapter) and adjust it to your needs.
Expand Down
Loading