@mongoosejs/studio 0.0.131 → 0.0.135
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.
- package/build.js +18 -0
- package/frontend/public/app.js +10381 -10357
- package/frontend/public/tw.css +10 -0
- package/frontend/src/async-button/async-button.html +1 -1
- package/frontend/src/async-button/async-button.js +17 -8
- package/frontend/src/detail-default/detail-default.html +2 -2
- package/frontend/src/detail-default/detail-default.js +11 -2
- package/frontend/src/document-details/document-property/document-property.css +0 -15
- package/frontend/src/document-details/document-property/document-property.html +4 -4
- package/frontend/src/splash/splash.html +2 -2
- package/package.json +1 -1
- package/astra.js +0 -159
- package/valnotes.md +0 -2
package/frontend/public/tw.css
CHANGED
|
@@ -2160,6 +2160,16 @@ video {
|
|
|
2160
2160
|
--tw-ring-color: rgb(0 168 165 / var(--tw-ring-opacity));
|
|
2161
2161
|
}
|
|
2162
2162
|
|
|
2163
|
+
.hover\:translate-x-0:hover {
|
|
2164
|
+
--tw-translate-x: 0px;
|
|
2165
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
.hover\:translate-x-0\.5:hover {
|
|
2169
|
+
--tw-translate-x: 0.125rem;
|
|
2170
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2163
2173
|
.hover\:border-gray-300:hover {
|
|
2164
2174
|
--tw-border-opacity: 1;
|
|
2165
2175
|
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<button v-bind="attrsToBind" :disabled="isDisabled" @click="handleClick">
|
|
2
2
|
<div v-if="status === 'in_progress'" style="text-align: center">
|
|
3
|
-
<svg style="height: 1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<svg style="height: 1em" class="mx-auto" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
4
4
|
<g>
|
|
5
5
|
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2" opacity="0.3" />
|
|
6
6
|
<path d="M12 2a10 10 0 0 1 10 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
@@ -9,19 +9,28 @@ module.exports = app => app.component('async-button', {
|
|
|
9
9
|
inheritAttrs: false,
|
|
10
10
|
methods: {
|
|
11
11
|
async handleClick(ev) {
|
|
12
|
-
if (this.status === 'in_progress')
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if (this.status === 'in_progress') return;
|
|
13
|
+
|
|
14
|
+
const btn = this.$el;
|
|
15
|
+
const prevWidth = btn.offsetWidth;
|
|
16
|
+
const prevHeight = btn.offsetHeight;
|
|
17
|
+
btn.style.width = `${prevWidth}px`;
|
|
18
|
+
btn.style.height = `${prevHeight}px`;
|
|
19
|
+
|
|
15
20
|
this.status = 'in_progress';
|
|
16
21
|
|
|
17
22
|
try {
|
|
18
|
-
|
|
23
|
+
if (typeof this.$attrs.onClick === 'function') {
|
|
24
|
+
await this.$attrs.onClick(ev);
|
|
25
|
+
}
|
|
26
|
+
this.status = 'success';
|
|
19
27
|
} catch (err) {
|
|
20
|
-
this.status = '
|
|
28
|
+
this.status = 'init';
|
|
21
29
|
throw err;
|
|
30
|
+
} finally {
|
|
31
|
+
btn.style.width = null;
|
|
32
|
+
btn.style.height = null;
|
|
22
33
|
}
|
|
23
|
-
|
|
24
|
-
this.status = 'success';
|
|
25
34
|
}
|
|
26
35
|
},
|
|
27
36
|
computed: {
|
|
@@ -36,4 +45,4 @@ module.exports = app => app.component('async-button', {
|
|
|
36
45
|
}
|
|
37
46
|
},
|
|
38
47
|
template: template
|
|
39
|
-
});
|
|
48
|
+
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<div>
|
|
2
|
-
{{
|
|
1
|
+
<div class="w-full">
|
|
2
|
+
<pre class="w-full whitespace-pre-wrap break-words font-mono text-sm text-gray-700 m-0">{{displayValue}}</pre>
|
|
3
3
|
</div>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const template = require('./detail-default.html');
|
|
4
|
-
|
|
5
4
|
module.exports = app => app.component('detail-default', {
|
|
6
5
|
template: template,
|
|
7
6
|
props: ['value'],
|
|
@@ -13,7 +12,17 @@ module.exports = app => app.component('detail-default', {
|
|
|
13
12
|
if (this.value === undefined) {
|
|
14
13
|
return 'undefined';
|
|
15
14
|
}
|
|
16
|
-
|
|
15
|
+
if (typeof this.value === 'string') {
|
|
16
|
+
return this.value;
|
|
17
|
+
}
|
|
18
|
+
if (typeof this.value === 'number' || typeof this.value === 'boolean' || typeof this.value === 'bigint') {
|
|
19
|
+
return String(this.value);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.stringify(this.value, null, 2);
|
|
23
|
+
} catch (err) {
|
|
24
|
+
return String(this.value);
|
|
25
|
+
}
|
|
17
26
|
}
|
|
18
27
|
}
|
|
19
28
|
});
|
|
@@ -21,18 +21,3 @@
|
|
|
21
21
|
float: right;
|
|
22
22
|
margin-top: -7px;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
.truncated-value-container,
|
|
26
|
-
.expanded-value-container {
|
|
27
|
-
position: relative;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.truncated-value-container button,
|
|
31
|
-
.expanded-value-container button {
|
|
32
|
-
transition: all 0.2s ease;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.truncated-value-container button:hover,
|
|
36
|
-
.expanded-value-container button:hover {
|
|
37
|
-
transform: translateX(2px);
|
|
38
|
-
}
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
</div>
|
|
69
69
|
<div v-else>
|
|
70
70
|
<!-- Show truncated or full value based on needsTruncation and isValueExpanded -->
|
|
71
|
-
<div v-if="needsTruncation && !isValueExpanded" class="
|
|
71
|
+
<div v-if="needsTruncation && !isValueExpanded" class="relative">
|
|
72
72
|
<div class="text-gray-700 whitespace-pre-wrap break-words font-mono text-sm">{{truncatedString}}</div>
|
|
73
73
|
<button
|
|
74
74
|
@click="toggleValueExpansion"
|
|
75
|
-
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium flex items-center gap-1"
|
|
75
|
+
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium flex items-center gap-1 transform transition-all duration-200 ease-in-out hover:translate-x-0.5"
|
|
76
76
|
>
|
|
77
77
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
78
78
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
|
@@ -80,11 +80,11 @@
|
|
|
80
80
|
Show more ({{valueAsString.length}} characters)
|
|
81
81
|
</button>
|
|
82
82
|
</div>
|
|
83
|
-
<div v-else-if="needsTruncation && isValueExpanded" class="
|
|
83
|
+
<div v-else-if="needsTruncation && isValueExpanded" class="relative">
|
|
84
84
|
<component :is="getComponentForPath(path)" :value="getValueForPath(path.path)"></component>
|
|
85
85
|
<button
|
|
86
86
|
@click="toggleValueExpansion"
|
|
87
|
-
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium flex items-center gap-1"
|
|
87
|
+
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium flex items-center gap-1 transform transition-all duration-200 ease-in-out hover:translate-x-0.5"
|
|
88
88
|
>
|
|
89
89
|
<svg class="w-4 h-4 rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
90
90
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<async-button
|
|
18
18
|
type="button"
|
|
19
19
|
@click="loginWithGithub"
|
|
20
|
-
class="rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600">
|
|
20
|
+
class="rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:bg-gray-500">
|
|
21
21
|
<svg viewBox="0 0 98 98" class="inline mr-1" height="1.5em" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg>
|
|
22
22
|
Login With GitHub
|
|
23
23
|
</async-button>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<async-button
|
|
27
27
|
type="button"
|
|
28
28
|
@click="loginWithGoogle"
|
|
29
|
-
class="rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600">
|
|
29
|
+
class="rounded bg-ultramarine-600 px-2 py-2 text-sm font-semibold text-white shadow-sm hover:bg-ultramarine-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ultramarine-600 disabled:bg-gray-500">
|
|
30
30
|
<svg class="inline" xmlns="http://www.w3.org/2000/svg" height="1.5em" viewBox="0 0 512 512"><path fill="#fff" d="M386 400c45-42 65-112 53-179H260v74h102c-4 24-18 44-38 57z"/><path fill="#fff" d="M90 341a192 192 0 0 0 296 59l-62-48c-53 35-141 22-171-60z"/><path fill="#fff" d="M153 292c-8-25-8-48 0-73l-63-49c-23 46-30 111 0 171z"/><path fill="#fff" d="M153 219c22-69 116-109 179-50l55-54c-78-75-230-72-297 55z"/></svg>
|
|
31
31
|
Login With Google
|
|
32
32
|
</async-button>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.135",
|
|
4
4
|
"description": "A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.",
|
|
5
5
|
"homepage": "https://studio.mongoosejs.io/",
|
|
6
6
|
"repository": {
|
package/astra.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const mongoose = require('mongoose');
|
|
4
|
-
const { createAstraUri, driver, Vectorize } = require('@datastax/astra-mongoose');
|
|
5
|
-
const express = require('express');
|
|
6
|
-
const studio = require('./express');
|
|
7
|
-
|
|
8
|
-
const app = express();
|
|
9
|
-
|
|
10
|
-
const m = new mongoose.Mongoose();
|
|
11
|
-
m.setDriver(driver);
|
|
12
|
-
m.set('autoCreate', false);
|
|
13
|
-
m.set('autoIndex', false);
|
|
14
|
-
|
|
15
|
-
(function () {
|
|
16
|
-
const schema = new m.Schema({
|
|
17
|
-
email: {
|
|
18
|
-
type: String,
|
|
19
|
-
required: true,
|
|
20
|
-
unique: true
|
|
21
|
-
},
|
|
22
|
-
firstName: {
|
|
23
|
-
type: String,
|
|
24
|
-
required: true
|
|
25
|
-
},
|
|
26
|
-
lastName: {
|
|
27
|
-
type: String,
|
|
28
|
-
required: true
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
schema.virtual('displayName').get(function() {
|
|
33
|
-
return this.firstName + ' ' + this.lastName.slice(0, 1) + '.';
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
m.model('User', schema);
|
|
37
|
-
})();
|
|
38
|
-
|
|
39
|
-
(function () {
|
|
40
|
-
const schema = new m.Schema({
|
|
41
|
-
make: {
|
|
42
|
-
type: String,
|
|
43
|
-
required: true
|
|
44
|
-
},
|
|
45
|
-
model: {
|
|
46
|
-
type: String,
|
|
47
|
-
required: true
|
|
48
|
-
},
|
|
49
|
-
year: {
|
|
50
|
-
type: Number,
|
|
51
|
-
required: true,
|
|
52
|
-
validate: (v) => Number.isInteger(v) && v >= 1950
|
|
53
|
-
},
|
|
54
|
-
images: {
|
|
55
|
-
type: [String]
|
|
56
|
-
},
|
|
57
|
-
numReviews: {
|
|
58
|
-
type: Number,
|
|
59
|
-
required: true,
|
|
60
|
-
default: 0
|
|
61
|
-
},
|
|
62
|
-
averageReview: {
|
|
63
|
-
type: Number,
|
|
64
|
-
required: true,
|
|
65
|
-
default: 0
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
m.model('Vehicle', schema);
|
|
70
|
-
})();
|
|
71
|
-
|
|
72
|
-
(function () {
|
|
73
|
-
const schema = new m.Schema({
|
|
74
|
-
rating: {
|
|
75
|
-
type: Number,
|
|
76
|
-
required: true,
|
|
77
|
-
validate: (v) => Number.isInteger(v)
|
|
78
|
-
},
|
|
79
|
-
text: {
|
|
80
|
-
type: String,
|
|
81
|
-
required: true,
|
|
82
|
-
validate: (v) => v.length >= 30
|
|
83
|
-
},
|
|
84
|
-
userId: {
|
|
85
|
-
type: 'ObjectId',
|
|
86
|
-
required: true
|
|
87
|
-
},
|
|
88
|
-
vehicleId: {
|
|
89
|
-
type: 'ObjectId',
|
|
90
|
-
required: true
|
|
91
|
-
}
|
|
92
|
-
}, { timestamps: true });
|
|
93
|
-
|
|
94
|
-
schema.virtual('user', {
|
|
95
|
-
ref: 'User',
|
|
96
|
-
localField: 'userId',
|
|
97
|
-
foreignField: '_id',
|
|
98
|
-
justOne: true
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
schema.virtual('vehicle', {
|
|
102
|
-
ref: 'Vehicle',
|
|
103
|
-
localField: 'vehicleId',
|
|
104
|
-
foreignField: '_id',
|
|
105
|
-
justOne: true
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
schema.pre('save', async function updateVehicleRating() {
|
|
109
|
-
if (!this.isNew) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
const vehicle = await mongoose.model('Vehicle').findById(this.vehicleId).orFail();
|
|
113
|
-
vehicle.numReviews += 1;
|
|
114
|
-
const vehicleReviews = await mongoose.model('Review').find({ vehicleId: this.vehicleId });
|
|
115
|
-
const reviewRatings = vehicleReviews.map((entry) => entry.rating);
|
|
116
|
-
reviewRatings.push(this.rating);
|
|
117
|
-
const average = calculateAverage(reviewRatings);
|
|
118
|
-
vehicle.averageReview = average;
|
|
119
|
-
await vehicle.save();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
function calculateAverage(ratings) {
|
|
123
|
-
if (ratings.length === 0) {
|
|
124
|
-
return 0;
|
|
125
|
-
}
|
|
126
|
-
let sum = 0;
|
|
127
|
-
for (let i = 0; i < ratings.length; i++) {
|
|
128
|
-
sum += ratings[i];
|
|
129
|
-
}
|
|
130
|
-
const average = sum / ratings.length;
|
|
131
|
-
return average;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
m.model('Review', schema);
|
|
135
|
-
})();
|
|
136
|
-
|
|
137
|
-
const uri = createAstraUri(
|
|
138
|
-
'https://fbced748-d6ed-40b1-ab9d-b618015a2c2c-us-east-2.apps.astra.datastax.com',
|
|
139
|
-
'AstraCS:kjSUArrrkLKrDlrMpUQOUYlw:50c9eda620df1099ad2dd77eb36e7755daaa48494acb158ff6de8df3deee40f6',
|
|
140
|
-
'reviews_dev2'
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
void async function main() {
|
|
144
|
-
await m.connect(uri);
|
|
145
|
-
const studioConnection = await mongoose.createConnection('mongodb://127.0.0.1:27017/mongoose_studio_test').asPromise();
|
|
146
|
-
|
|
147
|
-
app.use('/studio', await studio('/studio/api', m, { __build: true, apiKey: '123456789', studioConnection }));
|
|
148
|
-
|
|
149
|
-
await app.listen(7770);
|
|
150
|
-
console.log('Listening on port 7770');
|
|
151
|
-
}();
|
|
152
|
-
|
|
153
|
-
/*
|
|
154
|
-
# Astra Notes
|
|
155
|
-
|
|
156
|
-
1. Must use collections. Tables don't support `countDocuments()` or `estimatedDocumentCount()`.
|
|
157
|
-
2. Collections don't let you store keys that start with '$', which is problematic for `$chart`. Ended up creating separate connection to store ChatMessages in MongoDB.
|
|
158
|
-
3. `countDocuments()` with filter erroring out with more than 1000 documents caused trouble. Worked around it by converting `countDocuments()` to `find()` using Mongoose middleware.
|
|
159
|
-
*/
|
package/valnotes.md
DELETED