-
I was trying to follow along with the Export CSV example and was getting the found no values error. At @ZuperZee's suggestion, with the browser debugger, I found that my custom dashboard variables ($experiment) were not getting resolved. While everything works when I use the query inspector... If I hardcoded the variables, everything worked ok. I did stumble across something very similar here, and I don't think it is a htmlgraphics-panel problem. But still, I wonder if there is a solution/workaround for this. I'm pretty new to grafana and just want to use the currently selected bucket ($experiment) and measurement ($building_id) in the query. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
The Export CSV code doesn't handle query variables, but it can be added by replacing line 73 with Full new onInit code: const btn = htmlNode.querySelector('button');
const timeoutLength = 3000;
const defaultButtonText = 'Export to CSV';
const toCsv = (resultsData) => {
const [
{
frames: [
{
schema: { fields },
data: { values },
},
],
},
] = Object.values(resultsData.results);
if (values.length <= 0) {
btn.textContent = 'Export failed... (Found no values).';
console.warn('Got no values');
return;
}
// Ensure time is first
const orderFieldsAndValues = (values, fields) => {
const timeIndex = fields.findIndex(({ type, name }) => [type, name.toLowerCase()].includes('time'));
const timeField = fields[timeIndex];
const timeValues = values[timeIndex].map((v) => new Date(v).toISOString()); // Format time as iso string
const orderedFields = [timeField, ...fields.filter((_, i) => i !== timeIndex)];
const orderedValues = [timeValues, ...values.filter((_, i) => i !== timeIndex)];
return { orderedFields, orderedValues };
};
const { orderedFields, orderedValues } = orderFieldsAndValues(values, fields);
const fieldNames = orderedFields.map((field) => field.name);
const [first, ...rest] = orderedValues; // Need first for indexing
const csv = [
fieldNames.join(','),
...first.map((firstValue, i) => [firstValue, ...rest.map((v) => v[i])].join(',')),
].join('\r\n');
return csv;
};
const saveCsvFile = (csv, filename) => {
const elt = document.createElement('a');
elt.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv));
elt.setAttribute('download', filename);
elt.style.display = 'none';
htmlNode.appendChild(elt);
elt.click();
htmlNode.removeChild(elt);
};
btn.onclick = () => {
clearTimeout(btn.timeout);
btn.textContent = 'Exporting...';
// The refId (query name) only updates after a page refresh.
const [{ query, refId, datasource }] = data.request.targets;
const { from, to } = data.timeRange;
const filename = [refId, from.toISOString(), to.toISOString()].join('-') + '.csv';
const body = {
queries: [
{
datasource,
query: htmlGraphics.props.replaceVariables(query), // <-- changed
refId,
intervalMs: 0,
maxDataPoints: 1e9, // 1E9 = 1_000_000_000 (Max allowed 1E20)
},
],
from: String(from.valueOf()),
to: String(to.valueOf()),
};
fetch('/api/ds/query', {
headers: {
'cache-control': 'no-cache',
'content-type': 'application/json',
},
body: JSON.stringify(body),
method: 'POST',
})
.then((res) =>
res.json().then((data) => {
const csv = toCsv(data);
if (csv) {
saveCsvFile(toCsv(data), filename);
btn.textContent = 'Export finished';
}
btn.timeout = setTimeout(() => {
btn.textContent = defaultButtonText;
}, timeoutLength);
})
)
.catch((e) => {
btn.textContent = 'Export failed... (Failed retrieving data)';
console.warn(e);
btn.timeout = setTimeout(() => {
btn.textContent = defaultButtonText;
}, timeoutLength);
});
}; |
Beta Was this translation helpful? Give feedback.
-
Thanks! You're a lifesaver! |
Beta Was this translation helpful? Give feedback.
The Export CSV code doesn't handle query variables, but it can be added by replacing line 73 with
query: htmlGraphics.props.replaceVariables(query),
Full new onInit code: