forge-admin 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +73 -0
  2. package/app.db +0 -0
  3. package/components.json +20 -0
  4. package/dist/assets/index-BPVmexx_.css +1 -0
  5. package/dist/assets/index-BtNewH3n.js +258 -0
  6. package/dist/favicon.ico +0 -0
  7. package/dist/index.html +27 -0
  8. package/dist/placeholder.svg +1 -0
  9. package/dist/robots.txt +14 -0
  10. package/eslint.config.js +26 -0
  11. package/index.html +26 -0
  12. package/package.json +107 -0
  13. package/postcss.config.js +6 -0
  14. package/public/favicon.ico +0 -0
  15. package/public/placeholder.svg +1 -0
  16. package/public/robots.txt +14 -0
  17. package/src/App.css +42 -0
  18. package/src/App.tsx +32 -0
  19. package/src/admin/convertSchema.ts +83 -0
  20. package/src/admin/factory.ts +12 -0
  21. package/src/admin/introspecter.ts +6 -0
  22. package/src/admin/router.ts +38 -0
  23. package/src/admin/schema.ts +17 -0
  24. package/src/admin/sqlite.ts +73 -0
  25. package/src/admin/types.ts +35 -0
  26. package/src/components/AdminLayout.tsx +19 -0
  27. package/src/components/AdminSidebar.tsx +102 -0
  28. package/src/components/DataTable.tsx +166 -0
  29. package/src/components/ModelForm.tsx +221 -0
  30. package/src/components/NavLink.tsx +28 -0
  31. package/src/components/StatCard.tsx +32 -0
  32. package/src/components/ui/accordion.tsx +52 -0
  33. package/src/components/ui/alert-dialog.tsx +104 -0
  34. package/src/components/ui/alert.tsx +43 -0
  35. package/src/components/ui/aspect-ratio.tsx +5 -0
  36. package/src/components/ui/avatar.tsx +38 -0
  37. package/src/components/ui/badge.tsx +29 -0
  38. package/src/components/ui/breadcrumb.tsx +90 -0
  39. package/src/components/ui/button.tsx +47 -0
  40. package/src/components/ui/calendar.tsx +54 -0
  41. package/src/components/ui/card.tsx +43 -0
  42. package/src/components/ui/carousel.tsx +224 -0
  43. package/src/components/ui/chart.tsx +303 -0
  44. package/src/components/ui/checkbox.tsx +26 -0
  45. package/src/components/ui/collapsible.tsx +9 -0
  46. package/src/components/ui/command.tsx +132 -0
  47. package/src/components/ui/context-menu.tsx +178 -0
  48. package/src/components/ui/dialog.tsx +95 -0
  49. package/src/components/ui/drawer.tsx +87 -0
  50. package/src/components/ui/dropdown-menu.tsx +179 -0
  51. package/src/components/ui/form.tsx +129 -0
  52. package/src/components/ui/hover-card.tsx +27 -0
  53. package/src/components/ui/input-otp.tsx +61 -0
  54. package/src/components/ui/input.tsx +22 -0
  55. package/src/components/ui/label.tsx +17 -0
  56. package/src/components/ui/menubar.tsx +207 -0
  57. package/src/components/ui/navigation-menu.tsx +120 -0
  58. package/src/components/ui/pagination.tsx +81 -0
  59. package/src/components/ui/popover.tsx +29 -0
  60. package/src/components/ui/progress.tsx +23 -0
  61. package/src/components/ui/radio-group.tsx +36 -0
  62. package/src/components/ui/resizable.tsx +37 -0
  63. package/src/components/ui/scroll-area.tsx +38 -0
  64. package/src/components/ui/select.tsx +143 -0
  65. package/src/components/ui/separator.tsx +20 -0
  66. package/src/components/ui/sheet.tsx +107 -0
  67. package/src/components/ui/sidebar.tsx +637 -0
  68. package/src/components/ui/skeleton.tsx +7 -0
  69. package/src/components/ui/slider.tsx +23 -0
  70. package/src/components/ui/sonner.tsx +27 -0
  71. package/src/components/ui/switch.tsx +27 -0
  72. package/src/components/ui/table.tsx +72 -0
  73. package/src/components/ui/tabs.tsx +53 -0
  74. package/src/components/ui/textarea.tsx +21 -0
  75. package/src/components/ui/toast.tsx +111 -0
  76. package/src/components/ui/toaster.tsx +24 -0
  77. package/src/components/ui/toggle-group.tsx +49 -0
  78. package/src/components/ui/toggle.tsx +37 -0
  79. package/src/components/ui/tooltip.tsx +28 -0
  80. package/src/components/ui/use-toast.ts +3 -0
  81. package/src/config/define.ts +6 -0
  82. package/src/config/index.ts +0 -0
  83. package/src/config/load.ts +45 -0
  84. package/src/config/types.ts +5 -0
  85. package/src/hooks/use-mobile.tsx +19 -0
  86. package/src/hooks/use-toast.ts +186 -0
  87. package/src/index.css +142 -0
  88. package/src/lib/models.ts +138 -0
  89. package/src/lib/utils.ts +6 -0
  90. package/src/main.tsx +5 -0
  91. package/src/orm/cli/makemigrations.ts +63 -0
  92. package/src/orm/cli/migrate.ts +127 -0
  93. package/src/orm/cli.ts +30 -0
  94. package/src/orm/core/base-model.ts +6 -0
  95. package/src/orm/core/manager.ts +27 -0
  96. package/src/orm/core/query-builder.ts +74 -0
  97. package/src/orm/db/connection.ts +0 -0
  98. package/src/orm/db/sql-types.ts +72 -0
  99. package/src/orm/db/sqlite.ts +4 -0
  100. package/src/orm/decorators/field.ts +80 -0
  101. package/src/orm/decorators/model.ts +36 -0
  102. package/src/orm/decorators/relations.ts +0 -0
  103. package/src/orm/metadata/field-metadata.ts +0 -0
  104. package/src/orm/metadata/field-types.ts +12 -0
  105. package/src/orm/metadata/get-meta.ts +9 -0
  106. package/src/orm/metadata/index.ts +15 -0
  107. package/src/orm/metadata/keys.ts +2 -0
  108. package/src/orm/metadata/model-registry.ts +53 -0
  109. package/src/orm/metadata/modifiers.ts +26 -0
  110. package/src/orm/metadata/types.ts +45 -0
  111. package/src/orm/migration-engine/diff.ts +243 -0
  112. package/src/orm/migration-engine/operations.ts +186 -0
  113. package/src/orm/schema/build.ts +138 -0
  114. package/src/orm/schema/state.ts +23 -0
  115. package/src/orm/schema/writeMigrations.ts +21 -0
  116. package/src/orm/syncdb.ts +25 -0
  117. package/src/pages/Dashboard.tsx +127 -0
  118. package/src/pages/Index.tsx +18 -0
  119. package/src/pages/ModelPage.tsx +177 -0
  120. package/src/pages/NotFound.tsx +24 -0
  121. package/src/pages/SchemaEditor.tsx +170 -0
  122. package/src/pages/Settings.tsx +166 -0
  123. package/src/server.ts +69 -0
  124. package/src/vite-env.d.ts +1 -0
  125. package/tailwind.config.js +112 -0
  126. package/tailwind.config.ts +114 -0
  127. package/tsconfig.app.json +30 -0
  128. package/tsconfig.json +16 -0
  129. package/tsconfig.node.json +22 -0
  130. package/vite.config.js +23 -0
  131. package/vite.config.ts +18 -0
Binary file
@@ -0,0 +1,27 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <!-- TODO: Set the document title to the name of your application -->
7
+ <title>Lovable App</title>
8
+ <meta name="description" content="Lovable Generated Project" />
9
+ <meta name="author" content="Lovable" />
10
+
11
+ <!-- TODO: Update og:title to match your application name -->
12
+ <meta property="og:title" content="Lovable App" />
13
+ <meta property="og:description" content="Lovable Generated Project" />
14
+ <meta property="og:type" content="website" />
15
+ <meta property="og:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
16
+
17
+ <meta name="twitter:card" content="summary_large_image" />
18
+ <meta name="twitter:site" content="@Lovable" />
19
+ <meta name="twitter:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
20
+ <script type="module" crossorigin src="/assets/index-BtNewH3n.js"></script>
21
+ <link rel="stylesheet" crossorigin href="/assets/index-BPVmexx_.css">
22
+ </head>
23
+
24
+ <body>
25
+ <div id="root"></div>
26
+ </body>
27
+ </html>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
@@ -0,0 +1,14 @@
1
+ User-agent: Googlebot
2
+ Allow: /
3
+
4
+ User-agent: Bingbot
5
+ Allow: /
6
+
7
+ User-agent: Twitterbot
8
+ Allow: /
9
+
10
+ User-agent: facebookexternalhit
11
+ Allow: /
12
+
13
+ User-agent: *
14
+ Allow: /
@@ -0,0 +1,26 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import reactHooks from "eslint-plugin-react-hooks";
4
+ import reactRefresh from "eslint-plugin-react-refresh";
5
+ import tseslint from "typescript-eslint";
6
+
7
+ export default tseslint.config(
8
+ { ignores: ["dist"] },
9
+ {
10
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
+ files: ["**/*.{ts,tsx}"],
12
+ languageOptions: {
13
+ ecmaVersion: 2020,
14
+ globals: globals.browser,
15
+ },
16
+ plugins: {
17
+ "react-hooks": reactHooks,
18
+ "react-refresh": reactRefresh,
19
+ },
20
+ rules: {
21
+ ...reactHooks.configs.recommended.rules,
22
+ "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
23
+ "@typescript-eslint/no-unused-vars": "off",
24
+ },
25
+ },
26
+ );
package/index.html ADDED
@@ -0,0 +1,26 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <!-- TODO: Set the document title to the name of your application -->
7
+ <title>Lovable App</title>
8
+ <meta name="description" content="Lovable Generated Project" />
9
+ <meta name="author" content="Lovable" />
10
+
11
+ <!-- TODO: Update og:title to match your application name -->
12
+ <meta property="og:title" content="Lovable App" />
13
+ <meta property="og:description" content="Lovable Generated Project" />
14
+ <meta property="og:type" content="website" />
15
+ <meta property="og:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
16
+
17
+ <meta name="twitter:card" content="summary_large_image" />
18
+ <meta name="twitter:site" content="@Lovable" />
19
+ <meta name="twitter:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
20
+ </head>
21
+
22
+ <body>
23
+ <div id="root"></div>
24
+ <script type="module" src="/src/main.tsx"></script>
25
+ </body>
26
+ </html>
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "forge-admin",
3
+ "version": "0.0.0",
4
+ "private": false,
5
+ "description": "**URL**: https://lovable.dev/projects/REPLACE_WITH_PROJECT_ID",
6
+ "homepage": "https://github.com/joeldsouza28/tauri-builder-suite#readme",
7
+ "bugs": {
8
+ "url": "https://github.com/joeldsouza28/tauri-builder-suite/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/joeldsouza28/tauri-builder-suite.git"
13
+ },
14
+ "license": "ISC",
15
+ "author": "",
16
+ "type": "module",
17
+ "main": "eslint.config.js",
18
+ "scripts": {
19
+ "dev": "vite",
20
+ "backend": "tsx src/main.ts",
21
+ "build": "vite build",
22
+ "build:dev": "vite build --mode development",
23
+ "lint": "eslint .",
24
+ "preview": "vite preview",
25
+ "orm": "tsx src/orm/cli.ts",
26
+ "server": "tsx src/server.ts"
27
+ },
28
+ "dependencies": {
29
+ "@hookform/resolvers": "^3.10.0",
30
+ "@radix-ui/react-accordion": "^1.2.11",
31
+ "@radix-ui/react-alert-dialog": "^1.1.14",
32
+ "@radix-ui/react-aspect-ratio": "^1.1.7",
33
+ "@radix-ui/react-avatar": "^1.1.10",
34
+ "@radix-ui/react-checkbox": "^1.3.2",
35
+ "@radix-ui/react-collapsible": "^1.1.11",
36
+ "@radix-ui/react-context-menu": "^2.2.15",
37
+ "@radix-ui/react-dialog": "^1.1.14",
38
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
39
+ "@radix-ui/react-hover-card": "^1.1.14",
40
+ "@radix-ui/react-label": "^2.1.7",
41
+ "@radix-ui/react-menubar": "^1.1.15",
42
+ "@radix-ui/react-navigation-menu": "^1.2.13",
43
+ "@radix-ui/react-popover": "^1.1.14",
44
+ "@radix-ui/react-progress": "^1.1.7",
45
+ "@radix-ui/react-radio-group": "^1.3.7",
46
+ "@radix-ui/react-scroll-area": "^1.2.9",
47
+ "@radix-ui/react-select": "^2.2.5",
48
+ "@radix-ui/react-separator": "^1.1.7",
49
+ "@radix-ui/react-slider": "^1.3.5",
50
+ "@radix-ui/react-slot": "^1.2.3",
51
+ "@radix-ui/react-switch": "^1.2.5",
52
+ "@radix-ui/react-tabs": "^1.1.12",
53
+ "@radix-ui/react-toast": "^1.2.14",
54
+ "@radix-ui/react-toggle": "^1.1.9",
55
+ "@radix-ui/react-toggle-group": "^1.1.10",
56
+ "@radix-ui/react-tooltip": "^1.2.7",
57
+ "@tanstack/react-query": "^5.83.0",
58
+ "better-sqlite3": "^12.5.0",
59
+ "class-variance-authority": "^0.7.1",
60
+ "clsx": "^2.1.1",
61
+ "cmdk": "^1.1.1",
62
+ "date-fns": "^3.6.0",
63
+ "embla-carousel-react": "^8.6.0",
64
+ "express": "^5.2.1",
65
+ "input-otp": "^1.4.2",
66
+ "lucide-react": "^0.462.0",
67
+ "next-themes": "^0.3.0",
68
+ "react": "^18.3.1",
69
+ "react-day-picker": "^8.10.1",
70
+ "react-dom": "^18.3.1",
71
+ "react-hook-form": "^7.61.1",
72
+ "react-resizable-panels": "^2.1.9",
73
+ "react-router-dom": "^6.30.1",
74
+ "recharts": "^2.15.4",
75
+ "sonner": "^1.7.4",
76
+ "tailwind-merge": "^2.6.0",
77
+ "tailwindcss-animate": "^1.0.7",
78
+ "tsconfig-paths": "^4.2.0",
79
+ "tsx": "^4.21.0",
80
+ "vaul": "^0.9.9",
81
+ "zod": "^3.25.76"
82
+ },
83
+ "devDependencies": {
84
+ "@eslint/js": "^9.32.0",
85
+ "@tailwindcss/typography": "^0.5.16",
86
+ "@types/node": "^22.16.5",
87
+ "@types/react": "^18.3.23",
88
+ "@types/react-dom": "^18.3.7",
89
+ "@vitejs/plugin-react-swc": "^3.11.0",
90
+ "autoprefixer": "^10.4.21",
91
+ "eslint": "^9.32.0",
92
+ "eslint-plugin-react-hooks": "^5.2.0",
93
+ "eslint-plugin-react-refresh": "^0.4.20",
94
+ "globals": "^15.15.0",
95
+ "lovable-tagger": "^1.1.13",
96
+ "postcss": "^8.5.6",
97
+ "tailwindcss": "^3.4.17",
98
+ "typescript": "^5.8.3",
99
+ "typescript-eslint": "^8.38.0",
100
+ "vite": "^5.4.19"
101
+ },
102
+ "ts-node": {
103
+ "require": [
104
+ "tsconfig-paths/register"
105
+ ]
106
+ }
107
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
@@ -0,0 +1,14 @@
1
+ User-agent: Googlebot
2
+ Allow: /
3
+
4
+ User-agent: Bingbot
5
+ Allow: /
6
+
7
+ User-agent: Twitterbot
8
+ Allow: /
9
+
10
+ User-agent: facebookexternalhit
11
+ Allow: /
12
+
13
+ User-agent: *
14
+ Allow: /
package/src/App.css ADDED
@@ -0,0 +1,42 @@
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+
21
+ @keyframes logo-spin {
22
+ from {
23
+ transform: rotate(0deg);
24
+ }
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ @media (prefers-reduced-motion: no-preference) {
31
+ a:nth-of-type(2) .logo {
32
+ animation: logo-spin infinite 20s linear;
33
+ }
34
+ }
35
+
36
+ .card {
37
+ padding: 2em;
38
+ }
39
+
40
+ .read-the-docs {
41
+ color: #888;
42
+ }
package/src/App.tsx ADDED
@@ -0,0 +1,32 @@
1
+ import { Toaster } from "@/components/ui/toaster";
2
+ import { Toaster as Sonner } from "@/components/ui/sonner";
3
+ import { TooltipProvider } from "@/components/ui/tooltip";
4
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
+ import { BrowserRouter, Routes, Route } from "react-router-dom";
6
+ import Index from "./pages/Index";
7
+ import ModelPage from "./pages/ModelPage";
8
+ import SchemaEditor from "./pages/SchemaEditor";
9
+ import Settings from "./pages/Settings";
10
+ import NotFound from "./pages/NotFound";
11
+
12
+ const queryClient = new QueryClient();
13
+
14
+ const App = () => (
15
+ <QueryClientProvider client={queryClient}>
16
+ <TooltipProvider>
17
+ <Toaster />
18
+ <Sonner />
19
+ <BrowserRouter>
20
+ <Routes>
21
+ <Route path="/" element={<Index />} />
22
+ <Route path="/models/:modelName" element={<ModelPage />} />
23
+ <Route path="/schema" element={<SchemaEditor />} />
24
+ <Route path="/settings" element={<Settings />} />
25
+ <Route path="*" element={<NotFound />} />
26
+ </Routes>
27
+ </BrowserRouter>
28
+ </TooltipProvider>
29
+ </QueryClientProvider>
30
+ );
31
+
32
+ export default App;
@@ -0,0 +1,83 @@
1
+ type OrmField = {
2
+ name: string;
3
+ type: string;
4
+ options?: any;
5
+ };
6
+
7
+ type OrmModel = {
8
+ tableName: string;
9
+ fields: Record<string, OrmField>;
10
+ };
11
+
12
+ type OrmSchema = Record<string, OrmModel>;
13
+
14
+ export function ormSchemaToAdminConfig(schema: OrmSchema) {
15
+ return Object.values(schema).map(model => {
16
+ const fields = Object.values(model.fields);
17
+ return {
18
+ name: model.tableName,
19
+ displayName: toTitleCase(model.tableName),
20
+ icon: "", // you can plug icons later
21
+ fields: fields.map(f => ormFieldToAdminField(f)),
22
+ };
23
+ });
24
+ }
25
+
26
+ function ormFieldToAdminField(field: OrmField) {
27
+ const base = {
28
+ name: field.name,
29
+ label: toTitleCase(field.name),
30
+ } as any;
31
+
32
+ switch (field.type) {
33
+ case "primary":
34
+ return {
35
+ ...base,
36
+ type: "number",
37
+ required: true,
38
+ primaryKey: true
39
+ };
40
+
41
+ case "string":
42
+ return {
43
+ ...base,
44
+ type: "string",
45
+ required: true,
46
+ maxLength: field.options?.maxLength,
47
+ primaryKey: false
48
+ };
49
+
50
+ case "email":
51
+ return {
52
+ ...base,
53
+ type: "email",
54
+ required: true,
55
+ primaryKey: false
56
+ };
57
+
58
+ case "datetime":
59
+ let readonly = false;
60
+ if(field.options?.autoNowAdd){
61
+ readonly = true
62
+ }
63
+ return {
64
+ ...base,
65
+ type: "datetime",
66
+ primaryKey: false,
67
+ readonly
68
+ };
69
+
70
+ default:
71
+ return {
72
+ ...base,
73
+ type: "string",
74
+ primaryKey: false
75
+ };
76
+ }
77
+ }
78
+
79
+ function toTitleCase(str: string) {
80
+ return str
81
+ .replace(/_/g, " ")
82
+ .replace(/^\w/, c => c.toUpperCase());
83
+ }
@@ -0,0 +1,12 @@
1
+ // admin/schema/factory.ts
2
+ import { SQLiteIntrospector } from "./sqlite";
3
+
4
+ export function createSchemaIntrospector() {
5
+ const dbType = process.env.DB_TYPE;
6
+
7
+ switch (dbType) {
8
+ case "sqlite":
9
+ default:
10
+ return new SQLiteIntrospector();
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ // admin/schema/introspector.ts
2
+ import { AdminSchema } from "./types";
3
+
4
+ export interface SchemaIntrospector {
5
+ getSchema(): AdminSchema;
6
+ }
@@ -0,0 +1,38 @@
1
+ import { ormSchemaToAdminConfig } from "./convertSchema";
2
+ import { getModelByName } from "@/orm/metadata/model-registry";
3
+ import { createSchemaIntrospector } from "./factory";
4
+ import { loadOrmConfig, loadModels } from "@/config/load";
5
+
6
+
7
+ const config = await loadOrmConfig();
8
+ await loadModels(config.modelsPath);
9
+
10
+ const introspector = createSchemaIntrospector();
11
+
12
+ export const adminRouter = {
13
+ schema() {
14
+ let schema = introspector.getSchema();
15
+ const adminConfig = ormSchemaToAdminConfig(schema);
16
+ return adminConfig
17
+ },
18
+
19
+ list(model: string) {
20
+ let modelClass = getModelByName(model);
21
+ return modelClass.objects.all();
22
+ },
23
+
24
+ create(model: string, data: any) {
25
+ let modelClass = getModelByName(model);
26
+ modelClass.objects.create(data);
27
+ },
28
+
29
+ update(model: string, id: number, data: any) {
30
+ let modelClass = getModelByName(model);
31
+ return modelClass.objects.update(data, id);
32
+ },
33
+
34
+ delete(model: string, id: number) {
35
+ let modelClass = getModelByName(model);
36
+ return modelClass.objects.delete(id);
37
+ }
38
+ };
@@ -0,0 +1,17 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ export function getAdminSchema() {
5
+ const statePath = path.resolve(
6
+ process.cwd(),
7
+ "src/orm/migrations/_state.json"
8
+ );
9
+
10
+ if (!fs.existsSync(statePath)) {
11
+ throw new Error(
12
+ "No migration state found. Run makemigrations first."
13
+ );
14
+ }
15
+
16
+ return JSON.parse(fs.readFileSync(statePath, "utf8"));
17
+ }
@@ -0,0 +1,73 @@
1
+ // admin/schema/sqlite.ts
2
+ import { db } from "../orm/db/sqlite";
3
+ import { SchemaIntrospector } from "./introspecter";
4
+
5
+ export class SQLiteIntrospector implements SchemaIntrospector {
6
+ getSchema() {
7
+ const tables = db
8
+ .prepare(`
9
+ SELECT name FROM sqlite_master
10
+ WHERE type='table'
11
+ AND name NOT LIKE 'sqlite_%'
12
+ AND name != 'orm_migrations'
13
+ `)
14
+ .all()
15
+ .map((r: any) => r.name);
16
+
17
+ const schema: any = {};
18
+
19
+
20
+
21
+ for (const table of tables) {
22
+ schema[table] = {
23
+ tableName: table,
24
+ fields: {},
25
+ };
26
+ const columns = db
27
+ .prepare(`PRAGMA table_info("${table}")`)
28
+ .all();
29
+
30
+
31
+ schema[table] = {
32
+ tableName: table,
33
+ fields: {},
34
+ };
35
+
36
+ for (const col of columns) {
37
+ schema[table].fields[col.name] = {
38
+ name: col.name,
39
+ type: mapSQLiteType(col),
40
+ ...(mapSQLiteOptions(col) && {
41
+ options: mapSQLiteOptions(col),
42
+ readonly: mapSQLiteOptions(col)?.autoNowAdd
43
+ }),
44
+ };
45
+ }
46
+
47
+ }
48
+
49
+ return schema;
50
+ }
51
+ }
52
+
53
+ function mapSQLiteType(col: any) {
54
+ if (col.pk === 1) return "primary";
55
+ const t = col.type.toLowerCase();
56
+ if (t.includes("date") || t.includes("time")) {
57
+ return "datetime";
58
+ }
59
+ return "string";
60
+ }
61
+
62
+
63
+ function mapSQLiteOptions(col: any) {
64
+ const t = col.type.toLowerCase();
65
+
66
+ const options: any = {};
67
+ // SQLite can't know this — best guess
68
+ if (t.includes("date") || t.includes("time")) {
69
+ options.autoNowAdd = true; // unknown, default false
70
+ }
71
+
72
+ return Object.keys(options).length ? options : undefined;
73
+ }
@@ -0,0 +1,35 @@
1
+ export type ModelType = {
2
+ name: string,
3
+ displayName: string,
4
+ icon: "", // you can plug icons later
5
+ fields: FieldMeta[],
6
+ }
7
+ export type FieldMeta = {
8
+ name: string;
9
+ type: string;
10
+ label: string;
11
+ required: boolean;
12
+ primaryKey: boolean,
13
+ readonly: boolean,
14
+ default: string;
15
+ options?: any;
16
+ maxLength?: number;
17
+ nullable: boolean;
18
+ };
19
+
20
+
21
+
22
+ // admin/schema/types.ts
23
+ export type AdminSchema = {
24
+ [tableName: string]: {
25
+ tableName: string;
26
+ fields: {
27
+ [fieldName: string]: {
28
+ name: string;
29
+ type: "string" | "number" | "boolean" | "date";
30
+ primary: boolean;
31
+ nullable: boolean;
32
+ };
33
+ };
34
+ };
35
+ };
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from 'react';
2
+ import { AdminSidebar } from './AdminSidebar';
3
+ import { ModelType } from '@/admin/types';
4
+
5
+ interface AdminLayoutProps {
6
+ children: ReactNode;
7
+ models: ModelType[]
8
+ }
9
+
10
+ export function AdminLayout({ children, models }: AdminLayoutProps) {
11
+ return (
12
+ <div className="flex min-h-screen w-full bg-background">
13
+ <AdminSidebar models={models}/>
14
+ <main className="flex-1 overflow-auto">
15
+ {children}
16
+ </main>
17
+ </div>
18
+ );
19
+ }