quar 1.1.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.
@@ -0,0 +1,57 @@
1
+ @import './variables.css';
2
+
3
+ .insert-tab {
4
+ width: 40%;
5
+ max-width: 400px;
6
+ height: 100%;
7
+ background-color: var(--bg-color);
8
+ position: fixed;
9
+ top: 0;
10
+ right: -100%;
11
+ z-index: 1000;
12
+ overflow-y: auto;
13
+ padding: 20px;
14
+ border-left: 2px solid var(--muted-color);
15
+ transition: right 0.3s ease-in-out;
16
+ }
17
+
18
+ .insert-tab.active {
19
+ right: 0;
20
+ }
21
+
22
+ #insert-form {
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: 10px;
26
+ }
27
+
28
+ #insert-form label {
29
+ font-size: 16px;
30
+ font-weight: 600;
31
+ color: var(--text-color);
32
+ }
33
+
34
+ #insert-form input, select {
35
+ width: 100%;
36
+ padding: 10px;
37
+ border: 1px solid var(--muted-color);
38
+ border-radius: 5px;
39
+ background-color: var(--bg-color);
40
+ color: var(--text-color);
41
+ }
42
+
43
+ #insert-form .btn {
44
+ background: transparent;
45
+ color: var(--text-color);
46
+ border: none;
47
+ padding: 5px 10px;
48
+ border: 1px solid var(--muted-color);
49
+ border-radius: 5px;
50
+ transition: background 0.1s ease-in-out;
51
+ cursor: pointer;
52
+
53
+ &:hover {
54
+ background: var(--blue-color);
55
+ color: var(--bg-color);
56
+ }
57
+ }
@@ -0,0 +1,71 @@
1
+ @import './variables.css';
2
+
3
+ .popup-overlay {
4
+ display: none;
5
+ position: fixed;
6
+ top: 0;
7
+ left: 0;
8
+ width: 100vw;
9
+ height: 100vh;
10
+ background: rgba(0, 0, 0, 0.5);
11
+ justify-content: center;
12
+ align-items: center;
13
+ z-index: 9999;
14
+ }
15
+
16
+ .popup-box {
17
+ background: var(--bg-color);
18
+ padding: 20px 25px;
19
+ border-radius: 10px;
20
+ max-width: 400px;
21
+ text-align: center;
22
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
23
+ animation: slideIn 0.4s ease;
24
+ position: relative;
25
+ }
26
+
27
+ .popup-box h2 {
28
+ margin-top: 0;
29
+ color: var(--red-color);
30
+ }
31
+
32
+ .popup-box.warning h2 {
33
+ color: var(--yellow-color);
34
+ }
35
+
36
+ .popup-box.info h2 {
37
+ color: var(--green-color);
38
+ }
39
+
40
+ .popup-box p {
41
+ margin: 10px 0 20px;
42
+ }
43
+
44
+ .close-btn {
45
+ background: var(--red-color);
46
+ color: white;
47
+ border: none;
48
+ padding: 8px 16px;
49
+ border-radius: 5px;
50
+ cursor: pointer;
51
+ }
52
+
53
+ .popup-box.warning .close-btn {
54
+ background: var(--yellow-color);
55
+ }
56
+
57
+ .popup-box.info .close-btn {
58
+ background: var(--green-color);
59
+ }
60
+
61
+ @keyframes slideIn {
62
+ from {
63
+ transform: translateY(-30px);
64
+ opacity: 0;
65
+ }
66
+
67
+ to {
68
+ transform: translateY(0);
69
+ opacity: 1;
70
+ }
71
+ }
@@ -0,0 +1,341 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
2
+
3
+ * {
4
+ margin: 0;
5
+ padding: 0;
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ body {
10
+ font-family: 'Inter', sans-serif;
11
+ font-size: 14px;
12
+ display: flex;
13
+ background: var(--bg-color);
14
+ color: #E0E0E0;
15
+ }
16
+
17
+ .sidebar {
18
+ position: fixed;
19
+ top: 0;
20
+ width: 15vw;
21
+ background: #282b30;
22
+ border-right: 1px solid var(--muted-color);
23
+ height: 100vh;
24
+ }
25
+
26
+ .sidebar-header {
27
+ font-size: 13px;
28
+ font-weight: 600;
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: space-between;
32
+ background: #1e2124;
33
+ padding: 10px;
34
+ border-bottom: 1px solid var(--muted-color);
35
+ }
36
+
37
+ .sidebar-header .btn {
38
+ color: #E0E0E0;
39
+ background-color: transparent;
40
+ border: none;
41
+ font-size: 12px;
42
+ padding: 0 4px;
43
+ border-radius: 5px;
44
+ cursor: pointer;
45
+ transition: background 0.1s ease-in-out;
46
+
47
+ &:hover {
48
+ background: #2E3A59;
49
+ }
50
+ }
51
+
52
+ .model-wrapper {
53
+ padding: 10px;
54
+ }
55
+
56
+ .model {
57
+ cursor: pointer;
58
+ display: flex;
59
+ align-items: center;
60
+ justify-content: space-between;
61
+ padding: 5px;
62
+ margin: 5px 0;
63
+ border-radius: 5px;
64
+ color: #E0E0E0;
65
+
66
+ &:hover {
67
+ background: #2E3A59;
68
+ }
69
+ }
70
+
71
+ .model span {
72
+ color: var(--muted-color);
73
+ }
74
+
75
+ .main {
76
+ margin-left: auto;
77
+ height: 100vh;
78
+ width: 85vw;
79
+ display: flex;
80
+ flex-direction: column;
81
+ }
82
+
83
+ .tabs {
84
+ display: flex;
85
+ border-bottom: 1px solid var(--muted-color);
86
+ background: #1e2124;
87
+ }
88
+
89
+ .tab {
90
+ padding: 5px 10px;
91
+ display: flex;
92
+ align-items: center;
93
+ color: var(--muted-color);
94
+ border-left: 1px solid var(--muted-color);
95
+ border-right: 1px solid var(--muted-color);
96
+ position: relative;
97
+ margin: 1px 0;
98
+ cursor: pointer;
99
+ transition: color 0.2s ease-in-out;
100
+
101
+ &:hover {
102
+ color: white;
103
+ }
104
+ }
105
+
106
+
107
+ .tab.active {
108
+ color: white;
109
+ background-color: #2E3A59;
110
+ }
111
+
112
+ .tab .close {
113
+ cursor: pointer;
114
+ font-weight: bold;
115
+ padding: 0 5px;
116
+ }
117
+
118
+ .operations {
119
+ display: flex;
120
+ background: #1e2124;
121
+ align-items: center;
122
+ padding: 8px 5px;
123
+ gap: 10px;
124
+ }
125
+
126
+ .operations .btn {
127
+ background: var(--muted-color);
128
+ color: #E0E0E0;
129
+ border: none;
130
+ padding: 4px 8px;
131
+ border-radius: 5px;
132
+ cursor: pointer;
133
+ transition: background 0.1s ease-in-out;
134
+
135
+ &:hover {
136
+ background: #2E3A59;
137
+ }
138
+ }
139
+
140
+ .operations .btn:disabled {
141
+ background-color: #3a3f4b;
142
+ color: #888;
143
+ cursor: not-allowed;
144
+ }
145
+
146
+ .operations .limit-wrapper,
147
+ .count-wrapper,
148
+ .page-wrapper {
149
+ display: flex;
150
+ align-items: center;
151
+ padding: 2px 5px;
152
+ gap: 5px;
153
+ border-radius: 5px;
154
+ background-color: var(--muted-color);
155
+ cursor: pointer;
156
+
157
+ &:hover {
158
+ background: #2E3A59;
159
+ }
160
+ }
161
+
162
+ .operations .limit-wrapper:hover #limit {
163
+ background: #2E3A59;
164
+ }
165
+
166
+ .operations .text {
167
+ padding: 2px 5px;
168
+ width: 100%;
169
+ height: 100%;
170
+ font-size: 12px;
171
+ }
172
+
173
+ .operations .limit-div,
174
+ .count-div,
175
+ .page-div {
176
+ width: fit-content;
177
+ border-left: 2px solid #424549;
178
+ height: 100%;
179
+ color: #E0E0E0;
180
+ }
181
+
182
+ .operations .count-div,
183
+ .page-div {
184
+ padding: 2px 5px;
185
+ font-size: 12px;
186
+ }
187
+
188
+ .operations .limit-wrapper #limit {
189
+ background-color: var(--muted-color);
190
+ border: none;
191
+ color: #E0E0E0;
192
+ padding: 2px 5px;
193
+ width: fit-content;
194
+ height: 100%;
195
+ font-size: 12px;
196
+
197
+ &:hover {
198
+ background: #2E3A59;
199
+ }
200
+ }
201
+
202
+ .content {
203
+ padding: 10px;
204
+ flex: 1;
205
+ border-top: 1px solid var(--muted-color);
206
+ background: #23272a;
207
+ overflow-y: scroll;
208
+ -ms-overflow-style: none;
209
+ scrollbar-width: none;
210
+ }
211
+
212
+ .content::-webkit-scrollbar {
213
+ display: none;
214
+ }
215
+
216
+ .hidden {
217
+ display: none;
218
+ }
219
+
220
+ .document {
221
+ padding: 10px;
222
+ border: 1px solid var(--muted-color);
223
+ /* background: var(--bg-color); */
224
+ background: #1e2124;
225
+ max-height: 80vh;
226
+ border-radius: 10px;
227
+ margin-top: 10px;
228
+ }
229
+
230
+ .tree {
231
+ padding-left: 20px;
232
+ }
233
+
234
+ .tree li {
235
+ list-style-type: none;
236
+ padding: 5px 5px;
237
+ font-size: 14px;
238
+ border-radius: 5px;
239
+ transition: background 0.1s ease-in-out;
240
+
241
+ &:hover {
242
+ background: #2E3A59;
243
+ }
244
+ }
245
+
246
+ .tree li .String {
247
+ color: var(--green-color);
248
+ }
249
+
250
+ .tree li .String::after {
251
+ content: '"';
252
+ color: var(--green-color);
253
+ }
254
+
255
+ .tree li .String::before {
256
+ content: '"';
257
+ color: var(--green-color);
258
+ }
259
+
260
+ .tree li .Number {
261
+ color: var(--blue-color);
262
+ }
263
+
264
+ .tree li .ObjectId {
265
+ color: var(--red-color);
266
+ }
267
+
268
+ .tree li .ObjectId::after {
269
+ content: ' )';
270
+ color: var(--red-color);
271
+ }
272
+
273
+ .tree li .ObjectId::before {
274
+ content: 'ObjectId( ';
275
+ color: var(--red-color);
276
+ }
277
+
278
+ .collapsible {
279
+ cursor: pointer;
280
+ user-select: none;
281
+ }
282
+
283
+ .tree li .nested {
284
+ display: none;
285
+ }
286
+
287
+ .tree li .active {
288
+ display: block;
289
+ }
290
+
291
+ .caret::before {
292
+ content: "▶";
293
+ color: #555;
294
+ display: inline-block;
295
+ font-size: 10px;
296
+ margin-right: 6px;
297
+ transform: rotate(0deg);
298
+ transition: transform 0.3s ease;
299
+ }
300
+
301
+ .caret-down::before {
302
+ transform: rotate(90deg);
303
+ }
304
+
305
+ .document-actions {
306
+ display: flex;
307
+ justify-content: space-between;
308
+ padding: 10px;
309
+ }
310
+
311
+ .document-actions .updateDocument {
312
+ background: transparent;
313
+ color: #E0E0E0;
314
+ border: none;
315
+ padding: 5px 10px;
316
+ border: 1px solid var(--muted-color);
317
+ border-radius: 5px;
318
+ transition: background 0.1s ease-in-out;
319
+ cursor: pointer;
320
+
321
+ &:hover {
322
+ background: var(--green-color);
323
+ color: var(--bg-color);
324
+ }
325
+ }
326
+
327
+ .document-actions .deleteDocument {
328
+ background: transparent;
329
+ color: #E0E0E0;
330
+ border: none;
331
+ padding: 5px 10px;
332
+ border: 1px solid var(--muted-color);
333
+ border-radius: 5px;
334
+ transition: background 0.1s ease-in-out;
335
+ cursor: pointer;
336
+
337
+ &:hover {
338
+ background: var(--red-color);
339
+ color: var(--bg-color);
340
+ }
341
+ }
@@ -0,0 +1,9 @@
1
+ :root{
2
+ --bg-color: #171f2a;
3
+ --text-color: #fff;
4
+ --muted-color: #555A6B;
5
+ --blue-color: #4FC3F7;
6
+ --green-color: #00ffaa;
7
+ --red-color: #FF5370;
8
+ --yellow-color: #FFEB3B;
9
+ }
package/server.js ADDED
@@ -0,0 +1,239 @@
1
+ import express from 'express';
2
+ import mongoose from 'mongoose';
3
+ import path from "path"
4
+ import loadModels from './utils/loadModels.js';
5
+
6
+ const app = express();
7
+ const PORT = 8319;
8
+
9
+ app.set('view engine', 'zare');
10
+ app.set("views", path.join(import.meta.dirname, "views"));
11
+ app.set("port", PORT);
12
+
13
+ app.use(express.static(path.join(import.meta.dirname, "public")));
14
+ app.use(express.json());
15
+ app.use(express.urlencoded({ extended: true }));
16
+
17
+ app.get('/', async (_, res) => {
18
+ try {
19
+ const modelNames = mongoose.modelNames();
20
+
21
+ modelNames.sort((a, b) => a.localeCompare(b));
22
+
23
+ const result = await Promise.all(
24
+ modelNames.map(async name => {
25
+ const model = mongoose.model(name);
26
+ const count = await model.countDocuments();
27
+ return { name, count };
28
+ })
29
+ );
30
+
31
+ res.render('pages/index', { models: result });
32
+ } catch (error) {
33
+ res.status(500).json({ error: error.message || "Internal server error" });
34
+ }
35
+ });
36
+
37
+ app.get("/models", async (_, res) => {
38
+
39
+ try {
40
+
41
+ if (!app.locals.modelPath) return res.status(409).json({ error: "model directory path not set" })
42
+ loadModels(app.locals.modelPath)
43
+ const modelNames = mongoose.modelNames();
44
+ modelNames.sort((a, b) => a.localeCompare(b));
45
+
46
+ const result = await Promise.all(
47
+ modelNames.map(async name => {
48
+ const model = mongoose.model(name);
49
+ const count = await model.countDocuments();
50
+ return { name, count };
51
+ })
52
+ );
53
+
54
+ res.status(200).json({ models: result });
55
+ } catch (error) {
56
+ res.status(500).json({ error: error.message || "Internal server error" });
57
+ }
58
+ });
59
+
60
+ app.get("/models/:modelName", async (req, res) => {
61
+ try {
62
+
63
+ const { modelName } = req.params;
64
+ const { page = 1, limit = 100 } = req.query;
65
+ const model = mongoose.model(modelName);
66
+ const modelSchema = model.schema.paths;
67
+ const documents = await model.find({}).limit(limit).skip((page - 1) * limit);
68
+ const totalCount = await model.countDocuments();
69
+ const count = documents.length;
70
+ const totalPages = Math.ceil(totalCount / limit);
71
+
72
+ res.status(200).json({ documents, schema: modelSchema, totalCount, count, totalPages });
73
+ } catch (error) {
74
+ res.status(500).json({ error: error.message || "Internal server error" });
75
+ }
76
+ });
77
+
78
+ app.get("/schema/:modelName", async (req, res) => {
79
+ try {
80
+ const modelName = req.params.modelName;
81
+ const Model = mongoose.model(modelName);
82
+
83
+ if (!Model) return res.status(404).json({ error: 'Model not found' });
84
+
85
+ const paths = Model.schema.paths;
86
+ const schema = {};
87
+
88
+ function getSchema(paths) {
89
+ for (const path in paths) {
90
+
91
+ if (path === '_id' || path === '__v') continue;
92
+
93
+ if (paths[path].instance === 'Embedded') {
94
+ getSchema(paths[path].schema.paths);
95
+ continue;
96
+ };
97
+
98
+ const field = paths[path];
99
+ const fieldType = field.instance;
100
+ const fieldOptions = Object.assign({}, field.options);
101
+
102
+ delete fieldOptions["type"];
103
+
104
+ schema[path] = {
105
+ type: fieldType,
106
+ ...fieldOptions
107
+ }
108
+ }
109
+ }
110
+ getSchema(paths)
111
+ res.status(200).json(schema);
112
+ } catch (error) {
113
+ res.status(500).json({ error: error.message || "Intenral Server Error" })
114
+ }
115
+ });
116
+
117
+ app.get("/id/:modelName", async (req, res) => {
118
+
119
+ try {
120
+ const { modelName } = req.params;
121
+ const Model = mongoose.model(modelName)
122
+ if (!Model) return res.status(404).json({ error: "model not found" });
123
+
124
+ const docs = await Model.find({});
125
+ const ids = [];
126
+
127
+ docs.map(doc => ids.push(doc._id))
128
+
129
+ res.status(200).json(ids)
130
+ } catch (error) {
131
+ res.status(500).json({ error: error.message || "Internal server error" })
132
+ }
133
+ })
134
+
135
+ app.post("/insert/:modelName", async (req, res) => {
136
+
137
+ try {
138
+ const { modelName } = req.params;
139
+ const body = req.body;
140
+
141
+ const Model = mongoose.model(modelName);
142
+
143
+ if (!Model) return res.status(404).json({ error: "model not found" });
144
+
145
+ const paths = Model.schema.paths;
146
+
147
+ function getSchema(paths) {
148
+
149
+ let schema = {};
150
+ for (const path in paths) {
151
+
152
+ if (path === '_id' || path === '__v') continue;
153
+
154
+ if (paths[path].instance === 'Embedded') {
155
+ schema[path] = getSchema(paths[path].schema.paths);
156
+ continue;
157
+ };
158
+
159
+ schema[path] = paths[path].instance;
160
+ }
161
+
162
+ return schema;
163
+ }
164
+
165
+ const schema = getSchema(paths)
166
+
167
+ function getData(body, schema) {
168
+
169
+ let data = {};
170
+
171
+ for (const key in schema) {
172
+ if (typeof schema[key] === 'object' && schema[key] !== null) {
173
+
174
+ data[key] = getData(body, schema[key]);
175
+ continue;
176
+ }
177
+
178
+ if (Object.keys(body).includes(key)) {
179
+ data[key] = body[key];
180
+ }
181
+ }
182
+
183
+ return data;
184
+ }
185
+
186
+ const data = getData(body, schema)
187
+
188
+ const result = await Model.create(data)
189
+
190
+ res.status(200).json(result)
191
+ } catch (error) {
192
+ res.status(500).json({ error: error.message || "Internal server error" })
193
+ }
194
+ })
195
+
196
+ app.put("/update/:modelName/:id", async (req, res) => {
197
+ try {
198
+ const { modelName, id } = req.params;
199
+ const model = mongoose.model(modelName);
200
+ const updatedDoc = req.body;
201
+ delete updatedDoc._id;
202
+ const result = await model.findByIdAndUpdate(id, updatedDoc, { new: true });
203
+
204
+ res.status(200).json(result);
205
+ } catch (error) {
206
+
207
+ res.status(500).json({ error: error.message || "Internal server error" });
208
+ }
209
+ });
210
+
211
+ app.delete("/delete/:modelName/:id", async (req, res) => {
212
+ try {
213
+ const { modelName, id } = req.params;
214
+ const model = mongoose.model(modelName);
215
+
216
+ await model.findByIdAndDelete(id);
217
+ const count = await model.countDocuments();
218
+
219
+ res.status(200).json({ count });
220
+ } catch (error) {
221
+ res.status(500).json({ error: error.message || "Internal server error" });
222
+ }
223
+ });
224
+
225
+ app.delete("/delete-all/:modelName", async (req, res) => {
226
+ try {
227
+ const { modelName } = req.params;
228
+ const model = mongoose.model(modelName);
229
+ if (!model) return res.status(404).json({ error: "model not found" });
230
+
231
+ await model.deleteMany({});
232
+
233
+ res.status(200).json({ success: true });
234
+ } catch (error) {
235
+ res.status(500).json({ error: error.message || "Internal server error" });
236
+ }
237
+ })
238
+
239
+ export default app;