Compare commits
No commits in common. "ai-dev" and "master" have entirely different histories.
@ -5,6 +5,8 @@ const Managed_tablesService = require('../services/managed_tables');
|
|||||||
const Managed_tablesDBApi = require('../db/api/managed_tables');
|
const Managed_tablesDBApi = require('../db/api/managed_tables');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
|
const config = require('../config');
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -158,27 +160,27 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
|
|||||||
* id:
|
* id:
|
||||||
* description: ID of the updated item
|
* description: ID of the updated item
|
||||||
* type: string
|
* type: string
|
||||||
data:
|
* data:
|
||||||
description: Data of the updated item
|
* description: Data of the updated item
|
||||||
type: object
|
* type: object
|
||||||
$ref: "#/components/schemas/Managed_tables"
|
* $ref: "#/components/schemas/Managed_tables"
|
||||||
required:
|
* required:
|
||||||
- id
|
* - id
|
||||||
responses:
|
* responses:
|
||||||
200:
|
* 200:
|
||||||
description: The item data was successfully updated
|
* description: The item data was successfully updated
|
||||||
content:
|
* content:
|
||||||
application/json:
|
* application/json:
|
||||||
schema:
|
* schema:
|
||||||
$ref: "#/components/schemas/Managed_tables"
|
* $ref: "#/components/schemas/Managed_tables"
|
||||||
400:
|
* 400:
|
||||||
description: Invalid ID supplied
|
* description: Invalid ID supplied
|
||||||
401:
|
* 401:
|
||||||
$ref: "#/components/responses/UnauthorizedError"
|
* $ref: "#/components/responses/UnauthorizedError"
|
||||||
404:
|
* 404:
|
||||||
description: Item not found
|
* description: Item not found
|
||||||
500:
|
* 500:
|
||||||
description: Some server error
|
* description: Some server error
|
||||||
*/
|
*/
|
||||||
router.put('/:id', wrapAsync(async (req, res) => {
|
router.put('/:id', wrapAsync(async (req, res) => {
|
||||||
await Managed_tablesService.update(req.body.data, req.body.id, req.currentUser);
|
await Managed_tablesService.update(req.body.data, req.body.id, req.currentUser);
|
||||||
@ -202,21 +204,21 @@ router.put('/:id', wrapAsync(async (req, res) => {
|
|||||||
* required: true
|
* required: true
|
||||||
* schema:
|
* schema:
|
||||||
* type: string
|
* type: string
|
||||||
responses:
|
* responses:
|
||||||
200:
|
* 200:
|
||||||
description: The item was successfully deleted
|
* description: The item was successfully deleted
|
||||||
content:
|
* content:
|
||||||
application/json:
|
* application/json:
|
||||||
schema:
|
* schema:
|
||||||
$ref: "#/components/schemas/Managed_tables"
|
* $ref: "#/components/schemas/Managed_tables"
|
||||||
400:
|
* 400:
|
||||||
description: Invalid ID supplied
|
* description: Invalid ID supplied
|
||||||
401:
|
* 401:
|
||||||
$ref: "#/components/responses/UnauthorizedError"
|
* $ref: "#/components/responses/UnauthorizedError"
|
||||||
404:
|
* 404:
|
||||||
description: Item not found
|
* description: Item not found
|
||||||
500:
|
* 500:
|
||||||
description: Some server error
|
* description: Some server error
|
||||||
*/
|
*/
|
||||||
router.delete('/:id', wrapAsync(async (req, res) => {
|
router.delete('/:id', wrapAsync(async (req, res) => {
|
||||||
await Managed_tablesService.remove(req.params.id, req.currentUser);
|
await Managed_tablesService.remove(req.params.id, req.currentUser);
|
||||||
@ -242,19 +244,19 @@ router.delete('/:id', wrapAsync(async (req, res) => {
|
|||||||
* ids:
|
* ids:
|
||||||
* description: IDs of the updated items
|
* description: IDs of the updated items
|
||||||
* type: array
|
* type: array
|
||||||
responses:
|
* responses:
|
||||||
200:
|
* 200:
|
||||||
description: The items was successfully deleted
|
* description: The items was successfully deleted
|
||||||
content:
|
* content:
|
||||||
application/json:
|
* application/json:
|
||||||
schema:
|
* schema:
|
||||||
$ref: "#/components/schemas/Managed_tables"
|
* $ref: "#/components/schemas/Managed_tables"
|
||||||
401:
|
* 401:
|
||||||
$ref: "#/components/responses/UnauthorizedError"
|
* $ref: "#/components/responses/UnauthorizedError"
|
||||||
404:
|
* 404:
|
||||||
description: Items not found
|
* description: Items not found
|
||||||
500:
|
* 500:
|
||||||
description: Some server error
|
* description: Some server error
|
||||||
*/
|
*/
|
||||||
router.post('/deleteByIds', wrapAsync(async (req, res) => {
|
router.post('/deleteByIds', wrapAsync(async (req, res) => {
|
||||||
await Managed_tablesService.deleteByIds(req.body.data, req.currentUser);
|
await Managed_tablesService.deleteByIds(req.body.data, req.currentUser);
|
||||||
@ -272,20 +274,20 @@ router.post('/deleteByIds', wrapAsync(async (req, res) => {
|
|||||||
* summary: Get all managed_tables
|
* summary: Get all managed_tables
|
||||||
* description: Get all managed_tables
|
* description: Get all managed_tables
|
||||||
* responses:
|
* responses:
|
||||||
200:
|
* 200:
|
||||||
description: Managed_tables list successfully received
|
* description: Managed_tables list successfully received
|
||||||
content:
|
* content:
|
||||||
application/json:
|
* application/json:
|
||||||
schema:
|
* schema:
|
||||||
type: array
|
* type: array
|
||||||
items:
|
* items:
|
||||||
$ref: "#/components/schemas/Managed_tables"
|
* $ref: "#/components/schemas/Managed_tables"
|
||||||
401:
|
* 401:
|
||||||
$ref: "#/components/responses/UnauthorizedError"
|
* $ref: "#/components/responses/UnauthorizedError"
|
||||||
404:
|
* 404:
|
||||||
description: Data not found
|
* description: Data not found
|
||||||
500:
|
* 500:
|
||||||
description: Some server error
|
* description: Some server error
|
||||||
*/
|
*/
|
||||||
router.get('/', wrapAsync(async (req, res) => {
|
router.get('/', wrapAsync(async (req, res) => {
|
||||||
const filetype = req.query.filetype
|
const filetype = req.query.filetype
|
||||||
@ -414,21 +416,21 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
* required: true
|
* required: true
|
||||||
* schema:
|
* schema:
|
||||||
* type: string
|
* type: string
|
||||||
responses:
|
* responses:
|
||||||
200:
|
* 200:
|
||||||
description: Selected item successfully received
|
* description: Selected item successfully received
|
||||||
content:
|
* content:
|
||||||
application/json:
|
* application/json:
|
||||||
schema:
|
* schema:
|
||||||
$ref: "#/components/schemas/Managed_tables"
|
* $ref: "#/components/schemas/Managed_tables"
|
||||||
400:
|
* 400:
|
||||||
description: Invalid ID supplied
|
* description: Invalid ID supplied
|
||||||
401:
|
* 401:
|
||||||
$ref: "#/components/responses/UnauthorizedError"
|
* $ref: "#/components/responses/UnauthorizedError"
|
||||||
404:
|
* 404:
|
||||||
description: Item not found
|
* description: Item not found
|
||||||
500:
|
* 500:
|
||||||
description: Some server error
|
* description: Some server error
|
||||||
*/
|
*/
|
||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await Managed_tablesDBApi.findBy(
|
const payload = await Managed_tablesDBApi.findBy(
|
||||||
@ -440,37 +442,6 @@ router.get('/:id', wrapAsync(async (req, res) => {
|
|||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /api/managed_tables/{id}/generate-plugin:
|
|
||||||
* post:
|
|
||||||
* security:
|
|
||||||
* - bearerAuth: []
|
|
||||||
* tags: [Managed_tables]
|
|
||||||
* summary: Generate WordPress plugin code for this table
|
|
||||||
* description: Generate WordPress plugin code for this table using AI
|
|
||||||
* parameters:
|
|
||||||
* - in: path
|
|
||||||
* name: id
|
|
||||||
* description: ID of the managed table
|
|
||||||
* required: true
|
|
||||||
* schema:
|
|
||||||
* type: string
|
|
||||||
* responses:
|
|
||||||
* 200:
|
|
||||||
* description: Plugin code successfully generated
|
|
||||||
* 401:
|
|
||||||
* $ref: "#/components/responses/UnauthorizedError"
|
|
||||||
* 404:
|
|
||||||
* description: Managed table not found
|
|
||||||
* 500:
|
|
||||||
* description: Some server error
|
|
||||||
*/
|
|
||||||
router.post('/:id/generate-plugin', wrapAsync(async (req, res) => {
|
|
||||||
const payload = await Managed_tablesService.generatePluginCode(req.params.id);
|
|
||||||
res.status(200).send(payload);
|
|
||||||
}));
|
|
||||||
|
|
||||||
router.use('/', require('../helpers').commonErrorHandler);
|
router.use('/', require('../helpers').commonErrorHandler);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -3,8 +3,13 @@ const Managed_tablesDBApi = require('../db/api/managed_tables');
|
|||||||
const processFile = require("../middlewares/upload");
|
const processFile = require("../middlewares/upload");
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
const csv = require('csv-parser');
|
||||||
|
const axios = require('axios');
|
||||||
|
const config = require('../config');
|
||||||
const stream = require('stream');
|
const stream = require('stream');
|
||||||
const OpenAiService = require('./openai');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = class Managed_tablesService {
|
module.exports = class Managed_tablesService {
|
||||||
static async create(data, currentUser) {
|
static async create(data, currentUser) {
|
||||||
@ -23,9 +28,9 @@ module.exports = class Managed_tablesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
static async bulkImport(req, res) {
|
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -90,7 +95,7 @@ module.exports = class Managed_tablesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
@ -127,44 +132,7 @@ module.exports = class Managed_tablesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async generatePluginCode(id) {
|
|
||||||
const table = await Managed_tablesDBApi.findBy({ id });
|
|
||||||
if (!table) {
|
|
||||||
throw new ValidationError('managed_tablesNotFound');
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns = table.table_columns_managed_table || [];
|
|
||||||
const columnDefinitions = columns.map(c => ({
|
|
||||||
name: c.column_name,
|
|
||||||
label: c.label,
|
|
||||||
type: c.data_type,
|
|
||||||
isPrimary: c.is_primary_key,
|
|
||||||
isNullable: c.is_nullable
|
|
||||||
}));
|
|
||||||
|
|
||||||
const prompt = `
|
|
||||||
Generate a professional WordPress plugin (PHP) that provides a full CRUD admin interface for a custom MySQL table.
|
|
||||||
|
|
||||||
Table Name: ${table.table_name}
|
|
||||||
Plugin Label: ${table.label}
|
|
||||||
|
|
||||||
Columns:
|
|
||||||
${JSON.stringify(columnDefinitions, null, 2)}
|
|
||||||
|
|
||||||
Requirements:
|
|
||||||
1. Use WordPress best practices and $wpdb for all database operations.
|
|
||||||
2. Create a top-level admin menu item for this plugin.
|
|
||||||
3. Implement a list table view with searching and sorting.
|
|
||||||
4. Implement Add/Edit forms with proper validation and sanitization.
|
|
||||||
5. Implement a Delete action with nonces for security.
|
|
||||||
6. Include a activation hook to create the table if it doesn't exist (use dbDelta).
|
|
||||||
7. Use clean, well-commented code.
|
|
||||||
8. The plugin should be a single PHP file for simplicity.
|
|
||||||
|
|
||||||
Output only the PHP code block.
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = await OpenAiService.askGpt(prompt);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,118 +0,0 @@
|
|||||||
import React, { useState } from 'react'
|
|
||||||
import { mdiCodeBraces, mdiContentCopy, mdiLoading, mdiCheck } from '@mdi/js'
|
|
||||||
import axios from 'axios'
|
|
||||||
import BaseButton from '../BaseButton'
|
|
||||||
import CardBox from '../CardBox'
|
|
||||||
import CardBoxComponentBody from '../CardBoxComponentBody'
|
|
||||||
import CardBoxComponentTitle from '../CardBoxComponentTitle'
|
|
||||||
import CardBoxComponentFooter from '../CardBoxComponentFooter'
|
|
||||||
import BaseIcon from '../BaseIcon'
|
|
||||||
|
|
||||||
interface PluginGeneratorProps {
|
|
||||||
managedTableId: string
|
|
||||||
tableName: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const PluginGenerator: React.FC<PluginGeneratorProps> = ({ managedTableId, tableName }) => {
|
|
||||||
const [code, setCode] = useState<string | null>(null)
|
|
||||||
const [isGenerating, setIsGenerating] = useState(false)
|
|
||||||
const [copied, setCopied] = useState(false)
|
|
||||||
const [error, setError] = useState<string | null>(null)
|
|
||||||
|
|
||||||
const handleGenerate = async () => {
|
|
||||||
setIsGenerating(true)
|
|
||||||
setError(null)
|
|
||||||
try {
|
|
||||||
const response = await axios.post(`/managed_tables/${managedTableId}/generate-plugin`)
|
|
||||||
if (response.data && response.data.success) {
|
|
||||||
setCode(response.data.data)
|
|
||||||
} else {
|
|
||||||
setError(response.data.error || 'Failed to generate plugin code.')
|
|
||||||
}
|
|
||||||
} catch (err: any) {
|
|
||||||
console.error(err)
|
|
||||||
setError(err.response?.data?.error || 'An error occurred while generating the plugin.')
|
|
||||||
} finally {
|
|
||||||
setIsGenerating(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCopy = () => {
|
|
||||||
if (code) {
|
|
||||||
navigator.clipboard.writeText(code)
|
|
||||||
setCopied(true)
|
|
||||||
setTimeout(() => setCopied(false), 2000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CardBox className="mt-6 border-2 border-blue-500 shadow-lg">
|
|
||||||
<CardBoxComponentTitle title="WordPress Plugin AI Generator" icon={mdiCodeBraces} />
|
|
||||||
|
|
||||||
<CardBoxComponentBody>
|
|
||||||
<div className="mb-4">
|
|
||||||
<p className="text-gray-600 dark:text-gray-400 mb-2">
|
|
||||||
Generate a custom WordPress plugin for the table <span className="font-bold text-blue-600">"{tableName}"</span>.
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-500">
|
|
||||||
This will create a complete PHP plugin with admin CRUD operations using WordPress best practices.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error && (
|
|
||||||
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
|
|
||||||
<span className="block sm:inline">{error}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{code ? (
|
|
||||||
<div className="relative group">
|
|
||||||
<div className="absolute right-2 top-2 z-10">
|
|
||||||
<BaseButton
|
|
||||||
color={copied ? 'success' : 'info'}
|
|
||||||
icon={copied ? mdiCheck : mdiContentCopy}
|
|
||||||
label={copied ? 'Copied' : 'Copy Code'}
|
|
||||||
small
|
|
||||||
onClick={handleCopy}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<pre className="p-4 bg-gray-900 text-green-400 rounded-lg overflow-x-auto max-h-[500px] text-xs font-mono border-2 border-gray-700 aside-scrollbars">
|
|
||||||
<code>{code}</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex flex-col items-center justify-center py-12 bg-gray-50 dark:bg-gray-800 rounded-lg border-2 border-dashed border-gray-300 dark:border-gray-700">
|
|
||||||
<BaseIcon path={mdiCodeBraces} size={48} className="text-gray-300 dark:text-gray-600 mb-4" />
|
|
||||||
<p className="text-gray-400 italic mb-6">No code generated yet.</p>
|
|
||||||
<BaseButton
|
|
||||||
color="info"
|
|
||||||
label={isGenerating ? 'Generating Code...' : 'Generate WordPress Plugin'}
|
|
||||||
icon={isGenerating ? mdiLoading : mdiCodeBraces}
|
|
||||||
className={isGenerating ? 'animate-pulse' : ''}
|
|
||||||
disabled={isGenerating}
|
|
||||||
onClick={handleGenerate}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardBoxComponentBody>
|
|
||||||
|
|
||||||
{code && (
|
|
||||||
<CardBoxComponentFooter>
|
|
||||||
<div className="flex justify-between items-center w-full">
|
|
||||||
<span className="text-xs text-gray-500">Generated using AI based on your table schema.</span>
|
|
||||||
<BaseButton
|
|
||||||
color="info"
|
|
||||||
outline
|
|
||||||
label="Regenerate"
|
|
||||||
icon={mdiCodeBraces}
|
|
||||||
onClick={handleGenerate}
|
|
||||||
disabled={isGenerating}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</CardBoxComponentFooter>
|
|
||||||
)}
|
|
||||||
</CardBox>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PluginGenerator
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { mdiChartTimelineVariant, mdiUpload, mdiCodeBraces } from '@mdi/js'
|
import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
@ -31,7 +31,6 @@ import { useRouter } from 'next/router'
|
|||||||
import {saveFile} from "../../helpers/fileSaver";
|
import {saveFile} from "../../helpers/fileSaver";
|
||||||
import dataFormatter from '../../helpers/dataFormatter';
|
import dataFormatter from '../../helpers/dataFormatter';
|
||||||
import ImageField from "../../components/ImageField";
|
import ImageField from "../../components/ImageField";
|
||||||
import PluginGenerator from '../../components/Managed_tables/PluginGenerator';
|
|
||||||
|
|
||||||
import {hasPermission} from "../../helpers/userPermissions";
|
import {hasPermission} from "../../helpers/userPermissions";
|
||||||
|
|
||||||
@ -362,10 +361,8 @@ const EditManaged_tables = () => {
|
|||||||
const { managed_tablesId } = router.query
|
const { managed_tablesId } = router.query
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (managed_tablesId) {
|
|
||||||
dispatch(fetch({ id: managed_tablesId }))
|
dispatch(fetch({ id: managed_tablesId }))
|
||||||
}
|
}, [managed_tablesId])
|
||||||
}, [managed_tablesId, dispatch])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof managed_tables === 'object') {
|
if (typeof managed_tables === 'object') {
|
||||||
@ -921,11 +918,6 @@ const EditManaged_tables = () => {
|
|||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
|
|
||||||
<PluginGenerator
|
|
||||||
managedTableId={managed_tablesId as string}
|
|
||||||
tableName={initialValues.table_name}
|
|
||||||
/>
|
|
||||||
</SectionMain>
|
</SectionMain>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user