diff --git a/app/assets/javascripts/kanaui/dashboard.js b/app/assets/javascripts/kanaui/dashboard.js
index bdff069..f7f8d20 100644
--- a/app/assets/javascripts/kanaui/dashboard.js
+++ b/app/assets/javascripts/kanaui/dashboard.js
@@ -1,11 +1,11 @@
-$(document).ready(function() {
- var spinOptions = {
- top: '150px',
- lines: 10,
- length: 8,
- width: 4,
- radius: 8,
- speed: 1
- }
- $('#loading-spinner').spin(spinOptions);
+$(document).ready(function () {
+ var spinOptions = {
+ top: "150px",
+ lines: 10,
+ length: 8,
+ width: 4,
+ radius: 8,
+ speed: 1,
+ };
+ $("#loading-spinner").spin(spinOptions);
});
diff --git a/app/assets/javascripts/kanaui/kiddo/axes.js b/app/assets/javascripts/kanaui/kiddo/axes.js
index 7f1b812..73a4271 100644
--- a/app/assets/javascripts/kanaui/kiddo/axes.js
+++ b/app/assets/javascripts/kanaui/kiddo/axes.js
@@ -1,20 +1,18 @@
-;(function(Kiddo, d3){
- Kiddo.Axes = function(){
+(function (Kiddo, d3) {
+ Kiddo.Axes = function () {
var self = this;
- var makeXAxis = function(){
- return d3.svg.axis()
- .scale(self.x)
- .orient("bottom")
- .ticks(6);
- }
+ var makeXAxis = function () {
+ return d3.svg.axis().scale(self.x).orient("bottom").ticks(6);
+ };
- var makeYAxis = function(){
- return d3.svg.axis()
+ var makeYAxis = function () {
+ return d3.svg
+ .axis()
.scale(self.y)
.orient("left")
- .tickFormat(d3.format(',d'));
- }
+ .tickFormat(d3.format(",d"));
+ };
var xAxis = makeXAxis();
var yAxis = makeYAxis();
@@ -22,34 +20,43 @@
return {
x: xAxis,
y: yAxis,
- render: function(svg, yTitle){
- svg.append("g")
- .attr("class", "grid")
- .attr("transform", "translate(" + self.margin_left + "," + self.height + ")")
- .call(makeXAxis().tickSize(-self.height, 0, 0).tickFormat(""));
-
- svg.append("g")
- .attr("class", "grid")
- .attr("transform", "translate(" + self.margin_left + ",0)")
- .call(makeYAxis().tickSize(-self.width, 0, 0).tickFormat(""));
-
- svg.append("g")
- .attr("class", "x axis")
- .attr("transform", "translate(" + self.margin_left + "," + self.height + ")")
- .call(xAxis);
-
- svg.append("g")
- .attr("class", "y axis")
- .attr("transform", "translate(" + self.margin_left + ",0)")
- .call(yAxis);
- //.append("text")
- //.attr("transform", "rotate(-90)")
- //.attr("y", 6)
- //.attr("dy", ".71em")
- //.style("text-anchor", "end")
- //.text(yTitle);
-
- }
+ render: function (svg, yTitle) {
+ svg
+ .append("g")
+ .attr("class", "grid")
+ .attr(
+ "transform",
+ "translate(" + self.margin_left + "," + self.height + ")"
+ )
+ .call(makeXAxis().tickSize(-self.height, 0, 0).tickFormat(""));
+
+ svg
+ .append("g")
+ .attr("class", "grid")
+ .attr("transform", "translate(" + self.margin_left + ",0)")
+ .call(makeYAxis().tickSize(-self.width, 0, 0).tickFormat(""));
+
+ svg
+ .append("g")
+ .attr("class", "x axis")
+ .attr(
+ "transform",
+ "translate(" + self.margin_left + "," + self.height + ")"
+ )
+ .call(xAxis);
+
+ svg
+ .append("g")
+ .attr("class", "y axis")
+ .attr("transform", "translate(" + self.margin_left + ",0)")
+ .call(yAxis);
+ //.append("text")
+ //.attr("transform", "rotate(-90)")
+ //.attr("y", 6)
+ //.attr("dy", ".71em")
+ //.style("text-anchor", "end")
+ //.text(yTitle);
+ },
};
};
-})(window.Kiddo = window.Kiddo || {}, d3)
+})((window.Kiddo = window.Kiddo || {}), d3);
diff --git a/app/assets/javascripts/kanaui/kiddo/charts/line_chart.js b/app/assets/javascripts/kanaui/kiddo/charts/line_chart.js
index 66c9a93..b75b749 100644
--- a/app/assets/javascripts/kanaui/kiddo/charts/line_chart.js
+++ b/app/assets/javascripts/kanaui/kiddo/charts/line_chart.js
@@ -1,72 +1,156 @@
-;(function(Kiddo, d3){
- Kiddo.LineChart = function(){
+(function (Kiddo, d3) {
+ Kiddo.LineChart = function () {
var self = this;
this.x = d3.time.scale().range([0, this.width]);
this.y = d3.scale.linear().range([this.height, 0]);
- var valueline = d3.svg.line()
- .x(function(d) { return self.x(d.x); })
- .y(function(d) { return self.y(d.y); });
+ var valueline = d3.svg
+ .line()
+ .x(function (d) {
+ return self.x(d.x);
+ })
+ .y(function (d) {
+ return self.y(d.y);
+ })
+ .interpolate("monotone"); // Smooth line interpolation
var axes = Kiddo.Axes.apply(this);
var helper = new Kiddo.Helper();
- self.color = d3.scale.category10();
+ // Custom blue color theme matching the image
+ var blueColors = [
+ "#1565C0",
+ "#1976D2",
+ "#2196F3",
+ "#42A5F5",
+ "#64B5F6",
+ "#90CAF9",
+ "#BBDEFB",
+ "#E3F2FD",
+ ];
+ self.color = d3.scale.ordinal().range(blueColors);
return {
- render: function(svg, json){
+ render: function (svg, json) {
var title = json.title,
datasets = json.data;
// Scale the range of the data before rendering axes
- var allValues = datasets.reduce(function(result, element){
+ var allValues = datasets.reduce(function (result, element) {
return result.concat(element.values);
}, []);
- var x_domain = d3.extent(allValues, function(d){
+ var x_domain = d3.extent(allValues, function (d) {
return new Date(d.x);
});
self.x.domain(x_domain);
- var y_domain = [d3.min(datasets, function (datum) {
- return d3.min(datum.values, function (d) {
- return d.y;
- });
- }),
- d3.max(datasets, function (datum) {
- return d3.max(datum.values, function (d) {
- return d.y;
- });
- })];
+ var y_domain = [
+ d3.min(datasets, function (datum) {
+ return d3.min(datum.values, function (d) {
+ return d.y;
+ });
+ }),
+ d3.max(datasets, function (datum) {
+ return d3.max(datum.values, function (d) {
+ return d.y;
+ });
+ }),
+ ];
self.y.domain(y_domain);
+ // Render axes first
axes.render(svg, title);
self.color.domain(d3.keys(datasets));
- datasets.forEach(function(dataset){
+ // Create legend container at the top
+ var legendContainer = svg
+ .append("g")
+ .attr("class", "chart-legend")
+ .attr("transform", "translate(" + (self.width - 100) + ", -25)");
+
+ // Calculate total values for legend
+ var legendData = datasets.map(function (dataset, index) {
+ var latestValue = dataset.values[dataset.values.length - 1];
+ var totalCount = dataset.values.length;
+ return {
+ name: dataset.name,
+ value: latestValue ? latestValue.y : 0,
+ count: totalCount,
+ color: self.color(dataset.name),
+ index: index,
+ };
+ });
+
+ // Create legend items
+ var legendItems = legendContainer
+ .selectAll(".legend-item")
+ .data(legendData)
+ .enter()
+ .append("g")
+ .attr("class", "legend-item");
+
+ var xOffset = 0;
+ legendItems.each(function (d, i) {
+ var legendItem = d3.select(this);
+
+ // Add colored circle
+ legendItem
+ .append("circle")
+ .attr("cx", xOffset + 6)
+ .attr("cy", 0)
+ .attr("r", 6)
+ .style("fill", d.color);
+
+ // Add text label
+ var labelText =
+ d.name + " :: " + d.count + ": " + d3.format(",.2f")(d.value);
+ legendItem
+ .append("text")
+ .attr("x", xOffset + 18)
+ .attr("y", 0)
+ .attr("dy", "0.35em")
+ .style("font-size", "0.875rem")
+ .style("font-weight", "500")
+ .style("fill", "#6B7280")
+ .text(labelText);
+
+ // Calculate width for next item
+ var textWidth = this.getBBox().width;
+ xOffset += textWidth + 40; // Add spacing between items
+ });
+
+ // Render data lines
+ datasets.forEach(function (dataset) {
var data = dataset.values,
name = dataset.name;
- data.forEach(function(d) {
- d.date = d.x.split('T')[0]; // Support both date and date/times
+ data.forEach(function (d) {
+ d.date = d.x.split("T")[0]; // Support both date and date/times
d.x = helper.parseDate(d.date);
d.y = +d.y;
});
- svg.append('path')
- .attr('class', 'line')
- .attr('d', valueline(data))
+ svg
+ .append("path")
+ .attr("class", "line")
+ .attr("d", valueline(data))
.attr("transform", "translate(" + self.margin_left + ",0)")
- .style("stroke", function() { return self.color(name); });
+ .style("stroke", function () {
+ return self.color(name);
+ })
+ .style("stroke-width", "0.125rem")
+ .style("fill", "none")
+ .style("opacity", 0.9);
});
self.datasets = datasets;
Kiddo.Utils.MouseOver.apply(self).render(svg, self.x, self.y);
- }
- }
+ },
+ };
};
-})(window.Kiddo = window.Kiddo || {}, d3)
+})((window.Kiddo = window.Kiddo || {}), d3);
diff --git a/app/assets/javascripts/kanaui/kiddo/charts/pie_chart.js b/app/assets/javascripts/kanaui/kiddo/charts/pie_chart.js
index 9cf7cb7..e297828 100644
--- a/app/assets/javascripts/kanaui/kiddo/charts/pie_chart.js
+++ b/app/assets/javascripts/kanaui/kiddo/charts/pie_chart.js
@@ -1,51 +1,84 @@
-;(function(Kiddo, d3){
- Kiddo.PieChart = function(){
+(function (Kiddo, d3) {
+ Kiddo.PieChart = function () {
var self = this;
var radius = Math.min(this.width, this.height) / 2;
- var color = d3.scale.category10();
- var arc = d3.svg.arc()
+ // Custom blue color theme - matching the line chart
+ var blueColors = [
+ "#1565C0",
+ "#1976D2",
+ "#2196F3",
+ "#42A5F5",
+ "#64B5F6",
+ "#90CAF9",
+ "#BBDEFB",
+ "#E3F2FD",
+ ];
+ var color = d3.scale.ordinal().range(blueColors);
+
+ var arc = d3.svg
+ .arc()
.outerRadius(radius - 10)
.innerRadius(0);
- var pie = d3.layout.pie()
+ var pie = d3.layout
+ .pie()
.sort(null)
- .value(function(d) { return d.value; });
+ .value(function (d) {
+ return d.value;
+ });
return {
- render: function(svg, json){
+ render: function (svg, json) {
var data = json.data;
- svg.attr('transform', "translate(" + self.width / 2 + "," + self.height / 2 + ")");
+ svg.attr(
+ "transform",
+ "translate(" + self.width / 2 + "," + self.height / 2 + ")"
+ );
- data.forEach(function(d){
+ data.forEach(function (d) {
d.value = +d.value;
});
- var g = svg.selectAll(".arc")
+ var g = svg
+ .selectAll(".arc")
.data(pie(data))
- .enter().append("g")
+ .enter()
+ .append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
- .style("fill", function(d) { return color(d.data.value); });
+ .style("fill", function (d, i) {
+ return color(i);
+ }) // Use index for consistent coloring
+ .style("stroke", "#ffffff")
+ .style("stroke-width", "1px"); // Add white borders for better separation
- var colorCircle = function(value){
- return(
- ' '
+ var colorCircle = function (value, index) {
+ return (
+ ' '
);
- }
+ };
g.append("foreignObject")
.attr("width", 200)
.attr("height", 150)
.attr("dy", ".35em")
.attr("x", 250)
- .attr("y", function(d, i) { return 50 * i - 200; })
- .html(function(d) { return colorCircle(d.data.value) + d.data.label + ": " + d.data.value; })
+ .attr("y", function (d, i) {
+ return 50 * i - 200;
+ })
+ .html(function (d, i) {
+ return (
+ colorCircle(d.data.value, i) + d.data.label + ": " + d.data.value
+ );
+ })
.attr("class", "chart_values");
- }
- }
+ },
+ };
};
-})(window.Kiddo = window.Kiddo || {}, d3)
+})((window.Kiddo = window.Kiddo || {}), d3);
diff --git a/app/assets/javascripts/kanaui/kiddo/charts/utils/mouse_over.js b/app/assets/javascripts/kanaui/kiddo/charts/utils/mouse_over.js
index 417b930..e472b41 100644
--- a/app/assets/javascripts/kanaui/kiddo/charts/utils/mouse_over.js
+++ b/app/assets/javascripts/kanaui/kiddo/charts/utils/mouse_over.js
@@ -1,46 +1,58 @@
-;(function(Kiddo, d3){
+(function (Kiddo, d3) {
Kiddo.Utils = Kiddo.Utils || {};
- Kiddo.Utils.MouseOver = function(){
+ Kiddo.Utils.MouseOver = function () {
var self = this;
var helper = new Kiddo.Helper();
return {
- render: function(svg, x, y){
- var focus = svg.append("g")
- .attr("class", "focus")
- .style("display", "none");
+ render: function (svg, x, y) {
+ var focus = svg
+ .append("g")
+ .attr("class", "focus")
+ .style("display", "none");
- var canvas = svg.append("g")
+ var canvas = svg
+ .append("g")
.attr("id", "mouseover_canvas")
.style("display", "none");
- var info = canvas.append("rect")
+ var info = canvas
+ .append("rect")
.attr("class", "information")
.attr("width", self.width / 2);
// The magic:
- svg.append("rect")
+ svg
+ .append("rect")
.attr("class", "overlay")
.attr("width", self.width)
.attr("height", self.height)
- .attr('transform', 'translate(' + self.margin_left + ',0)')
- .on("mouseover", function() { focus.style("display", null); canvas.style("display", null); })
- .on("mouseout", function() { focus.style("display", "none"); canvas.style("display", "none"); })
+ .attr("transform", "translate(" + self.margin_left + ",0)")
+ .on("mouseover", function () {
+ focus.style("display", null);
+ canvas.style("display", null);
+ })
+ .on("mouseout", function () {
+ focus.style("display", "none");
+ canvas.style("display", "none");
+ })
.on("mousemove", mousemove);
- var infoTitleBg = canvas.append("rect")
+ var infoTitleBg = canvas
+ .append("rect")
.attr("class", "info-title__bg")
.attr("width", self.width)
.attr("height", 30);
- var infoTitle = canvas.append("text")
+ var infoTitle = canvas
+ .append("text")
.attr("dy", "1em")
.attr("dx", 0)
.attr("class", "info-title")
.attr("id", "info-title");
- var addInfoDimensions = function(element) {
+ var addInfoDimensions = function (element) {
// On mouseover, element is the current label_idx
var box = element.node().getBBox();
// infoBox is the .information rect
@@ -53,12 +65,16 @@
info.attr("width", box.width + margin);
infoTitleBg.attr("width", box.width + margin);
- $('#mouseover_canvas #info-title').attr("dx", (box.width + margin) / 2 - infoTitleBox.width / 2);
+ $("#mouseover_canvas #info-title").attr(
+ "dx",
+ (box.width + margin) / 2 - infoTitleBox.width / 2
+ );
}
};
- self.datasets.forEach(function(element, index){
- focus.append("circle")
+ self.datasets.forEach(function (element, index) {
+ focus
+ .append("circle")
.attr("r", 4.5)
.attr("id", "circle_" + index)
.attr("transform", "translate(" + self.margin_left + ",0)");
@@ -67,14 +83,14 @@
function mousemove() {
var _this = this;
- $('#mouseover_canvas .chart_values').detach().remove();
- $('#mouseover_canvas .chart_circles').detach().remove();
+ $("#mouseover_canvas .chart_values").detach().remove();
+ $("#mouseover_canvas .chart_circles").detach().remove();
info.attr("height", infoTitleBg.node().getBBox().height + 10);
info.attr("width", 1);
infoTitle.attr("width", 1);
var elementsForLegend = [];
- self.datasets.forEach(function(element, index){
+ self.datasets.forEach(function (element, index) {
var data = element.values;
var name = element.name;
@@ -84,58 +100,63 @@
d1 = data[i];
if (d0 !== undefined && d1 !== undefined) {
- var d = x0 - d0.x > d1.x - x0 ? d1 : d0;
+ var d = x0 - d0.x > d1.x - x0 ? d1 : d0;
} else if (d0 !== undefined) {
- var d = d0;
+ var d = d0;
} else if (d1 !== undefined) {
- var d = d1;
+ var d = d1;
} else {
- return;
+ return;
}
- focus.select("#circle_" + index)
+ focus
+ .select("#circle_" + index)
.attr("cx", x(d.x))
.attr("cy", y(d.y))
.style("fill", self.color(name));
var canvasPosition = x(x0) > self.width / 2 ? 50 : self.width / 2;
- canvas
- .attr("transform", "translate(" + canvasPosition + ",0)");
+ canvas.attr("transform", "translate(" + canvasPosition + ",0)");
- canvas.select("#info-title")
- .text(d.date);
+ canvas.select("#info-title").text(d.date);
- elementsForLegend.push({element: element, d: d});
+ elementsForLegend.push({ element: element, d: d });
});
elementsForLegend.sort(function (a, b) {
- return a.d.y > b.d.y ? -1 : (a.d.y < b.d.y ? 1 : 0);
+ return a.d.y > b.d.y ? -1 : a.d.y < b.d.y ? 1 : 0;
});
// Limit the number of legend items (document largest values only)
- elementsForLegend.slice(0,10).forEach(function(element, index) {
- canvas.append("circle")
- .attr("r", 5.5)
- .attr("cx", 15)
- .attr("cy", (index + 2) * 25)
- .attr("class", "chart_circles")
- .style("fill", self.color(element.element.name))
- .style("stroke", "black")
-
- var text = canvas.append("text")
- .attr("y", (index + 2) * 25)
- .attr("x", 25)
- .attr("cx", 25)
- .attr("dy", ".35em")
- .attr("class", "chart_values")
- .attr("id", "label_" + index)
- .text(element.d === undefined ? element.element.name : helper.formatValueDisplay(element.element.name, element.d));
-
- addInfoDimensions(text);
+ elementsForLegend.slice(0, 10).forEach(function (element, index) {
+ canvas
+ .append("circle")
+ .attr("r", 5.5)
+ .attr("cx", 15)
+ .attr("cy", (index + 2) * 25)
+ .attr("class", "chart_circles")
+ .style("fill", self.color(element.element.name))
+ .style("stroke", "black");
+
+ var text = canvas
+ .append("text")
+ .attr("y", (index + 2) * 25)
+ .attr("x", 25)
+ .attr("cx", 25)
+ .attr("dy", ".35em")
+ .attr("class", "chart_values")
+ .attr("id", "label_" + index)
+ .text(
+ element.d === undefined
+ ? element.element.name
+ : helper.formatValueDisplay(element.element.name, element.d)
+ );
+
+ addInfoDimensions(text);
});
}
- }
+ },
};
};
-})(window.Kiddo = window.Kiddo || {}, d3)
+})((window.Kiddo = window.Kiddo || {}), d3);
diff --git a/app/assets/javascripts/kanaui/kiddo/helper.js b/app/assets/javascripts/kanaui/kiddo/helper.js
index 8530f61..967a282 100644
--- a/app/assets/javascripts/kanaui/kiddo/helper.js
+++ b/app/assets/javascripts/kanaui/kiddo/helper.js
@@ -1,16 +1,20 @@
-;(function(Kiddo, d3){
- Kiddo.Helper = function(){
- var formatCurrency = function(d) { return "$" + formatValue(d); };
+(function (Kiddo, d3) {
+ Kiddo.Helper = function () {
+ var formatCurrency = function (d) {
+ return "$" + formatValue(d);
+ };
var formatValue = d3.format(",.2f");
return {
parseDate: d3.time.format("%Y-%m-%d").parse,
- bisectDate: d3.bisector(function(d) { return d.x; }).left,
+ bisectDate: d3.bisector(function (d) {
+ return d.x;
+ }).left,
formatCurrency: formatCurrency,
formatValue: formatValue,
- formatValueDisplay: function(name, d) {
+ formatValueDisplay: function (name, d) {
return name + ": " + formatValue(d.y); // Add currency boolean on backend later -- formatCurrency(d.y); }
- }
- }
+ },
+ };
};
-})(window.Kiddo = window.Kiddo || {}, d3)
+})((window.Kiddo = window.Kiddo || {}), d3);
diff --git a/app/assets/javascripts/kanaui/kiddo/kiddo_initialize.js b/app/assets/javascripts/kanaui/kiddo/kiddo_initialize.js
index 8dc9ea0..85b8332 100644
--- a/app/assets/javascripts/kanaui/kiddo/kiddo_initialize.js
+++ b/app/assets/javascripts/kanaui/kiddo/kiddo_initialize.js
@@ -1,11 +1,13 @@
-;(function(d3, $, window, document, undefined){
- $(document).ready(function(){
- if($('#chartAnchor').length == 0) { return; }
+(function (d3, $, window, document, undefined) {
+ $(document).ready(function () {
+ if ($("#chartAnchor").length == 0) {
+ return;
+ }
- d3.json($('#chartAnchor').data('reports-path'), function(error, json){
- $('#loading-spinner').remove();
+ d3.json($("#chartAnchor").data("reports-path"), function (error, json) {
+ $("#loading-spinner").remove();
- var renderer = new Kiddo.Renderer('#chartAnchor');
+ var renderer = new Kiddo.Renderer("#chartAnchor");
if (error) {
ajaxErrorAlert(error);
@@ -14,34 +16,36 @@
var data = json[0];
- if (data === undefined ||
- data.data === undefined ||
- data.data.length == 0) {
+ if (
+ data === undefined ||
+ data.data === undefined ||
+ data.data.length == 0
+ ) {
return renderer.noData();
}
- var render = function(type){
- switch(type){
- case 'COUNTERS':
+ var render = function (type) {
+ switch (type) {
+ case "COUNTERS":
renderer.pieChart(data);
break;
- case 'TIMELINE':
+ case "TIMELINE":
renderer.lineChart(data);
// Date controls only make sense for timelines
- $('#date-controls').show();
+ $("#date-controls").show();
break;
- case 'TABLE':
+ case "TABLE":
renderer.table(data);
break;
default:
- console.log('No such type implemented: ' + type);
+ console.log("No such type implemented: " + type);
renderer.noData();
}
};
- try{
+ try {
render(data.type);
- } catch (ex){
+ } catch (ex) {
console.log(ex);
renderer.noData();
}
diff --git a/app/assets/javascripts/kanaui/kiddo/renderer.js b/app/assets/javascripts/kanaui/kiddo/renderer.js
index f9dfc4f..cff1985 100644
--- a/app/assets/javascripts/kanaui/kiddo/renderer.js
+++ b/app/assets/javascripts/kanaui/kiddo/renderer.js
@@ -1,39 +1,47 @@
-;(function(Kiddo, d3){
- Kiddo.Renderer = function(selector){
+(function (Kiddo, d3) {
+ Kiddo.Renderer = function (selector) {
this.element = d3.select(selector);
var settings = Kiddo.Settings.apply(this);
var helper = new Kiddo.Helper();
var svg = this.element
- .append('svg')
- .attr('width', settings.raw_width)
- .attr('height', settings.raw_height)
- .attr('style', 'overflow: visible')
- .append('g')
- .attr('transform', 'translate(' + settings.margin_left + ',' + settings.margin_top + ')');
+ .append("svg")
+ .attr("width", settings.raw_width)
+ .attr("height", settings.raw_height)
+ .attr("style", "overflow: visible")
+ .append("g")
+ .attr(
+ "transform",
+ "translate(" + settings.margin_left + "," + settings.margin_top + ")"
+ );
return {
- lineChart: function(data){
+ lineChart: function (data) {
var chart = Kiddo.LineChart.apply(settings);
chart.render(svg, data);
},
- pieChart: function(data){var chart = Kiddo.PieChart.apply(settings);
+ pieChart: function (data) {
+ var chart = Kiddo.PieChart.apply(settings);
chart.render(svg, data);
},
- table: function(data){
+ table: function (data) {
svg.node().parentNode.remove();
- new ReportsDataTables(null).buildTable(data['data'][0], $(selector));
+ new ReportsDataTables(null).buildTable(data["data"][0], $(selector));
},
- noData: function(){
- svg.append('text')
- .attr('class', 'chart-info')
- .attr('transform', 'translate(' + settings.width / 2 + ',' + settings.height / 2 + ')')
- .text('No data to display.');
- }
+ noData: function () {
+ svg
+ .append("text")
+ .attr("class", "chart-info")
+ .attr(
+ "transform",
+ "translate(" + settings.width / 2 + "," + settings.height / 2 + ")"
+ )
+ .text("No data to display.");
+ },
};
};
-})(window.Kiddo = window.Kiddo || {}, d3);
+})((window.Kiddo = window.Kiddo || {}), d3);
diff --git a/app/assets/javascripts/kanaui/kiddo/settings.js b/app/assets/javascripts/kanaui/kiddo/settings.js
index 15fb194..c061ee1 100644
--- a/app/assets/javascripts/kanaui/kiddo/settings.js
+++ b/app/assets/javascripts/kanaui/kiddo/settings.js
@@ -1,10 +1,13 @@
-;(function(Kiddo, d3){
- Kiddo.Settings = function(){
- var margin_top = 30,
+(function (Kiddo, d3) {
+ Kiddo.Settings = function () {
+ var margin_top = 30,
margin_bottom = 40,
margin_left = 50,
margin_right = 150,
- raw_width = parseInt(this.element.node().getBoundingClientRect().width, 10),
+ raw_width = parseInt(
+ this.element.node().getBoundingClientRect().width,
+ 10
+ ),
raw_height = 500;
return {
@@ -15,7 +18,7 @@
raw_width: raw_width,
raw_height: raw_height,
width: raw_width - margin_left - margin_right,
- height: raw_height - margin_top - margin_bottom
- }
+ height: raw_height - margin_top - margin_bottom,
+ };
};
-})(window.Kiddo = window.Kiddo || {}, d3)
+})((window.Kiddo = window.Kiddo || {}), d3);
diff --git a/app/assets/javascripts/kanaui/reports.dataTables.js b/app/assets/javascripts/kanaui/reports.dataTables.js
index 1fc277e..9ef85f1 100644
--- a/app/assets/javascripts/kanaui/reports.dataTables.js
+++ b/app/assets/javascripts/kanaui/reports.dataTables.js
@@ -1,127 +1,153 @@
function ReportsDataTables(reports) {
- this.reports = reports;
+ this.reports = reports;
}
-ReportsDataTables.prototype.build = function(data, id, wrapper) {
- log.debug('Building dataTable for id ' + id);
- log.trace(data);
-
- var dataTableWrapper = $('
' + data['name'] + ' ');
- wrapper.append(dataTableWrapper);
-
- var dataTable = $('');
- dataTableWrapper.append(dataTable);
-
- var aaData = [];
- for (var i in data['values']) {
- aaData.push([data.values[i]['x'], data.values[i]['y']])
- }
-
- dataTable.DataTable({
- "aaData": aaData,
- "aoColumns": [
- { "sTitle": "Date" },
- { "sTitle": "Value" },
- ]
+ReportsDataTables.prototype.build = function (data, id, wrapper) {
+ log.debug("Building dataTable for id " + id);
+ log.trace(data);
+
+ var dataTableWrapper = $(
+ '
' +
+ data["name"] +
+ " "
+ );
+ wrapper.append(dataTableWrapper);
+
+ var dataTable = $(
+ ''
+ );
+ dataTableWrapper.append(dataTable);
+
+ var aaData = [];
+ for (var i in data["values"]) {
+ aaData.push([data.values[i]["x"], data.values[i]["y"]]);
+ }
+
+ dataTable.DataTable({
+ aaData: aaData,
+ aoColumns: [{ sTitle: "Date" }, { sTitle: "Value" }],
+ });
+};
+
+ReportsDataTables.prototype.buildTable = function (data, wrapper) {
+ var id = data["name"];
+ var dataTableWrapper = $(
+ '
'
+ );
+ wrapper.append(dataTableWrapper);
+
+ var dataTable = $(
+ ''
+ );
+ dataTableWrapper.append(dataTable);
+
+ var aaData = [];
+ for (var i in data["values"]) {
+ aaData.push(data["values"][i]);
+ }
+
+ var aoColumns = [];
+ var columnsVisible = [];
+ for (var i in data["header"]) {
+ var isVisible = isColumnVisible(data["header"][i]);
+ aoColumns.push({
+ sTitle: data["header"][i],
+ name: data["header"][i],
+ visible: isVisible,
});
-}
+ if (isVisible) {
+ columnsVisible.push(data["header"][i]);
+ }
+ }
-ReportsDataTables.prototype.buildTable = function(data, wrapper) {
- var id = data['name'];
- var dataTableWrapper = $('
');
- wrapper.append(dataTableWrapper);
+ dataTable.DataTable({
+ aaData: aaData,
+ aoColumns: aoColumns,
+ scrollX: true,
+ sDom: 'C<"clear">lfrtip',
+ });
- var dataTable = $('');
- dataTableWrapper.append(dataTable);
+ dataTable.on("column-visibility.dt", function (e, settings, column, state) {
+ setColumnVisible(settings.aoColumns[column].name, state);
+ });
- var aaData = [];
- for (var i in data['values']) {
- aaData.push(data['values'][i])
- }
+ $("#copy-url").click(function (e) {
+ var pathPlusParams = $(this).data("reports-path");
+ var sPageURL = decodeURIComponent(pathPlusParams.substring(1)).split("?");
+ var params = sPageURL[1].split("&");
- var aoColumns = [];
- var columnsVisible = [];
- for (var i in data['header']) {
- var isVisible = isColumnVisible(data['header'][i]);
- aoColumns.push({ "sTitle": data['header'][i], "name": data['header'][i], "visible": isVisible })
- if (isVisible) {
- columnsVisible.push(data['header'][i]);
- }
+ var columnsVisible = $("#visible-table-columns").val();
+ var placeholder = $("#url-placeholder");
+
+ var urlToShare = window.location.origin + "/" + sPageURL[0] + "?";
+ for (var i in params) {
+ var keyValue = params[i].split("=");
+ if (keyValue[0] == "columns") {
+ continue;
+ }
+ urlToShare += "&" + params[i];
}
- dataTable.DataTable({
- "aaData": aaData,
- "aoColumns": aoColumns,
- "scrollX": true,
- "sDom": 'C<"clear">lfrtip'
- });
+ placeholder.val(urlToShare + "&columns=" + columnsVisible);
+ placeholder.removeClass("hidden");
+ placeholder.select();
- dataTable.on( 'column-visibility.dt', function ( e, settings, column, state ) {
- setColumnVisible(settings.aoColumns[column].name, state);
- });
+ document.execCommand("Copy");
+ placeholder.addClass("hidden");
+ alert("URL copied into the clipboard!");
+ });
- $("#copy-url").click(function(e){
- var pathPlusParams = $(this).data("reports-path");
- var sPageURL = decodeURIComponent(pathPlusParams.substring(1)).split('?');
- var params = sPageURL[1].split('&');
-
- var columnsVisible = $("#visible-table-columns").val();
- var placeholder = $("#url-placeholder");
-
- var urlToShare = window.location.origin + "/" + sPageURL[0] + "?";
- for (var i in params) {
- var keyValue = params[i].split('=');
- if (keyValue[0] == 'columns') {
- continue;
- }
- urlToShare += "&" + params[i];
- }
-
- placeholder.val(urlToShare + "&columns=" + columnsVisible);
- placeholder.removeClass("hidden");
- placeholder.select();
-
- document.execCommand("Copy");
- placeholder.addClass("hidden");
- alert("URL copied into the clipboard!")
- });
+ $("#visible-table-columns").val(columnsVisible.join());
+};
- $("#visible-table-columns").val(columnsVisible.join());
-}
-
-ReportsDataTables.prototype.buildCSVURL = function(position) {
- return this.reports.buildDataURL(position, 'csv');
-}
+ReportsDataTables.prototype.buildCSVURL = function (position) {
+ return this.reports.buildDataURL(position, "csv");
+};
function setColumnVisible(column, isVisible) {
- var columnsVisible = $("#visible-table-columns").val();
- if (columnsVisible == undefined || columnsVisible == null || columnsVisible.length == 0) {
- columnsVisible = [];
- } else {
- columnsVisible = (columnsVisible).split(",");
- }
-
- var columnIndex = columnsVisible.indexOf(column);
- if (isVisible && columnIndex == -1) {
- columnsVisible.push(column);
- } else if (!isVisible && columnIndex != -1) {
- columnsVisible.splice(columnIndex, 1);
- }
-
- $("#visible-table-columns").val(columnsVisible.join());
+ var columnsVisible = $("#visible-table-columns").val();
+ if (
+ columnsVisible == undefined ||
+ columnsVisible == null ||
+ columnsVisible.length == 0
+ ) {
+ columnsVisible = [];
+ } else {
+ columnsVisible = columnsVisible.split(",");
+ }
+
+ var columnIndex = columnsVisible.indexOf(column);
+ if (isVisible && columnIndex == -1) {
+ columnsVisible.push(column);
+ } else if (!isVisible && columnIndex != -1) {
+ columnsVisible.splice(columnIndex, 1);
+ }
+
+ $("#visible-table-columns").val(columnsVisible.join());
}
function isColumnVisible(column) {
- var columnsVisible = $("#visible-table-columns").val();
- if ((columnsVisible == undefined || columnsVisible == null || columnsVisible.length == 0) && column != 'tenant_record_id') {
- return true;
- }
- columnsVisible = (columnsVisible).split(",");
-
- for (var i in columnsVisible) {
- if (columnsVisible[i] == column) {
- return true;
- }
+ var columnsVisible = $("#visible-table-columns").val();
+ if (
+ (columnsVisible == undefined ||
+ columnsVisible == null ||
+ columnsVisible.length == 0) &&
+ column != "tenant_record_id"
+ ) {
+ return true;
+ }
+ columnsVisible = columnsVisible.split(",");
+
+ for (var i in columnsVisible) {
+ if (columnsVisible[i] == column) {
+ return true;
}
+ }
- return false;
+ return false;
}
diff --git a/app/assets/stylesheets/kanaui/kanaui.css b/app/assets/stylesheets/kanaui/kanaui.css
index e8b0f4c..fc3cd73 100644
--- a/app/assets/stylesheets/kanaui/kanaui.css
+++ b/app/assets/stylesheets/kanaui/kanaui.css
@@ -4,3 +4,770 @@
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_tree .
*/
+
+.kenui-analytics-dashboard-index .analytics-header {
+ display: flex;
+ align-items: start;
+ justify-content: space-between;
+ padding: 0;
+ border-bottom: 0.0625rem solid #e9eaeb;
+}
+
+.kenui-analytics-dashboard-index .analytics-header h2 {
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 2.5rem;
+ color: #414651;
+ margin-bottom: 1.25rem;
+}
+
+.kenui-analytics-dashboard-index .trigger-invoice-box button {
+ margin-left: 0.3125rem;
+ padding: 0.5rem 1rem;
+}
+
+.kenui-analytics-dashboard-index .refresh-button {
+ font-weight: 500;
+ font-size: 1rem;
+ line-height: 1.5rem;
+}
+
+.kenui-analytics-dashboard-index .refresh-button img {
+ filter: brightness(0) saturate(100%) invert(78%) sepia(47%) saturate(491%)
+ hue-rotate(170deg) brightness(100%) contrast(102%);
+}
+
+.kenui-analytics-dashboard-index .custom-date-input-wrapper {
+ padding: 0 0.625rem !important;
+ border: 0.0625rem solid #d5d7da !important;
+ border-radius: 0.375rem;
+ cursor: pointer;
+ max-width: 8.5rem;
+}
+
+.kenui-analytics-dashboard-index .custom-date-input-wrapper svg {
+ margin-right: 0.5rem;
+ flex-shrink: 0;
+}
+
+.kenui-analytics-dashboard-index .custom-date-input-wrapper input {
+ border: none;
+ outline: none;
+ box-shadow: none;
+ padding: 0 !important;
+ font-size: 1rem;
+ color: #6b7280;
+ height: 2.5rem;
+}
+
+.kenui-analytics-dashboard-index .custom-date-input-wrapper input::placeholder {
+ color: #717680;
+}
+
+.kenui-analytics-dashboard-index .custom-date-input-wrapper input.form-control {
+ border: none;
+ box-shadow: none;
+ background-color: transparent;
+}
+
+.kenui-analytics-dashboard-index select.form-select {
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ display: block;
+ height: 2.5rem;
+ width: 100%;
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #212529;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 0.0625rem solid #ced4da;
+ border-radius: 0.375rem;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ background-image: url("data:image/svg+xml;utf8, ");
+ background-repeat: no-repeat;
+ background-position: right 0.625rem center;
+ background-size: 1rem 1rem;
+ padding-right: 1.875rem;
+ max-width: 10rem;
+}
+
+.kenui-analytics-dashboard-index select.form-select:focus {
+ box-shadow: none;
+ outline: none;
+ border-color: #1570ef;
+}
+
+.kenui-analytics-dashboard-index .well ul {
+ list-style-type: none;
+ margin-top: 0.625rem;
+ background: #fafafa;
+ width: fit-content;
+ padding: 0.625rem;
+ border-radius: 0.5rem;
+}
+
+.kenui-analytics-dashboard-index .well ul li a {
+ color: #717680;
+ font-weight: 400;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ text-decoration: underline;
+ text-decoration-style: solid;
+ text-decoration-skip-ink: auto;
+ padding: 0.625rem;
+}
+
+.kenui-analytics-dashboard-index .analytics-header b,
+.kenui-analytics-dashboard-index .analytics-header b a {
+ text-decoration: none;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ color: #414651;
+}
+
+.kenui-analytics-dashboard-index .custom-tabs {
+ background-color: #fafafa;
+ border: 0.0625rem solid #e9eaeb;
+ border-radius: 0.375rem;
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ margin-bottom: 1.5rem;
+ padding: 0.25rem;
+ width: fit-content;
+ height: 2.5rem;
+}
+
+.kenui-analytics-dashboard-index .custom-tabs a.custom-tab {
+ background: transparent;
+ border: none;
+ font-weight: 500;
+ font-size: 0.875rem;
+ color: #717680;
+ padding: 0.375rem 0.75rem;
+ border-radius: 0.25rem;
+ cursor: pointer;
+ height: 2rem;
+ display: flex;
+ align-items: center;
+ text-decoration: none;
+}
+
+.kenui-analytics-dashboard-index .custom-tabs .activelink {
+ color: #414651 !important;
+ background-color: #ffffff !important;
+ box-shadow: 0 0.0625rem 0.188rem rgba(10, 13, 18, 0.1);
+}
+
+.kenui-analytics-dashboard-index #chartAnchor {
+ background: #ffffff;
+}
+
+.kenui-analytics-dashboard-index #chartAnchor svg {
+ background: #ffffff;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+}
+
+.kenui-analytics-dashboard-index .grid line {
+ stroke: transparent;
+ stroke-width: 0.0625rem;
+ stroke-opacity: 1;
+ shape-rendering: crispEdges;
+}
+
+.kenui-analytics-dashboard-index .grid:nth-of-type(2) line {
+ stroke: #f3f4f6;
+ stroke-opacity: 0.6;
+}
+
+.kenui-analytics-dashboard-index .grid path {
+ stroke: none;
+ fill: none;
+}
+
+.kenui-analytics-dashboard-index .axis line,
+.kenui-analytics-dashboard-index .axis path {
+ stroke: #f5f5f5;
+ stroke-width: 0.0625rem;
+ shape-rendering: crispEdges;
+}
+
+.kenui-analytics-dashboard-index .y.axis path {
+ stroke: transparent !important;
+ stroke-width: 0.0625rem;
+}
+
+.kenui-analytics-dashboard-index .y.axis line,
+.kenui-analytics-dashboard-index .y.axis path {
+ stroke: #f5f5f5;
+ stroke-width: 0.0625rem;
+}
+
+.kenui-analytics-dashboard-index .axis text {
+ font-size: 0.75rem;
+ fill: #6b7280;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+}
+
+.kenui-analytics-dashboard-index .line {
+ fill: none;
+ stroke-width: 0.125rem;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.kenui-analytics-dashboard-index .chart-legend {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+}
+
+.kenui-analytics-dashboard-index .chart-legend circle {
+ stroke: none;
+}
+
+.kenui-analytics-dashboard-index .information {
+ fill: #ffffff;
+ stroke: #f5f5f5;
+ stroke-width: 0.0625rem;
+ filter: drop-shadow(0 0.25rem 0.375rem rgba(0, 0, 0, 0.1));
+ rx: 0.25rem;
+}
+
+.kenui-analytics-dashboard-index .info-title__bg {
+ fill: #f9fafb;
+ stroke: #f5f5f5;
+ stroke-width: 0.0625rem;
+ rx: 0.25rem 0.25rem 0 0;
+}
+
+.kenui-analytics-dashboard-index .info-title {
+ font-size: 1rem;
+ font-weight: 600;
+ fill: #374151;
+}
+
+/* app/views/kanaui/reports/edit.html.erb */
+
+.kanaui-reports-edit .new-report-title {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+ letter-spacing: 0;
+ color: #1b1c1e;
+ padding: 1.5rem 0;
+}
+
+.kanaui-reports-edit .icon-container {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ border: 0.0625rem solid #d5d7da;
+ border-radius: 0.375rem;
+ width: 2.5rem;
+ height: 2.5rem;
+ padding: 0.25rem;
+}
+
+.kanaui-reports-edit .icon-container img {
+ width: 1rem;
+ height: 1rem;
+}
+
+.kanaui-reports-edit .form-control {
+ border-radius: 6px;
+}
+
+.kanaui-reports-edit .form-group select.form-control {
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ background-image: url('data:image/svg+xml;utf8, ');
+ background-repeat: no-repeat;
+ background-position: right 0.625rem center;
+ background-size: 1rem 1rem;
+ padding-right: 1.875rem;
+}
+
+.kanaui-reports-edit select.form-control:focus {
+ border-color: #1570ef !important;
+ box-shadow: none;
+ outline: none;
+}
+
+.kanaui-reports-edit .control-label {
+ font-size: 0.875rem !important;
+ font-weight: 500 !important;
+ line-height: 1.25rem !important;
+ color: #414651 !important;
+}
+
+.kanaui-reports-edit textarea.form-control {
+ height: 10rem !important;
+}
+
+.kanaui-reports-edit textarea.form-control:focus {
+ border-color: #1570ef !important;
+ outline: 0 !important;
+ box-shadow: none !important;
+}
+
+.kanaui-reports-edit .form-group span {
+ font-weight: 400;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ color: #535862;
+}
+
+/* app/views/kanaui/reports/index.html.erb */
+
+.kanaui-reports-index .configured-reports {
+ max-width: 80rem;
+ width: 100%;
+}
+
+.kanaui-reports-index .configured-reports .configured-reports-header {
+ display: flex;
+ align-items: start;
+ justify-content: space-between;
+ padding: 0;
+ border-bottom: 0.0625rem solid #e9eaeb;
+}
+
+.kanaui-reports-index .configured-reports .configured-reports-header h2 {
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+ color: #414651;
+ margin-bottom: 1.25rem;
+}
+
+.kanaui-reports-index th {
+ padding: 0.375rem 1.625rem 0.375rem 0.75rem;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.125rem;
+ letter-spacing: 0;
+ color: #717680;
+ text-transform: capitalize;
+}
+
+.kanaui-reports-index td {
+ font-weight: 500 !important;
+ font-size: 0.875rem !important;
+ padding: 1rem 0.5rem !important;
+ line-height: 1.125rem !important;
+ text-align: start;
+ color: #535862 !important;
+ text-transform: capitalize !important;
+}
+
+.kanaui-reports-index td a {
+ color: #175cd3 !important;
+}
+
+.kanaui-reports-index .table-button {
+ background-color: transparent !important;
+ border: none !important;
+ padding: 0 !important;
+ flex-direction: row-reverse;
+ text-transform: capitalize;
+ gap: 0.0625rem;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ letter-spacing: 0;
+ margin-left: 0.75rem;
+ text-decoration: none;
+}
+
+.kanaui-reports-index .delete-button {
+ color: #d92d20 !important;
+}
+
+.kanaui-reports-index .edit-button {
+ color: #535862 !important;
+}
+
+.kanaui-reports-index .refresh-button {
+ color: #175cd3 !important;
+}
+
+.kanaui-reports-index .modal-content {
+ border-radius: 1rem;
+ min-width: 40.5rem;
+}
+
+.kanaui-reports-index .modal-body {
+ padding-bottom: 0.375rem !important;
+ padding-top: 1.25rem !important;
+}
+
+.kanaui-reports-index .modal-header {
+ padding: 1.5rem 1.5rem 1rem 1.5rem !important;
+}
+
+.kanaui-reports-index .modal-footer {
+ padding: 1rem 1.5rem 1.5rem 1.5rem !important;
+}
+
+.kanaui-reports-index .modal-title {
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+ color: #181d27;
+}
+
+.kanaui-reports-index .close-button {
+ background: transparent;
+ padding: 0;
+ margin-top: -1.25rem;
+}
+
+.kanaui-reports-index .close-button:hover {
+ background: transparent;
+ padding: 0;
+}
+
+.kanaui-reports-index .modal-header .icon-container {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ border: 0.0625rem solid #d5d7da;
+ border-radius: 0.375rem;
+ width: 2.5rem;
+ height: 2.5rem;
+ padding: 0.25rem;
+}
+
+.kanaui-reports-index .modal-header .icon-container img {
+ width: 1.25rem;
+ height: 1.25rem;
+}
+
+.kanaui-reports-index .dataTables_wrapper.no-footer .dataTables_scrollBody {
+ border-bottom: none !important;
+}
+
+.kanaui-reports-index p {
+ margin-bottom: 0 !important;
+}
+
+.kanaui-reports-index pre {
+ padding: 0.625rem;
+ background: #f4f4f4;
+ border-radius: 0.5rem;
+ overflow: auto;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+/* app/views/kanaui/reports/new.html.erb */
+
+.kanaui-reports-new .new-report-title {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+ letter-spacing: 0;
+ color: #1b1c1e;
+ padding: 1.5rem 0;
+}
+
+.kanaui-reports-new .icon-container {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ border: 0.0625rem solid #d5d7da;
+ border-radius: 0.375rem;
+ width: 2.5rem;
+ height: 2.5rem;
+ padding: 0.25rem;
+}
+
+.kanaui-reports-new .icon-container img {
+ width: 1rem;
+ height: 1rem;
+}
+
+.kanaui-reports-new .form-control {
+ border-radius: 0.375rem;
+}
+
+.kanaui-reports-new .form-group select.form-control {
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ background-image: url('data:image/svg+xml;utf8, ');
+ background-repeat: no-repeat;
+ background-position: right 0.625rem center;
+ background-size: 1rem 1rem;
+ padding-right: 1.875rem;
+}
+
+.kanaui-reports-new select.form-control:focus {
+ border-color: #1570ef !important;
+ box-shadow: none;
+ outline: none;
+}
+
+.kanaui-reports-new .control-label {
+ font-size: 0.875rem !important;
+ font-weight: 500 !important;
+ line-height: 1.25rem !important;
+ color: #414651 !important;
+}
+
+.kanaui-reports-new textarea.form-control {
+ height: 10rem !important;
+}
+
+.kanaui-reports-new textarea.form-control:focus {
+ border-color: #1570ef !important;
+ outline: 0 !important;
+ box-shadow: none !important;
+}
+
+.kanaui-reports-new .form-group span {
+ font-weight: 400;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ color: #535862;
+}
+
+/* app/views/kanaui/settings/index.html.erb */
+
+.kanaui-settings-index .analytics-settings-title {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+ letter-spacing: 0;
+ color: #1b1c1e;
+ padding: 1.5rem 0;
+}
+
+.kanaui-settings-index .icon-container {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ border: 0.0625rem solid #d5d7da;
+ border-radius: 0.375rem;
+ width: 2.5rem;
+ height: 2.5rem;
+ padding: 0.25rem;
+}
+
+.kanaui-settings-index .icon-container img {
+ width: 1rem;
+ height: 1rem;
+}
+
+.kanaui-settings-index .form-control {
+ border-radius: 0.375rem;
+}
+
+.kanaui-settings-index .control-label {
+ font-size: 0.875rem !important;
+ font-weight: 500 !important;
+ line-height: 1.25rem !important;
+ color: #414651 !important;
+}
+
+.kenui-analytics-dashboard-index li.advanced-controls span {
+ color: #717680;
+ font-weight: 400;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ text-decoration-style: solid;
+ text-decoration-skip-ink: auto;
+ padding: 0.625rem;
+}
+
+/* Advanced Controls - Slicing & Dicing Section */
+.kenui-analytics-dashboard-index .advanced-controls {
+ margin: 0.625rem 0;
+ padding: 0;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .form-horizontal {
+ background: #fafafa;
+ border: 0.0625rem solid #e9eaeb;
+ border-radius: 0.5rem;
+ padding: 0.625rem;
+ margin-top: 0.625rem;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls fieldset {
+ border: none;
+ margin: 0;
+ padding: 0;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls legend {
+ font-weight: 600;
+ font-size: 1rem;
+ line-height: 1.5rem;
+ color: #414651;
+ margin: 0;
+ padding: 0;
+ border: none;
+ width: auto;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .form-group {
+ margin-bottom: 1rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .control-label {
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ color: #414651;
+ margin: 0;
+ min-width: 100%;
+ flex-shrink: 0;
+}
+
+.url-placeholder-input {
+ max-width: 10rem;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .col-sm-10 {
+ min-width: 100%;
+ flex: 1;
+ padding: 0;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls select.form-control {
+ height: 6rem;
+ min-width: 16rem;
+ width: 100%;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls select.form-control:focus {
+ border-color: #1570ef;
+ box-shadow: 0 0 0 0.125rem rgba(21, 112, 239, 0.25);
+ outline: none;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .col-sm-offset-2 {
+ margin-left: 0;
+ margin-top: 0.625rem;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .btn-default {
+ background-color: #1570ef;
+ border: 0.0625rem solid #1570ef;
+ color: #ffffff;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ padding: 0.5rem 0.625rem;
+ border-radius: 0.375rem;
+ transition: all 0.15s ease-in-out;
+ cursor: pointer;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .btn-default:hover {
+ background-color: #0d5bb8;
+ border-color: #0d5bb8;
+ color: #ffffff;
+}
+
+.kenui-analytics-dashboard-index .advanced-controls .btn-default:focus {
+ box-shadow: 0 0 0 0.125rem rgba(21, 112, 239, 0.25);
+ outline: none;
+}
+
+/* Current Analytics Query Section */
+.kenui-analytics-dashboard-index .well ul li:has(.query-label) {
+ background: #f8f9fa;
+ border: 0.0625rem solid #e9eaeb;
+ border-radius: 0.5rem;
+ padding: 0.625rem;
+ margin: 0.625rem 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.kenui-analytics-dashboard-index .well ul li:has(.query-label) a {
+ color: #1570ef;
+ text-decoration: none;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ padding: 0;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ transition: color 0.15s ease-in-out;
+}
+
+.kenui-analytics-dashboard-index .well ul li:has(.query-label) a:hover {
+ color: #0d5bb8;
+ text-decoration: underline;
+}
+
+.kenui-analytics-dashboard-index .well ul li:has(.query-label) pre {
+ background: #ffffff;
+ border: 0.0625rem solid #d5d7da;
+ border-radius: 0.375rem;
+ padding: 0.625rem;
+ margin: 0;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 0.8125rem;
+ line-height: 1.4;
+ color: #374151;
+ overflow-x: auto;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ box-shadow: 0 0.0625rem 0.1875rem rgba(0, 0, 0, 0.1);
+}
+
+.kenui-analytics-dashboard-index .well ul li:has(.query-label) .query-label {
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ color: #414651;
+ margin: 0;
+}
+
+/* Responsive adjustments for smaller screens */
+@media (max-width: 768px) {
+ .kenui-analytics-dashboard-index .advanced-controls .form-group {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.625rem;
+ }
+
+ .kenui-analytics-dashboard-index .advanced-controls .control-label {
+ min-width: auto;
+ width: 100%;
+ }
+
+ .kenui-analytics-dashboard-index .advanced-controls .col-sm-10 {
+ width: 100%;
+ }
+
+ .kenui-analytics-dashboard-index .well ul li:has(.query-label) pre {
+ font-size: 0.75rem;
+ padding: 0.5rem 0.75rem;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/kanaui/reports.css b/app/assets/stylesheets/kanaui/reports.css
index 06d0b74..2da896a 100644
--- a/app/assets/stylesheets/kanaui/reports.css
+++ b/app/assets/stylesheets/kanaui/reports.css
@@ -57,9 +57,23 @@
fill: #202020;
}
-.chart-title{
- padding: 20px;
- text-indent: 30px;
+.chart-title-container {
+ height: 31.25rem;
+ width: 1.25rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+}
+
+.chart-title {
+ font-weight: 500;
+ font-size: 0.75rem;
+ line-height: 1.125rem;
+ text-align: center;
+ color: #535862;
+ white-space: nowrap;
+ transform: rotate(-90deg);
}
.nav-element.current{
diff --git a/app/controllers/kanaui/dashboard_controller.rb b/app/controllers/kanaui/dashboard_controller.rb
index 24bf770..bdfd1c5 100644
--- a/app/controllers/kanaui/dashboard_controller.rb
+++ b/app/controllers/kanaui/dashboard_controller.rb
@@ -19,6 +19,22 @@ def index
@reports = JSON.parse(raw_reports)
@report = current_report(@reports) || {}
+ # If no report name is provided, redirect to the default (second) report
+ if @raw_name.blank? && @reports.is_a?(Array) && @reports[1].present?
+ default_name = @reports[1]['reportName']
+ query_params = { start_date: @start_date,
+ end_date: @end_date,
+ name: default_name,
+ smooth: params[:smooth],
+ sql_only: params[:sql_only],
+ format: params[:format] }
+
+ query_params[:fake] = params[:fake] unless params[:fake].blank?
+ query_params[:type] = params[:type] unless params[:type].blank?
+
+ redirect_to dashboard_index_path(query_params) and return
+ end
+
query = build_slice_and_dice_query
# get columns visibility from query parameters to be used by tables
diff --git a/app/views/kanaui/dashboard/index.html.erb b/app/views/kanaui/dashboard/index.html.erb
index c1da0ee..ba9ea43 100644
--- a/app/views/kanaui/dashboard/index.html.erb
+++ b/app/views/kanaui/dashboard/index.html.erb
@@ -1,193 +1,316 @@
-
-
-
-
-
-
-
- <% if params[:name] %>
-
- <% end %>
-
-
-
<%= link_to 'Available Reports', kanaui_engine.url_for(:controller => :reports) %>
-
- <% if Rails.env.development? && @reports.empty? %>
-
- <%= link_to "Fake pie", kanaui_engine.dashboard_index_path(:fake => 1, :name => 'fake_pie', :type => 'pie') %>
-
-
- <%= link_to "Fake line", kanaui_engine.dashboard_index_path(:fake => 1, :name => 'fake_line', :type => 'line') %>
-
- <% end %>
- <% @reports.each do |r| %>
- <% link = kanaui_engine.dashboard_index_path(params.to_h.merge(:name => r['reportName'])) %>
-
- <%= link_to r['reportPrettyName'], link, :class => "truncate-text", title: r['reportName'].titleize %>
-
- <% end %>
-
-
-
-
-
-
-
<%= link_to 'Settings', kanaui_engine.url_for(:controller => :settings) %>
-
-
-
-
-
-
-
- <% if params[:name] %>
-
- <%= @raw_name.titleize %>
-
-
-
-
-
- <% @available_start_dates.each do |key, value| %>
- <%= link_to key, kanaui_engine.dashboard_index_path(params.to_h.merge(:start_date => value)) %>
- <% end %>
-
-
-
-
- <% if @report['reportType'] == 'TABLE' %>
-
-
Copy URL
-
- <% end %>
- <%= link_to 'Download raw data', kanaui_engine.reports_path(params.to_h.merge(:format => 'csv')), class: 'btn btn-default' %>
-
-
- Advanced controls
-
-
-
-
- <% if @report['reportType'] == 'TIMELINE' %>
- <% at_least_two_months = params[:start_date].blank? || params[:end_date].blank? || (params[:end_date].to_date.beginning_of_month - 1.month > params[:start_date].to_date) %>
- <% at_least_two_weeks = params[:start_date].blank? || params[:end_date].blank? || (params[:end_date].to_date.beginning_of_week - 1.week > params[:start_date].to_date) %>
- <% if params[:smooth] != 'AVERAGE_WEEKLY' && at_least_two_weeks %>
- <%= link_to 'Weekly average', kanaui_engine.dashboard_index_path(params.to_h.merge(:smooth => 'AVERAGE_WEEKLY')) %>
- <% end %>
- <% if params[:smooth] != 'AVERAGE_MONTHLY' && at_least_two_months %>
- <%= link_to 'Monthly average', kanaui_engine.dashboard_index_path(params.to_h.merge(:smooth => 'AVERAGE_MONTHLY')) %>
- <% end %>
- <% if params[:smooth] != 'SUM_WEEKLY' && at_least_two_weeks %>
- <%= link_to 'Weekly sum', kanaui_engine.dashboard_index_path(params.to_h.merge(:smooth => 'SUM_WEEKLY')) %>
- <% end %>
- <% if params[:smooth] != 'SUM_MONTHLY' && at_least_two_months %>
- <%= link_to 'Monthly sum', kanaui_engine.dashboard_index_path(params.to_h.merge(:smooth => 'SUM_MONTHLY')) %>
+
+ <%= render partial: 'kaui/components/breadcrumb/breadcrumb', locals: {
+ breadcrumbs: [
+ { label: 'Settings', href: '/' },
+ { label: "Analytics", href: '#' }
+ ]
+ } %>
+
+
+ <%= render template: 'kaui/layouts/kaui_setting_sidebar',
+ locals: {
+ identifier: "Settings",
+ controller: params[:controller],
+ menu_items: [
+ { label: 'Account', path: kaui_engine.admin_tenant_path(session[:tenant_id]), controller_suffix: "#{session[:tenant_id]}", icon_path: 'kaui/setting/account.svg' },
+ { label: 'Tenants', path: kaui_engine.admin_tenants_path, controller_suffix: 'admin_tenants', icon_path: 'kaui/setting/tenants.svg' },
+ { label: 'Users', path: kaui_engine.admin_allowed_users_path, controller_suffix: 'admin_allowed_users', icon_path: 'kaui/setting/users.svg' },
+ { label: 'Tags', path: kaui_engine.tags_path, controller_suffix: 'tags', icon_path: 'kaui/setting/tags.svg' },
+ { label: 'Tag Definitions', path: kaui_engine.tag_definitions_path, controller_suffix: 'tag_definitions', icon_path: 'kaui/setting/tag-definitions.svg' },
+ { label: 'Custom Fields', path: kaui_engine.custom_fields_path, controller_suffix: 'custom_fields', icon_path: 'kaui/setting/custom-field.svg' },
+ { label: 'Plugin Manager', path: "/kpm", controller_suffix: 'kpm', icon_path: 'kaui/setting/plugins.svg' },
+ { label: 'E-notifications', path: "/kenui", controller_suffix: 'kenui', icon_path: 'kaui/setting/e-notifications.svg' },
+ { label: 'Analytics', path: "/analytics", controller_suffix: 'analytics', icon_path: 'kaui/setting/analytics.svg' },
+ ]
+ }
+ %>
+
+
-
<%= javascript_tag do %>
- $(document).ready(function() {
- $('.calendar-icon').click(function() {
- $('.form-container').toggle();
- });
- });
-<% end %>
-
-
+<% end %>
\ No newline at end of file
diff --git a/app/views/kanaui/reports/_form.html.erb b/app/views/kanaui/reports/_form.html.erb
index afe379d..ccfaf55 100644
--- a/app/views/kanaui/reports/_form.html.erb
+++ b/app/views/kanaui/reports/_form.html.erb
@@ -1,63 +1,76 @@
<%= form_tag @report[:reportName].blank? ? url_for(:controller => :reports, :action => :create) : report_path(@report[:reportName]), :method => (@report[:reportName].blank? ? :post : :put), :class => 'form-horizontal' do %>
-
-
-
-
-
-
-
-
-
-
-
- <%= submit_tag 'Save', :class => 'btn btn-default' %>
-
+
+
+
+
+
+
+
+
+
+
+
+ <%= render "kaui/components/button/button", {
+ label: 'Close',
+ variant: "outline-secondary d-inline-flex align-items-center gap-1",
+ type: "button",
+ html_class: "kaui-button custom-hover mx-2",
+ html_options: {
+ onclick: "window.history.back();"
+ }
+ } %>
+ <%= render "kaui/components/button/button", {
+ label: 'Save',
+ variant: "outline-secondary d-inline-flex align-items-center gap-1",
+ type: "submit",
+ html_class: "kaui-dropdown custom-hover"
+ } %>
+
<% end %>
diff --git a/app/views/kanaui/reports/_reports_table.html.erb b/app/views/kanaui/reports/_reports_table.html.erb
index 04729a3..ce29499 100644
--- a/app/views/kanaui/reports/_reports_table.html.erb
+++ b/app/views/kanaui/reports/_reports_table.html.erb
@@ -1,4 +1,4 @@
-
+
Name
@@ -15,7 +15,7 @@
- <% reports.each do |report| %>
+ <% reports.each do |report| %>
<%= report[:reportName] %>
<%= report[:reportPrettyName] %>
@@ -24,18 +24,45 @@
<%= report[:sourceName] %>
<% unless report[:sourceQuery].blank? %>
-
+
Show SQL
+
-
+
+
<%= report[:sourceQuery] %>
-
-
-
+
+
+
+
<% end %>
<%= report[:refreshProcedureName] %>
@@ -49,12 +76,12 @@
- <%= link_to ' '.html_safe, refresh_report_path(report[:reportName]), :method => :put %>
- <%= link_to ' '.html_safe, edit_report_path(report[:reportName]) %>
- <%= link_to ' '.html_safe, report_path(report[:reportName]), :method => :delete %>
+ <%= link_to 'Delete', report_path(report[:reportName]), :method => :delete, :class => 'delete-button table-button' %>
+ <%= link_to 'Refresh', refresh_report_path(report[:reportName]), :method => :put, :class => 'refresh-button table-button' %>
+ <%= link_to 'Edit', edit_report_path(report[:reportName]), :class => 'edit-button table-button' %>
- <% end %>
+ <% end %>
diff --git a/app/views/kanaui/reports/edit.html.erb b/app/views/kanaui/reports/edit.html.erb
index 425568d..349081a 100644
--- a/app/views/kanaui/reports/edit.html.erb
+++ b/app/views/kanaui/reports/edit.html.erb
@@ -1,10 +1,17 @@
-
-
-
-
Update report
- <%= render 'form' %>
+
+
+
+
+
+
+
+
+
+
+ Update report
+
+ <%= render 'form' %>
+
-
-
-
+
\ No newline at end of file
diff --git a/app/views/kanaui/reports/index.html.erb b/app/views/kanaui/reports/index.html.erb
index f726618..02a970e 100644
--- a/app/views/kanaui/reports/index.html.erb
+++ b/app/views/kanaui/reports/index.html.erb
@@ -1,17 +1,33 @@
-
-
-
-
-
Configured reports
- <%= link_to ' '.html_safe, new_report_path %>
-
-
- <%= render :partial => 'kanaui/reports/reports_table', :locals => {:reports => @reports} %>
-
+
+
-
-
-
-
<%= link_to 'Dashboard', dashboard_index_path %>
-
-
+
\ No newline at end of file
diff --git a/app/views/kanaui/reports/new.html.erb b/app/views/kanaui/reports/new.html.erb
index 0e1e844..5fb24e8 100644
--- a/app/views/kanaui/reports/new.html.erb
+++ b/app/views/kanaui/reports/new.html.erb
@@ -1,10 +1,16 @@
-
-
-
-
-
Add new report
- <%= render 'form' %>
+
+
+
+
+
+
+
+
+
+
+ Add new report
+
+ <%= render 'form' %>
+
-
-
-
+
\ No newline at end of file
diff --git a/app/views/kanaui/settings/index.html.erb b/app/views/kanaui/settings/index.html.erb
index 93a9574..1523427 100644
--- a/app/views/kanaui/settings/index.html.erb
+++ b/app/views/kanaui/settings/index.html.erb
@@ -1,19 +1,40 @@
-
-
Analytics settings
-
-
- <%= form_tag kanaui_engine.settings_path, :method => :post, :class => 'form-horizontal' do %>
-
+
\ No newline at end of file