Skip to content

feat: configurable link actions#2321

Open
abdellah257 wants to merge 1 commit into
SciCatProject:masterfrom
abdellah257:configurable-link-actions
Open

feat: configurable link actions#2321
abdellah257 wants to merge 1 commit into
SciCatProject:masterfrom
abdellah257:configurable-link-actions

Conversation

@abdellah257
Copy link
Copy Markdown
Contributor

@abdellah257 abdellah257 commented Apr 13, 2026

Description

Add the option to configure the url of link type actions

Motivation

Support dynamic links that are selection dependent
example:

    "url": "https://<host_name>/proposal/getfile?download=1&file={{ @sourceFolder }}/{{ @file }}",
    "type": "link"
    "variables": {
            "sourceFolder": "#Dataset0SourceFolder",
            "files": "#Dataset0SelectedFilesPath",
            "file": "@files[0]"
    },

    "url": "https://<host_name>/{{ @instrumentCode }}/{{ @year }}/{{ @proposalIds[0] }}",
    "type": "link",
    "variables": {
            "instrumentCode": "#Instruments[0]Field[uniqueName]",
            "date": "#Dataset[0]Field[creationTime]",
            "proposalIds": "#Dataset[0]Field[proposalIds]"
            "year": "#date_format(@date, yyyy)"
    },

Changes:

Changes to: src/app/shared/modules/configurable-actions/configurable-action.component.ts

Tests included

  • Included for each change/fix?
  • Passing? (Merge will not be approved unless this is checked)

Documentation

  • swagger documentation updated [required]
  • official documentation updated [nice-to-have]

official documentation info

If you have updated the official documentation, please provide PR # and URL of the pages where the updates are included

Summary by Sourcery

New Features:

  • Allow link actions to use template variables in their URLs, including indexed array values, which are resolved at runtime before navigation.

@abdellah257 abdellah257 requested a review from a team as a code owner April 13, 2026 14:53
@abdellah257 abdellah257 self-assigned this Apr 13, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • Using encodeURIComponent on each substituted segment will encode path separators (e.g. /), which may break URLs like the sourceFolder/files example; consider encodeURI or more targeted encoding depending on how these variables are intended to be used.
  • When an array index is out of range you currently substitute an empty string, which can silently produce malformed URLs; consider either leaving the placeholder intact or surfacing an error so the misconfiguration is easier to detect.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Using `encodeURIComponent` on each substituted segment will encode path separators (e.g. `/`), which may break URLs like the `sourceFolder/files` example; consider `encodeURI` or more targeted encoding depending on how these variables are intended to be used.
- When an array index is out of range you currently substitute an empty string, which can silently produce malformed URLs; consider either leaving the placeholder intact or surfacing an error so the misconfiguration is easier to detect.

## Individual Comments

### Comment 1
<location path="src/app/shared/modules/configurable-actions/configurable-action.component.ts" line_range="523-532" />
<code_context>

   type_link() {
-    window.open(this.actionConfig.url, this.actionConfig.target || "_self");
+    const url = this.actionConfig.url.replace(
+      /\{\{\s*([@#]\w+(?:\[\d+\])?)\s*\}\}/g,
+      (_, variableName) => {
+        // Handle array indexing like @files[0]
+        const arrayMatch = variableName.match(/^([@#]\w+)\[(\d+)\]$/);
+        if (arrayMatch) {
+          const baseVariable = arrayMatch[1];
+          const index = parseInt(arrayMatch[2], 10);
+          const value = this.get_value_from_definition(baseVariable);
+
+          if (Array.isArray(value) && index < value.length) {
+            return encodeURIComponent(value[index]);
+          }
+          return "";
+        }
+
+        return encodeURIComponent(this.get_value_from_definition(variableName));
+      },
+    );
+    window.open(url, this.actionConfig.target || "_self");
   }
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against undefined or non-string values from get_value_from_definition before passing to encodeURIComponent.

If `get_value_from_definition` returns `undefined`, `null`, or non-primitive values, `encodeURIComponent` will stringify them to values like `"undefined"` or `"[object Object]"`, which can corrupt the URL. Consider normalizing to a safe default (e.g. `""` or a specific fallback) and/or explicitly handling non-string types before encoding.
</issue_to_address>

### Comment 2
<location path="src/app/shared/modules/configurable-actions/configurable-action.component.ts" line_range="522" />
<code_context>
   }

   type_link() {
-    window.open(this.actionConfig.url, this.actionConfig.target || "_self");
+    const url = this.actionConfig.url.replace(
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the URL templating and variable resolution logic into separate helper methods so that `type_link` remains a simple wrapper that just builds and opens the URL.

You can reduce the complexity of `type_link` by extracting the templating logic into focused helpers while keeping behavior identical.

For example:

```ts
type_link() {
  const url = this.buildActionUrl(this.actionConfig.url);
  window.open(url, this.actionConfig.target || "_self");
}

private buildActionUrl(template: string): string {
  return template.replace(
    /\{\{\s*([@#]\w+(?:\[\d+\])?)\s*\}\}/g,
    (_, variableName) => this.resolveTemplateVariable(variableName),
  );
}

private resolveTemplateVariable(variableName: string): string {
  const arrayMatch = variableName.match(/^([@#]\w+)\[(\d+)\]$/);
  if (arrayMatch) {
    const baseVariable = arrayMatch[1];
    const index = parseInt(arrayMatch[2], 10);
    const value = this.get_value_from_definition(baseVariable);

    if (Array.isArray(value) && index < value.length) {
      return encodeURIComponent(value[index]);
    }
    return "";
  }

  return encodeURIComponent(this.get_value_from_definition(variableName));
}
```

This keeps `type_link` focused on “open URL”, isolates regex/substitution into `buildActionUrl`, and makes the array-index logic reusable and easier to test in `resolveTemplateVariable`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/app/shared/modules/configurable-actions/configurable-action.component.ts Outdated
@abdellah257 abdellah257 changed the title Configurable Link Actions feat: Configurable Link Actions Apr 13, 2026
@abdellah257 abdellah257 changed the title feat: Configurable Link Actions feat: configurable Link Actions Apr 13, 2026
@abdellah257 abdellah257 changed the title feat: configurable Link Actions feat: configurable link actions Apr 13, 2026
@abdellah257 abdellah257 removed their assignment Apr 14, 2026
@abdellah257 abdellah257 requested a review from Junjiequan April 14, 2026 07:34
@abdellah257 abdellah257 force-pushed the configurable-link-actions branch 2 times, most recently from 80a8946 to 1aa4909 Compare April 20, 2026 06:57
Copy link
Copy Markdown
Member

@nitrosx nitrosx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good feature!!!

The changes assumes that we have only one instrument.
I think we should implement the feature assuming that we can have a list of instruments.
Could you please make the appropriate changes

@abdellah257
Copy link
Copy Markdown
Contributor Author

changes assumes that we have only one instrument.
I think we should implement the feature assuming that we can have a list of instruments.
Could you please make the appropriate changes

Thanks for the review !

I see your point ! however it seems supporting multiple Instruments for now might be a bit too early, since we are still using UpdateObsoleteDatasetDTO, this would require migrating the dataset components to use the new UpdateDatasetDTO to have new state management support (store/reduce/actions), so a lot of changes for one PR

@nitrosx
Copy link
Copy Markdown
Member

nitrosx commented Apr 27, 2026

@abdellah257 No problem!!!
Can you still make sure that instruments is an array and the keys to extract the values are consistent with the other properties.
We can stick with one instrument and it would be an array of one, but at least is ready for the transition.
Happy to discuss further

@abdellah257 abdellah257 requested a review from nitrosx April 29, 2026 06:20
Copy link
Copy Markdown
Member

@nitrosx nitrosx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering if it would make more sense to change the configuration to the following:

"url": "https://<host_name>/{{ @instrumentCode }}/{{ @year) }}/{{ @proposalIds[0] }}",
    "type": "link",
    "variables": {
            "instrumentCode": "#InstrumentField[uniqueName]",
            "date": "#Dataset[0]Field[creationTime]",
            "year"  "#date_format(@date,"+%Y")",
            "proposalIds": "#Dataset[0]Field[proposalIds]"
    },

This way the computation is moved to the variable definition and not when you build the url, which requires only substitution.

Comment thread src/app/shared/modules/configurable-actions/configurable-action.component.ts Outdated
Comment thread src/app/shared/modules/configurable-actions/configurable-action.component.ts Outdated
@abdellah257
Copy link
Copy Markdown
Contributor Author

  • The recursive computation at actionItems variables has been addressed, and dependencies between variables solved, so now we can maintain computations at variables field.
  • elements selection ei: @var[0] can be done either at url level or at variables (see PR description examples)

@abdellah257 abdellah257 force-pushed the configurable-link-actions branch 9 times, most recently from 3267f9a to ee0d65a Compare May 19, 2026 14:58
@abdellah257 abdellah257 requested a review from nitrosx May 20, 2026 07:20
@abdellah257 abdellah257 force-pushed the configurable-link-actions branch from ee0d65a to f8cf265 Compare May 20, 2026 11:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants