Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f35f78b
Move `isValidURL` to separate file
mwiencek May 29, 2025
6c69f62
Move `getUnicodeUrl` to separate file
mwiencek May 29, 2025
194c21b
Move external-links-editor types to separate file
mwiencek May 29, 2025
e8c1a89
Add 'T' suffix to all external-links-editor types
mwiencek May 30, 2025
a0a89a7
Move external-links-editor `TypeDescription` component to separate file
mwiencek May 29, 2025
c09dc10
Make `TypeDescription` flow-strict
mwiencek May 29, 2025
6909d6b
Move `LinkTypeSelect` component to separate file
mwiencek May 29, 2025
cd0b688
Make `LinkTypeSelect` flow-strict-local
mwiencek May 29, 2025
bff5cbe
Move `ExternalLinkRelationship` component to separate file
mwiencek May 29, 2025
66ffd3f
Move `ExternalLink` component to separate file
mwiencek May 29, 2025
c87c8d8
Move edit/externalLinks.js to external-links-editor/components/Extern…
mwiencek Jun 1, 2025
1da517a
Move `URLInputPopover` from edit/ to external-links-editor/
mwiencek Aug 27, 2025
94b370c
Move `ExternalLinkAttributeDialog` and `UrlRelationshipCreditFieldset`
mwiencek Jul 22, 2025
e56028a
Convert ExternalLink.js to Flow component syntax
mwiencek Jun 1, 2025
32015ee
Convert ExternalLinkRelationship.js to Flow component syntax
mwiencek Jun 1, 2025
527f703
Move `getFormData` out of the `ExternalLinksEditor` class
mwiencek Jun 1, 2025
735741d
Update weight-balanced-tree to v0.16.0
mwiencek Jun 23, 2025
ee826a9
Clarify some refinements in URLCleanup.js
mwiencek Jun 23, 2025
6ba980f
Refactor `getSourceEntityData`
mwiencek Jul 17, 2025
29d5acb
Change weird boolean types in URLCleanup.js
mwiencek Aug 25, 2025
d408c0b
Remove repeated sorting from within a loop in `filterApplicableTypes`
mwiencek Aug 25, 2025
3ed759e
Remove `getPossibleTypes`
mwiencek Aug 25, 2025
4f9e3c4
Remove confusing/redundant type
mwiencek Aug 25, 2025
8d7dc16
Replace `arraysEqual` call with set comparison
mwiencek Aug 25, 2025
fc0c484
Use the three-argument form of `useReducer`
mwiencek Aug 27, 2025
a0c5761
Add `advanceUniqueId`
mwiencek Aug 28, 2025
8d20f71
Remove unused attributes code in `edit.relationshipEdit`
mwiencek Aug 28, 2025
ece2878
Define types for seeded release data
mwiencek Aug 29, 2025
fe272f7
Pull seeded release data from the catalyst stash
mwiencek Aug 29, 2025
69d6a7c
Remove unused `this.releaseLoaded` fallback
mwiencek Aug 29, 2025
d8d5b29
Controller::ReleaseEditor: Serialize new `source_entity` with `isNewE…
mwiencek Feb 5, 2026
b9a81fc
Fix react/jsx-no-bind in UrlRelationshipCreditFieldset
mwiencek Feb 5, 2026
8320209
External links editor refactor
mwiencek Jun 1, 2025
8b39a5d
Remove unused ESLint rule exclusions for root/static/scripts/external…
mwiencek Aug 28, 2025
cf5e87d
MBS-13716: Upgrade React to v19
mwiencek Aug 28, 2025
eaac2d3
Handle .eu in `isMusicBrainz` link utility
mwiencek Feb 12, 2026
621b7f6
Add `deepFreezeInDevelopment`
mwiencek Feb 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ env:
MTCAPTCHA_PUBLIC_KEY: ${{ secrets.MTCAPTCHA_PUBLIC_KEY }}
MTCAPTCHA_PRIVATE_KEY: ${{ secrets.MTCAPTCHA_PRIVATE_KEY }}
MTCAPTCHA_PRIVATE_TEST_KEY: ${{ secrets.MTCAPTCHA_PRIVATE_TEST_KEY }}
TESTS_IMAGE_TAG: v-2026-02-10.0
TESTS_IMAGE_TAG: v-2026-02-12.react19.0

jobs:
build-tests-image:
Expand Down
16 changes: 1 addition & 15 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -959,20 +959,11 @@ export default [
{
files: [
'root/static/scripts/common/components/TagEditor.js',
'root/static/scripts/edit/externalLinks.js',
],
rules: {
'react/no-access-state-in-setstate': 'off',
},
},
{
files: [
'root/static/scripts/edit/externalLinks.js',
],
rules: {
'react/no-multi-comp': 'off',
},
},
{
files: [
'root/search/components/ArtistResults.js',
Expand All @@ -986,13 +977,9 @@ export default [
'root/static/scripts/common/components/CDTocReleaseListRow.js',
'root/static/scripts/common/components/TagEditor.js',
'root/static/scripts/edit/check-duplicates.js',
'root/static/scripts/edit/components/ExternalLinkAttributeDialog.js',
'root/static/scripts/edit/components/FormRowNameWithGuessCase.js',
'root/static/scripts/edit/components/FormRowSelectList.js',
'root/static/scripts/edit/components/ReleaseMergeStrategy.js',
'root/static/scripts/edit/components/URLInputPopover.js',
'root/static/scripts/edit/components/UrlRelationshipCreditFieldset.js',
'root/static/scripts/edit/externalLinks.js',
'root/static/scripts/event/components/EventEditForm.js',
'root/static/scripts/relationship-editor/components/DialogPreview.js',
],
Expand All @@ -1008,7 +995,6 @@ export default [
'root/static/scripts/common/i18n/expand2.js',
'root/static/scripts/common/utility/cloneDeep.mjs',
'root/static/scripts/edit/components/withLoadedTypeInfo.js',
'root/static/scripts/edit/externalLinks.js',
'root/static/scripts/relationship-editor/components/DialogEntityCredit.js',
'root/static/scripts/relationship-editor/components/DialogTargetType.js',
'root/static/scripts/relationship-editor/components/RelationshipEditor.js',
Expand Down Expand Up @@ -1042,12 +1028,12 @@ export default [
'root/static/scripts/common/utility/createFastObjectCloneFunction.js',
'root/static/scripts/edit/components/ArtistCreditEditor.js',
'root/static/scripts/edit/components/ArtistCreditEditor/utilities.js',
'root/static/scripts/edit/components/ExternalLinkAttributeDialog.js',
'root/static/scripts/edit/components/Multiselect.js',
'root/static/scripts/edit/components/withLoadedTypeInfo.js',
'root/static/scripts/edit/utility/compactEntityJson.js',
'root/static/scripts/edit/utility/reducerWithErrorHandling.js',
'root/static/scripts/edit/utility/subfieldErrors.js',
'root/static/scripts/external-links-editor/components/ExternalLinkRelationshipDialog.js',
'root/static/scripts/guess-case/MB/GuessCase/Main.js',
'root/static/scripts/relationship-editor/components/DialogAttribute/MultiselectAttribute.js',
'root/static/scripts/relationship-editor/components/DialogEntityCredit.js',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// flow-typed signature: bd8a9984746306d26194a489f3aeff35
// flow-typed version: 388e9edcf0/react-dom_v18.x.x/flow_>=v0.127.x
// @flow strict

declare module 'react-dom_shared-types' {
/**
Expand Down Expand Up @@ -105,33 +104,13 @@ declare module 'react-dom_shared-types' {
}

declare module 'react-dom' {
import * as React from 'react';

declare var version: string;

declare function findDOMNode(
componentOrElement: Element | ?React.Component<any, any>
): null | Element | Text;

declare function render<ElementType: React.ElementType>(
element: React.MixedElement,
container: Element,
callback?: () => void
): React.ElementRef<ElementType>;

declare function hydrate<ElementType: React.ElementType>(
element: React.MixedElement,
container: Element,
callback?: () => void
): React.ElementRef<ElementType>;

declare function createPortal(
node: React.Node,
container: Element
): React$Portal;

declare function unmountComponentAtNode(container: any): boolean;

declare function flushSync(callback: () => mixed): void;

declare function unstable_batchedUpdates<A, B, C, D, E>(
Expand All @@ -142,15 +121,6 @@ declare module 'react-dom' {
d: D,
e: E
): void;

declare function unstable_renderSubtreeIntoContainer<
ElementType: React.ElementType
>(
parentComponent: React.Component<any, any>,
nextElement: React.MixedElement,
container: any,
callback?: () => void
): React.ElementRef<ElementType>;
}

declare module 'react-dom/client' {
Expand Down Expand Up @@ -216,83 +186,3 @@ declare module 'react-dom/server' {
element: React.Node
): stream$Readable;
}

declare module 'react-dom/test-utils' {
import * as React from 'react';

declare interface Thenable {
then(resolve: () => mixed, reject?: () => mixed): mixed,
}

declare var Simulate: {
[eventName: string]: (
element: Element,
eventData?: { [key: string]: mixed, ... }
) => void,
...
};

declare function renderIntoDocument(
instance: React.MixedElement
): React.Component<any, any>;

declare function mockComponent(
componentClass: React.ElementType,
mockTagName?: string
): { [key: string]: mixed, ... };

declare function isElement(element: React.MixedElement): boolean;

declare function isElementOfType(
element: React.MixedElement,
componentClass: React.ElementType
): boolean;

declare function isDOMComponent(instance: any): boolean;

declare function isCompositeComponent(
instance: React.Component<any, any>
): boolean;

declare function isCompositeComponentWithType(
instance: React.Component<any, any>,
componentClass: React.ElementType
): boolean;

declare function findAllInRenderedTree(
tree: React.Component<any, any>,
test: (child: React.Component<any, any>) => boolean
): Array<React.Component<any, any>>;

declare function scryRenderedDOMComponentsWithClass(
tree: React.Component<any, any>,
className: string
): Array<Element>;

declare function findRenderedDOMComponentWithClass(
tree: React.Component<any, any>,
className: string
): ?Element;

declare function scryRenderedDOMComponentsWithTag(
tree: React.Component<any, any>,
tagName: string
): Array<Element>;

declare function findRenderedDOMComponentWithTag(
tree: React.Component<any, any>,
tagName: string
): ?Element;

declare function scryRenderedComponentsWithType(
tree: React.Component<any, any>,
componentClass: React.ElementType
): Array<React.Component<any, any>>;

declare function findRenderedComponentWithType(
tree: React.Component<any, any>,
componentClass: React.ElementType
): ?React.Component<any, any>;

declare function act(callback: () => void | Thenable): Thenable;
}
1 change: 1 addition & 0 deletions lib/MusicBrainz/Server.pm
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ sub TO_JSON {
release_artwork_count
release_cdtoc_count
seeded_relationships
seeded_release_data
series_ordering_types
server_details
server_languages
Expand Down
3 changes: 3 additions & 0 deletions lib/MusicBrainz/Server/Controller/Artist.pm
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,9 @@ sub edit_credit : Chained('credit') PathPart('edit') Edit {
my $artist = $c->stash->{artist};
my $ac = $c->stash->{ac};

# Needed by `getSourceEntityData` on the client.
$c->stash( source_entity => $artist->TO_JSON );

$self->edit_action(
$c,
form => 'EditArtistCredit',
Expand Down
8 changes: 6 additions & 2 deletions lib/MusicBrainz/Server/Controller/ReleaseEditor.pm
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ sub _init_release_editor
$c->req->body_params->{redirect_uri}
);

$options{seeded_data} = $c->json->encode($self->_seeded_data($c) // {});
$options{seeded_release_data} = $self->_seeded_data($c);

my @medium_formats = $c->model('MediumFormat')->get_all;
my $discid_formats = [ grep { $_ } map { $_->has_discids ? ($_->id) : () } @medium_formats ];
my %medium_format_dates = map { $_->id => $_->year } @medium_formats;
my $release = $c->stash->{release};

$c->stash(
template => 'release/edit/layout.tt',
Expand All @@ -48,7 +49,7 @@ sub _init_release_editor
statuses => select_options_tree($c, 'ReleaseStatus'),
languages => build_grouped_options($c, language_options($c)),
scripts => build_grouped_options($c, script_options($c)),
source_entity => to_json_object($c->stash->{release}),
source_entity => to_json_object($release) // {entityType => 'release', isNewEntity => \1},
packagings => select_options_tree($c, 'ReleasePackaging'),
countries => select_options($c, 'CountryArea'),
formats => select_options_tree($c, 'MediumFormat'),
Expand Down Expand Up @@ -102,6 +103,9 @@ sub add : Path('/release/add') Edit RequireAuth
$self->_init_release_editor($c, return_to => $return_to);
}

# NOTE-SEEDED-DATA-TYPES-1: The types of the final seeded data format
# are to be kept in sync with root/types/releaseeditor.js.

sub _seeded_data
{
my ($self, $c) = @_;
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"pg-cursor": "2.11.0",
"po2json": "https://github.com/metabrainz/po2json.git#ba28b657a4af3a3b3753e874bfc233379011c94b",
"punycode": "2.3.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-table": "7.8.0",
"redux": "4.2.1",
"shell-quote": "1.8.3",
Expand All @@ -63,7 +63,7 @@
"tldts": "7.0.10",
"webpack": "5.103.0",
"webpack-node-externals": "3.0.0",
"weight-balanced-tree": "0.9.0",
"weight-balanced-tree": "0.16.0",
"whatwg-fetch": "3.6.20",
"yargs": "3.10.0"
},
Expand Down
2 changes: 1 addition & 1 deletion root/components/forms.tt
Original file line number Diff line number Diff line change
Expand Up @@ -273,5 +273,5 @@
[%- END -%]

[%- MACRO external_links_editor BLOCK -%]
<div id="external-links-editor-container"></div>
[%- React.embed(c, 'static/scripts/external-links-editor/components/StandaloneExternalLinksEditor') -%]
[%- END -%]
6 changes: 4 additions & 2 deletions root/release/EditRelationships.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ import * as React from 'react';
import {CatalystContext} from '../context.mjs';
import Layout from '../layout/index.js';
import manifest from '../static/manifest.mjs';
import {
getSourceEntityData,
} from '../static/scripts/common/utility/catalyst.js';
import ReleaseRelationshipEditor
from '../static/scripts/release/components/ReleaseRelationshipEditor.js';

import ReleaseHeader from './ReleaseHeader.js';

component EditRelationships() {
const $c = React.useContext(CatalystContext);
const release = $c.stash.source_entity;
invariant(release?.entityType === 'release');
const release: ReleaseT = getSourceEntityData($c, 'release');

return (
<Layout
Expand Down
1 change: 0 additions & 1 deletion root/release/edit/layout.tt
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
[%- END %]
returnTo: "[% return_to | js %]",
redirectURI: "[% redirect_uri | js %]",
seed: [% closing_tag_escape(seeded_data) OR 'null' %]
});
</script>
[%- END -%]
1 change: 1 addition & 0 deletions root/server/components.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ export default {
'static/scripts/edit/components/HydratedArtistDateRangeFieldset': (): Promise<mixed> => import('../static/scripts/edit/components/HydratedArtistDateRangeFieldset.js'),
'static/scripts/edit/components/HydratedDateRangeFieldset': (): Promise<mixed> => import('../static/scripts/edit/components/HydratedDateRangeFieldset.js'),
'static/scripts/edit/components/InformationIcon': (): Promise<mixed> => import('../static/scripts/edit/components/InformationIcon.js'),
'static/scripts/external-links-editor/components/StandaloneExternalLinksEditor': (): Promise<mixed> => import('../static/scripts/external-links-editor/components/StandaloneExternalLinksEditor.js'),
'static/scripts/recording/RecordingName': (): Promise<mixed> => import('../static/scripts/recording/RecordingName.js'),
'static/scripts/relationship-editor/components/RelationshipEditorWrapper': (): Promise<mixed> => import('../static/scripts/relationship-editor/components/RelationshipEditorWrapper.js'),
'static/scripts/release-editor/components/EditNoteTab': (): Promise<mixed> => import('../static/scripts/release-editor/components/EditNoteTab.js'),
Expand Down
13 changes: 6 additions & 7 deletions root/static/scripts/admin/components/PossibleSpammersList.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,15 @@ function reducer(state: StateT, action: ActionT): StateT {
{type: 'update-spammer-button', const action} => {
return {
...state,
users: tree.update(
state.users,
action.state,
cmpUserState,
(existingValue) => spammerButtonReducer(
users: tree.update(state.users, {
cmp: cmpUserState,
key: action.state,
onConflict: (existingValue) => spammerButtonReducer(
existingValue,
action,
),
onNotFoundThrowError,
),
onNotFound: onNotFoundThrowError,
}),
};
}
{type: 'set-users-fetch-error', const error} => {
Expand Down
9 changes: 7 additions & 2 deletions root/static/scripts/common/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import DescriptiveLink from './components/DescriptiveLink.js';
import EditorLink from './components/EditorLink.js';
import EntityLink from './components/EntityLink.js';
import {bracketedText} from './utility/bracketed.js';
import {getSourceEntityData} from './utility/catalyst.js';
import {
getCatalystContext,
getSourceEntityData,
} from './utility/catalyst.js';
import clean from './utility/clean.js';
import {cloneArrayDeep, cloneObjectDeep} from './utility/cloneDeep.mjs';
import formatTrackLength from './utility/formatTrackLength.js';
Expand Down Expand Up @@ -136,7 +139,9 @@ import MB from './MB.js';
if (MB._sourceEntityInstance != null) {
return MB._sourceEntityInstance;
}
MB._sourceEntityInstance = MB.entity(getSourceEntityData());
MB._sourceEntityInstance = MB.entity(getSourceEntityData(
getCatalystContext(),
));
return MB._sourceEntityInstance;
};

Expand Down
Loading
Loading