This commit is contained in:
Flatlogic Bot 2026-02-22 00:27:00 +00:00
parent ec68c7b1dd
commit 5a85e3e1d9
4 changed files with 283 additions and 96 deletions

View File

@ -5,8 +5,6 @@ const Managed_tablesService = require('../services/managed_tables');
const Managed_tablesDBApi = require('../db/api/managed_tables');
const wrapAsync = require('../helpers').wrapAsync;
const config = require('../config');
const router = express.Router();
@ -160,27 +158,27 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Managed_tables"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Managed_tables"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
data:
description: Data of the updated item
type: object
$ref: "#/components/schemas/Managed_tables"
required:
- id
responses:
200:
description: The item data was successfully updated
content:
application/json:
schema:
$ref: "#/components/schemas/Managed_tables"
400:
description: Invalid ID supplied
401:
$ref: "#/components/responses/UnauthorizedError"
404:
description: Item not found
500:
description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Managed_tablesService.update(req.body.data, req.body.id, req.currentUser);
@ -204,21 +202,21 @@ router.put('/:id', wrapAsync(async (req, res) => {
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Managed_tables"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
responses:
200:
description: The item was successfully deleted
content:
application/json:
schema:
$ref: "#/components/schemas/Managed_tables"
400:
description: Invalid ID supplied
401:
$ref: "#/components/responses/UnauthorizedError"
404:
description: Item not found
500:
description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Managed_tablesService.remove(req.params.id, req.currentUser);
@ -244,19 +242,19 @@ router.delete('/:id', wrapAsync(async (req, res) => {
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Managed_tables"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
responses:
200:
description: The items was successfully deleted
content:
application/json:
schema:
$ref: "#/components/schemas/Managed_tables"
401:
$ref: "#/components/responses/UnauthorizedError"
404:
description: Items not found
500:
description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Managed_tablesService.deleteByIds(req.body.data, req.currentUser);
@ -274,20 +272,20 @@ router.post('/deleteByIds', wrapAsync(async (req, res) => {
* summary: Get all managed_tables
* description: Get all managed_tables
* responses:
* 200:
* description: Managed_tables list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Managed_tables"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
200:
description: Managed_tables list successfully received
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Managed_tables"
401:
$ref: "#/components/responses/UnauthorizedError"
404:
description: Data not found
500:
description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
@ -416,21 +414,21 @@ router.get('/autocomplete', async (req, res) => {
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Managed_tables"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
responses:
200:
description: Selected item successfully received
content:
application/json:
schema:
$ref: "#/components/schemas/Managed_tables"
400:
description: Invalid ID supplied
401:
$ref: "#/components/responses/UnauthorizedError"
404:
description: Item not found
500:
description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await Managed_tablesDBApi.findBy(
@ -442,6 +440,37 @@ router.get('/:id', wrapAsync(async (req, res) => {
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);
module.exports = router;

View File

@ -3,13 +3,8 @@ const Managed_tablesDBApi = require('../db/api/managed_tables');
const processFile = require("../middlewares/upload");
const ValidationError = require('./notifications/errors/validation');
const csv = require('csv-parser');
const axios = require('axios');
const config = require('../config');
const stream = require('stream');
const OpenAiService = require('./openai');
module.exports = class Managed_tablesService {
static async create(data, currentUser) {
@ -28,9 +23,9 @@ module.exports = class Managed_tablesService {
await transaction.rollback();
throw error;
}
};
}
static async bulkImport(req, res, sendInvitationEmails = true, host) {
static async bulkImport(req, res) {
const transaction = await db.sequelize.transaction();
try {
@ -95,7 +90,7 @@ module.exports = class Managed_tablesService {
await transaction.rollback();
throw error;
}
};
}
static async deleteByIds(ids, currentUser) {
const transaction = await db.sequelize.transaction();
@ -132,7 +127,44 @@ 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;
}
};

View File

@ -0,0 +1,118 @@
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">&quot;{tableName}&quot;</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

View File

@ -1,4 +1,4 @@
import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
import { mdiChartTimelineVariant, mdiUpload, mdiCodeBraces } from '@mdi/js'
import Head from 'next/head'
import React, { ReactElement, useEffect, useState } from 'react'
import DatePicker from "react-datepicker";
@ -31,6 +31,7 @@ import { useRouter } from 'next/router'
import {saveFile} from "../../helpers/fileSaver";
import dataFormatter from '../../helpers/dataFormatter';
import ImageField from "../../components/ImageField";
import PluginGenerator from '../../components/Managed_tables/PluginGenerator';
import {hasPermission} from "../../helpers/userPermissions";
@ -361,8 +362,10 @@ const EditManaged_tables = () => {
const { managed_tablesId } = router.query
useEffect(() => {
dispatch(fetch({ id: managed_tablesId }))
}, [managed_tablesId])
if (managed_tablesId) {
dispatch(fetch({ id: managed_tablesId }))
}
}, [managed_tablesId, dispatch])
useEffect(() => {
if (typeof managed_tables === 'object') {
@ -918,6 +921,11 @@ const EditManaged_tables = () => {
</Form>
</Formik>
</CardBox>
<PluginGenerator
managedTableId={managed_tablesId as string}
tableName={initialValues.table_name}
/>
</SectionMain>
</>
)
@ -935,4 +943,4 @@ EditManaged_tables.getLayout = function getLayout(page: ReactElement) {
)
}
export default EditManaged_tables
export default EditManaged_tables