Browse Source

add coarse option for project requirement.

master
Gisle Aune 3 years ago
parent
commit
a3336b183c
  1. 4
      entities/project.go
  2. 16
      frontend/src/lib/modals/RequirementCreateModal.svelte
  3. 2
      frontend/src/lib/models/project.ts
  4. 1
      models/project.go
  5. 1
      ports/mysql/mysqlcore/models.go
  6. 14
      ports/mysql/mysqlcore/projects.sql.go
  7. 6
      ports/mysql/projects.go
  8. 7
      ports/mysql/queries/projects.sql
  9. 9
      scripts/goose-mysql/20220702121613_requirement_coarse.sql
  10. 10
      usecases/projects/result.go

4
entities/project.go

@ -36,6 +36,7 @@ type Requirement struct {
ProjectID int `json:"projectId"` ProjectID int `json:"projectId"`
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
IsCoarse bool `json:"isCoarse"`
Status models.Status `json:"status"` Status models.Status `json:"status"`
} }
@ -49,6 +50,9 @@ func (requirement *Requirement) Update(update models.RequirementUpdate) {
if update.Status != nil && update.Status.Valid() { if update.Status != nil && update.Status.Valid() {
requirement.Status = *update.Status requirement.Status = *update.Status
} }
if update.IsCoarse != nil {
requirement.IsCoarse = *update.IsCoarse
}
} }
type RequirementStat struct { type RequirementStat struct {

16
frontend/src/lib/modals/RequirementCreateModal.svelte

@ -8,6 +8,7 @@
import { getScopeContext } from "$lib/components/contexts/ScopeContext.svelte"; import { getScopeContext } from "$lib/components/contexts/ScopeContext.svelte";
import StatInput from "$lib/components/controls/StatInput.svelte"; import StatInput from "$lib/components/controls/StatInput.svelte";
import StatusSelect from "$lib/components/controls/StatusSelect.svelte"; import StatusSelect from "$lib/components/controls/StatusSelect.svelte";
import Checkbox from "$lib/components/layout/Checkbox.svelte";
import type { ProjectEntry, Requirement, RequirementInput } from "$lib/models/project"; import type { ProjectEntry, Requirement, RequirementInput } from "$lib/models/project";
import Status from "$lib/models/status"; import Status from "$lib/models/status";
import { statDiff } from "$lib/utils/stat"; import { statDiff } from "$lib/utils/stat";
@ -49,23 +50,25 @@ import { statDiff } from "$lib/utils/stat";
description: "", description: "",
stats: [], stats: [],
status: Status.Available, status: Status.Available,
isCoarse: false,
} }
projectId = project.id; projectId = project.id;
show = true; show = true;
} }
function initEdit(prev: Requirement, project: ProjectEntry) {
function initEdit(current: Requirement, project: ProjectEntry) {
requirement = { requirement = {
name: prev.name,
description: prev.description,
status: prev.status,
stats: prev.stats.map(s => ({acquired: s.acquired, required: s.required, statId: s.id})),
name: current.name,
description: current.description,
status: current.status,
stats: current.stats.map(s => ({acquired: s.acquired, required: s.required, statId: s.id})),
isCoarse: current.isCoarse,
} }
oldStats = [...requirement.stats]; oldStats = [...requirement.stats];
projectId = project.id; projectId = project.id;
requirementId = prev.id;
requirementId = current.id;
show = true; show = true;
} }
@ -118,6 +121,7 @@ import { statDiff } from "$lib/utils/stat";
<StatusSelect bind:status={requirement.status} /> <StatusSelect bind:status={requirement.status} />
<label for="stats">Stats</label> <label for="stats">Stats</label>
<StatInput showRequired bind:value={requirement.stats} /> <StatInput showRequired bind:value={requirement.stats} />
<Checkbox bind:checked={requirement.isCoarse} label="Hide 0-requirement stats." />
</ModalBody> </ModalBody>
</Modal> </Modal>
</form> </form>

2
frontend/src/lib/models/project.ts

@ -37,6 +37,7 @@ export interface Requirement {
totalAcquired: number totalAcquired: number
totalRequired: number totalRequired: number
totalPlanned: number totalPlanned: number
isCoarse: boolean
stats: StatProgressWithPlanned[] stats: StatProgressWithPlanned[]
items: Item[] items: Item[]
} }
@ -45,5 +46,6 @@ export interface RequirementInput {
name: string name: string
description: string description: string
status: Status status: Status
isCoarse: boolean
stats: StatValueInput[] stats: StatValueInput[]
} }

1
models/project.go

@ -11,4 +11,5 @@ type RequirementUpdate struct {
Name *string `json:"name"` Name *string `json:"name"`
Description *string `json:"description"` Description *string `json:"description"`
Status *Status `json:"status"` Status *Status `json:"status"`
IsCoarse *bool `json:"isCoarse"`
} }

1
ports/mysql/mysqlcore/models.go

@ -47,6 +47,7 @@ type ProjectRequirement struct {
Name string Name string
Status int Status int
Description string Description string
IsCoarse bool
} }
type ProjectRequirementStat struct { type ProjectRequirementStat struct {

14
ports/mysql/mysqlcore/projects.sql.go

@ -156,8 +156,8 @@ func (q *Queries) InsertProject(ctx context.Context, arg InsertProjectParams) (s
} }
const insertProjectRequirement = `-- name: InsertProjectRequirement :execresult const insertProjectRequirement = `-- name: InsertProjectRequirement :execresult
INSERT INTO project_requirement (scope_id, project_id, name, status, description)
VALUES (?, ?, ?, ?, ?)
INSERT INTO project_requirement (scope_id, project_id, name, status, description, is_coarse)
VALUES (?, ?, ?, ?, ?, ?)
` `
type InsertProjectRequirementParams struct { type InsertProjectRequirementParams struct {
@ -166,6 +166,7 @@ type InsertProjectRequirementParams struct {
Name string Name string
Status int Status int
Description string Description string
IsCoarse bool
} }
func (q *Queries) InsertProjectRequirement(ctx context.Context, arg InsertProjectRequirementParams) (sql.Result, error) { func (q *Queries) InsertProjectRequirement(ctx context.Context, arg InsertProjectRequirementParams) (sql.Result, error) {
@ -175,11 +176,12 @@ func (q *Queries) InsertProjectRequirement(ctx context.Context, arg InsertProjec
arg.Name, arg.Name,
arg.Status, arg.Status,
arg.Description, arg.Description,
arg.IsCoarse,
) )
} }
const listProjectRequirements = `-- name: ListProjectRequirements :many const listProjectRequirements = `-- name: ListProjectRequirements :many
SELECT id, scope_id, project_id, name, status, description FROM project_requirement WHERE project_id = ?
SELECT id, scope_id, project_id, name, status, description, is_coarse FROM project_requirement WHERE project_id = ?
` `
func (q *Queries) ListProjectRequirements(ctx context.Context, projectID int) ([]ProjectRequirement, error) { func (q *Queries) ListProjectRequirements(ctx context.Context, projectID int) ([]ProjectRequirement, error) {
@ -198,6 +200,7 @@ func (q *Queries) ListProjectRequirements(ctx context.Context, projectID int) ([
&i.Name, &i.Name,
&i.Status, &i.Status,
&i.Description, &i.Description,
&i.IsCoarse,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@ -326,7 +329,8 @@ const updateProjectRequirement = `-- name: UpdateProjectRequirement :exec
UPDATE project_requirement UPDATE project_requirement
SET name = ?, SET name = ?,
status = ?, status = ?,
description = ?
description = ?,
is_coarse = ?
WHERE id = ? AND scope_id = ? WHERE id = ? AND scope_id = ?
` `
@ -334,6 +338,7 @@ type UpdateProjectRequirementParams struct {
Name string Name string
Status int Status int
Description string Description string
IsCoarse bool
ID int ID int
ScopeID int ScopeID int
} }
@ -343,6 +348,7 @@ func (q *Queries) UpdateProjectRequirement(ctx context.Context, arg UpdateProjec
arg.Name, arg.Name,
arg.Status, arg.Status,
arg.Description, arg.Description,
arg.IsCoarse,
arg.ID, arg.ID,
arg.ScopeID, arg.ScopeID,
) )

6
ports/mysql/projects.go

@ -139,7 +139,7 @@ func (r *projectRepository) FetchRequirements(ctx context.Context, scopeID int,
return []entities.Requirement{}, []entities.RequirementStat{}, nil return []entities.Requirement{}, []entities.RequirementStat{}, nil
} }
query, args, err := squirrel.Select("id, scope_id, project_id, name, status, description").
query, args, err := squirrel.Select("id, scope_id, project_id, name, status, description, is_coarse").
From("project_requirement"). From("project_requirement").
Where(squirrel.Eq{"scope_id": scopeID}). Where(squirrel.Eq{"scope_id": scopeID}).
Where(squirrel.Eq{"id": requirementIDs}). Where(squirrel.Eq{"id": requirementIDs}).
@ -162,6 +162,7 @@ func (r *projectRepository) FetchRequirements(ctx context.Context, scopeID int,
&requirement.Name, &requirement.Name,
&requirement.Status, &requirement.Status,
&requirement.Description, &requirement.Description,
&requirement.IsCoarse,
); err != nil { ); err != nil {
return nil, nil, err return nil, nil, err
} }
@ -217,6 +218,7 @@ func (r *projectRepository) ListRequirements(ctx context.Context, projectID int)
ProjectID: row.ProjectID, ProjectID: row.ProjectID,
Name: row.Name, Name: row.Name,
Description: row.Description, Description: row.Description,
IsCoarse: row.IsCoarse,
Status: models.Status(row.Status), Status: models.Status(row.Status),
}) })
} }
@ -240,6 +242,7 @@ func (r *projectRepository) CreateRequirement(ctx context.Context, requirement e
Name: requirement.Name, Name: requirement.Name,
Status: int(requirement.Status), Status: int(requirement.Status),
Description: requirement.Description, Description: requirement.Description,
IsCoarse: requirement.IsCoarse,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -261,6 +264,7 @@ func (r *projectRepository) UpdateRequirement(ctx context.Context, requirement e
Name: requirement.Name, Name: requirement.Name,
Status: int(requirement.Status), Status: int(requirement.Status),
Description: requirement.Description, Description: requirement.Description,
IsCoarse: requirement.IsCoarse,
ID: requirement.ID, ID: requirement.ID,
ScopeID: requirement.ScopeID, ScopeID: requirement.ScopeID,
}) })

7
ports/mysql/queries/projects.sql

@ -23,14 +23,15 @@ DELETE FROM project WHERE id = ? AND scope_id = ?;
SELECT * FROM project_requirement WHERE project_id = ?; SELECT * FROM project_requirement WHERE project_id = ?;
-- name: InsertProjectRequirement :execresult -- name: InsertProjectRequirement :execresult
INSERT INTO project_requirement (scope_id, project_id, name, status, description)
VALUES (?, ?, ?, ?, ?);
INSERT INTO project_requirement (scope_id, project_id, name, status, description, is_coarse)
VALUES (?, ?, ?, ?, ?, ?);
-- name: UpdateProjectRequirement :exec -- name: UpdateProjectRequirement :exec
UPDATE project_requirement UPDATE project_requirement
SET name = ?, SET name = ?,
status = ?, status = ?,
description = ?
description = ?,
is_coarse = ?
WHERE id = ? AND scope_id = ?; WHERE id = ? AND scope_id = ?;
-- name: DeleteProjectRequirement :exec -- name: DeleteProjectRequirement :exec

9
scripts/goose-mysql/20220702121613_requirement_coarse.sql

@ -0,0 +1,9 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE project_requirement ADD COLUMN is_coarse BOOLEAN NOT NULL DEFAULT 0;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
ALTER TABLE project_requirement DROP COLUMN IF EXISTS is_coarse;
-- +goose StatementEnd

10
usecases/projects/result.go

@ -60,6 +60,7 @@ type RequirementResult struct {
TotalAcquired int `json:"totalAcquired"` TotalAcquired int `json:"totalAcquired"`
TotalRequired int `json:"totalRequired"` TotalRequired int `json:"totalRequired"`
TotalPlanned int `json:"totalPlanned"` TotalPlanned int `json:"totalPlanned"`
IsCoarse bool `json:"isCoarse"`
Stats []RequirementResultStat `json:"stats"` Stats []RequirementResultStat `json:"stats"`
Items []items.Result `json:"items"` Items []items.Result `json:"items"`
@ -150,6 +151,7 @@ func generateRequirementResult(req entities.Requirement, scope scopes.Result, re
Description: req.Description, Description: req.Description,
Status: req.Status, Status: req.Status,
StatusName: scope.StatusName(req.Status), StatusName: scope.StatusName(req.Status),
IsCoarse: req.IsCoarse,
Stats: make([]RequirementResultStat, 0, 8), Stats: make([]RequirementResultStat, 0, 8),
Items: make([]items.Result, 0, 8), Items: make([]items.Result, 0, 8),
@ -199,9 +201,11 @@ func generateRequirementResult(req entities.Requirement, scope scopes.Result, re
resReq.Stats = append(resReq.Stats, *rs) resReq.Stats = append(resReq.Stats, *rs)
} }
} }
for _, stat := range scope.Stats {
if rs := resStats[stat.ID]; rs != nil && rs.Required == 0 {
resReq.Stats = append(resReq.Stats, *rs)
if !req.IsCoarse {
for _, stat := range scope.Stats {
if rs := resStats[stat.ID]; rs != nil && rs.Required == 0 {
resReq.Stats = append(resReq.Stats, *rs)
}
} }
} }

Loading…
Cancel
Save