SoftwareBrothers / adminjs

AdminJS is an admin panel for apps written in node.js
https://adminjs.co
MIT License
8.27k stars 670 forks source link

[Bug]: Relations: Bugs in deleting many-to-many item #1662

Open nickgieschen opened 7 months ago

nickgieschen commented 7 months ago

Contact Details

nickgieschen3636 in the discord channel

What happened?

I am trying to remove one item from a many-to-many relation. However, when I delete just one item, it deletes all related entites. Also, the delete error message has weird wording.

Step 1: Delete one item

2024-04-22_10-22-16

Step 2: Confirm (with buggy message)

2024-04-22_10-22-52

Step 3: ALL items are deleted

2024-04-22_10-23-08

Bug prevalence

Always

AdminJS dependencies version

"@adminjs/design-system": "^4.1.1",
"@adminjs/fastify": "^4.1.2",
"@adminjs/relations": "^1.1.2",
"@adminjs/sql": "^2.2.1",

"adminjs": "^7.7.2",

What browsers do you see the problem on?

Chrome

Relevant log output

n/a

Relevant code that's giving you issues

n/a
dziraf commented 7 months ago

Have you done any modifications to Keyword resource delete action? Can you share your configuration of relations feature and what's sent in the Network tab in the browser?

The modal should display two buttons unless configured differently:

Remove relation removes the relation from the junction table while Delete record first removes the relation, then deletes the target record. I've looked at the source code and I don't see why it'd delete all records 🤔

nickgieschen commented 7 months ago

Here you go. Haven't touched any delete actions.

{
    resource: db.table("tracks"),
    features: [
      owningRelationSettingsFeature({
        componentLoader,
        licenseKey: process.env.ADMINJS_REFERENCE_LICENSE!,
        relations: {
          genres: {
            type: RelationType.ManyToMany,
            junction: {
              joinKey: "track_id",
              inverseJoinKey: "genre_id",
              throughResourceId: "track_genres",
            },
            target: {
              resourceId: "genres",
            },
          },
          instruments: {
            type: RelationType.ManyToMany,
            junction: {
              joinKey: "track_id",
              inverseJoinKey: "mood_id",
              throughResourceId: "track_moods",
            },
            target: {
              resourceId: "moods",
            },
          },
          keywords: {
            type: RelationType.ManyToMany,
            junction: {
              joinKey: "track_id",
              inverseJoinKey: "keyword_id",
              throughResourceId: "track_keywords",
            },
            target: {
              resourceId: "keywords",
            },
            deleteOptions: {
                enableDeleteRelation: false,
                enableDeleteRelatedRecord: true
            }
          },
          moods: {
            type: RelationType.ManyToMany,
            junction: {
              joinKey: "track_id",
              inverseJoinKey: "mood_id",
              throughResourceId: "track_moods",
            },
            target: {
              resourceId: "moods",
            },
          },
        },
      }),
    ],
    options: {
      navigation: navigation,
      listProperties: ["id", "title"],
      actions: {
        bulkDelete: {
          isVisible: false,
        },
        show: {
          after: [sqlDurationToString],
        },
        edit: {
          before: [stringToSqlDuration],
          after: [sqlDurationToString],
        },
      },
      properties: {
        main_track_id: {
          type: "reference",
          components: {
            edit: components.ParentTrackEditComponent,
          },
        },
        track_relations: {
            type: "string",
            components: {
                show: components.TrackRelationsComponent,
            },
            position: Number.MAX_SAFE_INTEGER,
        },
      },
    },
  };

[Uploading 0.0.0.0.har.gz…]()

dziraf commented 7 months ago

I tried to reproduce it using the example from the documentation and @adminjs/sql but it looks to be working fine for me.

https://github.com/SoftwareBrothers/adminjs/assets/16668924/40455658-3b4c-4e13-a04c-ed6310369a3d

Could you share what's sent in the request in the browser's Network tab when you click the delete button?

nickgieschen commented 7 months ago

A couple things:

  1. As of @adminjs/relations@1.1.1 the Remove relation button doesn't exist. I confirmed this in the source of both 1.1.1 and 1.1.2.

  2. In @adminjs/relations@1.1.0 when I click Remove relation all of the related entities are still deleted, instead of just the one I want deleted. Here's the network log:

{
  "log": {
    "version": "1.2",
    "creator": {
      "name": "WebInspector",
      "version": "537.36"
    },
    "pages": [
      {
        "startedDateTime": "2024-04-23T00:52:29.215Z",
        "id": "page_2",
        "title": "http://0.0.0.0:3000/admin/resources/tracks/records/0001e7f5-f30c-4c94-95c6-bd886db6d639/show?tab=instruments",
        "pageTimings": {
          "onContentLoad": 642.9910000006203,
          "onLoad": 891.6900000185706
        }
      }
    ],
    "entries": [
      {
        "_initiator": {
          "type": "script",
          "stack": {
            "callFrames": [
              {
                "functionName": "dispatchXhrRequest",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 6075,
                "columnNumber": 14
              },
              {
                "functionName": "xhr",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 5877,
                "columnNumber": 11
              },
              {
                "functionName": "dispatchRequest",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 6175,
                "columnNumber": 11
              },
              {
                "functionName": "request",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 6527,
                "columnNumber": 34
              },
              {
                "functionName": "wrap",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 3695,
                "columnNumber": 16
              },
              {
                "functionName": "recordAction",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 7067,
                "columnNumber": 41
              },
              {
                "functionName": "s",
                "scriptId": "244",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/components.bundle.js",
                "lineNumber": 10109,
                "columnNumber": 30
              },
              {
                "functionName": "onClick",
                "scriptId": "244",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/components.bundle.js",
                "lineNumber": 10139,
                "columnNumber": 26
              },
              {
                "functionName": "callCallback",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 24252,
                "columnNumber": 14
              },
              {
                "functionName": "invokeGuardedCallbackDev",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 24301,
                "columnNumber": 16
              },
              {
                "functionName": "invokeGuardedCallback",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 24365,
                "columnNumber": 31
              },
              {
                "functionName": "invokeGuardedCallbackAndCatchFirstError",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 24379,
                "columnNumber": 25
              },
              {
                "functionName": "executeDispatch",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 29127,
                "columnNumber": 3
              },
              {
                "functionName": "processDispatchQueueItemsInOrder",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 29159,
                "columnNumber": 7
              },
              {
                "functionName": "processDispatchQueue",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 29172,
                "columnNumber": 5
              },
              {
                "functionName": "dispatchEventsForPlugins",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 29183,
                "columnNumber": 3
              },
              {
                "functionName": "",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 29373,
                "columnNumber": 12
              },
              {
                "functionName": "batchedUpdates$1",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 46206,
                "columnNumber": 12
              },
              {
                "functionName": "batchedUpdates",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 24079,
                "columnNumber": 12
              },
              {
                "functionName": "dispatchEventForPluginEventSystem",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 29372,
                "columnNumber": 3
              },
              {
                "functionName": "dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 26551,
                "columnNumber": 5
              },
              {
                "functionName": "dispatchEvent",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 26543,
                "columnNumber": 5
              },
              {
                "functionName": "dispatchDiscreteEvent",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 26516,
                "columnNumber": 5
              }
            ]
          }
        },
        "_priority": "High",
        "_resourceType": "xhr",
        "cache": {},
        "connection": "113539",
        "pageref": "page_2",
        "request": {
          "method": "GET",
          "url": "http://0.0.0.0:3000/admin/api/resources/tracks/records/0001e7f5-f30c-4c94-95c6-bd886db6d639/deleteRelation?targetRecordId=fc409d53-76ce-4841-b53b-c0fc2adaa13b&relation=genres",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Accept",
              "value": "application/json, text/plain, */*"
            },
            {
              "name": "Accept-Encoding",
              "value": "gzip, deflate"
            },
            {
              "name": "Accept-Language",
              "value": "en-US,en"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Host",
              "value": "0.0.0.0:3000"
            },
            {
              "name": "Referer",
              "value": "http://0.0.0.0:3000/admin/resources/tracks/records/0001e7f5-f30c-4c94-95c6-bd886db6d639/show?tab=genres"
            },
            {
              "name": "Sec-GPC",
              "value": "1"
            },
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
            }
          ],
          "queryString": [
            {
              "name": "targetRecordId",
              "value": "fc409d53-76ce-4841-b53b-c0fc2adaa13b"
            },
            {
              "name": "relation",
              "value": "genres"
            }
          ],
          "cookies": [],
          "headersSize": 573,
          "bodySize": 0
        },
        "response": {
          "status": 200,
          "statusText": "OK",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Date",
              "value": "Tue, 23 Apr 2024 00:52:50 GMT"
            },
            {
              "name": "Keep-Alive",
              "value": "timeout=72"
            },
            {
              "name": "access-control-allow-credentials",
              "value": "true"
            },
            {
              "name": "access-control-allow-origin",
              "value": "http://localhost:8080"
            },
            {
              "name": "content-length",
              "value": "11680"
            },
            {
              "name": "content-type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "cookies": [],
          "content": {
            "size": 11680,
            "mimeType": "application/json",
            "compression": 0,
            "text": "{\"record\":{\"params\":{\"id\":\"0001e7f5-f30c-4c94-95c6-bd886db6d639\",\"album_id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"title\":\"Lights in the dark\",\"display_title\":\"Lights in the dark\",\"alternate_title\":\"Lights in the dark_Alt Mix No Piano\",\"description\":\"Beneath The Surface is a collection of tracks that combines mysterious synths and ominous sound design. Great for Documentary, Sci-Fi, Drama, Key a min\",\"track_number\":39,\"is_main\":false,\"main_track_number\":38,\"version\":\"Alt Mix No Piano\",\"duration.minutes\":2,\"bpm\":100,\"tempo\":\"Med Slow\",\"genre\":\"TENSION, Hybrid, Suspense, Sci-Fi, Drama, Score\",\"instrumentation\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"keywords\":\"Dystopia, Cyborg, Drama, Apocalypse, Intense, Pulsing, Imminent Danger, Mysterious, Looming, Ominous, Dark, Terrifying, Deranged, Industrial, Eerie, Frightening, Mystery, Action, Investigation, Anxiety, Space ship, Mars, Planets, Outer Space, Texture, ET, Distant, Anxious, Danger, Crime, City, Cyber, Ambient, Atmospheric, Synths, Film/TV, Run, Escape, Detective, Soothing, Soft\",\"code\":\"SSM0148_39\",\"composers\":\"Emilio Merone (PRS) 50% [184755142], Mauro Colavecchi (PRS) 50% [742926721]\",\"publishers\":\"SPACE AND SOUND MUSIC (SOCAN) 100%\",\"artists\":\"Emilio Merone, Mauro Colavecchi\",\"filename\":\"SSM0148_39_Lights in the dark_Alt Mix No Piano.wav\",\"mood\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"artist1_first_name\":null,\"artist1_middle_name\":null,\"artist1_last_name\":null,\"artist1_society\":null,\"artist1_ipi\":null,\"writer1_first_name\":\"Emilio\",\"writer1_middle_name\":null,\"writer1_last_name\":\"Merone\",\"writer1_capacity\":\"Composer\",\"writer1_society\":\"PRS\",\"writer1_ipi\":\"184755142\",\"writer1_territory\":\"WORLD\",\"writer1_owner_performance_share\":\"25.0000\",\"writer1_owner_mechanical_share\":\"0.0000\",\"writer1_collection_performance_share\":\"25.0000\",\"writer1_collection_mechanical_share\":\"0.0000\",\"writer1_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer2_first_name\":\"Mauro\",\"writer2_middle_name\":null,\"writer2_last_name\":\"Colavecchi\",\"writer2_capacity\":\"Composer\",\"writer2_society\":\"PRS\",\"writer2_ipi\":\"742926721\",\"writer2_territory\":\"WORLD\",\"writer2_owner_performance_share\":\"25.0000\",\"writer2_owner_mechanical_share\":\"0.0000\",\"writer2_collection_performance_share\":\"25.0000\",\"writer2_collection_mechanical_share\":\"0.0000\",\"writer2_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer3_first_name\":null,\"writer3_middle_name\":null,\"writer3_last_name\":null,\"writer3_capacity\":null,\"writer3_society\":null,\"writer3_ipi\":null,\"writer3_territory\":null,\"writer3_owner_performance_share\":null,\"writer3_owner_mechanical_share\":null,\"writer3_collection_performance_share\":null,\"writer3_collection_mechanical_share\":null,\"writer3_original_publisher\":null,\"writer4_first_name\":null,\"writer4_middle_name\":null,\"writer4_last_name\":null,\"writer4_capacity\":null,\"writer4_society\":null,\"writer4_ipi\":null,\"writer4_territory\":null,\"writer4_owner_performance_share\":null,\"writer4_owner_mechanical_share\":null,\"writer4_collection_performance_share\":null,\"writer4_collection_mechanical_share\":null,\"writer4_original_publisher\":null,\"publisher1_name\":\"SPACE AND SOUND MUSIC B\",\"publisher1_capacity\":\"Original Publisher\",\"publisher1_society\":\"SOCAN\",\"publisher1_ipi\":\"809010864\",\"publisher1_territory\":\"WORLD\",\"publisher1_owner_performance_share\":\"50.0000\",\"publisher1_owner_mechanical_share\":\"100.0000\",\"publisher1_collection_performance_share\":\"100.0000\",\"publisher1_collection_mechanical_share\":\"100.0000\",\"publisher1_original_publisher\":\"SPACE AND SOUND MUSIC B\",\"publisher2_name\":null,\"publisher2_capacity\":null,\"publisher2_society\":null,\"publisher2_ipi\":null,\"publisher2_territory\":null,\"publisher2_owner_performance_share\":null,\"publisher2_owner_mechanical_share\":null,\"publisher2_collection_performance_share\":null,\"publisher2_collection_mechanical_share\":null,\"publisher2_original_publisher\":null,\"isrc\":\"CBAWZ2107503\",\"iswc\":null,\"sgae_work_number\":null,\"gema_work_number\":null,\"main_track_id\":\"063880c5-0ab0-4c10-9915-f7deda5623ff\"},\"populated\":{\"album_id\":{\"params\":{\"id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"code\":\"SSM0148\",\"title\":\"Beneath The Surface\",\"display_title\":\"Beneath The Surface\",\"description\":\"Beneath The Surface is a collection of tracks that combines mysterious synths and ominous sound design. Great for Documentary, Sci-Fi, Drama \",\"styles\":\"TENSION, Hybrid, Suspense, Action, Drama, Score\",\"release_date\":\"2022-04-11T07:00:00.000Z\"},\"populated\":{},\"baseError\":null,\"errors\":{},\"id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"title\":\"Beneath The Surface\",\"recordActions\":[{\"name\":\"show\",\"actionType\":\"record\",\"icon\":\"Monitor\",\"label\":\"show\",\"resourceId\":\"albums\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"edit\",\"actionType\":\"record\",\"icon\":\"Edit\",\"label\":\"edit\",\"resourceId\":\"albums\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"delete\",\"actionType\":\"record\",\"icon\":\"Trash2\",\"label\":\"delete\",\"resourceId\":\"albums\",\"guard\":\"confirmDelete\",\"showFilter\":false,\"showResourceActions\":true,\"component\":false,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"danger\",\"parent\":null,\"hasHandler\":true,\"custom\":{}}],\"bulkActions\":[]},\"main_track_id\":{\"params\":{\"id\":\"063880c5-0ab0-4c10-9915-f7deda5623ff\",\"album_id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"title\":\"Lights in the dark\",\"display_title\":\"Lights in the dark\",\"alternate_title\":\"Lights in the dark_Full Mix\",\"description\":\"Beneath The Surface is a collection of tracks that combines mysterious synths and ominous sound design. Great for Documentary, Sci-Fi, Drama, Key a min\",\"track_number\":38,\"is_main\":true,\"main_track_number\":null,\"version\":\"Full Mix\",\"duration.minutes\":2,\"bpm\":100,\"tempo\":\"Med Slow\",\"genre\":\"TENSION, Hybrid, Suspense, Sci-Fi, Drama, Score\",\"instrumentation\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"keywords\":\"Dystopia, Cyborg, Drama, Apocalypse, Intense, Pulsing, Imminent Danger, Mysterious, Looming, Ominous, Dark, Terrifying, Deranged, Industrial, Eerie, Frightening, Mystery, Action, Investigation, Anxiety, Space ship, Mars, Planets, Outer Space, Texture, ET, Distant, Anxious, Danger, Crime, City, Cyber, Ambient, Atmospheric, Synths, Film/TV, Run, Escape, Detective, Soothing, Soft\",\"code\":\"SSM0148_38\",\"composers\":\"Emilio Merone (PRS) 50% [184755142], Mauro Colavecchi (PRS) 50% [742926721]\",\"publishers\":\"SPACE AND SOUND MUSIC (SOCAN) 100%\",\"artists\":\"Emilio Merone, Mauro Colavecchi\",\"filename\":\"SSM0148_38_Lights in the dark_Full Mix.wav\",\"mood\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"artist1_first_name\":null,\"artist1_middle_name\":null,\"artist1_last_name\":null,\"artist1_society\":null,\"artist1_ipi\":null,\"writer1_first_name\":\"Emilio\",\"writer1_middle_name\":null,\"writer1_last_name\":\"Merone\",\"writer1_capacity\":\"Composer\",\"writer1_society\":\"PRS\",\"writer1_ipi\":\"184755142\",\"writer1_territory\":\"WORLD\",\"writer1_owner_performance_share\":\"25.0000\",\"writer1_owner_mechanical_share\":\"0.0000\",\"writer1_collection_performance_share\":\"25.0000\",\"writer1_collection_mechanical_share\":\"0.0000\",\"writer1_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer2_first_name\":\"Mauro\",\"writer2_middle_name\":null,\"writer2_last_name\":\"Colavecchi\",\"writer2_capacity\":\"Composer\",\"writer2_society\":\"PRS\",\"writer2_ipi\":\"742926721\",\"writer2_territory\":\"WORLD\",\"writer2_owner_performance_share\":\"25.0000\",\"writer2_owner_mechanical_share\":\"0.0000\",\"writer2_collection_performance_share\":\"25.0000\",\"writer2_collection_mechanical_share\":\"0.0000\",\"writer2_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer3_first_name\":null,\"writer3_middle_name\":null,\"writer3_last_name\":null,\"writer3_capacity\":null,\"writer3_society\":null,\"writer3_ipi\":null,\"writer3_territory\":null,\"writer3_owner_performance_share\":null,\"writer3_owner_mechanical_share\":null,\"writer3_collection_performance_share\":null,\"writer3_collection_mechanical_share\":null,\"writer3_original_publisher\":null,\"writer4_first_name\":null,\"writer4_middle_name\":null,\"writer4_last_name\":null,\"writer4_capacity\":null,\"writer4_society\":null,\"writer4_ipi\":null,\"writer4_territory\":null,\"writer4_owner_performance_share\":null,\"writer4_owner_mechanical_share\":null,\"writer4_collection_performance_share\":null,\"writer4_collection_mechanical_share\":null,\"writer4_original_publisher\":null,\"publisher1_name\":\"SPACE AND SOUND MUSIC B\",\"publisher1_capacity\":\"Original Publisher\",\"publisher1_society\":\"SOCAN\",\"publisher1_ipi\":\"809010864\",\"publisher1_territory\":\"WORLD\",\"publisher1_owner_performance_share\":\"50.0000\",\"publisher1_owner_mechanical_share\":\"100.0000\",\"publisher1_collection_performance_share\":\"100.0000\",\"publisher1_collection_mechanical_share\":\"100.0000\",\"publisher1_original_publisher\":\"SPACE AND SOUND MUSIC B\",\"publisher2_name\":null,\"publisher2_capacity\":null,\"publisher2_society\":null,\"publisher2_ipi\":null,\"publisher2_territory\":null,\"publisher2_owner_performance_share\":null,\"publisher2_owner_mechanical_share\":null,\"publisher2_collection_performance_share\":null,\"publisher2_collection_mechanical_share\":null,\"publisher2_original_publisher\":null,\"isrc\":\"CBAWZ2107502\",\"iswc\":null,\"sgae_work_number\":null,\"gema_work_number\":null,\"main_track_id\":null},\"populated\":{},\"baseError\":null,\"errors\":{},\"id\":\"063880c5-0ab0-4c10-9915-f7deda5623ff\",\"title\":\"Lights in the dark\",\"recordActions\":[{\"name\":\"show\",\"actionType\":\"record\",\"icon\":\"Monitor\",\"label\":\"show\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"edit\",\"actionType\":\"record\",\"icon\":\"Edit\",\"label\":\"edit\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"delete\",\"actionType\":\"record\",\"icon\":\"Trash2\",\"label\":\"delete\",\"resourceId\":\"tracks\",\"guard\":\"confirmDelete\",\"showFilter\":false,\"showResourceActions\":true,\"component\":false,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"danger\",\"parent\":null,\"hasHandler\":true,\"custom\":{}}],\"bulkActions\":[]}},\"baseError\":null,\"errors\":{},\"id\":\"0001e7f5-f30c-4c94-95c6-bd886db6d639\",\"title\":\"Lights in the dark\",\"recordActions\":[{\"name\":\"show\",\"actionType\":\"record\",\"icon\":\"Monitor\",\"label\":\"show\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"edit\",\"actionType\":\"record\",\"icon\":\"Edit\",\"label\":\"edit\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"delete\",\"actionType\":\"record\",\"icon\":\"Trash2\",\"label\":\"delete\",\"resourceId\":\"tracks\",\"guard\":\"confirmDelete\",\"showFilter\":false,\"showResourceActions\":true,\"component\":false,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"danger\",\"parent\":null,\"hasHandler\":true,\"custom\":{}}],\"bulkActions\":[]},\"notice\":{\"type\":\"success\",\"message\":\"[@adminjs/relations]_relationSuccessfullyDeleted\",\"resourceId\":\"tracks\"}}"
          },
          "redirectURL": "",
          "headersSize": 266,
          "bodySize": 11680,
          "_transferSize": 11946,
          "_error": null
        },
        "serverIPAddress": "0.0.0.0",
        "startedDateTime": "2024-04-23T00:52:50.441Z",
        "time": 31.350000004749745,
        "timings": {
          "blocked": 0.9990000002589077,
          "dns": -1,
          "ssl": -1,
          "connect": -1,
          "send": 0.05099999999999999,
          "wait": 29.604000001700594,
          "receive": 0.6960000027902424,
          "_blocked_queueing": 0.7530000002589077
        }
      },
      {
        "_initiator": {
          "type": "script",
          "stack": {
            "callFrames": [
              {
                "functionName": "dispatchXhrRequest",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 6075,
                "columnNumber": 14
              },
              {
                "functionName": "xhr",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 5877,
                "columnNumber": 11
              },
              {
                "functionName": "dispatchRequest",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 6175,
                "columnNumber": 11
              },
              {
                "functionName": "request",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 6527,
                "columnNumber": 34
              },
              {
                "functionName": "wrap",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 3695,
                "columnNumber": 16
              },
              {
                "functionName": "recordAction",
                "scriptId": "245",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/app.bundle.js",
                "lineNumber": 7067,
                "columnNumber": 41
              },
              {
                "functionName": "",
                "scriptId": "244",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/components.bundle.js",
                "lineNumber": 9974,
                "columnNumber": 36
              },
              {
                "functionName": "commitHookEffectListMount",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 43227,
                "columnNumber": 26
              },
              {
                "functionName": "commitPassiveMountOnFiber",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 45003,
                "columnNumber": 13
              },
              {
                "functionName": "commitPassiveMountEffects_complete",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 44968,
                "columnNumber": 9
              },
              {
                "functionName": "commitPassiveMountEffects_begin",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 44955,
                "columnNumber": 7
              },
              {
                "functionName": "commitPassiveMountEffects",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 44943,
                "columnNumber": 3
              },
              {
                "functionName": "flushPassiveEffectsImpl",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 47104,
                "columnNumber": 3
              },
              {
                "functionName": "flushPassiveEffects",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 47049,
                "columnNumber": 14
              },
              {
                "functionName": "",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 46834,
                "columnNumber": 9
              },
              {
                "functionName": "workLoop",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 19716,
                "columnNumber": 35
              },
              {
                "functionName": "flushWork",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 19689,
                "columnNumber": 15
              },
              {
                "functionName": "performWorkUntilDeadline",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 19983,
                "columnNumber": 22
              },
              {
                "functionName": "queue$2.<computed>",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 7630,
                "columnNumber": 7
              },
              {
                "functionName": "run",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 7604,
                "columnNumber": 5
              },
              {
                "functionName": "eventListener",
                "scriptId": "246",
                "url": "http://0.0.0.0:3000/admin/frontend/assets/global.bundle.js",
                "lineNumber": 7615,
                "columnNumber": 3
              }
            ],
            "parentId": {
              "id": "86",
              "debuggerId": "2397735161316708382.3804226132821107084"
            }
          }
        },
        "_priority": "High",
        "_resourceType": "xhr",
        "cache": {},
        "connection": "113539",
        "pageref": "page_2",
        "request": {
          "method": "GET",
          "url": "http://0.0.0.0:3000/admin/api/resources/tracks/records/0001e7f5-f30c-4c94-95c6-bd886db6d639/findRelation?relation=genres",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Accept",
              "value": "application/json, text/plain, */*"
            },
            {
              "name": "Accept-Encoding",
              "value": "gzip, deflate"
            },
            {
              "name": "Accept-Language",
              "value": "en-US,en"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Host",
              "value": "0.0.0.0:3000"
            },
            {
              "name": "Referer",
              "value": "http://0.0.0.0:3000/admin/resources/tracks/records/0001e7f5-f30c-4c94-95c6-bd886db6d639/show?tab=genres"
            },
            {
              "name": "Sec-GPC",
              "value": "1"
            },
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
            }
          ],
          "queryString": [
            {
              "name": "relation",
              "value": "genres"
            }
          ],
          "cookies": [],
          "headersSize": 519,
          "bodySize": 0
        },
        "response": {
          "status": 200,
          "statusText": "OK",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Date",
              "value": "Tue, 23 Apr 2024 00:52:50 GMT"
            },
            {
              "name": "Keep-Alive",
              "value": "timeout=72"
            },
            {
              "name": "access-control-allow-credentials",
              "value": "true"
            },
            {
              "name": "access-control-allow-origin",
              "value": "http://localhost:8080"
            },
            {
              "name": "content-length",
              "value": "11664"
            },
            {
              "name": "content-type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "cookies": [],
          "content": {
            "size": 11664,
            "mimeType": "application/json",
            "compression": 0,
            "text": "{\"meta\":{\"total\":\"0\",\"perPage\":10,\"page\":1,\"sortBy\":\"genre_id\",\"direction\":\"desc\"},\"records\":[],\"record\":{\"params\":{\"id\":\"0001e7f5-f30c-4c94-95c6-bd886db6d639\",\"album_id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"title\":\"Lights in the dark\",\"display_title\":\"Lights in the dark\",\"alternate_title\":\"Lights in the dark_Alt Mix No Piano\",\"description\":\"Beneath The Surface is a collection of tracks that combines mysterious synths and ominous sound design. Great for Documentary, Sci-Fi, Drama, Key a min\",\"track_number\":39,\"is_main\":false,\"main_track_number\":38,\"version\":\"Alt Mix No Piano\",\"duration.minutes\":2,\"bpm\":100,\"tempo\":\"Med Slow\",\"genre\":\"TENSION, Hybrid, Suspense, Sci-Fi, Drama, Score\",\"instrumentation\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"keywords\":\"Dystopia, Cyborg, Drama, Apocalypse, Intense, Pulsing, Imminent Danger, Mysterious, Looming, Ominous, Dark, Terrifying, Deranged, Industrial, Eerie, Frightening, Mystery, Action, Investigation, Anxiety, Space ship, Mars, Planets, Outer Space, Texture, ET, Distant, Anxious, Danger, Crime, City, Cyber, Ambient, Atmospheric, Synths, Film/TV, Run, Escape, Detective, Soothing, Soft\",\"code\":\"SSM0148_39\",\"composers\":\"Emilio Merone (PRS) 50% [184755142], Mauro Colavecchi (PRS) 50% [742926721]\",\"publishers\":\"SPACE AND SOUND MUSIC (SOCAN) 100%\",\"artists\":\"Emilio Merone, Mauro Colavecchi\",\"filename\":\"SSM0148_39_Lights in the dark_Alt Mix No Piano.wav\",\"mood\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"artist1_first_name\":null,\"artist1_middle_name\":null,\"artist1_last_name\":null,\"artist1_society\":null,\"artist1_ipi\":null,\"writer1_first_name\":\"Emilio\",\"writer1_middle_name\":null,\"writer1_last_name\":\"Merone\",\"writer1_capacity\":\"Composer\",\"writer1_society\":\"PRS\",\"writer1_ipi\":\"184755142\",\"writer1_territory\":\"WORLD\",\"writer1_owner_performance_share\":\"25.0000\",\"writer1_owner_mechanical_share\":\"0.0000\",\"writer1_collection_performance_share\":\"25.0000\",\"writer1_collection_mechanical_share\":\"0.0000\",\"writer1_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer2_first_name\":\"Mauro\",\"writer2_middle_name\":null,\"writer2_last_name\":\"Colavecchi\",\"writer2_capacity\":\"Composer\",\"writer2_society\":\"PRS\",\"writer2_ipi\":\"742926721\",\"writer2_territory\":\"WORLD\",\"writer2_owner_performance_share\":\"25.0000\",\"writer2_owner_mechanical_share\":\"0.0000\",\"writer2_collection_performance_share\":\"25.0000\",\"writer2_collection_mechanical_share\":\"0.0000\",\"writer2_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer3_first_name\":null,\"writer3_middle_name\":null,\"writer3_last_name\":null,\"writer3_capacity\":null,\"writer3_society\":null,\"writer3_ipi\":null,\"writer3_territory\":null,\"writer3_owner_performance_share\":null,\"writer3_owner_mechanical_share\":null,\"writer3_collection_performance_share\":null,\"writer3_collection_mechanical_share\":null,\"writer3_original_publisher\":null,\"writer4_first_name\":null,\"writer4_middle_name\":null,\"writer4_last_name\":null,\"writer4_capacity\":null,\"writer4_society\":null,\"writer4_ipi\":null,\"writer4_territory\":null,\"writer4_owner_performance_share\":null,\"writer4_owner_mechanical_share\":null,\"writer4_collection_performance_share\":null,\"writer4_collection_mechanical_share\":null,\"writer4_original_publisher\":null,\"publisher1_name\":\"SPACE AND SOUND MUSIC B\",\"publisher1_capacity\":\"Original Publisher\",\"publisher1_society\":\"SOCAN\",\"publisher1_ipi\":\"809010864\",\"publisher1_territory\":\"WORLD\",\"publisher1_owner_performance_share\":\"50.0000\",\"publisher1_owner_mechanical_share\":\"100.0000\",\"publisher1_collection_performance_share\":\"100.0000\",\"publisher1_collection_mechanical_share\":\"100.0000\",\"publisher1_original_publisher\":\"SPACE AND SOUND MUSIC B\",\"publisher2_name\":null,\"publisher2_capacity\":null,\"publisher2_society\":null,\"publisher2_ipi\":null,\"publisher2_territory\":null,\"publisher2_owner_performance_share\":null,\"publisher2_owner_mechanical_share\":null,\"publisher2_collection_performance_share\":null,\"publisher2_collection_mechanical_share\":null,\"publisher2_original_publisher\":null,\"isrc\":\"CBAWZ2107503\",\"iswc\":null,\"sgae_work_number\":null,\"gema_work_number\":null,\"main_track_id\":\"063880c5-0ab0-4c10-9915-f7deda5623ff\"},\"populated\":{\"album_id\":{\"params\":{\"id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"code\":\"SSM0148\",\"title\":\"Beneath The Surface\",\"display_title\":\"Beneath The Surface\",\"description\":\"Beneath The Surface is a collection of tracks that combines mysterious synths and ominous sound design. Great for Documentary, Sci-Fi, Drama \",\"styles\":\"TENSION, Hybrid, Suspense, Action, Drama, Score\",\"release_date\":\"2022-04-11T07:00:00.000Z\"},\"populated\":{},\"baseError\":null,\"errors\":{},\"id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"title\":\"Beneath The Surface\",\"recordActions\":[{\"name\":\"show\",\"actionType\":\"record\",\"icon\":\"Monitor\",\"label\":\"show\",\"resourceId\":\"albums\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"edit\",\"actionType\":\"record\",\"icon\":\"Edit\",\"label\":\"edit\",\"resourceId\":\"albums\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"delete\",\"actionType\":\"record\",\"icon\":\"Trash2\",\"label\":\"delete\",\"resourceId\":\"albums\",\"guard\":\"confirmDelete\",\"showFilter\":false,\"showResourceActions\":true,\"component\":false,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"danger\",\"parent\":null,\"hasHandler\":true,\"custom\":{}}],\"bulkActions\":[]},\"main_track_id\":{\"params\":{\"id\":\"063880c5-0ab0-4c10-9915-f7deda5623ff\",\"album_id\":\"d8311ee4-c04d-4d21-a8b6-5e158f219c05\",\"title\":\"Lights in the dark\",\"display_title\":\"Lights in the dark\",\"alternate_title\":\"Lights in the dark_Full Mix\",\"description\":\"Beneath The Surface is a collection of tracks that combines mysterious synths and ominous sound design. Great for Documentary, Sci-Fi, Drama, Key a min\",\"track_number\":38,\"is_main\":true,\"main_track_number\":null,\"version\":\"Full Mix\",\"duration.minutes\":2,\"bpm\":100,\"tempo\":\"Med Slow\",\"genre\":\"TENSION, Hybrid, Suspense, Sci-Fi, Drama, Score\",\"instrumentation\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"keywords\":\"Dystopia, Cyborg, Drama, Apocalypse, Intense, Pulsing, Imminent Danger, Mysterious, Looming, Ominous, Dark, Terrifying, Deranged, Industrial, Eerie, Frightening, Mystery, Action, Investigation, Anxiety, Space ship, Mars, Planets, Outer Space, Texture, ET, Distant, Anxious, Danger, Crime, City, Cyber, Ambient, Atmospheric, Synths, Film/TV, Run, Escape, Detective, Soothing, Soft\",\"code\":\"SSM0148_38\",\"composers\":\"Emilio Merone (PRS) 50% [184755142], Mauro Colavecchi (PRS) 50% [742926721]\",\"publishers\":\"SPACE AND SOUND MUSIC (SOCAN) 100%\",\"artists\":\"Emilio Merone, Mauro Colavecchi\",\"filename\":\"SSM0148_38_Lights in the dark_Full Mix.wav\",\"mood\":\"Dark, Agressive, Moody, Pulsing, Menecing, Anxious\",\"artist1_first_name\":null,\"artist1_middle_name\":null,\"artist1_last_name\":null,\"artist1_society\":null,\"artist1_ipi\":null,\"writer1_first_name\":\"Emilio\",\"writer1_middle_name\":null,\"writer1_last_name\":\"Merone\",\"writer1_capacity\":\"Composer\",\"writer1_society\":\"PRS\",\"writer1_ipi\":\"184755142\",\"writer1_territory\":\"WORLD\",\"writer1_owner_performance_share\":\"25.0000\",\"writer1_owner_mechanical_share\":\"0.0000\",\"writer1_collection_performance_share\":\"25.0000\",\"writer1_collection_mechanical_share\":\"0.0000\",\"writer1_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer2_first_name\":\"Mauro\",\"writer2_middle_name\":null,\"writer2_last_name\":\"Colavecchi\",\"writer2_capacity\":\"Composer\",\"writer2_society\":\"PRS\",\"writer2_ipi\":\"742926721\",\"writer2_territory\":\"WORLD\",\"writer2_owner_performance_share\":\"25.0000\",\"writer2_owner_mechanical_share\":\"0.0000\",\"writer2_collection_performance_share\":\"25.0000\",\"writer2_collection_mechanical_share\":\"0.0000\",\"writer2_original_publisher\":\"SPACE AND SOUND MUSIC\",\"writer3_first_name\":null,\"writer3_middle_name\":null,\"writer3_last_name\":null,\"writer3_capacity\":null,\"writer3_society\":null,\"writer3_ipi\":null,\"writer3_territory\":null,\"writer3_owner_performance_share\":null,\"writer3_owner_mechanical_share\":null,\"writer3_collection_performance_share\":null,\"writer3_collection_mechanical_share\":null,\"writer3_original_publisher\":null,\"writer4_first_name\":null,\"writer4_middle_name\":null,\"writer4_last_name\":null,\"writer4_capacity\":null,\"writer4_society\":null,\"writer4_ipi\":null,\"writer4_territory\":null,\"writer4_owner_performance_share\":null,\"writer4_owner_mechanical_share\":null,\"writer4_collection_performance_share\":null,\"writer4_collection_mechanical_share\":null,\"writer4_original_publisher\":null,\"publisher1_name\":\"SPACE AND SOUND MUSIC B\",\"publisher1_capacity\":\"Original Publisher\",\"publisher1_society\":\"SOCAN\",\"publisher1_ipi\":\"809010864\",\"publisher1_territory\":\"WORLD\",\"publisher1_owner_performance_share\":\"50.0000\",\"publisher1_owner_mechanical_share\":\"100.0000\",\"publisher1_collection_performance_share\":\"100.0000\",\"publisher1_collection_mechanical_share\":\"100.0000\",\"publisher1_original_publisher\":\"SPACE AND SOUND MUSIC B\",\"publisher2_name\":null,\"publisher2_capacity\":null,\"publisher2_society\":null,\"publisher2_ipi\":null,\"publisher2_territory\":null,\"publisher2_owner_performance_share\":null,\"publisher2_owner_mechanical_share\":null,\"publisher2_collection_performance_share\":null,\"publisher2_collection_mechanical_share\":null,\"publisher2_original_publisher\":null,\"isrc\":\"CBAWZ2107502\",\"iswc\":null,\"sgae_work_number\":null,\"gema_work_number\":null,\"main_track_id\":null},\"populated\":{},\"baseError\":null,\"errors\":{},\"id\":\"063880c5-0ab0-4c10-9915-f7deda5623ff\",\"title\":\"Lights in the dark\",\"recordActions\":[{\"name\":\"show\",\"actionType\":\"record\",\"icon\":\"Monitor\",\"label\":\"show\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"edit\",\"actionType\":\"record\",\"icon\":\"Edit\",\"label\":\"edit\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"delete\",\"actionType\":\"record\",\"icon\":\"Trash2\",\"label\":\"delete\",\"resourceId\":\"tracks\",\"guard\":\"confirmDelete\",\"showFilter\":false,\"showResourceActions\":true,\"component\":false,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"danger\",\"parent\":null,\"hasHandler\":true,\"custom\":{}}],\"bulkActions\":[]}},\"baseError\":null,\"errors\":{},\"id\":\"0001e7f5-f30c-4c94-95c6-bd886db6d639\",\"title\":\"Lights in the dark\",\"recordActions\":[{\"name\":\"show\",\"actionType\":\"record\",\"icon\":\"Monitor\",\"label\":\"show\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"edit\",\"actionType\":\"record\",\"icon\":\"Edit\",\"label\":\"edit\",\"resourceId\":\"tracks\",\"guard\":\"\",\"showFilter\":false,\"showResourceActions\":true,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"default\",\"parent\":null,\"hasHandler\":true,\"custom\":{}},{\"name\":\"delete\",\"actionType\":\"record\",\"icon\":\"Trash2\",\"label\":\"delete\",\"resourceId\":\"tracks\",\"guard\":\"confirmDelete\",\"showFilter\":false,\"showResourceActions\":true,\"component\":false,\"showInDrawer\":false,\"hideActionHeader\":false,\"containerWidth\":1,\"layout\":null,\"variant\":\"danger\",\"parent\":null,\"hasHandler\":true,\"custom\":{}}],\"bulkActions\":[]}}"
          },
          "redirectURL": "",
          "headersSize": 266,
          "bodySize": 11664,
          "_transferSize": 11930,
          "_error": null
        },
        "serverIPAddress": "0.0.0.0",
        "startedDateTime": "2024-04-23T00:52:50.507Z",
        "time": 9.79199999710545,
        "timings": {
          "blocked": 0.8610000102277845,
          "dns": -1,
          "ssl": -1,
          "connect": -1,
          "send": 0.04400000000000001,
          "wait": 8.327000001024455,
          "receive": 0.5599999858532101,
          "_blocked_queueing": 0.6320000102277845
        }
      }
    ]
  }
}
nickgieschen commented 7 months ago

The SQL is missing the where constraint for the related resource for a many-to-many. In other words, this will work with a many-to-one, but not many-to-many. When I click "Remove relation" Postgres logs:

2024-04-22 17:13:09.393 HST [6181] LOG: execute : delete from "public"."track_genres" where "track_id" = $1 2024-04-22 17:13:09.393 HST [6181] DETAIL: parameters: $1 = '0101355c-41c0-4b22-a379-636027de24a7'

However, it should be delete from "public"."track_genres" where "track_id" = $1 and "genre_id" = $2 since it's using a junction table.

This is confirmed in delete-relation.handler.js:

BaseResource.delete(BaseRecord.id()) has no where constraint for the related record.

dziraf commented 7 months ago

@nickgieschen does your junction table have an explicit primary key or a composite key? AdminJS won't work without explicit keys. The delete relation handler first finds the junction record using both keys to confirm that it exists and extracts the ID from it and later runs junctionResource.delete(junctionRecord.id()). If your resource has got a composite key only, the .id() will return the value of the first key property only. As of now, the BaseResource.delete method only accepts a single id and no filters.

The need for an explicit PK is mentioned in @adminjs/relations documentation.

nickgieschen commented 7 months ago

Yes, the junction tables all have a pkey. However, the primary key is a compose key. I see that it will not work with relations now. I think there is a problem with terminology, since a compose key can be a primary key.

Is there a way to override the actions's default behaviour, so I can still use relations with my current schema?

CREATE TABLE IF NOT EXISTS public.track_genres
(
    track_id uuid NOT NULL,
    genre_id uuid NOT NULL,
    is_primary boolean NOT NULL,
    CONSTRAINT track_genres_pkey PRIMARY KEY (track_id, genre_id),
    CONSTRAINT track_genres_genre_id_fkey FOREIGN KEY (genre_id)
        REFERENCES public.genres (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
        NOT VALID,
    CONSTRAINT track_genres_track_id_fkey FOREIGN KEY (track_id)
        REFERENCES public.tracks (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
        NOT VALID
)

TABLESPACE pg_default;
dziraf commented 7 months ago

this is a composite key, as I wrote above it won't work since AJS doesn't support composite keys