How to make Switchable Dimension with Radio Buttons
Hi harikm007​ DRay​ I am trying to create a radio button switcable dimensional changer and wanted to see if it can be done with Radio Buttons, my current script is: { "title": "", "style": "", "script": "", "showCarousel": true, "body": [ { "type": "Input.ChoiceSet", "id": "radiotVal", "displayType": "expanded", "layout": "horizontal", "isMultiSelect": false, "value": "1", "choices": [ { "title": "Total Revenue", "value": "1" }, { "title": "Total Quantity", "value": "2" } ] } ], "events": [ { "type": "valueChanged", "elementId": "radiotVal", "actions": [ { "type": "SwitchMeasure", "title": "DEBUG: event fires?", "script": "console.log('[BloX] valueChanged fired, selectVal=', {{radiotVal.value}}); alert('Radio changed to ' + {{radiotVal.value}});" } ] } ], "actions": [] } The radio buttons show up but they do not switch the measures for the widgets I targeted. I am also okay with not specifically targeting widgets but affecting all the widgets on the dashboard. This is the script for the action: var dimIndex = payload.data.selectVal - 1; var dimToSwapTo = payload.widget.metadata.panels[1].items[dimIndex].jaql; var widgetIds = payload.data.widgetToModify; payload.widget.dashboard.widgets.$$widgets .filter(i => widgetIds.includes(i.oid)) .forEach(function (widget) { if (widget.metadata.panels[1].$$widget.type == 'indicator') { widget.metadata.panels[0].items[0].jaql = dimToSwapTo; } else { widget.metadata.panels[1].items[0].jaql = dimToSwapTo; } widget.changesMade('plugin-BloX', 'metadata'); widget.refresh(); }) I am not sure if this is the correct Action script since this is used from: https://community.sisense.com/kb/blox/changing-measures-in-the-entire-dashboard-using-blox-user-interface/8802Solved38Views0likes4CommentsChange an SVG color in BloX with criteria based on token - and for it to work with the carousel
Hello, my aim is to have a bar grow (change width, seems to be working fine) and change color based on if it exceeds a threshold. The issue is that the threshold will be client dependent. I have this script that works as intended for the initial display with static thresholds, but I want to replace the "parseInt('80')" and "parseInt('65')" in the script with tokens like "{panel:Threshold Good}" and "{panel:Threshold Meh}". It also fails to display the conditional color when I cycle on the carousel. Any assistance would be appreciated! { "style": ".conditional-bar-good{fill:#006100; stroke:#006100} .conditional-bar-meh{fill:#9C6500; stroke:#9C6500} .conditional-bar-bad{fill:#9C0006; stroke:#9C0006} .conditional-bar-na{fill:#000000; stroke:#000000}", "script": "$(document).ready(function(){let barClass = document.getElementById('conditional-bar');let cbw = parseInt(barClass.getAttribute('width'));if(cbw >=parseInt('80')){barClass.className.baseVal = 'conditional-bar-good';}else if(cbw>=parseInt('65')){barClass.className.baseVal = 'conditional-bar-meh';}else{barClass.className.baseVal = 'conditional-bar-bad';};});", "title": "", "showCarousel": true, "body": [ { "type": "Container", "items": [ { "type": "TextBlock", "horizontalAlignment": "center", "spacing": "small", "text": "<svg width='80%' height='25'> <rect width='100%' height=100% rx='15' style='fill:#C6EFCE;stroke-width:1;stroke:#006100' /> <rect width='{panel:Threshold Good}%' height='100%' rx='15' style='fill:#FFEB9C;stroke-width:1;stroke:#9C6500' /> <rect width='{panel: Threshold Meh}%' height='100%' rx='15' style='fill:#FFC7CE;stroke-width:1;stroke:#9C0006' /> <rect id='conditional-bar' class='conditional-bar-na' y='20%' width='{panel:Value 1}%' height='60%' rx='10' style='fill-opacity: 0.7;stroke-width:3;' /></svg>" } ] }, { "spacing": "none", "type": "Container", "items": [ { "spacing": "none", "type": "TextBlock", "class": "condition_data", "text": "{panel:Label 1}", "horizontalAlignment": "center", "size": "medium", "weight": "bold" }, { "spacing": "none", "type": "TextBlock", "class": "condition_data", "text": "{panel:Value 1}%", "horizontalAlignment": "center", "size": "large", "weight": "bold" } ] } ], "actions": [] }38Views0likes3CommentsConditional Format in BloX using an image
Hi harikm007​ , DRay​ , Liliia_DevX​ I am using BloX to display a conditon format based on a if a value is above 10% or below 10% and then display a green or red arrow I have in my plugins folder to show. My script goes as follows: { "style": "@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@700;800&display=swap');", "script": "", "title": "", "conditions": [ { "minRange": "-Infinity", "maxRange": 0.10, "image": "/plugins/assets/icons/red_arrow.png", "color": "#D34A4A", "fontSize": "14px", "fontWeight": "600" }, { "minRange": 0.10, "maxRange": "Infinity", "image": "/plugins/assets/icons/green-up-arrow.svg", "color": "#079B65", "fontSize": "14px", "fontWeight": "600" } ], "titleStyle": [ { "display": "none" } ], "showCarousel": false, "body": [ { "type": "ColumnSet", "columns": [ { "type": "Column", "width": "stretch", "style": { "width": "430px", "height": "145px", "box-sizing": "border-box", "padding": "16px" }, "items": [ { "type": "ColumnSet", "columns": [ { "type": "Column", "width": "stretch", "items": [ { "type": "TextBlock", "text": "No shows - last full month", "style": { "font-family": "Inter, sans-serif", "font-size": "16px", "font-weight": "700", "text-align": "left", "color": "#212A31", "margin": "0" } } ] }, { "type": "Column", "width": "auto", "horizontalAlignment": "right", "style": { "text-align": "right", "min-width": "14px" }, "items": [ { "type": "ColumnSet", "style": { "align-items": "center" }, "columns": [ { "type": "Column", "width": "auto", "items": [ { "type": "Image", "url": "{conditions:image}", "altText": "delta", "horizontalAlignment": "right", "style": { "width": "12px", "height": "10px", "margin-right": "6px", "margin-top": "2px" } } ] }, { "type": "Column", "width": "150", "items": [ { "type": "TextBlock", "text": "{panel:# of unique Patient ID}", "style": { "font-family": "Inter, sans-serif", "font-size": "14px", "font-weight": "600", "color": "{conditions:color}", "text-align": "right", "margin": "0" } } ] } ] } ] } ] }, { "type": "TextBlock", "text": "{panel: No Show}", "style": { "margin-top": "16px", "font-family": "Manrope, Inter, sans-serif", "font-size": "28px", "line-height": "32px", "font-weight": "700", "text-align": "left", "color": "#212A31" } }, { "type": "TextBlock", "text": "Avg 10%", "style": { "margin-top": "8px", "font-family": "Inter, sans-serif", "font-size": "12px", "font-weight": "500", "text-align": "left", "color": "#969696" } } ] } ] } ], "actions": [] }Solved65Views1like3CommentsEnsuring Accurate PDF Export Headers When Programmatically Modifying Dashboard Filters in Sisense
When working with Sisense dashboards, programmatically modifying filters upon dashboard load via dashboard scripts for a specific user or circumstance is possible. However, an issue can sometimes occur when exporting these dashboards to PDF immediately after such modifications: the filter header displayed at the top of the exported PDF displaying the current dashboard filter state may not accurately reflect the current state of the dashboard filters. This article explains the cause of this issue and presents a solution to ensure that PDF exports display the correct filter information in the header.571Views1like0CommentsPercentage in formulas
Hello! I'm trying to work out how to get a percentage value in a formaula. The results are not what I'm expecting so i imagine it's my maths letting me down.. The end result needs to be a percentage count of all safeguarding events ever. What my formula is currently looking like is: ([# of unique EventUID], [Was the incident a safeguarding?]) / ([# of unique EventUID]) * 100 With [Was the incident a safeguarding?] being filtered to TRUE. This gives me a result of 266% Base values for objects are: [# of unique EventUID] = 19,761 [Was the incident a safeguarding?] N/A = 18,321 FALSE = 876 TRUE = 564 Any help would be appreciated94Views0likes6CommentsHide Widget based on grouped by Column Values
Hello I'm looking to hide a specific widget id if a specific value exists within a column value. I started with dashboard.on('widgetrefreshed', function (se, ev) { widgetList = ['682f7ab1602b5d7f74c97e6f', ] if(widgetList.includes(ev.widget.oid)) { $(`widget[widgetid="${ev.widget.oid}"]`).closest('.dashboard-layout-subcell-host').addClass('dontshowme-parent') } }); but I am not sure how to check if the value for a column called test_benchmarks contains 'ctv'109Views0likes9CommentsHelp with BloX Widget
Hello, I am hoping to get some guidance on how to use BloX to return a message. I have a field in a table that returns a value of Yes or No. I want to the BloX widget to return a message if the value is No. If the value is Yes, I want the BloX widget hidden. I have exhausted my AI effort attempts. It appears this is something the BloX widget should be able to do, but I just can't get it to work at all. Any advise would be helpful.56Views0likes5CommentsAdd presets to a Blox date filter widget
We have some dashboards that have widgets as filters. One of these is a Blox widget that functions as a date filter, which I created with help from the community here. I recently added presets to the date filter to make it easier and faster to apply date filtering. Create a Blox Widget Paste the script below in the script editor section. { "style": ".blox-slides button:hover{background-color:#014E66 !important;} .date-input-container { position: relative; } .date-input-container input[type='date'] { cursor: pointer; } .date-input-container::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 1; cursor: pointer; } .date-input-container input::-webkit-calendar-picker-indicator { opacity: 0; position: absolute; right: 10px; width: 20px; height: 20px; cursor: pointer; z-index: 2; }", "title": "", "showCarousel": true, "carouselAnimation": { "showButtons": false }, "script": "setTimeout(function() { const fromInput = document.getElementById('SelectVal_from'); const toInput = document.getElementById('SelectVal_to'); function formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return year + '-' + month + '-' + day; } function setDates(fromDate, toDate) { if (fromInput) fromInput.value = formatDate(fromDate); if (toInput) toInput.value = formatDate(toDate); } function getDateRanges() { const today = new Date(); const currentYear = today.getFullYear(); const currentMonth = today.getMonth(); const currentQuarter = Math.floor(currentMonth / 3); return { last30days: { from: new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000), to: today }, quarter: { from: new Date(currentYear, currentQuarter * 3, 1), to: new Date(currentYear, (currentQuarter + 1) * 3, 0) }, ytd: { from: new Date(currentYear, 0, 1), to: today }, lastyear: { from: new Date(currentYear - 1, 0, 1), to: new Date(currentYear - 1, 11, 31) } }; } const ranges = getDateRanges(); document.querySelectorAll('[data-filter-type]').forEach(function(btn) { btn.addEventListener('click', function() { const filterType = this.getAttribute('data-filter-type'); if (ranges[filterType]) { setDates(ranges[filterType].from, ranges[filterType].to); } }); }); if (fromInput) { fromInput.addEventListener('click', function(e) { if (e.target.tagName === 'INPUT') { e.target.showPicker ? e.target.showPicker() : e.target.click(); } }); fromInput.style.cursor = 'pointer'; } if (toInput) { toInput.addEventListener('click', function(e) { if (e.target.tagName === 'INPUT') { e.target.showPicker ? e.target.showPicker() : e.target.click(); } }); toInput.style.cursor = 'pointer'; } }, 1000);", "body": [ { "type": "Container", "width": "90%", "style": { "margin": "0 auto" }, "items": [ { "type": "ActionSet", "actions": [ { "type": "date-preset", "title": "Last 30 Days", "style": { "color": "white", "background-color": "#007FAA" }, "data": { "FilterType": "last30days", "FilterFields": [ "[Dm_dates.date_data (Calendar)]" ] } }, { "type": "date-preset", "title": "This Quarter", "style": { "color": "white", "background-color": "#007FAA" }, "data": { "FilterType": "quarter", "FilterFields": [ "[Dm_dates.date_data (Calendar)]" ] } }, { "type": "date-preset", "title": "Year to Date", "style": { "color": "white", "background-color": "#007FAA" }, "data": { "FilterType": "ytd", "FilterFields": [ "[Dm_dates.date_data (Calendar)]" ] } }, { "type": "date-preset", "title": "Last Year", "style": { "color": "white", "background-color": "#007FAA" }, "data": { "FilterType": "lastyear", "FilterFields": [ "[Dm_dates.date_data (Calendar)]" ] } } ] }, { "type": "Container", "style": { "display": "flex", "flexDirection": "row", "justifyContent": "space-between", "marginTop": "20px", "gap": "10px" }, "items": [ { "type": "Container", "style": { "width": "48%" }, "items": [ { "type": "TextBlock", "text": "From", "weight": "lighter", "color": "black" }, { "type": "Container", "style": { "position": "relative" }, "items": [ { "type": "Input.Date", "id": "SelectVal_from", "placeholder": "mm/dd/yyyy", "calendar": true, "style": { "width": "100%", "padding": "14px", "background-color": "#F4F4F8", "border-radius": "8px", "border": "1px solid #ccc", "font-size": "16px", "cursor": "pointer" } } ] } ] }, { "type": "Container", "style": { "width": "48%" }, "items": [ { "type": "TextBlock", "text": "To", "weight": "lighter", "color": "black" }, { "type": "Container", "style": { "position": "relative" }, "items": [ { "type": "Input.Date", "id": "SelectVal_to", "placeholder": "mm/dd/yyyy", "calendar": true, "style": { "width": "100%", "padding": "14px", "background-color": "#F4F4F8", "border-radius": "8px", "border": "1px solid #ccc", "font-size": "16px", "cursor": "pointer" } } ] } ] } ] }, { "type": "ActionSet", "style": { "marginTop": "20px", "text-align": "center" }, "actions": [ { "type": "DateX", "id": "submit_btn", "title": "Apply", "style": { "color": "white", "background-color": "#007FAA" }, "data": { "FilterFields": [ "[Dm_dates.date_data (Calendar)]" ] } }, { "type": "filter-date-clear", "title": "Clear", "style": { "color": "white", "background-color": "#007FAA" }, "data": { "FilterFields": [ "[Dm_dates.date_data (Calendar)]" ] } } ] } ] } ] } Create the necessary actions for the buttons to work: date-preset const filterType = payload.data.FilterType; const filterDims = payload.data.FilterFields; const dash = payload.widget.dashboard; const now = new Date(); const yyyy = now.getFullYear(); const mm = String(now.getMonth() + 1).padStart(2, '0'); const dd = String(now.getDate()).padStart(2, '0'); const today = `${yyyy}-${mm}-${dd}`; let fromDate = ''; let toDate = today; //Year to date if (filterType === 'ytd') { fromDate = `${yyyy}-01-01`; //Quarter } else if (filterType === 'quarter') { const q = Math.floor(now.getMonth() / 3); const startMonth = q * 3 + 1; fromDate = `${yyyy}-${String(startMonth).padStart(2, '0')}-01`; //Last Year } else if (filterType === 'lastyear') { fromDate = `${yyyy - 1}-01-01`; toDate = `${yyyy - 1}-12-31`; // Last 30 days: from 30 days ago to today } else if (filterType === 'last30days') { const pastDate = new Date(now); pastDate.setDate(pastDate.getDate() - 30); const pastY = pastDate.getFullYear(); const pastM = String(pastDate.getMonth() + 1).padStart(2, '0'); const pastD = String(pastDate.getDate()).padStart(2, '0'); fromDate = `${pastY}-${pastM}-${pastD}`; } else { console.log('Unknown FilterType:', filterType); if (typeof sendResponse === 'function') sendResponse(false); return; } let newFilter = {}; $('#SelectVal_from').val(fromDate); $('#SelectVal_to').val(toDate); newFilter = { jaql: { dim: "", filter: { from: fromDate, to: toDate } } }; filterDims.forEach(function(dim) { newFilter.jaql.dim = dim; dash.filters.update(newFilter, { refresh: true, save: true }); }); Datex -- Apply button var today = new Date(); var dd = String(today.getDate()).padStart(2, '0'); var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0! var yyyy = today.getFullYear(); today = yyyy + '-' + mm + '-' + dd; const filVal_from = payload.data.SelectVal_from == '' ? '1800-01-01' : payload.data.SelectVal_from; const filVal_to = payload.data.SelectVal_to == '' ? '2100-01-01' : payload.data.SelectVal_to; const filterDims = payload.data.FilterFields; const dash = payload.widget.dashboard; let newFilter = {}; console.log(filVal_from); console.log(filVal_to); newFilter = { jaql: { dim: "", filter: { from: filVal_from, to: filVal_to } } }; filterDims.forEach(function (dim) { newFilter.jaql.dim = dim; dash.filters.update(newFilter, { refresh: true, save: true }) }) Clear dates var today = new Date(); var dd = String(today.getDate()).padStart(2, '0'); var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0! var yyyy = today.getFullYear(); today = yyyy + '-' + mm + '-' + dd; const filVal_from = "1800-01-01" const filVal_to = '2100-01-01' const filterDims = payload.data.FilterFields; const dash = payload.widget.dashboard; let newFilter = {}; newFilter = { jaql: { dim: "", filter: { from: filVal_from, to: filVal_to } } }; $('#SelectVal_from').val(''); $('#SelectVal_to').val(''); filterDims.forEach(function (dim) { newFilter.jaql.dim = dim; dash.filters.update(newFilter, { refresh: true, save: true }) }) Save everything and try it out.222Views2likes0CommentsCheckBox using Blox without Action Button
Hello everyone, I have created a Blox widget which shows a list of values with checkboxes. I am trying to make the check boxes "actionable", meaning that when a checkbox is ticked, then my dashboard filter adjusts. I have tried to utilize this widget script, but it doesn't seem to work: widget.on('processresult', function(se, ev){ ev.result.unshift(allObject) }) widget.on('ready', function(se, ev){ var filterName = 'Chain Name' var select = document.getElementById(`data.filters[2].filterJaql.members[0]`); dashboardFilter = prism.activeDashboard.filters.$$items.find(el => el.jaql.title == filterName) if(dashboardFilter && dashboardFilter.jaql.filter && dashboardFilter.jaql.filter.members) { select.value = dashboardFilter.jaql.filter.members[0] } select.addEventListener("change", function(e){ if(e.target.value == "All") { filter = { "explicit": false, "multiSelection": true, "all": true } }else { filter = { "explicit": true, "multiSelection": true, "members": [ e.target.value ] } } dashboardFilter = prism.activeDashboard.filters.$$items.find(el => el.jaql.title == filterName) var filterOptions = { save: true, refresh: true, } dashboardFilter.jaql.filter = filter prism.activeDashboard.filters.update(dashboardFilter, filterOptions) }); }) Can anyone help me with this?Solved137Views0likes6CommentsInput Parameters using BloX for What-If Analysis
Input Parameters using BloX for What-If Analysis This is an alternative to the paid or community Input Parameter plugins. This new BloX Input Parameter custom action: supports multiple levers (input parameters) with just one Apply button supports all widget types remembers previous selections even after refreshing/closing the dashboard loops through all widgets so dashboard designers do not have to specify widget IDs in the BloX code. Note: Be mindful of performance when considering this option as this will execute the BloX action on all widgets including those that the input parameters may not necessarily be relevant to. Input Parameter Implementation Instructions: Import the example dashboard attached below. Before importing the file, change the file extension from .txt to .dash. Make sure that you still have the Sample ECommerce Elasticube for this dashboard to properly display the data. Open the BloX Lever Configuration widget, then add the custom action given below to your Sisense environment. Go to the Actions tab, click the three-dot menu, then click Create Action. Copy the custom action code from below and paste it into your BloX custom action editor. Give this name for the action: ParameterSwap_V2_AllWidgets. You can also use a different name, but make sure the name of the action matches with the name referenced in the BloX code. Click Next, then Create. Click the Apply button to close the widget. Enter values to the levers and click Apply. The number on the widgets is now recalculated based on your input. There are three input parameters in this example. To add another input parameter: In the BloX code of the Lever Configuration widget, modify the number of input parameters in the BloX code under the paramsToModify parameter. For example, if you need 4 input parameters (levers), update the value to 4. On the left panel, add the additional swap_levers to the Values panel, i.e. swap_lever4, swap_lever5, etc. You can assign any arbitrary hard-coded number to these swap levers. To add the input box to the widget, copy one of the column elements then add it to the BloX code. Modify the id parameter to selectVal<lever number>, e.g. if this is the fourth lever, the id should be selectVal4. Similarly, modify the value parameter to match the swap_lever name you added in the previous step, e.g. [swap_lever4]. Update the title text as well and give it a meaningful description. Save the widget by clicking the Apply button. Add the additional levers to your widget formulas as needed so that they get recalculated when you enter the input values. Input Parameter BloX action: //initialize variables var swapParam = []; //create an array of swap_levers for (d = 0; d < payload.data.paramsToModify; d++) { swapParam[d] = "swap_lever" + (d + 1); } //loop through each of the specified widgets payload.widget.dashboard.widgets.$$widgets .forEach(function (widget) { //loop through each panel in the widget //exclude the filter panel (last panel) for (p = 0; p < widget.metadata.panels.length - 1; p++) { //loop through each item in the panel for (i = 0; i < widget.metadata.panels[p].items.length; i++) { //check if the panel item contains context (i.e. a formula) if (widget.metadata.panels[p].items[i].jaql.context != undefined) { var queryContext = widget.metadata.panels[p].items[i].jaql.context; //loop through each context in the item for (let [k, v] of Object.entries(queryContext)) { //loop through each swap_lever for (s = 0; s < swapParam.length; s++) { //check if the formula contains the swap_lever if (v.title == swapParam[s]) { var val = 'selectVal' + (s + 1); //update the formula with the swap_lever value that the user entered v.formula = payload.data[val]; } } } } } } //apply and save changes to the widget widget.changesMade('plugin-BloX', ['metadata']) //refresh the widget widget.refresh(); }) Resetting to Default Values The attached dashboard example includes a Reset button to reset the input parameters to pre-set default values. If you do not need this option, you can remove the second action from the BloX code, as shown in the highlighted part of the screenshot below. Instructions to implement the Reset button: Open the BloX Lever Configuration widget, then add the custom action given below to your Sisense environment. Go to the Actions tab, click the three-dot menu, then click Create Action. Copy the custom action code from below and paste it into your BloX custom action editor. Give this name for the action: ParameterSwap_V2_AllWidgets_Reset. You can also use a different name, but make sure the name of the action matches with the name referenced in the BloX code. Click Next, then Create. In the BloX code, update the defaultValues array with your required default values. See screenshot below for reference. There are three input parameters in this example, if you have more/less parameters, update the paramsToModify value to the correct number of parameters that you have. See screenshot below for reference. Click the Apply button to close the widget. Reset Input Parameter BloX action: //initialize variables var leverValues = payload.data.defaultValues; var swapParam = []; //create an array of swap_levers for (d = 0; d < payload.data.paramsToModify; d++) { swapParam[d] = "swap_lever" + (d + 1); } //loop through all widgets in the dashboard payload.widget.dashboard.widgets.$$widgets .forEach(function (widget) { //loop through each panel in the widget //exclude the filter panel (last panel) for (p = 0; p < widget.metadata.panels.length - 1; p++) { //loop through each item in the panel for (i = 0; i < widget.metadata.panels[p].items.length; i++) { //check if the panel item contains context (i.e. a formula) if (widget.metadata.panels[p].items[i].jaql.context != undefined) { var queryContext = widget.metadata.panels[p].items[i].jaql.context; //loop through each context in the item for (let [k, v] of Object.entries(queryContext)) { //loop through each swap_lever for (s = 0; s < swapParam.length; s++) { //check if the formula contains the swap_lever if (v.title == swapParam[s]) { var val = 'selectVal' + (s + 1); //update the formula with the default value v.formula = leverValues[s]; } } } } } } //apply and save changes to the widget widget.changesMade('plugin-BloX', ['metadata']) //refresh the widget widget.refresh(); }) We hope this is a helpful article and would love to hear about your experience in the comments!16KViews4likes12Comments