diff --git a/assets/tasksManager.js b/assets/tasksManager.js index 964cbe9..95d2918 100644 --- a/assets/tasksManager.js +++ b/assets/tasksManager.js @@ -1,9 +1,17 @@ "use strict"; - +//#region Variables const msPerH = 3600000; const msPerD = msPerH * 24; const boardId = "3478645467"; const mondayApiUrl = "https://api.monday.com/v2"; +let headers = { + 'Content-Type': 'application/json', + 'Referer': '', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"Windows"', + 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' +}; const weekday = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ]; @@ -12,18 +20,86 @@ const columnRenames = { "estado": "status", "label": "frequency", "label9": "house", - "numbers": "duration", + "numbers": "dur", "people": "assigned", - "status_1": "category", + "status_1": "cat", "subitems": "subitems", "text": "comments" }; +function createTreeMap(dataCategoriesAndValues, width, height, customColors) { + const treeMap = { + "name": "tasks", + "children": dataCategoriesAndValues + }; + // @ts-ignore + const root = d3.treemap().tile(d3.treemapSquarify) + .size([width, height]) + .padding(1) + .round(true) + // @ts-ignore + (d3.hierarchy(treeMap) + .sum(d => d.value) + .sort((a, b) => b.value - a.value)); + + // @ts-ignore Create the SVG container. + const svg = d3.create("svg") + .attr("viewBox", [0, 0, width, height]) + .attr("width", width) + .attr("height", height) + .attr("style", "font: bold 14px sans-serif; height: auto; max-width: 100%;"); + // Add a cell for each leaf of the hierarchy. + const leaf = svg.selectAll("g") + .data(root.leaves()) + .join("g") + .attr("transform", d => `translate(${d.x0},${d.y0})`); + + // @ts-ignore Append a tooltip. + const format = d3.format(",d"); + leaf.append("title") + .text(d => `${d.ancestors().reverse().map(d => d.data.name).join(".")}\n${format(d.value)}`); + + // Append a color rectangle. + leaf.append("rect") + .attr("id", (d, dIdx) => d.leafUid = `leaf${dIdx}`) + .attr("fill", d => { + while (d.depth > 1) d = d.parent; + return customColors[parseInt(d.data.name.substring(0, 1), 10)]; + }) + .attr("fill-opacity", 0.6) + .attr("width", d => d.x1 - d.x0) + .attr("height", d => d.y1 - d.y0 + 10); + + // Append a clipPath to ensure text does not overflow. + leaf.append("clipPath") + .attr("id", (d, dIdx) => d.clipUid = `clip${dIdx}`) + .append("use") + .attr("xlink:href", d => d.leafUid.href); + + // Append multiline text. The last line shows the value and has a specific formatting. + leaf.append("text") + .attr("clip-path", d => d.clipUid) + .selectAll("tspan") + .data(d => d.data.name.split(/(?=[A-Z][a-z])|\s+/g).concat(format(d.value))) + .join("tspan") + .attr("x", 3) + // @ts-ignore + // @ts-ignore + .attr("y", (d, i, nodes) => `${(i === nodes.length - 1) * 0.3 + 1.1 + i * 0.9}em`) + // @ts-ignore + .attr("fill-opacity", (d, i, nodes) => i === nodes.length - 1 ? 0.7 : null) + .text(d => d); + const treeMapSvgObj = Object.assign(svg.node()); + return treeMapSvgObj; +} +//#endregion // @ts-ignore class tasksManager extends React.Component { + //#region Constructor and functions constructor(props) { super(props); this.state = { + dayOffsetValue: 1, getDatedMondayItemsToJson: true, lastRefreshDateTime: "undefined", lastUpdatedItem: false, @@ -36,7 +112,6 @@ class tasksManager extends React.Component { nextVI: "undefined", }; }; - addMondayMeta = (mondayTasksCols) => { const currentDate = new Date(); const aYearFromNowDt = new Date(); @@ -49,7 +124,7 @@ class tasksManager extends React.Component { item["h_diff"] = +( (new Date(item["datetime"]).valueOf() - currentDate.valueOf()) / msPerH ).toFixed(2); - item["duration"] = +(parseFloat(item["duration"]).toFixed(1)); + item["dur"] = +(parseFloat(item["dur"]).toFixed(1)); item["date"] = item["datetime"].substring(0, 10); const notes = `${item["comments"]} ${item["subitems"]}`; item["notes"] = notes; @@ -58,14 +133,15 @@ class tasksManager extends React.Component { const mondayItemsJsonPayload = mondayTasksCols.map( (t) => { return { - "category": t["category"], + "cat": t["cat"], "task_name": t["task_name"], "datetime": t["datetime"], "wd": weekday[new Date(t["date"]).getDay()], - "duration": t["duration"], + "dur": t["dur"], "h_diff": t["h_diff"], "actions": t["notes"], - "task_id": t["task_id"] + "task_id": t["task_id"], + "gr": t["group"] } } ) @@ -73,12 +149,122 @@ class tasksManager extends React.Component { (a, b) => ("" + a["datetime"]).localeCompare(b["datetime"]) ).map( (t, i) => { - t["index"] = i + 1; + t["#"] = i + 1; return t; } ); }; + aggrTasksByCategory = (sortedMondayItemsJson) => { + //#region Prepare data and setState + const mondayTasksByCatDict = sortedMondayItemsJson.reduce( + (accumulator, item) => { + if (!accumulator[item["cat"]]) { + accumulator[item["cat"]] = 0; + } + accumulator[item["cat"]] += item["dur"] + return accumulator + }, {} + ); + const dataCategoriesAndValues = Object.keys(mondayTasksByCatDict).map( + (k) => { + const duration = +(mondayTasksByCatDict[k].toFixed(1)); + return { + "name": k, + "value": duration + } + } + ); + const mondayTasksDurationSum = dataCategoriesAndValues.map(t => t.value).filter(dur => dur > 0).reduce( + (accumulator, currentValue) => accumulator + currentValue, 0 + ).toFixed(1); + // @ts-ignore + this.setState({ + mondayTasksDurationSum: mondayTasksDurationSum + }); + const [width, height] = [350, 350]; + const customColors = [ + "#e15759", + "#59a14f", // ๐ + "#9c755f", // ๐ฐ + "#edc949", // ๐ + "#f28e2c", // ๐ฉ๐ฉ๐ฐ + "#ff9da7", // ๐ฌ + "#af7aa1", // ๐บ + "#4e79a7", // ๐ฎ + "#76b7b2", // ๐ + "#bab0ab", // โ + "" + ]; // d3.scaleOrdinal(treeMapChildren.map(d => d.name), d3.schemeTableau10); // alternative + const color = d3.scaleOrdinal(customColors); // for bubbleChart + const bubbleChart = dataCategoriesAndValues.map(nv => { + return { + "id": `tc.${nv.name}`, + "value": 1 + nv.value + } + }); + //#endregion + //#region Plot Bubble Chart + const margin = 1; // to avoid clipping the root circle stroke + const name = d => d.id.split(".").pop(); // "Strings" of "flare.util.Strings" + const group = d => d.id.split(".")[1]; // "util" of "flare.util.Strings" + const names = d => name(d).split(/(?=[A-Z][a-z])|\s+/g); // ["Legend", "Item"] of "flare.vis.legend.LegendItems" + + // Number format for values + const format = d3.format(",d"); + + // Create layout + const pack = d3.pack() + .size([width - margin * 2, height - margin * 2]) + .padding(3); + + // Compute the hierarchy from the (flat) bubbleChart data + const root = pack(d3.hierarchy({ children: bubbleChart }) + .sum(d => d.value)); + + const svg = d3.create("svg") + .attr("width", width) + .attr("height", height) + .attr("viewBox", [-margin, -margin, width, height]) + .attr("style", "max-width: 100%; height: auto; font: 1.4em sans-serif;") + .attr("text-anchor", "middle"); + + // Place each (leaf) node according to the layout's x and y values + const node = svg.append("g") + .selectAll() + .data(root.leaves()) + .join("g") + .attr("transform", d => `translate(${d.x},${d.y})`); + node.append("title") + .text(d => `${d.data.id}\n${format(d.value)}`); + + node.append("circle") + .attr("fill-opacity", 0.7) + .attr("fill", d => customColors[group(d.data)]) + .attr("r", d => d.r); + + // Add the labels + const text = node.append("text") + .attr("clip-path", d => `circle(${d.r})`); + + // Add a tspan for each CamelCase-separated word. + text.selectAll() + .data(d => names(d.data)) + .join("tspan") + .attr("x", 0) + .attr("y", (d, i, nodes) => `${i - nodes.length / 2 + 0.35}em`) + .text(d => d); + + // Add a tspan for the node's value. + text.append("tspan") + .attr("x", 0) + .attr("y", d => `${names(d.data).length / 2 + 0.35}em`) + .attr("fill-opacity", 0.7) + .text(d => format(d.value)); + + return Object.assign(svg.node(), { scales: { color } }); + //#endregion + }; aggrTasksByDay = (sortedMondayItemsJson) => { const [ nextClimbingDay, nextVI, nextVF @@ -93,12 +279,12 @@ class tasksManager extends React.Component { t => { return { "date": t["datetime"].substring(0, 10), - "duration": t["duration"] + "dur": t["dur"] } } ); const arrNext21D = Array.from({ length: 21 }, (_, n) => n).map((n) => { - return { "date": this.offsetNDay(n), "duration": 0 } + return { "date": this.offsetNDay(n), "dur": 0 } }); sortedMondayItemsJsonWithEmptyDates = sortedMondayItemsJsonWithEmptyDates .concat(arrNext21D).sort( @@ -109,7 +295,7 @@ class tasksManager extends React.Component { if (!accumulator[item["date"]]) { accumulator[item["date"]] = 0; } - accumulator[item["date"]] += item["duration"] + accumulator[item["date"]] += item["dur"] return accumulator }, {} ); @@ -132,129 +318,26 @@ class tasksManager extends React.Component { const durStr = setDurStrAsV ? "v".repeat(totV) : `${"|".repeat(usedTime)}${".".repeat(unUsedTime)}`; + const hDiff = Math.round((( + // @ts-ignore + new Date(k) - + // @ts-ignore + new Date((new Date().toISOString().substring(0, 10))) + ) + 3.6e6) / 3.6e5) / 10 return { "date": k, "wd": wd, "dur_offs": durOffs, - "dur_str": durStr - } - } - ); - }; - - aggrTasksByCategory = (sortedMondayItemsJson) => { - const mondayTasksByCatDict = sortedMondayItemsJson.reduce( - (accumulator, item) => { - if (!accumulator[item["category"]]) { - accumulator[item["category"]] = 0; - } - accumulator[item["category"]] += item["duration"] - return accumulator - }, {} - ); - const treeMapChildren = Object.keys(mondayTasksByCatDict).map( - (k) => { - const duration = +(mondayTasksByCatDict[k].toFixed(1)); - return { - "name": k, - "value": duration + "dur_str": durStr, + "h_diff": hDiff } } ); - const mondayTasksDurationSum = treeMapChildren.map(t => t.value).filter(dur => dur > 0).reduce( - (accumulator, currentValue) => accumulator + currentValue, 0 - ).toFixed(1); - // @ts-ignore - this.setState({ - mondayTasksDurationSum: mondayTasksDurationSum - }); - const [width, height] = [350, 350]; - const treeMap = { - "name": "tasks", - "children": treeMapChildren - } - const color = [ - "#e15759", - "#59a14f", // ๐ - "#9c755f", // ๐ฐ - "#edc949", // ๐ - "#f28e2c", // ๐ฉ๐ฉ๐ฐ - "#ff9da7", // ๐ฌ - "#af7aa1", // ๐บ - "#4e79a7", // ๐ฎ - "#76b7b2", // ๐ - "#bab0ab", // โ - "" - ]; // d3.scaleOrdinal(treeMapChildren.map(d => d.name), d3.schemeTableau10); - // @ts-ignore - const root = d3.treemap().tile(d3.treemapSquarify) - .size([width, height]) - .padding(1) - .round(true) - // @ts-ignore - (d3.hierarchy(treeMap) - .sum(d => d.value) - .sort((a, b) => b.value - a.value)); - - // @ts-ignore Create the SVG container. - const svg = d3.create("svg") - .attr("viewBox", [0, 0, width, height]) - .attr("width", width) - .attr("height", height) - .attr("style", "max-width: 100%; height: auto; font: 10px sans-serif;"); - - // Add a cell for each leaf of the hierarchy. - const leaf = svg.selectAll("g") - .data(root.leaves()) - .join("g") - .attr("transform", d => `translate(${d.x0},${d.y0})`); - - // @ts-ignore Append a tooltip. - const format = d3.format(",d"); - leaf.append("title") - .text(d => `${d.ancestors().reverse().map(d => d.data.name).join(".")}\n${format(d.value)}`); - - // Append a color rectangle. - leaf.append("rect") - .attr("id", (d, dIdx) => d.leafUid = `leaf${dIdx}`) - .attr("fill", d => { - while (d.depth > 1) d = d.parent; - return color[parseInt(d.data.name.substring(0, 1), 10)]; - }) - .attr("fill-opacity", 0.6) - .attr("width", d => d.x1 - d.x0) - .attr("height", d => d.y1 - d.y0); - - // Append a clipPath to ensure text does not overflow. - leaf.append("clipPath") - .attr("id", (d, dIdx) => d.clipUid = `clip${dIdx}`) - .append("use") - .attr("xlink:href", d => d.leafUid.href); - - // Append multiline text. The last line shows the value and has a specific formatting. - leaf.append("text") - .attr("clip-path", d => d.clipUid) - .selectAll("tspan") - .data(d => d.data.name.split(/(?=[A-Z][a-z])|\s+/g).concat(format(d.value))) - .join("tspan") - .attr("x", 3) - // @ts-ignore - // @ts-ignore - .attr("y", (d, i, nodes) => `${(i === nodes.length - 1) * 0.3 + 1.1 + i * 0.9}em`) - // @ts-ignore - .attr("fill-opacity", (d, i, nodes) => i === nodes.length - 1 ? 0.7 : null) - .text(d => d); - const treeMapSvgObj = Object.assign(svg.node()); - return treeMapSvgObj; }; - getDatedMondayTasksToMultipleJson = async ( mondayKey, boardId, columnRenames ) => { - const headers = { - "Authorization": mondayKey, - "Content-Type": "application/json", - }; + headers["Authorization"] = mondayKey; const query = "boards (ids: " + boardId + ") { " + "items_page (limit: 500) { items { " + "group { title id } id name column_values { column { id } text value } " + @@ -278,7 +361,9 @@ class tasksManager extends React.Component { mondayItemsRawJson["data"]["boards"][0]["items_page"]["items"].map( (rawItem, _rawItemIdx) => { const taskIds = { - "task_id": rawItem["id"], "task_name": rawItem["name"] + "task_id": rawItem["id"], + "task_name": rawItem["name"], + "group": rawItem["group"]["title"] }; mondayTasksCols.push(taskIds); rawItemIdx = _rawItemIdx; @@ -302,7 +387,6 @@ class tasksManager extends React.Component { }); return sortedMondayItemsJson; }; - offsetNDay = (n, dateToOffset, precision = "day") => { const dateToOffsetAsValue = dateToOffset ? new Date(dateToOffset).valueOf() : @@ -317,20 +401,16 @@ class tasksManager extends React.Component { 19 // sec ); }; - putMondayDateItem = async ( mondayKey, boardId, itemId, dateTimeToSet ) => { + headers["Authorization"] = mondayKey; const query = `mutation { change_column_value ( ${"" }board_id: ${boardId}, item_id: ${itemId}, column_id: "date", value: "{${"" }\\"date\\":\\"${dateTimeToSet.substring(0, 10)}\\", ${"" }\\"time\\":\\"${dateTimeToSet.substring(11)}\\", ${"" }\\"changed_at\\":\\"${new Date().toISOString().substring(0, 19)}\\"${"" }}") { name } }`; - const headers = { - "Authorization": mondayKey, - "Content-Type": "application/json", - }; const body = JSON.stringify({ "query": query }); const mondayPutResponsePremise = await fetch( mondayApiUrl, @@ -350,21 +430,22 @@ class tasksManager extends React.Component { this.setState({ lastUpdatedItem: lastUpdatedItem }); } }; - setBgBasedOnHDiff = (taskRow) => { const hToNextDay = new Date().getHours(); - const hToNextWeek = (7 - (new Date().getDay() % 7)) * 24 + hToNextDay; + const hToNextWeek = ((8 - (new Date().getDay() % 7)) * 24) - hToNextDay; const hDiff = parseFloat(taskRow["h_diff"]); const bgRanges = [ - { "bgRange": -9e3, "bgColor": "#C669" }, // passed - { "bgRange": 0, "bgColor": "#C666" }, // now - { "bgRange": 24 - hToNextDay, "bgColor": "#C663" }, // today - { "bgRange": 48 - hToNextDay, "bgColor": "#C863" }, // tomorrow - { "bgRange": Math.max(49 - hToNextDay, hToNextWeek), "bgColor": "#CA63" }, // this week - { "bgRange": 168 + hToNextWeek, "bgColor": "#CC62" }, // next week - { "bgRange": 720 - hToNextDay, "bgColor": "#CE61" }, // this month - { "bgRange": 8760, "bgColor": "#9F61" }, // this year - { "bgRange": 9e9, "bgColor": "#BF60" } + { "bgRange": -9e3, "bgColor": "#C66D" }, // passed + { "bgRange": 0, "bgColor": "#C669" }, // now + { "bgRange": 24 - hToNextDay, "bgColor": "#C667" }, // today + { "bgRange": 48 - hToNextDay, "bgColor": "#C665" }, // tomorrow + { "bgRange": 72 - hToNextDay, "bgColor": "#C865" }, // in 2d + { "bgRange": 96 - hToNextDay, "bgColor": "#C965" }, // in 3d + { "bgRange": Math.max(96 - hToNextDay, hToNextWeek), "bgColor": "#CA65" }, // this week + { "bgRange": 168 + hToNextWeek, "bgColor": "#CC63" }, // next week + { "bgRange": 720 - hToNextDay, "bgColor": "#CE62" }, // this month + { "bgRange": 8760, "bgColor": "#9F62" }, // this year + { "bgRange": 9e9, "bgColor": "#BBFF6606" } ]; let bgColor = "#0000"; bgRanges.filter( @@ -374,18 +455,24 @@ class tasksManager extends React.Component { }); return bgColor; }; - + setDayOffsetValue = (k) => { + // @ts-ignore + this.setState({ dayOffsetValue: k }) + }; + //#endregion render() { + //#region State listeners if (this.state.getDatedMondayItemsToJson) { //@ts-ignore this.getDatedMondayTasksToMultipleJson(monday_key, boardId, columnRenames); } if (this.state.mondayTasksByCategory.length) { - const treeMapPlaceholder = document.querySelector("#treeMap"); - if (!treeMapPlaceholder) { return; } - treeMapPlaceholder.innerHTML = ""; - treeMapPlaceholder.appendChild(this.state.mondayTasksByCategory[0]); + const tasksByCategoryPlaceholder = document.querySelector("#tasksByCategory"); + if (!tasksByCategoryPlaceholder) { return; } + tasksByCategoryPlaceholder.innerHTML = ""; + tasksByCategoryPlaceholder.appendChild(this.state.mondayTasksByCategory[0]); } + //#endregion // @ts-ignore return React.createElement( "div", { @@ -407,7 +494,7 @@ class tasksManager extends React.Component { id: "lastRefreshDateTime", style: { paddingLeft: "0.3em" } }, - `Last refresh datetime: ${this.state.lastRefreshDateTime}` + `Last refresh: ${this.state.lastRefreshDateTime}` ), // @ts-ignore React.createElement( @@ -416,7 +503,7 @@ class tasksManager extends React.Component { id: "lastUpdatedItem", style: { paddingLeft: "0.3em" } }, - this.state.lastUpdatedItem && `| ${this.state.lastUpdatedItem + this.state.lastUpdatedItem && `| Last upd. item: ${this.state.lastUpdatedItem }` ), // @ts-ignore @@ -426,19 +513,38 @@ class tasksManager extends React.Component { id: "tasksDurationSum", style: { paddingLeft: "0.3em" } }, - this.state.mondayTasksDurationSum && `| Total tasks duration (h): ${this.state.mondayTasksDurationSum - }` + this.state.mondayTasksDurationSum && `| Total tasks dur: ${this.state.mondayTasksDurationSum + }h/${(this.state.mondayTasksDurationSum / 18).toFixed(1) + }w | Day(s) offset: ` + ), + // @ts-ignore + React.createElement( + "input", + { + id: "seyDayOffset", + value: this.state.dayOffsetValue, + // @ts-ignore + onChange: (e) => this.setState({ dayOffsetValue: e.target.value }), + style: { + backgroundColor: "#FFF6", + fontStyle: "italic", + fontWeight: "bold", + paddingLeft: "0.3em", + width: "3em" + } + }, + null ), // @ts-ignore React.createElement( "div", { id: "mondayTableContainer", - className: "table-container", + className: "first-flex-container-item table-container", style: { - height: "calc(100% - 320px - 4em)", - marginTop: "0.3em", - paddingTop: "0.1em" + paddingTop: "0.1em", + width: "fit-content", + maxWidth: "calc(100% - 0.8em)" } }, (Object.keys(this.state.mondayTasksCols).length && !this.state.getDatedMondayItemsToJson) ? @@ -499,41 +605,39 @@ class tasksManager extends React.Component { } }, // @ts-ignore - taskRow[taskKey], - taskKey === "actions" && [ - // @ts-ignore - React.createElement( - "img", - { - src: "../public/prioritize.png", - alt: "Prioritize", - key: `${taskRow["task_id"]}PrioritizeImg`, - className: "clickable-icon", - onClick: () => this.putMondayDateItem( - //@ts-ignore - monday_key, boardId, - taskRow["task_id"], - this.offsetNDay(-1, taskRow["datetime"], "sec") - ) - } - ), - // @ts-ignore - React.createElement( - "img", - { - src: "../public/snooze.png", - alt: "Snooze", - key: `${taskRow["task_id"]}SnoozeImg`, - className: "clickable-icon", - onClick: () => this.putMondayDateItem( - //@ts-ignore - monday_key, boardId, - taskRow["task_id"], - this.offsetNDay(1, taskRow["datetime"], "sec") - ) - } - ), - ] + React.createElement( + "img", + { + src: "../public/prioritize.png", + alt: "Prioritize", + key: `${taskRow["task_id"]}PrioritizeImg`, + className: "clickable-icon", + onClick: () => this.putMondayDateItem( + //@ts-ignore + monday_key, boardId, + taskRow["task_id"], + this.offsetNDay(-1 * this.state.dayOffsetValue, taskRow["datetime"], "sec") + ) + } + ), + // @ts-ignore + React.createElement( + "img", + { + src: "../public/snooze.png", + alt: "Snooze", + key: `${taskRow["task_id"]}SnoozeImg`, + className: "clickable-icon", + onClick: () => this.putMondayDateItem( + //@ts-ignore + monday_key, boardId, + taskRow["task_id"], + this.offsetNDay(this.state.dayOffsetValue, taskRow["datetime"], "sec") + ) + } + ), + // @ts-ignore + taskRow[taskKey] ) : // @ts-ignore taskRow[taskKey] ) @@ -566,8 +670,9 @@ class tasksManager extends React.Component { id: "mondayTasksByDayTableContainer", className: "table-container", style: { + flexGrow: 1, height: "305px", - margin: "0.3em", + margin: "0.1em", width: "fit-content" } }, @@ -575,7 +680,7 @@ class tasksManager extends React.Component { // @ts-ignore React.createElement( "table", - null, + { style: { width: "100%" } }, // @ts-ignore React.createElement( "thead", @@ -584,12 +689,14 @@ class tasksManager extends React.Component { React.createElement( "tr", null, - // @ts-ignore - Object.keys(this.state.mondayTasksByDay[0]).map(taskKey => React.createElement( - "th", - { key: `${taskKey}HeaderByDay` }, - taskKey - )) + Object.keys(this.state.mondayTasksByDay[0]).map(taskKey => + // @ts-ignore + React.createElement( + "th", + { key: `${taskKey}HeaderByDay` }, + taskKey + ) + ) ) ), // @ts-ignore @@ -599,17 +706,14 @@ class tasksManager extends React.Component { // @ts-ignore this.state.mondayTasksByDay.map((taskRow, idxRow) => React.createElement( "tr", - { key: `TaskRow${idxRow}ByDay` }, + { + key: `TaskRow${idxRow}ByDay`, + style: { backgroundColor: this.setBgBasedOnHDiff(taskRow) } + }, // @ts-ignore Object.keys(this.state.mondayTasksByDay[0]).map(taskKey => React.createElement( "td", - { - key: `${taskKey}${idxRow}TdByDay`, - style: { - fontFamily: "monospace", - fontSize: "0.7rem" - } - }, + { key: `${taskKey}${idxRow}TdByDay` }, taskRow[taskKey] )) )) @@ -626,10 +730,11 @@ class tasksManager extends React.Component { React.createElement( "div", { - id: "treeMap", + id: "tasksByCategory", style: { + // backgroundColor: "#FFF3", only like this for treeMap height: "305px", - margin: "0.3em", + margin: "0.1em", overflow: "hidden", width: "min(50%, 305px)" } @@ -640,9 +745,10 @@ class tasksManager extends React.Component { ) } } - +//#region Append to DOM const domContainer = document.querySelector("#taskManager"); //@ts-ignore const root = ReactDOM.createRoot(domContainer); // @ts-ignore root.render(React.createElement(tasksManager)); +//#endregion \ No newline at end of file diff --git a/data/bubbleChart.json b/data/bubbleChart.json new file mode 100644 index 0000000..a499cb7 --- /dev/null +++ b/data/bubbleChart.json @@ -0,0 +1,882 @@ +[ + { + "name": "flare.analytics.AgglomerativeCluster", + "value": 3938 + }, + { + "name": "flare.analytics.CommunityStructure", + "value": 3812 + }, + { + "name": "flare.analytics.HierarchicalCluster", + "value": 6714 + }, + { + "name": "flare.analytics.MergeEdge", + "value": 743 + }, + { + "name": "flare.analytics.BetweennessCentrality", + "value": 3534 + }, + { + "name": "flare.analytics.LinkDistance", + "value": 5731 + }, + { + "name": "flare.analytics.MaxFlowMinCut", + "value": 7840 + }, + { + "name": "flare.analytics.ShortestPaths", + "value": 5914 + }, + { + "name": "flare.analytics.SpanningTree", + "value": 3416 + }, + { + "name": "flare.analytics.AspectRatioBanker", + "value": 7074 + }, + { + "name": "flare.animate.Easing", + "value": 17010 + }, + { + "name": "flare.animate.FunctionSequence", + "value": 5842 + }, + { + "name": "flare.animate.ArrayInterpolator", + "value": 1983 + }, + { + "name": "flare.animate.ColorInterpolator", + "value": 2047 + }, + { + "name": "flare.animate.DateInterpolator", + "value": 1375 + }, + { + "name": "flare.animate.Interpolator", + "value": 8746 + }, + { + "name": "flare.animate.MatrixInterpolator", + "value": 2202 + }, + { + "name": "flare.animate.NumberInterpolator", + "value": 1382 + }, + { + "name": "flare.animate.ObjectInterpolator", + "value": 1629 + }, + { + "name": "flare.animate.PointInterpolator", + "value": 1675 + }, + { + "name": "flare.animate.RectangleInterpolator", + "value": 2042 + }, + { + "name": "flare.animate.ISchedulable", + "value": 1041 + }, + { + "name": "flare.animate.Parallel", + "value": 5176 + }, + { + "name": "flare.animate.Pause", + "value": 449 + }, + { + "name": "flare.animate.Scheduler", + "value": 5593 + }, + { + "name": "flare.animate.Sequence", + "value": 5534 + }, + { + "name": "flare.animate.Transition", + "value": 9201 + }, + { + "name": "flare.animate.Transitioner", + "value": 19975 + }, + { + "name": "flare.animate.TransitionEvent", + "value": 1116 + }, + { + "name": "flare.animate.Tween", + "value": 6006 + }, + { + "name": "flare.data.Converters", + "value": 721 + }, + { + "name": "flare.data.DelimitedTextConverter", + "value": 4294 + }, + { + "name": "flare.data.GraphMLConverter", + "value": 9800 + }, + { + "name": "flare.data.IDataConverter", + "value": 1314 + }, + { + "name": "flare.data.JSONConverter", + "value": 2220 + }, + { + "name": "flare.data.DataField", + "value": 1759 + }, + { + "name": "flare.data.DataSchema", + "value": 2165 + }, + { + "name": "flare.data.DataSet", + "value": 586 + }, + { + "name": "flare.data.DataSource", + "value": 3331 + }, + { + "name": "flare.data.DataTable", + "value": 772 + }, + { + "name": "flare.data.DataUtil", + "value": 3322 + }, + { + "name": "flare.display.DirtySprite", + "value": 8833 + }, + { + "name": "flare.display.LineSprite", + "value": 1732 + }, + { + "name": "flare.display.RectSprite", + "value": 3623 + }, + { + "name": "flare.display.TextSprite", + "value": 10066 + }, + { + "name": "flare.flex.FlareVis", + "value": 4116 + }, + { + "name": "flare.physics.DragForce", + "value": 1082 + }, + { + "name": "flare.physics.GravityForce", + "value": 1336 + }, + { + "name": "flare.physics.IForce", + "value": 319 + }, + { + "name": "flare.physics.NBodyForce", + "value": 10498 + }, + { + "name": "flare.physics.Particle", + "value": 2822 + }, + { + "name": "flare.physics.Simulation", + "value": 9983 + }, + { + "name": "flare.physics.Spring", + "value": 2213 + }, + { + "name": "flare.physics.SpringForce", + "value": 1681 + }, + { + "name": "flare.query.AggregateExpression", + "value": 1616 + }, + { + "name": "flare.query.And", + "value": 1027 + }, + { + "name": "flare.query.Arithmetic", + "value": 3891 + }, + { + "name": "flare.query.Average", + "value": 891 + }, + { + "name": "flare.query.BinaryExpression", + "value": 2893 + }, + { + "name": "flare.query.Comparison", + "value": 5103 + }, + { + "name": "flare.query.CompositeExpression", + "value": 3677 + }, + { + "name": "flare.query.Count", + "value": 781 + }, + { + "name": "flare.query.DateUtil", + "value": 4141 + }, + { + "name": "flare.query.Distinct", + "value": 933 + }, + { + "name": "flare.query.Expression", + "value": 5130 + }, + { + "name": "flare.query.ExpressionIterator", + "value": 3617 + }, + { + "name": "flare.query.Fn", + "value": 3240 + }, + { + "name": "flare.query.If", + "value": 2732 + }, + { + "name": "flare.query.IsA", + "value": 2039 + }, + { + "name": "flare.query.Literal", + "value": 1214 + }, + { + "name": "flare.query.Match", + "value": 3748 + }, + { + "name": "flare.query.Maximum", + "value": 843 + }, + { + "name": "flare.query.add", + "value": 593 + }, + { + "name": "flare.query.and", + "value": 330 + }, + { + "name": "flare.query.average", + "value": 287 + }, + { + "name": "flare.query.count", + "value": 277 + }, + { + "name": "flare.query.distinct", + "value": 292 + }, + { + "name": "flare.query.div", + "value": 595 + }, + { + "name": "flare.query.eq", + "value": 594 + }, + { + "name": "flare.query.fn", + "value": 460 + }, + { + "name": "flare.query.gt", + "value": 603 + }, + { + "name": "flare.query.gte", + "value": 625 + }, + { + "name": "flare.query.iff", + "value": 748 + }, + { + "name": "flare.query.isa", + "value": 461 + }, + { + "name": "flare.query.lt", + "value": 597 + }, + { + "name": "flare.query.lte", + "value": 619 + }, + { + "name": "flare.query.max", + "value": 283 + }, + { + "name": "flare.query.min", + "value": 283 + }, + { + "name": "flare.query.mod", + "value": 591 + }, + { + "name": "flare.query.mul", + "value": 603 + }, + { + "name": "flare.query.neq", + "value": 599 + }, + { + "name": "flare.query.not", + "value": 386 + }, + { + "name": "flare.query.or", + "value": 323 + }, + { + "name": "flare.query.orderby", + "value": 307 + }, + { + "name": "flare.query.range", + "value": 772 + }, + { + "name": "flare.query.select", + "value": 296 + }, + { + "name": "flare.query.stddev", + "value": 363 + }, + { + "name": "flare.query.sub", + "value": 600 + }, + { + "name": "flare.query.sum", + "value": 280 + }, + { + "name": "flare.query.update", + "value": 307 + }, + { + "name": "flare.query.variance", + "value": 335 + }, + { + "name": "flare.query.where", + "value": 299 + }, + { + "name": "flare.query.xor", + "value": 354 + }, + { + "name": "flare.query._", + "value": 264 + }, + { + "name": "flare.query.Minimum", + "value": 843 + }, + { + "name": "flare.query.Not", + "value": 1554 + }, + { + "name": "flare.query.Or", + "value": 970 + }, + { + "name": "flare.query.Query", + "value": 13896 + }, + { + "name": "flare.query.Range", + "value": 1594 + }, + { + "name": "flare.query.StringUtil", + "value": 4130 + }, + { + "name": "flare.query.Sum", + "value": 791 + }, + { + "name": "flare.query.Variable", + "value": 1124 + }, + { + "name": "flare.query.Variance", + "value": 1876 + }, + { + "name": "flare.query.Xor", + "value": 1101 + }, + { + "name": "flare.scale.IScaleMap", + "value": 2105 + }, + { + "name": "flare.scale.LinearScale", + "value": 1316 + }, + { + "name": "flare.scale.LogScale", + "value": 3151 + }, + { + "name": "flare.scale.OrdinalScale", + "value": 3770 + }, + { + "name": "flare.scale.QuantileScale", + "value": 2435 + }, + { + "name": "flare.scale.QuantitativeScale", + "value": 4839 + }, + { + "name": "flare.scale.RootScale", + "value": 1756 + }, + { + "name": "flare.scale.Scale", + "value": 4268 + }, + { + "name": "flare.scale.ScaleType", + "value": 1821 + }, + { + "name": "flare.scale.TimeScale", + "value": 5833 + }, + { + "name": "flare.util.Arrays", + "value": 8258 + }, + { + "name": "flare.util.Colors", + "value": 10001 + }, + { + "name": "flare.util.Dates", + "value": 8217 + }, + { + "name": "flare.util.Displays", + "value": 12555 + }, + { + "name": "flare.util.Filter", + "value": 2324 + }, + { + "name": "flare.util.Geometry", + "value": 10993 + }, + { + "name": "flare.util.FibonacciHeap", + "value": 9354 + }, + { + "name": "flare.util.HeapNode", + "value": 1233 + }, + { + "name": "flare.util.IEvaluable", + "value": 335 + }, + { + "name": "flare.util.IPredicate", + "value": 383 + }, + { + "name": "flare.util.IValueProxy", + "value": 874 + }, + { + "name": "flare.util.DenseMatrix", + "value": 3165 + }, + { + "name": "flare.util.IMatrix", + "value": 2815 + }, + { + "name": "flare.util.SparseMatrix", + "value": 3366 + }, + { + "name": "flare.util.Maths", + "value": 17705 + }, + { + "name": "flare.util.Orientation", + "value": 1486 + }, + { + "name": "flare.util.ColorPalette", + "value": 6367 + }, + { + "name": "flare.util.Palette", + "value": 1229 + }, + { + "name": "flare.util.ShapePalette", + "value": 2059 + }, + { + "name": "flare.util.SizePalette", + "value": 2291 + }, + { + "name": "flare.util.Property", + "value": 5559 + }, + { + "name": "flare.util.Shapes", + "value": 19118 + }, + { + "name": "flare.util.Sort", + "value": 6887 + }, + { + "name": "flare.util.Stats", + "value": 6557 + }, + { + "name": "flare.util.Strings", + "value": 22026 + }, + { + "name": "flare.vis.Axes", + "value": 1302 + }, + { + "name": "flare.vis.Axis", + "value": 24593 + }, + { + "name": "flare.vis.AxisGridLine", + "value": 652 + }, + { + "name": "flare.vis.AxisLabel", + "value": 636 + }, + { + "name": "flare.vis.CartesianAxes", + "value": 6703 + }, + { + "name": "flare.vis.AnchorControl", + "value": 2138 + }, + { + "name": "flare.vis.ClickControl", + "value": 3824 + }, + { + "name": "flare.vis.Control", + "value": 1353 + }, + { + "name": "flare.vis.ControlList", + "value": 4665 + }, + { + "name": "flare.vis.DragControl", + "value": 2649 + }, + { + "name": "flare.vis.ExpandControl", + "value": 2832 + }, + { + "name": "flare.vis.HoverControl", + "value": 4896 + }, + { + "name": "flare.vis.IControl", + "value": 763 + }, + { + "name": "flare.vis.PanZoomControl", + "value": 5222 + }, + { + "name": "flare.vis.SelectionControl", + "value": 7862 + }, + { + "name": "flare.vis.TooltipControl", + "value": 8435 + }, + { + "name": "flare.vis.Data", + "value": 20544 + }, + { + "name": "flare.vis.DataList", + "value": 19788 + }, + { + "name": "flare.vis.DataSprite", + "value": 10349 + }, + { + "name": "flare.vis.EdgeSprite", + "value": 3301 + }, + { + "name": "flare.vis.NodeSprite", + "value": 19382 + }, + { + "name": "flare.vis.ArrowType", + "value": 698 + }, + { + "name": "flare.vis.EdgeRenderer", + "value": 5569 + }, + { + "name": "flare.vis.IRenderer", + "value": 353 + }, + { + "name": "flare.vis.ShapeRenderer", + "value": 2247 + }, + { + "name": "flare.vis.ScaleBinding", + "value": 11275 + }, + { + "name": "flare.vis.Tree", + "value": 7147 + }, + { + "name": "flare.vis.TreeBuilder", + "value": 9930 + }, + { + "name": "flare.vis.DataEvent", + "value": 2313 + }, + { + "name": "flare.vis.SelectionEvent", + "value": 1880 + }, + { + "name": "flare.vis.TooltipEvent", + "value": 1701 + }, + { + "name": "flare.vis.VisualizationEvent", + "value": 1117 + }, + { + "name": "flare.vis.Legend", + "value": 20859 + }, + { + "name": "flare.vis.LegendItem", + "value": 4614 + }, + { + "name": "flare.vis.LegendRange", + "value": 10530 + }, + { + "name": "flare.vis.BifocalDistortion", + "value": 4461 + }, + { + "name": "flare.vis.Distortion", + "value": 6314 + }, + { + "name": "flare.vis.FisheyeDistortion", + "value": 3444 + }, + { + "name": "flare.vis.ColorEncoder", + "value": 3179 + }, + { + "name": "flare.vis.Encoder", + "value": 4060 + }, + { + "name": "flare.vis.PropertyEncoder", + "value": 4138 + }, + { + "name": "flare.vis.ShapeEncoder", + "value": 1690 + }, + { + "name": "flare.vis.SizeEncoder", + "value": 1830 + }, + { + "name": "flare.vis.FisheyeTreeFilter", + "value": 5219 + }, + { + "name": "flare.vis.GraphDistanceFilter", + "value": 3165 + }, + { + "name": "flare.vis.VisibilityFilter", + "value": 3509 + }, + { + "name": "flare.vis.IOperator", + "value": 1286 + }, + { + "name": "flare.vis.Labeler", + "value": 9956 + }, + { + "name": "flare.vis.RadialLabeler", + "value": 3899 + }, + { + "name": "flare.vis.StackedAreaLabeler", + "value": 3202 + }, + { + "name": "flare.vis.AxisLayout", + "value": 6725 + }, + { + "name": "flare.vis.BundledEdgeRouter", + "value": 3727 + }, + { + "name": "flare.vis.CircleLayout", + "value": 9317 + }, + { + "name": "flare.vis.CirclePackingLayout", + "value": 12003 + }, + { + "name": "flare.vis.DendrogramLayout", + "value": 4853 + }, + { + "name": "flare.vis.ForceDirectedLayout", + "value": 8411 + }, + { + "name": "flare.vis.IcicleTreeLayout", + "value": 4864 + }, + { + "name": "flare.vis.IndentedTreeLayout", + "value": 3174 + }, + { + "name": "flare.vis.Layout", + "value": 7881 + }, + { + "name": "flare.vis.NodeLinkTreeLayout", + "value": 12870 + }, + { + "name": "flare.vis.PieLayout", + "value": 2728 + }, + { + "name": "flare.vis.RadialTreeLayout", + "value": 12348 + }, + { + "name": "flare.vis.RandomLayout", + "value": 870 + }, + { + "name": "flare.vis.StackedAreaLayout", + "value": 9121 + }, + { + "name": "flare.vis.TreeMapLayout", + "value": 9191 + }, + { + "name": "flare.vis.Operator", + "value": 2490 + }, + { + "name": "flare.vis.OperatorList", + "value": 5248 + }, + { + "name": "flare.vis.OperatorSequence", + "value": 4190 + }, + { + "name": "flare.vis.OperatorSwitch", + "value": 2581 + }, + { + "name": "flare.vis.SortOperator", + "value": 2023 + }, + { + "name": "flare.vis.Visualization", + "value": 16540 + } +] \ No newline at end of file diff --git a/data/treeMap.json b/data/treeMap.json new file mode 100644 index 0000000..9cc5832 --- /dev/null +++ b/data/treeMap.json @@ -0,0 +1,38 @@ +[ + { + "name": "1.๐ ", + "value": 12.3 + }, + { + "name": "3.๐", + "value": 8.6 + }, + { + "name": "7.๐ฎ", + "value": 2 + }, + { + "name": "2.๐ฐ", + "value": 8.2 + }, + { + "name": "8.๐", + "value": 4.5 + }, + { + "name": "9.โ", + "value": 1.1 + }, + { + "name": "4.๐ฉ๐ฉ๐ฐ", + "value": 1.7 + }, + { + "name": "5.๐ฌ", + "value": 2.8 + }, + { + "name": "6.๐บ", + "value": 0.5 + } +] \ No newline at end of file diff --git a/locale/EN.js b/locale/EN.js index e3edb82..bfc485a 100644 --- a/locale/EN.js +++ b/locale/EN.js @@ -54,16 +54,11 @@ function getEnglishContents() {
- Technical and cloud consultant expert in ETLs, BI, web development and NLP. -
-- Greatest experience in these clouds: Amazon Web Services (3+ years of experience), -
-- Azure (3 years of experience) and IBM (1 year of experience within the company). -
+