@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.
@@ -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
- return;
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
- await this.$attrs.onClick(ev);
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 = 'error';
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
- {{value}}
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
- return this.value;
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="truncated-value-container">
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="expanded-value-container">
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.131",
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
@@ -1,2 +0,0 @@
1
- 1. Export to PNG causes charts to scroll down
2
- 2. Chat summarization broken