Skip to content

Commit

Permalink
Merge pull request #280 from bitovi/TR-209
Browse files Browse the repository at this point in the history
[TR-209] Move URL-linked data elements from select-report-type to route-data
  • Loading branch information
justinbmeyer authored Jan 17, 2025
2 parents a423342 + 753554c commit 01067ae
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 112 deletions.
33 changes: 21 additions & 12 deletions public/canjs/controls/select-issue-type/select-issue-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { StacheElement, type, ObservableObject, ObservableArray, value, queues }
import {updateUrlParam, pushStateObservable} from "../../routing/state-storage.js";
import { bitoviTrainingIssueData } from "../../../examples/bitovi-training.js";

import routeData, { issueHierarchyFromNormalizedIssues } from "../../routing/route-data.js";
import routeData from "../../routing/route-data.js";
import "../status-filter.js";

import SimpleTooltip from "../../ui/simple-tooltip/simple-tooltip";

import { DROPDOWN_LABEL } from "../../../shared/style-strings.js";
import { issueHierarchyFromNormalizedIssues, toSelectedParts } from "../../routing/data-utils.js";

const TOOLTIP = new SimpleTooltip();
document.body.append(TOOLTIP);
Expand All @@ -33,13 +34,13 @@ document.body.append(RELEASES_TOOLTIP);
class TypeSelectionDropdown extends StacheElement {
static view = `
{{# for(issueType of this.issueHierarchy) }}
<label class="px-4 py-2 block {{#eq(this.routeData.primaryIssueType, issueType.name)}}bg-blue-101{{else}}${hoverEffect}{{/eq}}"><input
<label class="px-4 py-2 block {{#eq(this.primaryIssueType, issueType.name)}}bg-blue-101{{else}}${hoverEffect}{{/eq}}"><input
type="radio"
name="primaryIssueType"
checked:from="eq(this.routeData.primaryIssueType, issueType.name)"
checked:from="eq(this.primaryIssueType, issueType.name)"
on:change="this.onSelection(issueType.name)"/> {{issueType.name}}s </label>
{{/ }}
<label class="px-4 py-2 block {{#eq(this.routeData.primaryIssueType, 'Release')}}bg-blue-101{{else}}${hoverEffect}{{/eq}} border-t border-t-2 border-t-neutral-301"
<label class="px-4 py-2 block {{#eq(this.primaryIssueType, 'Release')}}bg-blue-101{{else}}${hoverEffect}{{/eq}} border-t border-t-2 border-t-neutral-301"
on:mouseenter="this.showReleases(scope.element)">
Releases <img class="inline" src="/images/chevron-right-new.svg"/>
</label>
Expand All @@ -60,10 +61,10 @@ customElements.define("select-type-dropdown", TypeSelectionDropdown);
class ReleasesTypeSelectionDropdown extends StacheElement {
static view = `
{{# for(issueType of this.issueHierarchy) }}
<label class="px-4 py-2 block {{#eq(this.routeData.secondaryIssueType, issueType.name)}}bg-blue-101{{else}}${hoverEffect}{{/eq}}"><input
<label class="px-4 py-2 block {{#eq(this.secondaryIssueType, issueType.name)}}bg-blue-101{{else}}${hoverEffect}{{/eq}}"><input
type="radio"
name="primaryIssueType"
checked:from="eq(this.routeData.secondaryIssueType, issueType.name)"
checked:from="eq(this.secondaryIssueType, issueType.name)"
on:change="this.onSelection('Release', issueType.name)"/> {{issueType.name}}s </label>
{{/ }}
`
Expand All @@ -76,15 +77,15 @@ customElements.define("select-release-type-dropdown", ReleasesTypeSelectionDropd
export class SelectIssueType extends StacheElement {
static view = `
<label for="reportOn" class="${DROPDOWN_LABEL}">Report on</label>
{{# not(this.routeData.primaryIssueType) }}
{{# not(this.primaryIssueType) }}
<button class="rounded bg-neutral-201 px-3 py-1" id="reportOn">Loading ... </button>
{{/ }}
{{# if(this.routeData.primaryIssueType) }}
{{# if(this.primaryIssueType) }}
<button class="rounded bg-neutral-201 px-3 py-1 ${hoverEffect}"
on:click="this.showChildOptions()"
id="reportOn">
{{this.routeData.primaryIssueType}}s
{{# if(this.routeData.secondaryIssueType) }} / {{this.routeData.secondaryIssueType}}s {{/ if }}
{{this.primaryIssueType}}s
{{# if(this.secondaryIssueType) }} / {{this.secondaryIssueType}}s {{/ if }}
<img class="inline" src="/images/chevron-down.svg"/>
</button>
{{/ }}
Expand All @@ -99,6 +100,14 @@ export class SelectIssueType extends StacheElement {
this.simplifiedIssueHierarchy;

},
get primaryIssueType() {
return this.routeData.selectedIssueType && toSelectedParts(this.routeData.selectedIssueType).primary;
},
get secondaryIssueType() {
return this.routeData.selectedIssueType && toSelectedParts(this.routeData.selectedIssueType).secondary;
}


};
onSelection(primaryType, secondaryType){
if(secondaryType) {
Expand All @@ -111,8 +120,8 @@ export class SelectIssueType extends StacheElement {
}
showChildOptions(){
let dropdown = new TypeSelectionDropdown().initialize({
primaryIssueType: this.routeData.primaryIssueType,
secondaryIssueType: this.routeData.secondaryIssueType,
primaryIssueType: this.primaryIssueType,
secondaryIssueType: this.secondaryIssueType,
issueHierarchy: this.issueHierarchy,
onSelection: this.onSelection.bind(this)
})
Expand Down
48 changes: 12 additions & 36 deletions public/canjs/controls/select-report-type/select-report-type.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { StacheElement, type, ObservableObject, ObservableArray, value } from "../../../can.js";
import { DROPDOWN_LABEL } from "../../../shared/style-strings.js";

import {saveJSONToUrl,updateUrlParam} from "../../routing/state-storage.js";
import routeData from "../../routing/route-data.js";

import "../status-filter.js";

Expand All @@ -18,20 +20,6 @@ import SimpleTooltip from "../../ui/simple-tooltip/simple-tooltip";
const TOOLTIP = new SimpleTooltip();
document.body.append(TOOLTIP);

const REPORTS = [{
key: "start-due",
name: "Gantt Chart"
},{
key: "due",
name: "Scatter Plot"
},{
key: "table",
name: "Estimation Table"
},{
key: "group-grid",
name: "Group Grid"
}];

const hoverEffect = "hover:bg-neutral-301 cursor-pointer";

class ReportSelectionDropdown extends StacheElement {
Expand All @@ -48,53 +36,41 @@ class ReportSelectionDropdown extends StacheElement {

customElements.define("report-selection-dropdown", ReportSelectionDropdown);

import { DROPDOWN_LABEL } from "../../../shared/style-strings.js";

export class SelectReportType extends StacheElement {
static view = `
<label for="reportType" class="${DROPDOWN_LABEL}">Report type</label>
{{# not(this.primaryReportType) }}
{{# not(this.routeData.primaryReportType) }}
---
{{/ }}
{{# if(this.primaryReportType) }}
{{# if(this.routeData.primaryReportType) }}
<button
class="rounded bg-neutral-201 px-3 py-1 ${hoverEffect}"
id="reportType"
on:click="this.showChildOptions()">{{this.primaryReportName}} <img class="inline" src="/images/chevron-down.svg"/></button>
{{/ }}
`;
static props ={
primaryReportType: saveJSONToUrl("primaryReportType", "start-due", String, {
parse: function(x) {
if( REPORTS.find( report => report.key === x) ) {
return x;
} else {
return "start-due"
}
},
stringify: x => ""+x
}),
reports: {
static props = {
routeData: {
get default(){
return REPORTS;
return routeData;
}
},
get primaryReportName(){
return this.reports.find( report => report.key === this.primaryReportType).name;
return this.routeData.reports.find( report => report.key === this.routeData.primaryReportType).name;
}
};

showChildOptions(){
let dropdown = new ReportSelectionDropdown().initialize({
primaryReportType: this.primaryReportType,
reports: this.reports,
primaryReportType: this.routeData.primaryReportType,
reports: this.routeData.reports,
onSelection: this.onSelection.bind(this)
})

TOOLTIP.belowElementInScrollingContainer(this, dropdown);
}
onSelection(reportType) {
this.primaryReportType = reportType;
this.routeData.primaryReportType = reportType;
TOOLTIP.leftElement();
}
connected(){
Expand All @@ -107,4 +83,4 @@ export class SelectReportType extends StacheElement {
}


customElements.define("select-report-type", SelectReportType);
customElements.define("select-report-type", SelectReportType);
48 changes: 48 additions & 0 deletions public/canjs/routing/data-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { mostCommonElement } from "../../utils/array/array-helpers.js";

/**
*
* @param {Array<import("../../../jira/normalized/normalize.js").NormalizedIssue>} normalizedIssues
* @returns {Array<{type: string, hierarchyLevel: number}>}
*/
export function issueHierarchyFromNormalizedIssues(normalizedIssues){
const levelsToNames = []
for( let issue of normalizedIssues) {
if(!levelsToNames[issue.hierarchyLevel]) {
levelsToNames[issue.hierarchyLevel] = [];
}
levelsToNames[issue.hierarchyLevel].push(issue.type)
}
return levelsToNames.map( (names, i) => {
return {name: mostCommonElement(names), hierarchyLevel: i}
}).filter( i => i ).reverse()
}

export function toSelectedParts(value){
if(value) {
if(value.startsWith("Release-")) {
return {primary: "Release", secondary: value.substring("Release-".length)}
} else {
return {primary: value}
}
} else {
return undefined;
}
}

export function makeAsyncFromObservableButStillSettableProperty(promiseProperty) {
return {
value({resolve, listenTo, lastSet}) {

listenTo(promiseProperty, ({value})=>{
value.then(resolve);
});
if(this[promiseProperty]) {
this[promiseProperty].then(resolve);
}
listenTo(lastSet, (value)=>{
resolve(value);
});
}
}
}
92 changes: 34 additions & 58 deletions public/canjs/routing/route-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ makeArrayOfStringsQueryParamValue,
pushStateObservable,
} from "./state-storage.js";


import { mostCommonElement } from "../../utils/array/array-helpers.js";

import {
getAllTeamData,
createFullyInheritedConfig,
Expand All @@ -28,6 +25,11 @@ import {
import { createNormalizeConfiguration } from "../../react/Configure/components/Teams/shared/normalize";

import { getSimplifiedIssueHierarchy } from "../../stateful-data/jira-data-requests.js";
import {
issueHierarchyFromNormalizedIssues,
makeAsyncFromObservableButStillSettableProperty,
toSelectedParts
} from "./data-utils.js";

const _15DAYS_IN_S = DAY_IN_MS / 1000 * 15;

Expand All @@ -38,6 +40,20 @@ const booleanParsing = {
stringify: (x) => "" + x,
};

const REPORTS = [{
key: "start-due",
name: "Gantt Chart"
},{
key: "due",
name: "Scatter Plot"
},{
key: "table",
name: "Estimation Table"
},{
key: "group-grid",
name: "Group Grid"
}];

class RouteData extends ObservableObject {
static props = {

Expand Down Expand Up @@ -182,6 +198,21 @@ class RouteData extends ObservableObject {
}
},

primaryReportType: saveJSONToUrl("primaryReportType", "start-due", String, {
parse: function(x) {
if( REPORTS.find( report => report.key === x) ) {
return x;
} else {
return "start-due"
}
},
stringify: x => ""+x
}),
reports: {
get default(){
return REPORTS;
}
},
get issueHierarchy(){
return this.derivedIssues && this.derivedIssues.length ?
issueHierarchyFromNormalizedIssues(this.derivedIssues) :
Expand Down Expand Up @@ -240,7 +271,6 @@ class RouteData extends ObservableObject {
}
}


// when the route changes, check stuff ...
listenTo(pushStateObservable, ()=>{
resolveCurrentValue();
Expand All @@ -258,15 +288,8 @@ class RouteData extends ObservableObject {
resolveCurrentValue();

}
},
get primaryIssueType() {
return this.selectedIssueType && toSelectedParts(this.selectedIssueType).primary;
},
get secondaryIssueType() {
return this.selectedIssueType && toSelectedParts(this.selectedIssueType).secondary;
}


}
}

Expand All @@ -275,50 +298,3 @@ console.log("routeData", routeData);

export default routeData;


/**
*
* @param {Array<import("../../../jira/normalized/normalize.js").NormalizedIssue>} normalizedIssues
* @returns {Array<{type: string, hierarchyLevel: number}>}
*/
export function issueHierarchyFromNormalizedIssues(normalizedIssues){
const levelsToNames = []
for( let issue of normalizedIssues) {
if(!levelsToNames[issue.hierarchyLevel]) {
levelsToNames[issue.hierarchyLevel] = [];
}
levelsToNames[issue.hierarchyLevel].push(issue.type)
}
return levelsToNames.map( (names, i) => {
return {name: mostCommonElement(names), hierarchyLevel: i}
}).filter( i => i ).reverse()
}

function toSelectedParts(value){
if(value) {
if(value.startsWith("Release-")) {
return {primary: "Release", secondary: value.substring("Release-".length)}
} else {
return {primary: value}
}
} else {
return undefined;
}
}

function makeAsyncFromObservableButStillSettableProperty(promiseProperty) {
return {
value({resolve, listenTo, lastSet}) {

listenTo(promiseProperty, ({value})=>{
value.then(resolve);
});
if(this[promiseProperty]) {
this[promiseProperty].then(resolve);
}
listenTo(lastSet, (value)=>{
resolve(value);
});
}
}
}
Loading

0 comments on commit 01067ae

Please sign in to comment.