diff --git a/src/org/april/agirstatool/cli/SQLUtils.java b/src/org/april/agirstatool/cli/SQLUtils.java index da40f3d..b81d411 100644 --- a/src/org/april/agirstatool/cli/SQLUtils.java +++ b/src/org/april/agirstatool/cli/SQLUtils.java @@ -24,6 +24,8 @@ import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import org.apache.commons.lang3.StringUtils; import org.april.agirstatool.core.AgirStatoolException; @@ -241,4 +243,30 @@ public final class SQLUtils // return result; } + + /** + * To date time. + * + * @param source + * the source + * @return the local date time + */ + public static LocalDateTime toLocalDateTime(final java.sql.Timestamp source) + { + LocalDateTime result; + + if (source == null) + { + result = null; + } + else + { + long seconds = source.getTime() / 1000; + long nanos = (source.getTime() - seconds * 1000) * 1000000; + result = LocalDateTime.ofEpochSecond(seconds, (int) nanos, ZoneOffset.UTC); + } + + // + return result; + } } diff --git a/src/org/april/agirstatool/core/AgirStatool.java b/src/org/april/agirstatool/core/AgirStatool.java index e924529..13b34f3 100644 --- a/src/org/april/agirstatool/core/AgirStatool.java +++ b/src/org/april/agirstatool/core/AgirStatool.java @@ -238,6 +238,262 @@ public class AgirStatool } } + /** + * Fetch issue open closed dates. + * + * @param project + * the project + * @return the date count map + * @throws AgirStatoolException + * the agir statool exception + */ + public Issues fetchIssue(final Project project) throws AgirStatoolException + { + Issues result; + + result = new Issues(); + + // + PreparedStatement statement = null; + ResultSet resultSet = null; + try + { + StringList subSql = new StringList(); + if (project.getType() == Project.Type.CONSOLIDATED) + { + subSql.append("select "); + subSql.append(" id "); + subSql.append("from "); + subSql.append(" projects as childProject "); + subSql.append("where "); + subSql.append(" (childProject.id=" + project.getId() + " or childProject.parent_id=" + project.getId() + ")"); + subSql.append(" and childProject.status=1 and childProject.is_public=1"); + } + else if (project.getType() == Project.Type.ROOT) + { + subSql.append("select "); + subSql.append(" id "); + subSql.append("from "); + subSql.append(" projects as childProject "); + subSql.append("where "); + subSql.append(" childProject.status=1 and childProject.is_public=1"); + } + else + { + subSql.append(project.getId()); + } + + StringList sql = new StringList(); + sql.append("SELECT"); + sql.append(" id, "); + sql.append(" project_id, "); + sql.append(" created_on, "); + sql.append(" closed_on "); + sql.append("FROM "); + sql.append(" issues "); + sql.append("WHERE "); + sql.append(" project_id in (" + subSql.toString() + ") "); + + // System.out.println(sql.toStringSeparatedBy("\n")); + + this.connection.setAutoCommit(true); + statement = this.connection.prepareStatement(sql.toString()); + resultSet = statement.executeQuery(); + + while (resultSet.next()) + { + int id = resultSet.getInt(1); + int projectId = resultSet.getInt(2); + LocalDateTime createdOn = SQLUtils.toLocalDateTime(resultSet.getTimestamp(3)); + LocalDateTime closedOn = SQLUtils.toLocalDateTime(resultSet.getTimestamp(4)); + + Issue issue = new Issue(id, projectId, createdOn, closedOn); + + result.add(issue); + } + } + catch (SQLException exception) + { + throw new AgirStatoolException("Error fetching day closed count: " + exception.getMessage(), exception); + } + finally + { + SQLUtils.closeQuietly(statement, resultSet); + } + + // + return result; + } + + /** + * List projects extended. + * + * @return the projects + * @throws AgirStatoolException + * the agir statool exception + */ + public Projects fetchProjectsWithoutSubStats() throws AgirStatoolException + { + Projects result; + + result = fetchProjectsWithStats(Project.Type.ALONE); + // + return result; + } + + /** + * List projects with stats. + * + * @param type + * the type + * @return the projects + * @throws AgirStatoolException + * the agir statool exception + */ + public Projects fetchProjectsWithStats(final Project.Type type) throws AgirStatoolException + { + Projects result; + + result = new Projects(); + + // + PreparedStatement statement = null; + ResultSet resultSet = null; + try + { + StringList subSql = new StringList(); + if (type == Project.Type.CONSOLIDATED) + { + subSql.append("select "); + subSql.append(" id "); + subSql.append("from "); + subSql.append(" projects as childProject "); + subSql.append("where "); + subSql.append(" (childProject.id=currentProject.id or childProject.parent_id=currentProject.id)"); + subSql.append(" and childProject.status=1 and childProject.is_public=1"); + } + else + { + subSql.append("currentProject.id"); + } + + StringList sql = new StringList(); + sql.append("SELECT"); + sql.append(" id,"); + sql.append(" identifier,"); + sql.append(" name,"); + sql.append(" parent_id,"); + sql.append(" (select count(*) from projects as subproject where subproject.parent_id=currentProject.id and subproject.status = 1 and subproject.is_public = 1) as child_count, "); + sql.append(" updated_on,"); + + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ")) as issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 1) as new_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 2) as ongoing_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 3) as resolved_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 5) as closed_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 6) as rejected_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 7) as confirmed_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id=15) as maybe_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id=16) as waiting_issue_count, "); + + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.assigned_to_id is null) as unassigned_issue_count,"); + sql.append( + " (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 1 and issues.assigned_to_id is null) as unassigned_new_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + + ") and issues.status_id= 2 and issues.assigned_to_id is null) as unassigned_ongoing_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + + ") and issues.status_id= 3 and issues.assigned_to_id is null) as unassigned_resolved_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + + ") and issues.status_id= 5 and issues.assigned_to_id is null) as unassigned_closed_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + + ") and issues.status_id= 6 and issues.assigned_to_id is null) as unassigned_rejected_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + + ") and issues.status_id= 7 and issues.assigned_to_id is null) as unassigned_confirmed_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + + ") and issues.status_id=15 and issues.assigned_to_id is null) as unassigned_maybe_issue_count,"); + sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + + ") and issues.status_id=16 and issues.assigned_to_id is null) as unassigned_waiting_issue_count, "); + sql.append(" (select min(created_on) from issues where issues.project_id in (" + subSql.toString() + ")) as first_issue_create, "); + sql.append(" (select max(updated_on) from issues where issues.project_id in (" + subSql.toString() + ")) as last_issue_update "); + + sql.append("FROM "); + sql.append(" projects as currentProject "); + sql.append("WHERE "); + sql.append(" currentProject.status=1 and currentProject.is_public=1;"); + + // System.out.println(sql.toStringSeparatedBy("\n")); + + this.connection.setAutoCommit(true); + statement = this.connection.prepareStatement(sql.toString()); + resultSet = statement.executeQuery(); + + while (resultSet.next()) + { + long id = resultSet.getLong(1); + String identifier = resultSet.getString(2); + String name = resultSet.getString(3); + Long parentId = SQLUtils.getNullableLong(resultSet, 4); + + Project project = new Project(id, identifier, name, parentId); + project.setChildCount(resultSet.getLong(5)); + project.setLastUpdate(SQLUtils.toLocalDateTime(resultSet.getTimestamp(6))); + + project.issueStats().setCount(resultSet.getLong(7)); + project.issueStats().setNewCount(resultSet.getLong(8)); + project.issueStats().setOngoingCount(resultSet.getLong(9)); + project.issueStats().setResolvedCount(resultSet.getLong(10)); + project.issueStats().setClosedCount(resultSet.getLong(11)); + project.issueStats().setRejectedCount(resultSet.getLong(12)); + project.issueStats().setConfirmedCount(resultSet.getLong(13)); + project.issueStats().setMaybeCount(resultSet.getLong(14)); + project.issueStats().setWaitingCount(resultSet.getLong(15)); + + project.issueStats().setUnassignedCount(resultSet.getLong(16)); + project.issueStats().setUnassignedNewCount(resultSet.getLong(17)); + project.issueStats().setUnassignedOngoingCount(resultSet.getLong(18)); + project.issueStats().setUnassignedResolvedCount(resultSet.getLong(19)); + project.issueStats().setUnassignedClosedCount(resultSet.getLong(20)); + project.issueStats().setUnassignedRejectedCount(resultSet.getLong(21)); + project.issueStats().setUnassignedConfirmedCount(resultSet.getLong(22)); + project.issueStats().setUnassignedMaybeCount(resultSet.getLong(23)); + project.issueStats().setUnassignedWaitingCount(resultSet.getLong(24)); + + project.issueStats().setFirstCreate(SQLUtils.toLocalDateTime(resultSet.getTimestamp(25))); + project.issueStats().setLastUpdate(SQLUtils.toLocalDateTime(resultSet.getTimestamp(26))); + + result.add(project); + } + } + catch (SQLException exception) + { + throw new AgirStatoolException("Error reading projects extended: " + exception.getMessage(), exception); + } + finally + { + SQLUtils.closeQuietly(statement, resultSet); + } + + // + return result; + } + + /** + * List projects consolidated. + * + * @return the projects + * @throws AgirStatoolException + * the agir statool exception + */ + public Projects fetchProjectsWithSubStats() throws AgirStatoolException + { + Projects result; + + result = fetchProjectsWithStats(Project.Type.CONSOLIDATED); + + // + return result; + } + /** * Fetch week concluded count. * @@ -247,7 +503,7 @@ public class AgirStatool * @throws AgirStatoolException * the agir statool exception */ - public DateCountMap fetchWeekConcludedCount(final Project project) throws AgirStatoolException + public DateCountMap fetchWeekClosedOnCount(final Project project) throws AgirStatoolException { DateCountMap result; @@ -458,7 +714,7 @@ public class AgirStatool result = new Project(id, identifier, name, parentId); result.setChildCount(resultSet.getLong(5)); - result.setLastUpdate(AgirStatoolUtils.toLocaleDateTime(resultSet.getTimestamp(6))); + result.setLastUpdate(SQLUtils.toLocalDateTime(resultSet.getTimestamp(6))); result.issueStats().setCount(resultSet.getLong(7)); result.issueStats().setNewCount(resultSet.getLong(8)); result.issueStats().setOngoingCount(resultSet.getLong(9)); @@ -468,8 +724,8 @@ public class AgirStatool result.issueStats().setConfirmedCount(resultSet.getLong(13)); result.issueStats().setMaybeCount(resultSet.getLong(14)); result.issueStats().setWaitingCount(resultSet.getLong(15)); - result.issueStats().setFirstCreate(AgirStatoolUtils.toLocaleDateTime(resultSet.getTimestamp(16))); - result.issueStats().setLastUpdate(AgirStatoolUtils.toLocaleDateTime(resultSet.getTimestamp(17))); + result.issueStats().setFirstCreate(SQLUtils.toLocalDateTime(resultSet.getTimestamp(16))); + result.issueStats().setLastUpdate(SQLUtils.toLocalDateTime(resultSet.getTimestamp(17))); } } catch (SQLException exception) @@ -587,7 +843,7 @@ public class AgirStatool Project project = new Project(id, identifier, name, parentId); project.setChildCount(resultSet.getLong(5)); - project.setLastUpdate(AgirStatoolUtils.toLocaleDateTime(resultSet.getTimestamp(6))); + project.setLastUpdate(SQLUtils.toLocalDateTime(resultSet.getTimestamp(6))); result.add(project); } @@ -638,13 +894,17 @@ public class AgirStatool // Fill created and concluded issues history. { + { + Issues issues = fetchIssue(result); + result.issues().addAll(issues); + } { DateCountMap map = fetchWeekCreatedCount(result); DateCountList counts = AgirStatoolUtils.normalizedWeekCountList(map, result.issueStats().getFirstCreate().toLocalDate()); result.issueStats().setWeekCreatedIssueCounts(counts); } { - DateCountMap map = fetchWeekConcludedCount(result); + DateCountMap map = fetchWeekClosedOnCount(result); DateCountList counts = AgirStatoolUtils.normalizedWeekCountList(map, result.issueStats().getFirstCreate().toLocalDate()); result.issueStats().setWeekConcludedIssueCounts(counts); } @@ -654,13 +914,17 @@ public class AgirStatool logger.debug("Fetching Created/Closed history for " + project.getName()); if (project.hasIssue()) { + { + Issues issues = fetchIssue(project); + project.issues().addAll(issues); + } { DateCountMap map = fetchWeekCreatedCount(project); DateCountList counts = AgirStatoolUtils.normalizedWeekCountList(map, project.issueStats().getFirstCreate().toLocalDate()); project.issueStats().setWeekCreatedIssueCounts(counts); } { - DateCountMap map = fetchWeekConcludedCount(project); + DateCountMap map = fetchWeekClosedOnCount(project); DateCountList counts = AgirStatoolUtils.normalizedWeekCountList(map, project.issueStats().getFirstCreate().toLocalDate()); project.issueStats().setWeekConcludedIssueCounts(counts); } @@ -687,175 +951,6 @@ public class AgirStatool return result; } - /** - * List projects extended. - * - * @return the projects - * @throws AgirStatoolException - * the agir statool exception - */ - public Projects fetchProjectsWithoutSubStats() throws AgirStatoolException - { - Projects result; - - result = fetchProjectsWithStats(Project.Type.ALONE); - // - return result; - } - - /** - * List projects with stats. - * - * @param type - * the type - * @return the projects - * @throws AgirStatoolException - * the agir statool exception - */ - public Projects fetchProjectsWithStats(final Project.Type type) throws AgirStatoolException - { - Projects result; - - result = new Projects(); - - // - PreparedStatement statement = null; - ResultSet resultSet = null; - try - { - StringList subSql = new StringList(); - if (type == Project.Type.CONSOLIDATED) - { - subSql.append("select "); - subSql.append(" id "); - subSql.append("from "); - subSql.append(" projects as childProject "); - subSql.append("where "); - subSql.append(" (childProject.id=currentProject.id or childProject.parent_id=currentProject.id)"); - subSql.append(" and childProject.status=1 and childProject.is_public=1"); - } - else - { - subSql.append("currentProject.id"); - } - - StringList sql = new StringList(); - sql.append("SELECT"); - sql.append(" id,"); - sql.append(" identifier,"); - sql.append(" name,"); - sql.append(" parent_id,"); - sql.append(" (select count(*) from projects as subproject where subproject.parent_id=currentProject.id and subproject.status = 1 and subproject.is_public = 1) as child_count, "); - sql.append(" updated_on,"); - - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ")) as issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 1) as new_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 2) as ongoing_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 3) as resolved_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 5) as closed_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 6) as rejected_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 7) as confirmed_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id=15) as maybe_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id=16) as waiting_issue_count, "); - - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.assigned_to_id is null) as unassigned_issue_count,"); - sql.append( - " (select count(*) from issues where issues.project_id in (" + subSql.toString() + ") and issues.status_id= 1 and issues.assigned_to_id is null) as unassigned_new_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() - + ") and issues.status_id= 2 and issues.assigned_to_id is null) as unassigned_ongoing_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() - + ") and issues.status_id= 3 and issues.assigned_to_id is null) as unassigned_resolved_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() - + ") and issues.status_id= 5 and issues.assigned_to_id is null) as unassigned_closed_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() - + ") and issues.status_id= 6 and issues.assigned_to_id is null) as unassigned_rejected_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() - + ") and issues.status_id= 7 and issues.assigned_to_id is null) as unassigned_confirmed_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() - + ") and issues.status_id=15 and issues.assigned_to_id is null) as unassigned_maybe_issue_count,"); - sql.append(" (select count(*) from issues where issues.project_id in (" + subSql.toString() - + ") and issues.status_id=16 and issues.assigned_to_id is null) as unassigned_waiting_issue_count, "); - sql.append(" (select min(created_on) from issues where issues.project_id in (" + subSql.toString() + ")) as first_issue_create, "); - sql.append(" (select max(updated_on) from issues where issues.project_id in (" + subSql.toString() + ")) as last_issue_update "); - - sql.append("FROM "); - sql.append(" projects as currentProject "); - sql.append("WHERE "); - sql.append(" currentProject.status=1 and currentProject.is_public=1;"); - - // System.out.println(sql.toStringSeparatedBy("\n")); - - this.connection.setAutoCommit(true); - statement = this.connection.prepareStatement(sql.toString()); - resultSet = statement.executeQuery(); - - while (resultSet.next()) - { - long id = resultSet.getLong(1); - String identifier = resultSet.getString(2); - String name = resultSet.getString(3); - Long parentId = SQLUtils.getNullableLong(resultSet, 4); - - Project project = new Project(id, identifier, name, parentId); - project.setChildCount(resultSet.getLong(5)); - project.setLastUpdate(AgirStatoolUtils.toLocaleDateTime(resultSet.getTimestamp(6))); - - project.issueStats().setCount(resultSet.getLong(7)); - project.issueStats().setNewCount(resultSet.getLong(8)); - project.issueStats().setOngoingCount(resultSet.getLong(9)); - project.issueStats().setResolvedCount(resultSet.getLong(10)); - project.issueStats().setClosedCount(resultSet.getLong(11)); - project.issueStats().setRejectedCount(resultSet.getLong(12)); - project.issueStats().setConfirmedCount(resultSet.getLong(13)); - project.issueStats().setMaybeCount(resultSet.getLong(14)); - project.issueStats().setWaitingCount(resultSet.getLong(15)); - - project.issueStats().setUnassignedCount(resultSet.getLong(16)); - project.issueStats().setUnassignedNewCount(resultSet.getLong(17)); - project.issueStats().setUnassignedOngoingCount(resultSet.getLong(18)); - project.issueStats().setUnassignedResolvedCount(resultSet.getLong(19)); - project.issueStats().setUnassignedClosedCount(resultSet.getLong(20)); - project.issueStats().setUnassignedRejectedCount(resultSet.getLong(21)); - project.issueStats().setUnassignedConfirmedCount(resultSet.getLong(22)); - project.issueStats().setUnassignedMaybeCount(resultSet.getLong(23)); - project.issueStats().setUnassignedWaitingCount(resultSet.getLong(24)); - - project.issueStats().setFirstCreate(AgirStatoolUtils.toLocaleDateTime(resultSet.getTimestamp(25))); - project.issueStats().setLastUpdate(AgirStatoolUtils.toLocaleDateTime(resultSet.getTimestamp(26))); - - result.add(project); - } - } - catch (SQLException exception) - { - throw new AgirStatoolException("Error reading projects extended: " + exception.getMessage(), exception); - } - finally - { - SQLUtils.closeQuietly(statement, resultSet); - } - - // - return result; - } - - /** - * List projects consolidated. - * - * @return the projects - * @throws AgirStatoolException - * the agir statool exception - */ - public Projects fetchProjectsWithSubStats() throws AgirStatoolException - { - Projects result; - - result = fetchProjectsWithStats(Project.Type.CONSOLIDATED); - - // - return result; - } - public void putTouchFile() { diff --git a/src/org/april/agirstatool/core/AgirStatoolUtils.java b/src/org/april/agirstatool/core/AgirStatoolUtils.java index 074bf89..d9f9330 100644 --- a/src/org/april/agirstatool/core/AgirStatoolUtils.java +++ b/src/org/april/agirstatool/core/AgirStatoolUtils.java @@ -20,7 +20,6 @@ package org.april.agirstatool.core; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Locale; @@ -47,6 +46,162 @@ public class AgirStatoolUtils public static final DateTimeFormatter PATTERN_SHORTDATE = DateTimeFormatter.ofPattern("dd/MM/yyyy", Locale.FRANCE); public static final DateTimeFormatter PATTERN_LONGDATE = DateTimeFormatter.ofPattern("dd/MM/yyyy hh':'mm", Locale.FRANCE); + /** + * Builds the week labels. + * + * @param start + * the start + * @return the string list + */ + public static StringList buildWeekLabels(final LocalDate start) + { + StringList result; + + result = buildWeekLabels(start, LocalDate.now()); + + // + return result; + } + + /** + * Builds the week labels. + * + * @param start + * the start + * @param end + * the end + * @return the string list + */ + public static StringList buildWeekLabels(final LocalDate start, final LocalDate end) + { + StringList result; + + result = new StringList(); + + if (start != null) + { + LocalDate normalizedEnd = AgirStatoolUtils.normaliseWeekDate(end); + LocalDate date = AgirStatoolUtils.normaliseWeekDate(start); + while (date.isBefore(normalizedEnd) || date.isEqual(normalizedEnd)) + { + String label = date.format(DateTimeFormatter.ofPattern("yyyy-MMM", Locale.FRANCE)); + result.add(label); + date = date.plusWeeks(1); + } + } + + // + return result; + } + + /** + * Builds the week max ages. + * + * @param project + * the project + * @param start + * the start + * @param end + * the end + * @return the string list + */ + public static StringList buildWeekMaxAges(final Project project, final LocalDate start, final LocalDate end) + { + StringList result; + + result = new StringList(); + + if (start != null) + { + LocalDate date = AgirStatoolUtils.normaliseWeekDate(start); + LocalDate normalizedEnd = AgirStatoolUtils.normaliseWeekDate(end); + while (date.isBefore(normalizedEnd) || date.isEqual(normalizedEnd)) + { + Stat stat = project.issues().extractActivedAt(date).computeStat(date); + + result.add(String.valueOf(stat.getMax())); + + // + date = date.plusWeeks(1); + } + } + + // + return result; + } + + /** + * Builds the week mean ages. + * + * @param project + * the project + * @param start + * the start + * @param end + * the end + * @return the string list + */ + public static StringList buildWeekMeanAges(final Project project, final LocalDate start, final LocalDate end) + { + StringList result; + + result = new StringList(); + + if (start != null) + { + LocalDate date = AgirStatoolUtils.normaliseWeekDate(start); + LocalDate normalizedEnd = AgirStatoolUtils.normaliseWeekDate(end); + while (date.isBefore(normalizedEnd) || date.isEqual(normalizedEnd)) + { + Stat stat = project.issues().extractActivedAt(date).computeStat(date); + + result.add(String.format(Locale.ENGLISH, "%.2f", stat.getMean())); + + // + date = date.plusWeeks(1); + } + } + + // + return result; + } + + /** + * Builds the week min ages. + * + * @param project + * the project + * @param start + * the start + * @param end + * the end + * @return the string list + */ + public static StringList buildWeekMinAges(final Project project, final LocalDate start, final LocalDate end) + { + StringList result; + + result = new StringList(); + + if (start != null) + { + LocalDate date = AgirStatoolUtils.normaliseWeekDate(start); + LocalDate normalizedEnd = AgirStatoolUtils.normaliseWeekDate(end); + while (date.isBefore(normalizedEnd) || date.isEqual(normalizedEnd)) + { + Stat stat = project.issues().extractActivedAt(date).computeStat(date); + + result.add(String.valueOf(stat.getMin())); + + // + date = date.plusWeeks(1); + } + } + + // + return result; + } + /** * Normalise week date. * @@ -376,30 +531,6 @@ public class AgirStatoolUtils return result; } - /** - * To date time. - * - * @param source - * the source - * @return the local date time - */ - public static LocalDateTime toLocaleDateTime(final java.sql.Timestamp source) - { - LocalDateTime result; - - if (source == null) - { - result = null; - } - else - { - result = LocalDateTime.ofEpochSecond(source.getTime() / 1000, 0, ZoneOffset.UTC); - } - - // - return result; - } - /** * To year week. * diff --git a/src/org/april/agirstatool/core/Issue.java b/src/org/april/agirstatool/core/Issue.java new file mode 100644 index 0000000..f03bfc5 --- /dev/null +++ b/src/org/april/agirstatool/core/Issue.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 Christian Pierre MOMON + * + * This file is part of AgirStatool, simple key value database. + * + * AgirStatool is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * AgirStatool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with AgirStatool. If not, see . + */ +package org.april.agirstatool.core; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; + +/** + * The Class Issue. + */ +public class Issue +{ + private int id; + private Integer projectId; + private LocalDateTime createdOn; + private LocalDateTime closedOn; + + /** + * Instantiates a new issue. + * + * @param id + * the id + * @param createdOn + * the created on + */ + public Issue(final int id, final Integer projectId, final LocalDateTime createdOn) + { + this(id, projectId, createdOn, null); + } + + /** + * Instantiates a new issue. + * + * @param id + * the id + * @param createdOn + * the created on + * @param closedOn + * the closed on + */ + public Issue(final int id, final Integer projectId, final LocalDateTime createdOn, final LocalDateTime closedOn) + { + this.id = id; + this.projectId = projectId; + this.createdOn = createdOn; + this.closedOn = closedOn; + } + + /** + * Age in days. + * + * @return the int + */ + public int getAgeInDays() + { + int result; + + long start = this.createdOn.toEpochSecond(ZoneOffset.UTC); + long end; + if (this.closedOn == null) + { + end = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC); + } + else + { + end = this.closedOn.toEpochSecond(ZoneOffset.UTC); + } + + result = (int) ((end - start) / (24 * 60 * 60)); + + // + return result; + } + + /** + * Gets the age in days. + * + * @param date + * the date + * @return the age in days + */ + public int getAgeInDays(final LocalDate date) + { + int result; + + if (date == null) + { + result = 0; + } + else if ((this.closedOn != null) && (this.closedOn.isBefore(LocalDateTime.of(date, LocalTime.MAX)))) + { + long start = this.createdOn.toEpochSecond(ZoneOffset.UTC); + long end = this.closedOn.toEpochSecond(ZoneOffset.UTC); + + result = (int) ((end - start) / (24 * 60 * 60)); + } + else + { + long start = this.createdOn.toEpochSecond(ZoneOffset.UTC); + long end = LocalDateTime.of(date, LocalTime.MAX).toEpochSecond(ZoneOffset.UTC); + + result = (int) ((end - start) / (24 * 60 * 60)); + } + + // + return result; + } + + public LocalDateTime getClosedOn() + { + return this.closedOn; + } + + public LocalDateTime getCreatedOn() + { + return this.createdOn; + } + + public int getId() + { + return this.id; + } + + public Integer getProjectId() + { + return this.projectId; + } + + public void setClosedOn(final LocalDateTime closedOn) + { + this.closedOn = closedOn; + } + + public void setCreatedOn(final LocalDateTime createdOn) + { + this.createdOn = createdOn; + } + + public void setId(final int id) + { + this.id = id; + } + + public void setProjectId(final Integer projectId) + { + this.projectId = projectId; + } +} diff --git a/src/org/april/agirstatool/core/Issues.java b/src/org/april/agirstatool/core/Issues.java new file mode 100644 index 0000000..58fdd3a --- /dev/null +++ b/src/org/april/agirstatool/core/Issues.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2020 Christian Pierre MOMON + * + * This file is part of AgirStatool, simple key value database. + * + * AgirStatool is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * AgirStatool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with AgirStatool. If not, see . + */ +package org.april.agirstatool.core; + +import java.time.LocalDate; +import java.util.ArrayList; + +/** + * The Class IssueList. + */ +public class Issues extends ArrayList +{ + private static final long serialVersionUID = -6241164269103539500L; + + /** + * Instantiates a new issue list. + */ + public Issues() + { + super(); + } + + /** + * Instantiates a new issue list. + * + * @param capacity + * the capacity + */ + public Issues(final int capacity) + { + super(capacity); + } + + /** + * Compute stat. + * + * @param date + * the date + * @return the stat + */ + public Stat computeStat() + { + Stat result; + + result = new Stat(); + for (Issue issue : this) + { + int age = issue.getAgeInDays(); + result.addValue(age); + } + + // + return result; + } + + /** + * Compute stat. + * + * @param date + * the date + * @return the stat + */ + public Stat computeStat(final LocalDate date) + { + Stat result; + + result = new Stat(); + for (Issue issue : this) + { + int age = issue.getAgeInDays(date); + result.addValue(age); + } + + // + return result; + } + + /** + * Extract aticved at. + * + * @param date + * the date + * @return the issue list + */ + public Issues extractActivedAt(final LocalDate date) + { + Issues result; + + result = new Issues(); + + for (Issue issue : this) + { + LocalDate createdOn = issue.getCreatedOn().toLocalDate(); + LocalDate closedOn; + if (issue.getClosedOn() == null) + { + closedOn = null; + } + else + { + closedOn = issue.getClosedOn().toLocalDate(); + } + + if ((!createdOn.isAfter(date)) && ((issue.getClosedOn() == null) || (!closedOn.isBefore(date)))) + { + result.add(issue); + } + } + + // + return result; + } +} \ No newline at end of file diff --git a/src/org/april/agirstatool/core/Project.java b/src/org/april/agirstatool/core/Project.java index 09f4ca1..08fb56b 100644 --- a/src/org/april/agirstatool/core/Project.java +++ b/src/org/april/agirstatool/core/Project.java @@ -41,6 +41,7 @@ public class Project private Projects subProjects; private IssueStats stats; private LocalDateTime lastUpdate; + private Issues issues; /** * Instantiates a new project. @@ -64,6 +65,7 @@ public class Project this.subProjects = new Projects(); this.childCount = 0; this.stats = new IssueStats(); + this.issues = new Issues(); } public long getChildCount() @@ -171,6 +173,11 @@ public class Project return result; } + public Issues issues() + { + return this.issues; + } + public IssueStats issueStats() { return this.stats; diff --git a/src/org/april/agirstatool/core/Stat.java b/src/org/april/agirstatool/core/Stat.java new file mode 100644 index 0000000..79d604a --- /dev/null +++ b/src/org/april/agirstatool/core/Stat.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2020 Christian Pierre MOMON + * + * This file is part of AgirStatool, simple key value database. + * + * AgirStatool is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * AgirStatool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with AgirStatool. If not, see . + */ +package org.april.agirstatool.core; + +/** + * The Class Stat. + */ +public class Stat +{ + int count; + double total; + double min; + double max; + + /** + * Instantiates a new stat. + */ + public Stat() + { + this.count = 0; + this.total = 0; + this.min = 0; + this.max = 0; + } + + /** + * Adds the value. + * + * @param value + * the value + */ + public void addValue(final double value) + { + if (this.count == 0) + { + this.total = value; + this.min = value; + this.max = value; + } + else + { + // + if (value < this.min) + { + this.min = value; + } + + // + this.total += value; + + // + if (value > this.max) + { + this.max = value; + } + } + + this.count += 1; + } + + public int getCount() + { + return this.count; + } + + public double getMax() + { + return this.max; + } + + /** + * Gets the mean. + * + * @return the mean + */ + public double getMean() + { + double result; + + result = this.total / this.count; + + // + return result; + } + + public double getMin() + { + return this.min; + } + + public double getTotal() + { + return this.total; + } + + public void setCount(final int count) + { + this.count = count; + } + + public void setMax(final double max) + { + this.max = max; + } + + public void setMin(final double min) + { + this.min = min; + } + + public void setTotal(final double total) + { + this.total = total; + } +} diff --git a/src/org/april/agirstatool/core/pages/CreatedClosedCountChartView.java b/src/org/april/agirstatool/core/pages/CreatedClosedCountChartView.java index ead493c..032348b 100644 --- a/src/org/april/agirstatool/core/pages/CreatedClosedCountChartView.java +++ b/src/org/april/agirstatool/core/pages/CreatedClosedCountChartView.java @@ -20,8 +20,6 @@ package org.april.agirstatool.core.pages; import java.io.IOException; import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Locale; import org.apache.commons.codec.digest.DigestUtils; import org.april.agirstatool.charts.DateCountList; @@ -70,7 +68,7 @@ public class CreatedClosedCountChartView code = code.replaceAll("myChart", "myChart_" + DigestUtils.md5Hex(title + "lineChart")); - StringList labels = buildWeekLabels(start, end); + StringList labels = AgirStatoolUtils.buildWeekLabels(start, end); code = code.replaceAll("labels: \\[.*\\]", "labels: " + AgirStatoolUtils.toJSonStrings(labels)); DateCountList dates = project.issueStats().getWeekCreatedIssueCounts(); @@ -123,7 +121,7 @@ public class CreatedClosedCountChartView code = code.replaceAll("myChart", "myChart_" + DigestUtils.md5Hex(title + "lineBar")); - StringList labels = buildWeekLabels(project.issueStats().getFirstCreate().toLocalDate()); + StringList labels = AgirStatoolUtils.buildWeekLabels(project.issueStats().getFirstCreate().toLocalDate()); code = code.replaceAll("labels: \\[.*\\]", "labels: " + AgirStatoolUtils.toJSonStrings(labels)); StringList values = project.issueStats().getWeekCreatedIssueCounts().toValueList(); @@ -192,54 +190,6 @@ public class CreatedClosedCountChartView return result; } - /** - * Builds the week labels. - * - * @param start - * the start - * @return the string list - */ - private static StringList buildWeekLabels(final LocalDate start) - { - StringList result; - - result = buildWeekLabels(start, LocalDate.now()); - - // - return result; - } - - /** - * Builds the week labels. - * - * @param start - * the start - * @param end - * the end - * @return the string list - */ - private static StringList buildWeekLabels(final LocalDate start, final LocalDate end) - { - StringList result; - - result = new StringList(); - - if (start != null) - { - LocalDate normalizedEnd = AgirStatoolUtils.normaliseWeekDate(end); - LocalDate date = AgirStatoolUtils.normaliseWeekDate(start); - while (date.isBefore(normalizedEnd) || date.isEqual(normalizedEnd)) - { - String label = date.format(DateTimeFormatter.ofPattern("yyyy-MMM", Locale.FRANCE)); - result.add(label); - date = date.plusWeeks(1); - } - } - - // - return result; - } - /** * Builds the year. * diff --git a/src/org/april/agirstatool/core/pages/CreatedClosedDiffChartView.java b/src/org/april/agirstatool/core/pages/CreatedClosedDiffChartView.java index 5ade9b8..92d90cd 100644 --- a/src/org/april/agirstatool/core/pages/CreatedClosedDiffChartView.java +++ b/src/org/april/agirstatool/core/pages/CreatedClosedDiffChartView.java @@ -20,8 +20,6 @@ package org.april.agirstatool.core.pages; import java.io.IOException; import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Locale; import org.apache.commons.codec.digest.DigestUtils; import org.april.agirstatool.charts.DateCount; @@ -71,7 +69,7 @@ public class CreatedClosedDiffChartView code = code.replaceAll("myChart", "myChart_" + DigestUtils.md5Hex(title + "line2Chart")); - StringList labels = buildWeekLabels(start, end); + StringList labels = AgirStatoolUtils.buildWeekLabels(start, end); code = code.replaceAll("labels: \\[.*\\]", "labels: " + AgirStatoolUtils.toJSonStrings(labels)); DateCountList createdDates = project.issueStats().getWeekCreatedIssueCounts(); @@ -177,54 +175,6 @@ public class CreatedClosedDiffChartView return result; } - /** - * Builds the week labels. - * - * @param start - * the start - * @return the string list - */ - private static StringList buildWeekLabels(final LocalDate start) - { - StringList result; - - result = buildWeekLabels(start, LocalDate.now()); - - // - return result; - } - - /** - * Builds the week labels. - * - * @param start - * the start - * @param end - * the end - * @return the string list - */ - private static StringList buildWeekLabels(final LocalDate start, final LocalDate end) - { - StringList result; - - result = new StringList(); - - if (start != null) - { - LocalDate normalizedEnd = AgirStatoolUtils.normaliseWeekDate(end); - LocalDate date = AgirStatoolUtils.normaliseWeekDate(start); - while (date.isBefore(normalizedEnd) || date.isEqual(normalizedEnd)) - { - String label = date.format(DateTimeFormatter.ofPattern("yyyy-MMM", Locale.FRANCE)); - result.add(label); - date = date.plusWeeks(1); - } - } - - // - return result; - } - /** * Builds the year. * diff --git a/src/org/april/agirstatool/core/pages/IssueAgeChartView.java b/src/org/april/agirstatool/core/pages/IssueAgeChartView.java new file mode 100644 index 0000000..9e1068a --- /dev/null +++ b/src/org/april/agirstatool/core/pages/IssueAgeChartView.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2020 Christian Pierre MOMON + * + * This file is part of AgirStatool, simple key value database. + * + * AgirStatool is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * AgirStatool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with AgirStatool. If not, see . + */ +package org.april.agirstatool.core.pages; + +import java.io.IOException; +import java.time.LocalDate; + +import org.apache.commons.codec.digest.DigestUtils; +import org.april.agirstatool.core.AgirStatool; +import org.april.agirstatool.core.AgirStatoolException; +import org.april.agirstatool.core.AgirStatoolUtils; +import org.april.agirstatool.core.Project; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fr.devinsy.strings.StringList; +import fr.devinsy.xidyn.utils.XidynUtils; + +/** + * The Class projectsRawPageBuilder. + */ +public class IssueAgeChartView +{ + private static Logger logger = LoggerFactory.getLogger(IssueAgeChartView.class); + + /** + * Builds the. + * + * @param title + * the title + * @param project + * the project + * @param start + * the start + * @param end + * the end + * @return the string + * @throws AgirStatoolException + * the agir statool exception + */ + public static String build(final String title, final Project project, final LocalDate start, final LocalDate end) throws AgirStatoolException + { + String result; + + try + { + if (project.hasIssue()) + { + String source = XidynUtils.load(AgirStatool.class.getResource("/org/april/agirstatool/core/pages/issueAgeChartView.xhtml")); + String code = XidynUtils.extractBodyContent(source); + + code = code.replaceAll("myChart", "myChart_" + DigestUtils.md5Hex(title + "ageStatsChart")); + + StringList labels = AgirStatoolUtils.buildWeekLabels(start, end); + code = code.replaceAll("labels: \\[.*\\]", "labels: " + AgirStatoolUtils.toJSonStrings(labels)); + + StringList values = AgirStatoolUtils.buildWeekMinAges(project, start, end); + code = code.replaceAll("data: \\[.*\\]", "data: " + AgirStatoolUtils.toJSonNumbers(values)); + + values = AgirStatoolUtils.buildWeekMeanAges(project, start, end); + code = code.replaceAll("data : \\[.*\\]", "data: " + AgirStatoolUtils.toJSonNumbers(values)); + + values = AgirStatoolUtils.buildWeekMaxAges(project, start, end); + code = code.replaceAll("data : \\[.*\\]", "data: " + AgirStatoolUtils.toJSonNumbers(values)); + + result = code.toString(); + } + else + { + result = "No issue."; + } + } + catch (IOException exception) + { + throw new AgirStatoolException("Error building ProjectsRaw view: " + exception.getMessage(), exception); + } + + // + return result; + } + + /** + * Builds the full. + * + * @param title + * the title + * @param project + * the project + * @return the string + * @throws AgirStatoolException + * the agir statool exception + */ + public static String buildFull(final String title, final Project project) throws AgirStatoolException + { + String result; + + logger.debug("Building created/concluded chart view…"); + + if (project.hasIssue()) + { + result = build(title, project, project.issueStats().getFirstCreate().toLocalDate(), LocalDate.now()); + } + else + { + result = "No issue."; + } + + // + return result; + } + + /** + * Builds the last months. + * + * @param title + * the title + * @param project + * the project + * @param monthCount + * the month count + * @return the string + * @throws AgirStatoolException + * the agir statool exception + */ + public static String buildLastMonths(final String title, final Project project, final int monthCount) throws AgirStatoolException + { + String result; + + result = build(title, project, LocalDate.now().minusMonths(monthCount), LocalDate.now()); + + // + return result; + } + + /** + * Builds the previous year. + * + * @param title + * the title + * @param project + * the project + * @return the string + * @throws AgirStatoolException + * the agir statool exception + */ + public static String buildPreviousYear(final String title, final Project project) throws AgirStatoolException + { + String result; + + result = buildYear(title, project, LocalDate.now().getYear() - 1); + + // + return result; + } + + /** + * Builds the year. + * + * @param title + * the title + * @param project + * the project + * @param year + * the year + * @return the string + * @throws AgirStatoolException + * the agir statool exception + */ + public static String buildYear(final String title, final Project project, final int year) throws AgirStatoolException + { + String result; + + LocalDate start = LocalDate.of(year, 1, 1).minusDays(7); + LocalDate end = LocalDate.of(year + 1, 1, 1).minusDays(1); + + result = build(title, project, start, end); + + // + return result; + } + +} diff --git a/src/org/april/agirstatool/core/pages/ProjectPage.java b/src/org/april/agirstatool/core/pages/ProjectPage.java index 133615b..ec72329 100644 --- a/src/org/april/agirstatool/core/pages/ProjectPage.java +++ b/src/org/april/agirstatool/core/pages/ProjectPage.java @@ -62,12 +62,16 @@ public class ProjectPage data.setContent("createdClosed3MonthsChart", CreatedClosedCountChartView.buildLastMonths("Created/closed 3 months Count", project, 3)); data.setContent("created-Closed3MonthsChart", CreatedClosedDiffChartView.buildLastMonths("Created-closed 3 months Count", project, 3)); + data.setContent("age3MonthsChart", IssueAgeChartView.buildLastMonths("Issue Age 3 months Chart", project, 3)); data.setContent("createdClosed6MonthsChart", CreatedClosedCountChartView.buildLastMonths("Created/closed 6 months Count", project, 6)); data.setContent("created-Closed6MonthsChart", CreatedClosedDiffChartView.buildLastMonths("Created-closed 6 months Count", project, 6)); + data.setContent("age6MonthsChart", IssueAgeChartView.buildLastMonths("Issue Age 6 months", project, 6)); data.setContent("createdClosedPreviousYearChart", CreatedClosedCountChartView.buildPreviousYear("Created/closed last year Count", project)); data.setContent("created-ClosedPreviousYearChart", CreatedClosedDiffChartView.buildPreviousYear("Created-closed last year Count", project)); + data.setContent("agePreviousYearChart", IssueAgeChartView.buildPreviousYear("Issue Age Previous Year Chart", project)); data.setContent("createdClosedFullChart", CreatedClosedCountChartView.buildFull("Created/closed Count", project)); data.setContent("created-ClosedFullChart", CreatedClosedDiffChartView.buildFull("Created-closed Count", project)); + data.setContent("ageFullChart", IssueAgeChartView.buildFull("Issue Age Full Chart", project)); data.setContent("issueRawChart", IssueStatChartView.build("Issue Raw Count", project)); data.setContent("issueGroupedChart", IssueStatChartView.buildGrouped("Issue Grouped Count", project)); diff --git a/src/org/april/agirstatool/core/pages/issueAgeChartView.xhtml b/src/org/april/agirstatool/core/pages/issueAgeChartView.xhtml new file mode 100644 index 0000000..f156f66 --- /dev/null +++ b/src/org/april/agirstatool/core/pages/issueAgeChartView.xhtml @@ -0,0 +1,92 @@ + + + + + Agir Statool + + + + + + + +
+ + +
+ + diff --git a/src/org/april/agirstatool/core/pages/project.xhtml b/src/org/april/agirstatool/core/pages/project.xhtml index bbdb2a8..ac45b34 100644 --- a/src/org/april/agirstatool/core/pages/project.xhtml +++ b/src/org/april/agirstatool/core/pages/project.xhtml @@ -27,20 +27,24 @@ Chapril
CREATED/CLOSED FULL CHART
- + +
@@ -135,6 +139,7 @@ { document.getElementById ('createdClosedFullChart').style.display = 'none'; document.getElementById ('created-ClosedFullChart').style.display = 'none'; + document.getElementById ('ageFullChart').style.display = 'none'; if (selection == 'CC') { @@ -144,6 +149,10 @@ { document.getElementById ('created-ClosedFullChart').style.display = 'block'; } + else if (selection == 'AGE') + { + document.getElementById ('ageFullChart').style.display = 'block'; + } }