Skip to content

Commit 4ad07dc

Browse files
Merge branch 'develop' into fix-assets-underline
2 parents 7169ede + ab9b57d commit 4ad07dc

70 files changed

Lines changed: 28657 additions & 30683 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
.env.staging
55
.vscode/
66
node_modules/
7+
minio/
78
npm-debug.log
89
dump.rdb
910
static/dist/

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ RUN npm run build
2525

2626
FROM base AS production
2727
ENV NODE_ENV=production
28-
COPY package.json package-lock.json index.js ./
28+
COPY package.json package-lock.json index.js .eslintrc ./
2929
RUN npm install --production
3030
COPY --from=build $APP_HOME/dist ./dist
3131
CMD ["npm", "run", "start:prod"]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Stay in touch with Processing Foundation across other platforms:
1515
- [Instagram](https://www.instagram.com/p5xjs)
1616
- [Youtube](https://www.youtube.com/@ProcessingFoundation)
1717
- [X](https://x.com/p5xjs)
18-
- [Discord](https://discord.com/invite/esmGA6H6wm)
18+
- [Discord](https://discord.p5js.org)
1919
- [Forum](https://discourse.processing.org)
2020

2121
## Using the p5.js Editor 🤔

SECURITY.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Security Policy
2+
3+
## Reporting a Vulnerability
4+
5+
Please report security vulnerabilities by emailing: responsible.disclosure@processingfoundation.org
6+
7+
## What to Expect
8+
- We will acknowledge your email within 72 hours
9+
- We will provide regular updates about our progress
10+
- Once the issue is confirmed and fixed, we may ask you to verify the solution
11+
12+
## Disclosure Policy
13+
- Please do not disclose the vulnerability publicly until we have had a chance to address it
14+
- We do not offer bounties as we are a non-profit organization
15+
- We appreciate your efforts to responsibly disclose your findings
16+
17+
## Scope
18+
19+
You can use the above email to report vulnerabilities in p5.js and related repositories managed by the processing org, including the reference website.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent, waitFor } from '../../test-utils';
3+
import { DropdownMenu, DropdownMenuAlignment } from './DropdownMenu';
4+
5+
describe('DropdownMenu', () => {
6+
const renderDropdown = () => {
7+
render(
8+
<DropdownMenu
9+
aria-label="More options"
10+
align={DropdownMenuAlignment.RIGHT}
11+
>
12+
<li role="menuitem">Item One</li>
13+
<li role="menuitem">Item Two</li>
14+
<li role="menuitem">Item Three</li>
15+
</DropdownMenu>
16+
);
17+
};
18+
19+
it('should render the dropdown button', () => {
20+
renderDropdown();
21+
22+
const button = screen.getByRole('button', { name: 'More options' });
23+
expect(button).toBeInTheDocument();
24+
25+
expect(screen.queryByRole('menu')).not.toBeInTheDocument();
26+
});
27+
28+
it('should open dropdown and render menu items when button is clicked', () => {
29+
renderDropdown();
30+
31+
const button = screen.getByRole('button', { name: 'More options' });
32+
33+
fireEvent.click(button);
34+
35+
expect(screen.getByRole('menu')).toBeInTheDocument();
36+
37+
expect(screen.getByText('Item One')).toBeInTheDocument();
38+
expect(screen.getByText('Item Two')).toBeInTheDocument();
39+
expect(screen.getByText('Item Three')).toBeInTheDocument();
40+
});
41+
42+
it('should close the menu after selecting an item', async () => {
43+
renderDropdown();
44+
45+
const button = screen.getByRole('button', { name: 'More options' });
46+
fireEvent.click(button);
47+
48+
const item = screen.getByText('Item One');
49+
fireEvent.mouseUp(item);
50+
51+
await waitFor(() => {
52+
expect(screen.queryByRole('menu')).not.toBeInTheDocument();
53+
});
54+
});
55+
});

client/i18n.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ export const availableLanguages = [
4141
'zh-CN',
4242
'zh-TW',
4343
'tr',
44-
'ur'
44+
'ur',
45+
'ne'
4546
];
4647

4748
const detectedLanguage = getPreferredLanguage(
@@ -76,7 +77,8 @@ export function languageKeyToLabel(lang) {
7677
'zh-CN': '简体中文',
7778
'zh-TW': '正體中文',
7879
tr: 'Türkçe',
79-
ur: 'اردو'
80+
ur: 'اردو',
81+
ne: 'नेपाली'
8082
};
8183
return languageMap[lang];
8284
}

client/modules/About/statics/aboutData.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const ContactSectionLinks: ContactSectionLink[] = [
1919
{ label: 'About.X', href: 'https://x.com/p5xjs' },
2020
{
2121
label: 'About.Discord',
22-
href: 'https://discord.gg/esmGA6H6wm'
22+
href: 'https://discord.p5js.org'
2323
},
2424
{
2525
label: 'About.Forum',
@@ -87,7 +87,7 @@ export const AboutSectionInfo: AboutSectionInfoSection[] = [
8787
description: 'About.LinkDescriptions.Forum'
8888
},
8989
{
90-
url: 'https://discord.com/invite/esmGA6H6wm',
90+
url: 'https://discord.p5js.org',
9191
title: 'About.DiscordCTA',
9292
description: 'About.LinkDescriptions.Discord'
9393
}

client/modules/IDE/actions/project.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
showErrorModal,
1414
setPreviousPath
1515
} from './ide';
16+
import { clearLocalBackup } from '../utils/localBackup';
1617
import { clearState, saveState } from '../../../persistState';
1718

1819
const ROOT_URL = getConfig('API_URL');
@@ -164,6 +165,8 @@ export function saveProject(
164165
.then((response) => {
165166
dispatch(endSavingProject());
166167
dispatch(setUnsavedChanges(false));
168+
// Clear the localStorage backup after successful server save (#3891)
169+
clearLocalBackup(state.project.id);
167170
const { hasChanges, synchedProject } = getSynchedProject(
168171
getState(),
169172
response.data

client/modules/IDE/actions/uploader.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { apiClient } from '../../../utils/apiClient';
33
import { getConfig } from '../../../utils/getConfig';
44
import { isTestEnvironment } from '../../../utils/checkTestEnv';
55
import { handleCreateFile } from './files';
6+
import { showErrorModal } from './ide';
67

78
const s3BucketUrlBase = getConfig('S3_BUCKET_URL_BASE');
89
const awsRegion = getConfig('AWS_REGION');
@@ -22,7 +23,7 @@ function isS3Upload(file) {
2223
return !TEXT_FILE_REGEX.test(file.name) || file.size >= MAX_LOCAL_FILE_SIZE;
2324
}
2425

25-
export async function dropzoneAcceptCallback(userId, file, done) {
26+
export async function dropzoneAcceptCallback(userId, file, done, dispatch) {
2627
// if a user would want to edit this file as text, local interceptor
2728
if (!isS3Upload(file)) {
2829
try {
@@ -51,6 +52,13 @@ export async function dropzoneAcceptCallback(userId, file, done) {
5152
file.postData = response.data;
5253
done();
5354
} catch (error) {
55+
if (error?.response?.status === 403) {
56+
if (dispatch) {
57+
dispatch(showErrorModal('uploadLimit'));
58+
}
59+
done('Upload limit reached.');
60+
return;
61+
}
5462
done(
5563
error?.response?.data?.responseText?.message ||
5664
error?.message ||
@@ -82,6 +90,23 @@ export function dropzoneCompleteCallback(file) {
8290
content: file.content
8391
};
8492
dispatch(handleCreateFile(formParams, false));
93+
} else if (file.status === 'error' || file.xhr.status >= 400) {
94+
let uploadFileErrorMessage = 'Uploading file to AWS failed.';
95+
if (file.xhr?.response) {
96+
const parser = new DOMParser();
97+
const xmlDoc = parser.parseFromString(file.xhr.response, 'text/xml');
98+
const message = xmlDoc.getElementsByTagName('Message')[0]?.textContent;
99+
const code = xmlDoc.getElementsByTagName('Code')[0]?.textContent;
100+
uploadFileErrorMessage = `${code}: ${message}`;
101+
}
102+
file.previewElement.classList.add('dz-error');
103+
file.previewElement.classList.remove('dz-success');
104+
const dzErrorMessageElement = file.previewElement?.querySelector(
105+
'[data-dz-errormessage]'
106+
);
107+
if (dzErrorMessageElement) {
108+
dzErrorMessageElement.textContent = uploadFileErrorMessage;
109+
}
85110
}
86111
};
87112
}

client/modules/IDE/components/Banner.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { CrossIcon } from '../../../common/icons';
77
* Banner displays a dismissible announcement bar with a link and a close icon.
88
* It's typically used to highlight opportunities, but use and design can be flexible.
99
*
10-
* This component is **presentational only** — visibility logic (open/close state) should be
10+
* This component is presentational only — visibility logic (open/close state) should be
1111
* controlled by the parent via the `onClose` handler.
1212
*
1313
* @param {Object} props
@@ -26,6 +26,7 @@ const Banner = ({ onClose }) => {
2626
// URL can be updated depending on the opportunity or announcement.
2727
const bannerURL = 'https://processingfoundation.org/donate';
2828

29+
// currently holds donation copy, will switch back when temp maintenance is done
2930
const bannerCopy = (
3031
<>
3132
<Trans i18nKey="Banner.Copy" components={{ bold: <strong /> }} />

0 commit comments

Comments
 (0)