working export of roles and routes
This commit is contained in:
+131
-46
@@ -1,6 +1,23 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from "react";
|
||||||
import { X, Trash2 } from 'lucide-react';
|
import { X, Trash2 } from "lucide-react";
|
||||||
import { useFlowStore } from '../store/flowStore';
|
import { useFlowStore } from "../store/flowStore";
|
||||||
|
|
||||||
|
interface Permissions {
|
||||||
|
authRequired: boolean;
|
||||||
|
routes: string[];
|
||||||
|
canCreateUsers: boolean;
|
||||||
|
canEditUsers: boolean;
|
||||||
|
canDeleteUsers: boolean;
|
||||||
|
canManageRoles: boolean;
|
||||||
|
canLogin: boolean;
|
||||||
|
canRegister: boolean;
|
||||||
|
canGoogleLogin: boolean;
|
||||||
|
canAppleLogin: boolean;
|
||||||
|
canMicrosoftLogin: boolean;
|
||||||
|
canMagicLinkLogin: boolean;
|
||||||
|
needs2FA: boolean;
|
||||||
|
canSetPermissions: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface RoleModalProps {
|
interface RoleModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -9,21 +26,14 @@ interface RoleModalProps {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
permissions: {
|
permissions: Permissions;
|
||||||
authRequired: boolean;
|
|
||||||
routes: string[];
|
|
||||||
canCreateUsers: boolean;
|
|
||||||
canEditUsers: boolean;
|
|
||||||
canDeleteUsers: boolean;
|
|
||||||
canManageRoles: boolean;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const createInitialFormData = () => ({
|
const createInitialFormData = () => ({
|
||||||
id: `role_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
id: `role_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||||
name: '',
|
name: "",
|
||||||
slug: '',
|
slug: "",
|
||||||
permissions: {
|
permissions: {
|
||||||
authRequired: false,
|
authRequired: false,
|
||||||
routes: [],
|
routes: [],
|
||||||
@@ -31,6 +41,14 @@ const createInitialFormData = () => ({
|
|||||||
canEditUsers: false,
|
canEditUsers: false,
|
||||||
canDeleteUsers: false,
|
canDeleteUsers: false,
|
||||||
canManageRoles: false,
|
canManageRoles: false,
|
||||||
|
canLogin: false,
|
||||||
|
canRegister: false,
|
||||||
|
canGoogleLogin: false,
|
||||||
|
canAppleLogin: false,
|
||||||
|
canMicrosoftLogin: false,
|
||||||
|
canMagicLinkLogin: false,
|
||||||
|
needs2FA: false,
|
||||||
|
canSetPermissions: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,9 +66,9 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, value, type, checked } = e.target;
|
const { name, value, type, checked } = e.target;
|
||||||
if (type === 'checkbox') {
|
if (type === "checkbox") {
|
||||||
if (name.startsWith('permissions.')) {
|
if (name.startsWith("permissions.")) {
|
||||||
const permissionKey = name.split('.')[1];
|
const permissionKey = name.split(".")[1];
|
||||||
setFormData({
|
setFormData({
|
||||||
...formData,
|
...formData,
|
||||||
permissions: {
|
permissions: {
|
||||||
@@ -63,13 +81,13 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
setFormData({
|
setFormData({
|
||||||
...formData,
|
...formData,
|
||||||
[name]: value,
|
[name]: value,
|
||||||
...(name === 'name' && !role
|
...(name === "name" && !role
|
||||||
? {
|
? {
|
||||||
slug: value
|
slug: value
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/[^a-z0-9]/g, '-')
|
.replace(/[^a-z0-9]/g, "-")
|
||||||
.replace(/-+/g, '-')
|
.replace(/-+/g, "-")
|
||||||
.replace(/^-|-$/g, ''),
|
.replace(/^-|-$/g, ""),
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
});
|
});
|
||||||
@@ -121,12 +139,9 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
<div className="bg-white rounded-lg w-full max-w-2xl max-h-[80vh] overflow-hidden">
|
<div className="bg-white rounded-lg w-full max-w-2xl max-h-[80vh] overflow-hidden">
|
||||||
<div className="p-4 border-b border-gray-200 flex justify-between items-center">
|
<div className="p-4 border-b border-gray-200 flex justify-between items-center">
|
||||||
<h2 className="text-lg font-semibold">
|
<h2 className="text-lg font-semibold">
|
||||||
{role ? 'Edit Role' : 'Add New Role'}
|
{role ? "Edit Role" : "Add New Role"}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button onClick={onClose} className="p-1 hover:bg-gray-100 rounded">
|
||||||
onClick={onClose}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded"
|
|
||||||
>
|
|
||||||
<X className="w-5 h-5" />
|
<X className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,7 +149,9 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
<div className="p-4 overflow-y-auto">
|
<div className="p-4 overflow-y-auto">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium mb-1">Role Name</label>
|
<label className="block text-sm font-medium mb-1">
|
||||||
|
Role Name
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
@@ -146,7 +163,9 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium mb-1">Role Slug</label>
|
<label className="block text-sm font-medium mb-1">
|
||||||
|
Role Slug
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="slug"
|
name="slug"
|
||||||
@@ -159,28 +178,20 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-medium mb-2">Permissions</h3>
|
|
||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<label className="flex items-center">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="permissions.authRequired"
|
|
||||||
checked={formData.permissions.authRequired}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
|
||||||
/>
|
|
||||||
<span className="ml-2 text-sm">Authentication Required</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-sm font-medium">Accessible Routes</h4>
|
<h4 className="text-sm font-medium">Permissions</h4>
|
||||||
<label className="flex items-center">
|
<label className="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={formData.permissions.routes.length === routes.length}
|
checked={
|
||||||
onChange={(e) => handleSelectAllRoutes(e.target.checked)}
|
formData.permissions.routes.length > 0 &&
|
||||||
|
formData.permissions.routes.length === routes.length
|
||||||
|
}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleSelectAllRoutes(e.target.checked)
|
||||||
|
}
|
||||||
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
/>
|
/>
|
||||||
<span className="ml-2 text-sm">Select All</span>
|
<span className="ml-2 text-sm">Select All</span>
|
||||||
@@ -191,8 +202,12 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
<label key={route.id} className="flex items-center">
|
<label key={route.id} className="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={formData.permissions.routes.includes(route.id)}
|
checked={formData.permissions.routes.includes(
|
||||||
onChange={(e) => handleRouteChange(route.id, e.target.checked)}
|
route.id
|
||||||
|
)}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleRouteChange(route.id, e.target.checked)
|
||||||
|
}
|
||||||
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
/>
|
/>
|
||||||
<span className="ml-2 text-sm">
|
<span className="ml-2 text-sm">
|
||||||
@@ -239,6 +254,76 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h4 className="text-sm font-medium">
|
||||||
|
Authentication Management
|
||||||
|
</h4>
|
||||||
|
<div className="space-y-2 ml-4">
|
||||||
|
<label className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="permissions.authRequired"
|
||||||
|
checked={formData.permissions.authRequired}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm">
|
||||||
|
Authentication Required
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="permissions.canLogin"
|
||||||
|
checked={formData.permissions.canLogin}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm">Can Login</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="permissions.canRegister"
|
||||||
|
checked={formData.permissions.canRegister}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm">Can Register</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="permissions.canGoogleLogin"
|
||||||
|
checked={formData.permissions.canGoogleLogin}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm">Can Use Google Login</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="permissions.needs2FA"
|
||||||
|
checked={formData.permissions.needs2FA}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm">Requires 2FA</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="permissions.canSetPermissions"
|
||||||
|
checked={formData.permissions.canSetPermissions}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm">Can Set Permissions</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label className="flex items-center">
|
<label className="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -275,7 +360,7 @@ export function RoleModal({ isOpen, onClose, role }: RoleModalProps) {
|
|||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||||
>
|
>
|
||||||
{role ? 'Update' : 'Save'} Role
|
{role ? "Update" : "Save"} Role
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useFlowStore } from "../store/flowStore";
|
|||||||
import { TranslationService } from "../services/TranslationService";
|
import { TranslationService } from "../services/TranslationService";
|
||||||
|
|
||||||
export function SettingsForm() {
|
export function SettingsForm() {
|
||||||
const { settings, updateSettings } = useFlowStore();
|
const { settings, updateSettings, routes } = useFlowStore();
|
||||||
|
|
||||||
const handleChange = (
|
const handleChange = (
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
|
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
|
||||||
@@ -21,8 +21,29 @@ export function SettingsForm() {
|
|||||||
|
|
||||||
const handleExportConfiguration = () => {
|
const handleExportConfiguration = () => {
|
||||||
const models = useFlowStore.getState().models;
|
const models = useFlowStore.getState().models;
|
||||||
|
const roles = useFlowStore.getState().roles;
|
||||||
|
const routes = useFlowStore.getState().routes;
|
||||||
|
|
||||||
const configuration = {
|
const configuration = {
|
||||||
models: models.map((model) => TranslationService.translateModel(model)),
|
models: models.map((model) => TranslationService.translateModel(model)),
|
||||||
|
roles: roles.map((role) => ({
|
||||||
|
name: role.name,
|
||||||
|
slug: role.slug,
|
||||||
|
permissions: {
|
||||||
|
...role.permissions,
|
||||||
|
routes: role.permissions.routes
|
||||||
|
.map((routeId) => {
|
||||||
|
const route = routes.find((r) => r.id === routeId);
|
||||||
|
return route
|
||||||
|
? {
|
||||||
|
method: route.method,
|
||||||
|
url: route.url,
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
})
|
||||||
|
.filter(Boolean),
|
||||||
|
},
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
const blob = new Blob([JSON.stringify(configuration, null, 2)], {
|
const blob = new Blob([JSON.stringify(configuration, null, 2)], {
|
||||||
@@ -31,7 +52,7 @@ export function SettingsForm() {
|
|||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = "model-configuration.json";
|
a.download = "configuration.json";
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
|
|||||||
Reference in New Issue
Block a user