diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 392f49e46d0..1e33667921c 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -30,11 +30,13 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.BACKPORT_ACTION_PAT }} - name: Create backport pull requests - uses: korthout/backport-action@v3 + id: create_backport_pr + uses: korthout/backport-action@v4 with: # Token for git actions, see https://github.com/korthout/backport-action/issues/379 github_token: ${{ secrets.BACKPORT_ACTION_PAT }} auto_merge_method: squash + auto_merge_enabled: true copy_assignees: true copy_milestone: true copy_requested_reviewers: true @@ -49,3 +51,45 @@ jobs: { "conflict_resolution": "draft_commit_conflicts" } + - name: Link all backport PRs to original issue + if: ${{ steps.get-issues.outputs.issues != '' && steps.create_backport_pr.outputs.created_pull_numbers != '' }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.BACKPORT_ACTION_PAT }} + script: | + const issueNumbers = "${{ steps.get-issues.outputs.issues }}".split(',').map(s => s.trim()).filter(Boolean); + const prNumbers = "${{ steps.create_backport_pr.outputs.created_pull_numbers }}".split(' ').map(s => s.trim()).filter(Boolean); + + for (const prNumber of prNumbers) { + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: Number(prNumber) + }); + + for (const issueNumber of issueNumbers) { + const { data: issue } = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: Number(issueNumber) + }); + + console.log(`Linking PR #${prNumber} to issue #${issueNumber}`); + + await github.graphql(` + mutation AddLinkedIssue($pullRequestId: ID!, $issueId: ID!) { + addLinkedIssue(input: { + pullRequestId: $pullRequestId, + issueId: $issueId + }) { + pullRequest { + number + } + } + } + `, { + pullRequestId: pr.node_id, + issueId: issue.node_id + }); + } + } diff --git a/web/client/components/charts/WidgetChart.jsx b/web/client/components/charts/WidgetChart.jsx index a1623a8d7f2..b0625fb7a04 100644 --- a/web/client/components/charts/WidgetChart.jsx +++ b/web/client/components/charts/WidgetChart.jsx @@ -46,6 +46,28 @@ const applyPercentageToLabel = (label, value, total) => { } return label; }; + +const parseAxisTickValues = (tickValues) => { + const values = tickValues + ? tickValues + .split(',') + .map(value => value.trim()) + .filter(Boolean) + : undefined; + return values?.length > 0 ? values : undefined; +}; + +const getAxisTickOptions = (options = {}) => { + const tickvals = parseAxisTickValues(options?.tickvals); + const ticktext = parseAxisTickValues(options?.ticktext); + if (tickvals && ticktext) { + return { tickvals, ticktext }; + } + if (tickvals) { + return { tickvals }; + } + return {}; +}; /** * Returns the labels for the pie chart, adds % to the labels, for legend, if the prop `includeLegendPercent` is true * @param {string|number[]} labels the values of the chart ["California", "Ohio", ...] @@ -462,6 +484,7 @@ function getLayoutOptions({ return { ...acc, [`yaxis${idx === 0 ? '' : idx + 1}`]: { + ...getAxisTickOptions(options), automargin: true, type: options?.type, tickangle: options.angle ?? 'auto', @@ -505,6 +528,7 @@ function getLayoutOptions({ // dtick used to force show all x axis labels. // TODO: enable only when "category" with time dimension // dtick: xAxisAngle ? 0.25 : undefined, + ...getAxisTickOptions(options), automargin: true, type: options?.type, tickangle: options.angle ?? 'auto', diff --git a/web/client/components/charts/__tests__/WidgetChart-test.js b/web/client/components/charts/__tests__/WidgetChart-test.js index aa6b8fd51ce..7d005f91f00 100644 --- a/web/client/components/charts/__tests__/WidgetChart-test.js +++ b/web/client/components/charts/__tests__/WidgetChart-test.js @@ -193,6 +193,32 @@ describe('WidgetChart', () => { ]} />, document.getElementById("container")); }); + it('renders custom tick values and labels for both axes', () => { + const { layout } = toPlotly({ + data: [DATASET_1.data], + traces: [{ + type: 'line', + options: { + groupByAttributes: 'name', + aggregationAttribute: 'value' + } + }], + xAxisOpts: [{ + id: 0, + tickvals: ' 1, 2, 3 ', + ticktext: ' A, B, C ' + }], + yAxisOpts: [{ + id: 0, + tickvals: ' 4, 5 ', + ticktext: ' D, E ' + }] + }); + expect(layout.xaxis.tickvals).toEqual(['1', '2', '3']); + expect(layout.xaxis.ticktext).toEqual(['A', 'B', 'C']); + expect(layout.yaxis.tickvals).toEqual(['4', '5']); + expect(layout.yaxis.ticktext).toEqual(['D', 'E']); + }); }); const TYPES = ['pie', 'line', 'bar']; diff --git a/web/client/components/widgets/builder/wizard/chart/ChartAxisOptions.jsx b/web/client/components/widgets/builder/wizard/chart/ChartAxisOptions.jsx index 21be8453b65..933f3607334 100644 --- a/web/client/components/widgets/builder/wizard/chart/ChartAxisOptions.jsx +++ b/web/client/components/widgets/builder/wizard/chart/ChartAxisOptions.jsx @@ -199,6 +199,40 @@ function AxisOptions({ hideFormula onChange={handleChange} />} + + +   + } /> + + + { + handleChange('tickvals', value); + }} + /> + + + + +   + } /> + + + { + handleChange('ticktext', value); + }} + /> + + diff --git a/web/client/components/widgets/builder/wizard/chart/__tests__/ChartAxisOptions-test.jsx b/web/client/components/widgets/builder/wizard/chart/__tests__/ChartAxisOptions-test.jsx index da1f804720b..f5e248a0643 100644 --- a/web/client/components/widgets/builder/wizard/chart/__tests__/ChartAxisOptions-test.jsx +++ b/web/client/components/widgets/builder/wizard/chart/__tests__/ChartAxisOptions-test.jsx @@ -22,18 +22,21 @@ describe('ChartAxisOptions', () => { document.body.innerHTML = ''; setTimeout(done); }); + const getControlLabels = () => [...document.querySelectorAll('.control-label')] + .map(node => node.innerText.trim()); it('should render with default', () => { ReactDOM.render(, document.getElementById('container')); - const controlLabelsNodes = document.querySelectorAll('.control-label'); - expect([...controlLabelsNodes].map(node => node.innerText)).toEqual([ + expect(getControlLabels()).toEqual([ // y 'widgets.advanced.yAxisType', 'styleeditor.color', 'styleeditor.fontSize', 'styleeditor.fontFamily', 'widgets.advanced.prefix', - 'widgets.advanced.format ', + 'widgets.advanced.format', 'widgets.advanced.suffix', + 'widgets.advanced.axisTickVals', + 'widgets.advanced.axisTickText', 'widgets.advanced.side', 'widgets.advanced.anchor', // x @@ -41,6 +44,8 @@ describe('ChartAxisOptions', () => { 'styleeditor.color', 'styleeditor.fontSize', 'styleeditor.fontFamily', + 'widgets.advanced.axisTickVals', + 'widgets.advanced.axisTickText', 'widgets.advanced.side', 'widgets.advanced.anchor' ]); @@ -75,16 +80,17 @@ describe('ChartAxisOptions', () => { } done(); }}/>, document.getElementById('container')); - const controlLabelsNodes = document.querySelectorAll('.control-label'); - expect([...controlLabelsNodes].map(node => node.innerText)).toEqual([ + expect(getControlLabels()).toEqual([ // y 'widgets.advanced.yAxisType', 'styleeditor.color', 'styleeditor.fontSize', 'styleeditor.fontFamily', 'widgets.advanced.prefix', - 'widgets.advanced.format ', + 'widgets.advanced.format', 'widgets.advanced.suffix', + 'widgets.advanced.axisTickVals', + 'widgets.advanced.axisTickText', 'widgets.advanced.side', 'widgets.advanced.anchor', // x @@ -92,6 +98,8 @@ describe('ChartAxisOptions', () => { 'styleeditor.color', 'styleeditor.fontSize', 'styleeditor.fontFamily', + 'widgets.advanced.axisTickVals', + 'widgets.advanced.axisTickText', 'widgets.advanced.side', 'widgets.advanced.anchor' ]); diff --git a/web/client/translations/data.de-DE.json b/web/client/translations/data.de-DE.json index 07855cd88f0..a2dc7ec8771 100644 --- a/web/client/translations/data.de-DE.json +++ b/web/client/translations/data.de-DE.json @@ -2450,6 +2450,10 @@ "prefix": "Präfix", "suffix": "Suffix", "examples": "Beispiele", + "axisTickVals": "Achsen-Markierungswerte", + "axisTickValsTooltip": "Optional. Erzwingt, dass die Achse nur die angegebenen Werte anzeigt (kommagetrennt). Wenn auch Tick-Text gesetzt ist, wird jeder Wert mit der entsprechenden Beschriftung angezeigt.", + "axisTickText": "Achsen-Markierungstext", + "axisTickTextTooltip": "Benutzerdefinierte Beschriftungen (kommagetrennt), die anstelle der in Tick-Werte definierten Werte angezeigt werden, in der entsprechenden Reihenfolge.", "formatExamples": "
  • .0% : gerundeter Prozentsatz, '12% '
  • .2s : SI -Präfix mit zwei signifikanten Ziffern, '42M'
  • , .2r : gruppierte Tausende mit zwei signifikanten Ziffern '4.200'
Weitere Informationen zur Formatierungssyntax hier.
", "formula": "Formel", "formulaExamples": "
Transformiert den Wert mithilfe einer Formel. Verwenden Sie die Variable value im Ausdruck:
Beispiele
  • value + 2
  • value / 100
Weitere Informationen zur Syntax hier.
", diff --git a/web/client/translations/data.en-US.json b/web/client/translations/data.en-US.json index 04ca55ff251..219cf1b3f55 100644 --- a/web/client/translations/data.en-US.json +++ b/web/client/translations/data.en-US.json @@ -2411,6 +2411,10 @@ "prefix": "Prefix", "suffix": "Suffix", "examples": "Examples", + "axisTickVals": "Axis Tick Values", + "axisTickValsTooltip": "Optional. If set, forces the axis to show only these comma-separated tick values. If Tick Text is also set, each value is replaced by the label at the same index.", + "axisTickText": "Axis Tick Text", + "axisTickTextTooltip": "Comma-separated custom labels shown at the tick positions defined in Tick Values, matched by index (one label per value).", "formatExamples": "
  • .0%: rounded percentage, '12%'
  • .2s:SI-prefix with two significant digits, '42M'
  • ,.2r: grouped thousands with two significant digits '4,200'
More information about formatting syntax here.
", "formula": "Formula", "formulaExamples": "
Transform the value using a formula. Use the variable value in the expression:
Examples
  • value + 2
  • value / 100
More information about the syntax here.
", diff --git a/web/client/translations/data.es-ES.json b/web/client/translations/data.es-ES.json index 93f297e2502..418f13cdb85 100644 --- a/web/client/translations/data.es-ES.json +++ b/web/client/translations/data.es-ES.json @@ -2411,6 +2411,10 @@ "prefix": "Prefijo", "suffix": "Sufijo", "examples": "Ejemplos", + "axisTickVals": "Valores de marcas del eje", + "axisTickValsTooltip": "Opcional. Fuerza el eje a mostrar solo los valores indicados (separados por comas). Si también se indica el Texto de Marca, cada valor se muestra con la etiqueta correspondiente.", + "axisTickText": "Texto de marcas del eje", + "axisTickTextTooltip": "Etiquetas personalizadas (separadas por comas) que se muestran en lugar de los valores definidos en Valores de Marca, en el orden correspondiente.", "formatExamples": "
  • .0% : porcentaje redondeado, '12% '
  • .2s : SI -prefijo con dos dígitos significativos, '42M'
  • , .2r : miles agrupados con dos dígitos significativos '4200'
Más información sobre la sintaxis de formato aquí.
", "formula": "Fórmula", "formulaExamples": "
Transforma el valor usando una fórmula. Usa la variable valor en la expresión:
Ejemplos
  • valor + 2
  • value / 100
Más información sobre la sintaxis aquí.
", diff --git a/web/client/translations/data.fr-FR.json b/web/client/translations/data.fr-FR.json index 18a22a92c4c..c1e40f3c623 100644 --- a/web/client/translations/data.fr-FR.json +++ b/web/client/translations/data.fr-FR.json @@ -2411,6 +2411,10 @@ "prefix": "Prefix", "suffix": "Suffixe", "examples": "Exemples", + "axisTickVals": "Valeurs des graduations de l'axe", + "axisTickValsTooltip": "Optionnel. Force l'axe à n'afficher que les valeurs indiquées (séparées par des virgules). Si le Texte de Graduation est aussi renseigné, chaque valeur est affichée avec l'étiquette correspondante.", + "axisTickText": "Texte des graduations de l'axe", + "axisTickTextTooltip": "Étiquettes personnalisées (séparées par des virgules) à afficher à la place des valeurs définies dans les Valeurs de Graduation, dans l'ordre correspondant.", "formatExamples": "
  • .0%: pourcentage arrondi, '12%'
  • .2s:SI -préfixe avec deux chiffres significatifs, '42M'
  • ,.2r: groupé des milliers avec deux chiffres significatifs '4 200'
Plus d'informations sur la syntaxe de formatage ici.
", "formula": "Formule", "formulaExamples": "
Transformez la valeur à l'aide d'une formule. Utilisez la variable valeur dans l'expression:
Exemples
  • valeur + 2
  • valeur / 100
Plus d'informations sur la syntaxe ici .
", diff --git a/web/client/translations/data.it-IT.json b/web/client/translations/data.it-IT.json index 126884d3e9f..27f677a2c14 100644 --- a/web/client/translations/data.it-IT.json +++ b/web/client/translations/data.it-IT.json @@ -2411,6 +2411,10 @@ "prefix": "Prefisso", "suffix": "Suffisso", "examples": "Esempi", + "axisTickVals": "Valori tacche asse", + "axisTickValsTooltip": "Opzionale. Forza l'asse a mostrare solo i valori indicati (separati da virgola). Se è presente anche il Testo Tacca, ogni valore viene visualizzato con l'etichetta corrispondente.", + "axisTickText": "Testo tacche asse", + "axisTickTextTooltip": "Etichette personalizzate (separate da virgola) da mostrare al posto dei valori definiti nei Valori Tacca, nell'ordine corrispondente.", "formatExamples": "
  • .0%: percentuale arrotondata, '12%'
  • .2s:Sistema internazionale con due cifre siginificative, '42M'
  • ,.2r: Migliaia raggruppate con due cifre siginficative '4,200'
Maggior informazioni sul formato qui.
", "formula": "Formula", "formulaExamples": "
Trasforma il valore utilizzando una formula. Utilizza la variable value nell'espressione
Esempi:
  • value + 2
  • value / 100
Maggiori informazioni sulla sintassi qui.
", diff --git a/web/client/translations/data.nl-NL.json b/web/client/translations/data.nl-NL.json index 9a9168ca574..9cc7e19234b 100644 --- a/web/client/translations/data.nl-NL.json +++ b/web/client/translations/data.nl-NL.json @@ -2337,6 +2337,10 @@ "prefix": "Prefix", "suffix": "Suffix", "examples": "Voorbeelden", + "axisTickVals": "Waarden van asmarkeringen", + "axisTickValsTooltip": "Optioneel. Dwingt de as om alleen de opgegeven waarden te tonen (komma-gescheiden). Als ook Tick-tekst is ingesteld, wordt elke waarde weergegeven met het bijbehorende label.", + "axisTickText": "Tekst van asmarkeringen", + "axisTickTextTooltip": "Aangepaste labels (komma-gescheiden) die in plaats van de waarden uit Tick-waarden worden weergegeven, in de bijbehorende volgorde.", "formatExamples": "
  • .0%: afgeronde percentage, '12%'
  • .2s:SI-prefix met twee significante cijfers, '42M'
  • ,.2r: gegroepeerde duidendtallen met twee significante cijfers '4,200'
Meer informatie over formattering syntaxis hier.
", "formula": "Formule", "formulaExamples": "
Transformeer de waarde met een formule. Gebruik een variabele waarde in de expressie:
Voorbeelden
  • waarde + 2
  • waarde / 100
Meer informatie over de syntaxis hier.
",