add quality issue
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Cutive+Mono&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--feature-item-height: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -8,7 +14,7 @@ ul {
|
|||||||
border: 3px solid var(--background-color);
|
border: 3px solid var(--background-color);
|
||||||
color: var(--background-color);
|
color: var(--background-color);
|
||||||
background-color: white;
|
background-color: white;
|
||||||
height: 62px;
|
height: var(--feature-item-height);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -32,3 +38,8 @@ ul {
|
|||||||
color: white;
|
color: white;
|
||||||
transition-delay: 3s;
|
transition-delay: 3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.numeric {
|
||||||
|
font-family: 'Cutive Mono', monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|||||||
31
src/modules/feature/FeatureItem.vue
Normal file
31
src/modules/feature/FeatureItem.vue
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Feature } from '@/modules/feature/feature'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ feature: Feature }>()
|
||||||
|
const hasQualityIssues = computed(() => props.feature.qualityIssue > 0)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="feature-item">
|
||||||
|
<div class="bin">
|
||||||
|
<div>
|
||||||
|
{{ feature.name }}
|
||||||
|
<span class="numeric">({{ feature.complexity }})</span>
|
||||||
|
</div>
|
||||||
|
<div class="lead-time numeric">{{ feature.leadTime }} days</div>
|
||||||
|
<div v-if="hasQualityIssues" class="red-bin numeric">
|
||||||
|
{{ feature.qualityIssue }} issues
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.feature-item {
|
||||||
|
.red-bin {
|
||||||
|
background-color: #ff7979;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import FeatureItem from '@/modules/feature/FeatureItem.vue'
|
||||||
import { Feature } from '@/modules/feature/feature'
|
import { Feature } from '@/modules/feature/feature'
|
||||||
import { FeatureStep } from '@/modules/feature/feature-steps'
|
import { FeatureStep } from '@/modules/feature/feature-steps'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
@@ -34,13 +35,11 @@ const isLive = computed(
|
|||||||
<h5>📝⌛</h5>
|
<h5>📝⌛</h5>
|
||||||
<ul v-if="hasFeaturesInProgress">
|
<ul v-if="hasFeaturesInProgress">
|
||||||
<li v-for="feature in featuresInProgress" :key="feature.name">
|
<li v-for="feature in featuresInProgress" :key="feature.name">
|
||||||
<Starport :port="feature.name" style="height: 62px">
|
<Starport
|
||||||
<div class="bin">
|
:port="feature.name"
|
||||||
<div>
|
style="height: var(--feature-item-height)"
|
||||||
{{ feature.name }}
|
>
|
||||||
</div>
|
<FeatureItem :feature="feature" />
|
||||||
<div class="lead-time">{{ feature.leadTime }} days</div>
|
|
||||||
</div>
|
|
||||||
</Starport>
|
</Starport>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -56,13 +55,11 @@ const isLive = computed(
|
|||||||
</div>
|
</div>
|
||||||
<ul class="done-list" v-if="hasFeaturesDone">
|
<ul class="done-list" v-if="hasFeaturesDone">
|
||||||
<li v-for="feature in featuresDone" :key="feature.name">
|
<li v-for="feature in featuresDone" :key="feature.name">
|
||||||
<Starport :port="feature.name" style="height: 62px">
|
<Starport
|
||||||
<div class="bin">
|
:port="feature.name"
|
||||||
<div>
|
style="height: var(--feature-item-height)"
|
||||||
{{ feature.name }}
|
>
|
||||||
</div>
|
<FeatureItem :feature="feature" />
|
||||||
<div class="lead-time">{{ feature.leadTime }} days</div>
|
|
||||||
</div>
|
|
||||||
</Starport>
|
</Starport>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -71,11 +68,7 @@ const isLive = computed(
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Cutive+Mono&display=swap');
|
|
||||||
|
|
||||||
.feature-step {
|
.feature-step {
|
||||||
--success-color: #20bf6b;
|
|
||||||
|
|
||||||
header {
|
header {
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border: solid 2px var(--background-color);
|
border: solid 2px var(--background-color);
|
||||||
@@ -100,11 +93,6 @@ const isLive = computed(
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lead-time {
|
|
||||||
font-family: 'Cutive Mono', monospace;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.done-list {
|
.done-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@@ -3,6 +3,46 @@ import { FeatureStep } from '@/modules/feature/feature-steps'
|
|||||||
import { features } from '@/modules/feature/feature.fixture'
|
import { features } from '@/modules/feature/feature.fixture'
|
||||||
import { pickRandomElement, popNElement, shuffleArray } from '@/utils'
|
import { pickRandomElement, popNElement, shuffleArray } from '@/utils'
|
||||||
|
|
||||||
|
const hasQualityIssue = (
|
||||||
|
complexity: number,
|
||||||
|
tasksInParallel: number
|
||||||
|
): boolean => {
|
||||||
|
let probabilityOfQualityIssue = 0
|
||||||
|
|
||||||
|
switch (complexity) {
|
||||||
|
case 1:
|
||||||
|
probabilityOfQualityIssue = 0.8
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
probabilityOfQualityIssue = 0.7
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
probabilityOfQualityIssue = 0.6
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
probabilityOfQualityIssue = 0.5
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let multiplicator = 1
|
||||||
|
|
||||||
|
switch (tasksInParallel) {
|
||||||
|
case 1:
|
||||||
|
multiplicator = 1
|
||||||
|
case 2:
|
||||||
|
multiplicator = 1.05
|
||||||
|
case 3:
|
||||||
|
multiplicator = 1.08
|
||||||
|
case 4:
|
||||||
|
multiplicator = 1.1
|
||||||
|
case 5:
|
||||||
|
multiplicator = 1.15
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.random() > probabilityOfQualityIssue / multiplicator
|
||||||
|
}
|
||||||
|
|
||||||
export const createFeatureBoard = () => {
|
export const createFeatureBoard = () => {
|
||||||
const boardFeatures = shuffleArray(features)
|
const boardFeatures = shuffleArray(features)
|
||||||
|
|
||||||
@@ -24,6 +64,7 @@ export const createFeatureBoard = () => {
|
|||||||
if (isFeatureLive) {
|
if (isFeatureLive) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
feature.leadTime++
|
feature.leadTime++
|
||||||
|
|
||||||
switch (feature.status) {
|
switch (feature.status) {
|
||||||
@@ -32,7 +73,20 @@ export const createFeatureBoard = () => {
|
|||||||
break
|
break
|
||||||
case 'done':
|
case 'done':
|
||||||
feature.status = 'doing'
|
feature.status = 'doing'
|
||||||
feature.step--
|
|
||||||
|
if (
|
||||||
|
hasQualityIssue(
|
||||||
|
feature.complexity,
|
||||||
|
features.filter(
|
||||||
|
(f) => f.status === 'doing' && f.step === feature.step
|
||||||
|
).length
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
feature.step = Math.min(4, feature.step + 1)
|
||||||
|
feature.qualityIssue++
|
||||||
|
} else {
|
||||||
|
feature.step--
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,24 +6,14 @@ export type FeatureStep = {
|
|||||||
|
|
||||||
export const featureSteps: FeatureStep[] = [
|
export const featureSteps: FeatureStep[] = [
|
||||||
{
|
{
|
||||||
title: 'Pitch',
|
title: 'Product',
|
||||||
stepIndex: 6,
|
stepIndex: 4,
|
||||||
blueBuckets: 2
|
blueBuckets: 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Design',
|
title: 'Design',
|
||||||
stepIndex: 5,
|
|
||||||
blueBuckets: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Investigation',
|
|
||||||
stepIndex: 4,
|
|
||||||
blueBuckets: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Product',
|
|
||||||
stepIndex: 3,
|
stepIndex: 3,
|
||||||
blueBuckets: 2
|
blueBuckets: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Development',
|
title: 'Development',
|
||||||
|
|||||||
@@ -208,5 +208,6 @@ export const features: Feature[] = featureNames.map((name) => ({
|
|||||||
complexity: Math.floor(Math.random() * 5),
|
complexity: Math.floor(Math.random() * 5),
|
||||||
leadTime: 0,
|
leadTime: 0,
|
||||||
status: 'doing',
|
status: 'doing',
|
||||||
step: Infinity
|
step: Infinity,
|
||||||
|
qualityIssue: 0
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ export type Feature = {
|
|||||||
leadTime: number
|
leadTime: number
|
||||||
status: FeatureStatus
|
status: FeatureStatus
|
||||||
step: number
|
step: number
|
||||||
|
qualityIssue: number
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user