refactor(UI): 🏗️ Ui changes and API changes
Some checks failed
CI / Test (1.23) (push) Failing after -22m40s
CI / Test (1.22) (push) Failing after -22m36s
CI / Build (push) Failing after -23m32s
CI / Lint (push) Failing after -23m7s

This commit is contained in:
Hein
2026-02-06 17:03:28 +02:00
parent 8b1eed6c42
commit 35a548e7e2
10 changed files with 648 additions and 20 deletions

View File

@@ -16,6 +16,7 @@ Created comprehensive documentation for all libraries and frameworks:
Complete database abstraction with GORM support:
**Models** (storage/models.go):
- User: Authentication and user management
- APIKey: API key-based authentication
- Hook: Webhook registrations with user ownership
@@ -25,12 +26,14 @@ Complete database abstraction with GORM support:
- MessageCache: WhatsApp message caching
**Database Management** (storage/db.go):
- PostgreSQL and SQLite support
- Connection pooling
- Auto-migration support
- Health check functionality
**Repository Pattern** (storage/repository.go):
- Generic repository with CRUD operations
- Specialized repositories for each model
- User-specific queries (by username, email)
@@ -39,6 +42,7 @@ Complete database abstraction with GORM support:
- Event log queries with time-based filtering
**Seed Data** (storage/seed.go):
- Creates default admin user (username: admin, password: admin123)
- Safe to run multiple times
@@ -47,6 +51,7 @@ Complete database abstraction with GORM support:
Full-featured authentication system:
**Core Auth** (auth/auth.go):
- JWT token generation and validation
- API key authentication
- Password hashing with bcrypt
@@ -55,6 +60,7 @@ Full-featured authentication system:
- Permission checking based on roles (admin, user, viewer)
**Middleware** (auth/middleware.go):
- AuthMiddleware: Requires authentication (JWT or API key)
- OptionalAuthMiddleware: Extracts user if present
- RoleMiddleware: Enforces role-based access control
@@ -65,6 +71,7 @@ Full-featured authentication system:
Complete REST API server with authentication:
**Server Setup** (webserver/server.go):
- Gorilla Mux router integration
- Authentication middleware
- Role-based route protection
@@ -72,6 +79,7 @@ Complete REST API server with authentication:
- Admin-only routes
**Core Handlers** (webserver/handlers.go):
- Health check endpoint
- User login with JWT
- Get current user profile
@@ -82,6 +90,7 @@ Complete REST API server with authentication:
- Create user (admin)
**CRUD Handlers** (webserver/handlers_crud.go):
- Hook management (list, create, get, update, delete)
- WhatsApp account management (list, create, get, update, delete)
- API key listing
@@ -93,19 +102,23 @@ Complete REST API server with authentication:
Complete RESTful API:
**Public Endpoints**:
- `GET /health` - Health check
- `POST /api/v1/auth/login` - User login
**Authenticated Endpoints**:
- `GET /api/v1/users/me` - Get current user
- `PUT /api/v1/users/me/password` - Change password
**API Keys**:
- `GET /api/v1/api-keys` - List user's API keys
- `POST /api/v1/api-keys` - Create API key
- `POST /api/v1/api-keys/{id}/revoke` - Revoke API key
**Hooks**:
- `GET /api/v1/hooks` - List user's hooks
- `POST /api/v1/hooks` - Create hook
- `GET /api/v1/hooks/{id}` - Get hook details
@@ -113,6 +126,7 @@ Complete RESTful API:
- `DELETE /api/v1/hooks/{id}` - Delete hook
**WhatsApp Accounts**:
- `GET /api/v1/whatsapp-accounts` - List user's accounts
- `POST /api/v1/whatsapp-accounts` - Create account
- `GET /api/v1/whatsapp-accounts/{id}` - Get account details
@@ -120,6 +134,7 @@ Complete RESTful API:
- `DELETE /api/v1/whatsapp-accounts/{id}` - Delete account
**Admin Endpoints**:
- `GET /api/v1/admin/users` - List all users
- `POST /api/v1/admin/users` - Create user
- `GET /api/v1/admin/users/{id}` - Get user
@@ -203,6 +218,7 @@ log.Fatal(server.Start(":8825"))
### 3. API Usage Examples
**Login**:
```bash
curl -X POST http://localhost:8825/api/v1/auth/login \
-H "Content-Type: application/json" \
@@ -210,6 +226,7 @@ curl -X POST http://localhost:8825/api/v1/auth/login \
```
**Create Hook** (with JWT):
```bash
curl -X POST http://localhost:8825/api/v1/hooks \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
@@ -224,6 +241,7 @@ curl -X POST http://localhost:8825/api/v1/hooks \
```
**Create API Key**:
```bash
curl -X POST http://localhost:8825/api/v1/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
@@ -232,6 +250,7 @@ curl -X POST http://localhost:8825/api/v1/api-keys \
```
**Use API Key**:
```bash
curl http://localhost:8825/api/v1/hooks \
-H "Authorization: ApiKey YOUR_API_KEY"
@@ -252,6 +271,7 @@ curl http://localhost:8825/api/v1/hooks \
To complete Phase 2, implement the frontend:
1. **Initialize Frontend Project**:
```bash
npm create @tanstack/start@latest
cd frontend
@@ -279,6 +299,267 @@ To complete Phase 2, implement the frontend:
- Serve static files through Go server
- Configure reverse proxy if needed
## Using Oranguru
1. import { Gridler } from '../Gridler';
- Gridler is the grid component
- GlidlerAPIAdaptorForGoLangv2 is used to connect Gridler to RestHeadSpecAPI
```ts
const GridExample = () => {
const columns: GridlerColumns = [
{
Cell: (row) => {
const process = `${
row?.cql2?.length > 0
? '🔖'
: row?.cql1?.length > 0
? '📕'
: row?.status === 1
? '💡'
: row?.status === 2
? '🔒'
: '⚙️'
} ${String(row?.id_process ?? '0')}`;
return {
data: process,
displayData: process,
status: row?.status,
} as any;
},
id: 'id_process',
title: 'RID',
width: 100,
},
{
id: 'process',
title: 'Process',
tooltip: (buffer) => {
return `Process: ${buffer?.process}\nType: ${buffer?.processtype}\nStatus: ${buffer?.status}`;
},
width: 200,
},
{
id: 'processtype',
title: 'Type',
},
{
disableSort: true,
id: 'status',
title: 'Status',
width: 100,
},
];
return (<Gridler
columns={columns}
height="100%"
keyField="id_process"
onChange={(v) => {
//console.log('GridlerGoAPIExampleEventlog onChange', v);
setValues(v);
}}
ref={ref}
scrollToRowKey={selectRow ? parseInt(selectRow, 10) : undefined}
searchStr={search}
sections={{ ...sections, rightElementDisabled: false }}
selectFirstRowOnMount={true}
selectMode="row"
title="Go API Example"
uniqueid="gridtest"
values={values}
>
<GlidlerAPIAdaptorForGoLangv2
authtoken={apiKey}
options={[{ type: 'preload', value: 'PRO' }]}
//options={[{ type: 'fieldfilter', name: 'process', value: 'test' }]}
url={`${apiUrl}/public/process`}
/>
<Gridler.FormAdaptor
changeOnActiveClick={true}
descriptionField={'process'}
onRequestForm={(request, data) => {
console.log('Form requested', request, data);
//Show form insert,update,delete
}}
/>
</Gridler>
)
}
```
2. Former is a form wrapper that uses react-hook-form to handle forms.
```ts
import { TextInput } from '@mantine/core';
import { useUncontrolled } from '@mantine/hooks';
import { url } from 'inspector';
import { Controller } from 'react-hook-form';
import { TextInputCtrl, NativeSelectCtrl } from '../../FormerControllers';
import { InlineWrapper } from '../../FormerControllers/Inputs/InlineWrapper';
import NumberInputCtrl from '../../FormerControllers/Inputs/NumberInputCtrl';
import { Former } from '../Former';
import { FormerRestHeadSpecAPI } from '../FormerRestHeadSpecAPI';
export const ApiFormData = (props: {
onChange?: (values: Record<string, unknown>) => void;
primeData?: Record<string, unknown>;
values?: Record<string, unknown>;
}) => {
const [values, setValues] = useUncontrolled<Record<string, unknown>>({
defaultValue: { authToken: '', url: '', ...props.primeData },
finalValue: { authToken: '', url: '', ...props.primeData },
onChange: props.onChange,
value: props.values,
});
return (
<Former
disableHTMlForm
id="api-form-data"
layout={{ saveButtonTitle: 'Save URL Parameters' }}
onAPICall={FormerRestHeadSpecAPI({
authToken: authToken,
url: url,
})}
onChange={setValues}
primeData={props.primeData}
request="update"
uniqueKeyField="id"
values={values}
>
<TextInputCtrl label="Test" name="test" />
<NumberInputCtrl label="AgeTest" name="age" />
<InlineWrapper label="Select One" promptWidth={200}>
<NativeSelectCtrl data={['One', 'Two', 'Three']} name="option1" />
</InlineWrapper>
{/* Controllers can be use but we prefer to use the build TextInputCtrl and such for better integration with Former's state management and validation. However, you can also use the Controller component from react-hook-form to integrate custom inputs like this: */}
<Controller
name="url"
render={({ field }) => <TextInput label="URL" type="url" {...field} />}
/>
<Controller
name="authToken"
render={({ field }) => <TextInput label="Auth Token" type="password" {...field} />}
/>
</Former>
);
};
```
3. Controls TextInputCtrl,NumberInputCtrl,NativeSelectCtrl and InlineWrapper
- InlineWrapper is used to display the title on the left and control to the right.
```ts
const Renderable = () => {
return (
<Former>
<Stack h="100%" mih="400px" miw="400px" w="100%">
<TextInputCtrl label="Test" name="test" />
<NumberInputCtrl label="AgeTest" name="age" />
<InlineWrapper label="Select One" promptWidth={200}>
<NativeSelectCtrl data={["One","Two","Three"]} name="option1"/>
</InlineWrapper>
</Stack>
</Former>
);
};
```
4. Boxer is an advanced multi select control with infinite query lookap features for an API.
```ts
// Server-Side Example (Simulated)
export const ServerSide: Story = {
render: () => {
const [value, setValue] = useState<null | string>(null);
// Simulate server-side API call
const handleAPICall = async (params: {
page: number;
pageSize: number;
search?: string;
}): Promise<{ data: Array<BoxerItem>; total: number }> => {
// Simulate network delay
await new Promise((resolve) => setTimeout(resolve, 500));
// Filter based on search
let filteredData = [...sampleData];
if (params.search) {
filteredData = filteredData.filter((item) =>
item.label.toLowerCase().includes(params.search!.toLowerCase())
);
}
// Paginate
const start = params.page * params.pageSize;
const end = start + params.pageSize;
const paginatedData = filteredData.slice(start, end);
return {
data: paginatedData,
total: filteredData.length,
};
};
return (
<div style={{ width: 300 }}>
<Boxer
clearable
dataSource="server"
label="Favorite Fruit (Server-side)"
onAPICall={handleAPICall}
onChange={setValue}
pageSize={10}
placeholder="Select a fruit (Server-side)"
searchable
value={value}
/>
<div style={{ marginTop: 20 }}>
<strong>Selected Value:</strong> {value ?? 'None'}
</div>
</div>
);
},
};
// Multi-Select Example
export const MultiSelect: Story = {
render: () => {
const [value, setValue] = useState<Array<string>>([]);
return (
<div style={{ width: 300 }}>
<Boxer
clearable
data={sampleData}
dataSource="local"
label="Favorite Fruits"
multiSelect
onChange={setValue}
placeholder="Select fruits"
searchable
value={value}
/>
<div style={{ marginTop: 20 }}>
<strong>Selected Values:</strong>{' '}
{value.length > 0 ? value.join(', ') : 'None'}
</div>
</div>
);
},
};
```
## Database Schema
```
@@ -354,6 +635,7 @@ sessions
## Summary
Phase 2 backend is **100% complete** with:
- ✅ Comprehensive tool documentation
- ✅ Complete database layer with models and repositories
- ✅ Full authentication system (JWT + API keys)