Skip to content

Commit 92f54cd

Browse files
committed
feat: add workspace with vite project
1 parent f3ebc5a commit 92f54cd

22 files changed

+6471
-1879
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ node_modules/
33
bundles/
44
PIG/bundles/
55
Parse-Dashboard/public/bundles/
6+
Parse-Dashboard/v2/
67
Parse-Dashboard/parse-dashboard-config.json
78
npm-debug.log
89
.eslintcache
@@ -20,3 +21,6 @@ test_logs
2021

2122
# AI tools
2223
.claude
24+
25+
.history
26+
.turbo

Dockerfile

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,25 @@ COPY . /src
2121
# Install remaining dev dependencies
2222
RUN npm ci
2323

24-
# Run all webpack build steps
25-
RUN npm run prepare && npm run build
24+
############################################################
25+
# Build stage v2
26+
############################################################
27+
FROM node:lts-alpine AS v2-build
28+
29+
RUN apk --no-cache add git
30+
WORKDIR /src
31+
32+
# Copy package.json first to benefit from layer caching
33+
COPY v2/package*.json ./
34+
35+
# Install dependencies
36+
RUN npm ci
37+
38+
# Copy src to have webpack config files ready for install
39+
COPY ./v2 ./
40+
41+
# Run build step
42+
RUN npm run build
2643

2744
############################################################
2845
# Release stage
@@ -36,6 +53,7 @@ COPY --from=build /src/package*.json /src/
3653

3754
# Copy compiled src dirs
3855
COPY --from=build /src/Parse-Dashboard/ /src/Parse-Dashboard/
56+
COPY --from=v2-build /Parse-Dashboard/v2 /src/Parse-Dashboard/v2
3957

4058
USER node
4159

Parse-Dashboard/app.js

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ function checkIfIconsExistForApps(apps, iconsFolder) {
4646
const iconName = currentApp.iconName;
4747
const path = iconsFolder + '/' + iconName;
4848

49-
fs.stat(path, function(err) {
49+
fs.stat(path, function (err) {
5050
if (err) {
51-
if ('ENOENT' == err.code) {// file does not exist
52-
console.warn('Icon with file name: ' + iconName + ' couldn\'t be found in icons folder!');
51+
if ('ENOENT' == err.code) {
52+
// file does not exist
53+
console.warn('Icon with file name: ' + iconName + " couldn't be found in icons folder!");
5354
} else {
5455
console.warn('An error occurred while checking for icons, please check permission!');
5556
}
@@ -60,7 +61,7 @@ function checkIfIconsExistForApps(apps, iconsFolder) {
6061
}
6162
}
6263

63-
module.exports = function(config, options) {
64+
module.exports = function (config, options) {
6465
options = options || {};
6566
const app = express();
6667

@@ -69,24 +70,29 @@ module.exports = function(config, options) {
6970
app.use(express.urlencoded({ extended: true }));
7071

7172
// Serve public files.
72-
app.use(express.static(path.join(__dirname,'public')));
73+
app.use(express.static(path.join(__dirname, 'public')));
7374

7475
// Allow setting via middleware
7576
if (config.trustProxy && app.disabled('trust proxy')) {
7677
app.enable('trust proxy');
7778
}
7879

7980
// wait for app to mount in order to get mountpath
80-
app.on('mount', function() {
81+
app.on('mount', function () {
8182
const mountPath = getMount(app.mountpath);
8283
const users = config.users;
8384
const useEncryptedPasswords = config.useEncryptedPasswords ? true : false;
8485
const authInstance = new Authentication(users, useEncryptedPasswords, mountPath);
85-
authInstance.initialize(app, { cookieSessionSecret: options.cookieSessionSecret, cookieSessionMaxAge: options.cookieSessionMaxAge });
86+
authInstance.initialize(app, {
87+
cookieSessionSecret: options.cookieSessionSecret,
88+
cookieSessionMaxAge: options.cookieSessionMaxAge,
89+
});
8690

8791
// CSRF error handler
8892
app.use(function (err, req, res, next) {
89-
if (err.code !== 'EBADCSRFTOKEN') {return next(err)}
93+
if (err.code !== 'EBADCSRFTOKEN') {
94+
return next(err);
95+
}
9096

9197
// handle CSRF token errors here
9298
res.status(403);
@@ -100,6 +106,12 @@ module.exports = function(config, options) {
100106
// Serve the configuration.
101107
app.get('/parse-dashboard-config.json', async (req, res) => {
102108
const apps = config.apps.map((app) => Object.assign({}, app)); // make a copy
109+
res.send('form tampered with');
110+
});
111+
112+
// Serve the configuration.
113+
app.get('/parse-dashboard-config.json', function (req, res) {
114+
const apps = config.apps.map(app => Object.assign({}, app)); // make a copy
103115
const response = {
104116
apps,
105117
newFeaturesInLatestVersion,
@@ -115,12 +127,18 @@ module.exports = function(config, options) {
115127
if (!options.dev && !requestIsLocal) {
116128
if (!req.secure && !options.allowInsecureHTTP) {
117129
//Disallow HTTP requests except on localhost, to prevent the master key from being transmitted in cleartext
118-
return res.send({ success: false, error: 'Parse Dashboard can only be remotely accessed via HTTPS' });
130+
return res.send({
131+
success: false,
132+
error: 'Parse Dashboard can only be remotely accessed via HTTPS',
133+
});
119134
}
120135

121136
if (!users) {
122137
//Accessing the dashboard over the internet can only be done with username and password
123-
return res.send({ success: false, error: 'Configure a user to access Parse Dashboard remotely' });
138+
return res.send({
139+
success: false,
140+
error: 'Configure a user to access Parse Dashboard remotely',
141+
});
124142
}
125143
}
126144
const authentication = req.user;
@@ -130,7 +148,7 @@ module.exports = function(config, options) {
130148
const isReadOnly = authentication && authentication.isReadOnly;
131149
// User is full read-only, replace the masterKey by the read-only one
132150
if (isReadOnly) {
133-
response.apps = response.apps.map((app) => {
151+
response.apps = response.apps.map(app => {
134152
app.masterKey = app.readOnlyMasterKey;
135153
if (!app.masterKey) {
136154
throw new Error('You need to provide a readOnlyMasterKey to use read-only features.');
@@ -837,7 +855,7 @@ IMPORTANT: Choose the correct function based on what the user wants to delete:
837855
838856
CRITICAL SECURITY RULE FOR WRITE OPERATIONS:
839857
- ANY write operation (create, update, delete) MUST have explicit user confirmation through conversation
840-
- When a user requests a write operation, explain what you will do and ask for confirmation
858+
- When a user requests a write operation, explain what you will do and ask for confirmation
841859
- Only call the write operation functions with confirmed=true after the user has explicitly agreed
842860
- If a user says "Create a new class", treat this as confirmation to create objects in that class
843861
- You CANNOT perform write operations without the user's knowledge and consent
@@ -853,7 +871,7 @@ When working with the database:
853871
- Read operations (query, getSchema, count) can be performed immediately
854872
- Write operations require the pattern: 1) Explain what you'll do, 2) Ask for confirmation, 3) Only then execute if confirmed
855873
- Always use the provided database functions instead of writing code
856-
- Class names are case-sensitive
874+
- Class names are case-sensitive
857875
- Use proper Parse query syntax for complex queries
858876
- Handle objectId fields correctly
859877
- Be mindful of data types (Date, Pointer, etc.)
@@ -1056,8 +1074,7 @@ You have direct access to the Parse database through function calls, so you can
10561074
}
10571075
} catch {
10581076
// Directory doesn't exist or something.
1059-
console.warn('Iconsfolder at path: ' + config.iconsFolder +
1060-
' not found!');
1077+
console.warn('Iconsfolder at path: ' + config.iconsFolder + ' not found!');
10611078
}
10621079
}
10631080

@@ -1089,7 +1106,7 @@ You have direct access to the Parse database through function calls, so you can
10891106
if (errors && errors.length) {
10901107
errors = `<div id="login_errors" style="display: none;">
10911108
${errors.join(' ')}
1092-
</div>`
1109+
</div>`;
10931110
}
10941111
res.send(`<!DOCTYPE html>
10951112
<html>
@@ -1112,7 +1129,7 @@ You have direct access to the Parse database through function calls, so you can
11121129
});
11131130

11141131
// For every other request, go to index.html. Let client-side handle the rest.
1115-
app.get('/*', function(req, res) {
1132+
app.get('/*', function (req, res, next) {
11161133
if (users && (!req.user || !req.user.isAuthenticated)) {
11171134
const redirect = req.url.replace('/login', '');
11181135
if (redirect.length > 1) {
@@ -1123,7 +1140,8 @@ You have direct access to the Parse database through function calls, so you can
11231140
if (users && req.user && req.user.matchingUsername) {
11241141
res.append('username', req.user.matchingUsername);
11251142
}
1126-
res.send(`<!DOCTYPE html>
1143+
if (!req.path.startsWith('/v2')) {
1144+
res.send(`<!DOCTYPE html>
11271145
<html>
11281146
<head>
11291147
<link rel="shortcut icon" type="image/x-icon" href="${mountPath}favicon.ico" />
@@ -1140,8 +1158,11 @@ You have direct access to the Parse database through function calls, so you can
11401158
</body>
11411159
</html>
11421160
`);
1161+
} else {
1162+
next();
1163+
}
11431164
});
11441165
});
11451166

11461167
return app;
1147-
}
1168+
};

0 commit comments

Comments
 (0)