add the dumb strategy to add a new feature a day in the flow
This commit is contained in:
@@ -14,13 +14,13 @@ ul {
|
||||
border: 3px solid var(--background-color);
|
||||
color: var(--background-color);
|
||||
background-color: white;
|
||||
height: var(--feature-item-height);
|
||||
min-height: var(--feature-item-height);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12pt;
|
||||
padding: 0 0.5rem;
|
||||
padding: 0 0.5rem 0.2rem;
|
||||
text-align: center;
|
||||
transition-property: border, color, background-color, font-size;
|
||||
transition-duration: 1s;
|
||||
|
||||
@@ -7,16 +7,14 @@ const hasQualityIssues = computed(() => props.feature.qualityIssue > 0)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="feature-item">
|
||||
<div class="bin">
|
||||
<div class="feature-item 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>
|
||||
{{ feature.qualityIssue }} 🔴
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -24,8 +22,8 @@ const hasQualityIssues = computed(() => props.feature.qualityIssue > 0)
|
||||
<style scoped lang="scss">
|
||||
.feature-item {
|
||||
.red-bin {
|
||||
background-color: #ff7979;
|
||||
padding: 0 0.5rem;
|
||||
border: 2px solid #ff7979;
|
||||
padding: 0 0.5rem 0.1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -23,16 +23,13 @@ const hasFeaturesInProgress = computed(
|
||||
() => featuresInProgress.value.length > 0
|
||||
)
|
||||
const hasFeaturesDone = computed(() => featuresDone.value.length > 0)
|
||||
const isLive = computed(
|
||||
() => props.step.title.toLocaleLowerCase() === 'release'
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li class="feature-step">
|
||||
<header>{{ step.title }}</header>
|
||||
<section class="doing">
|
||||
<h5>📝⌛</h5>
|
||||
<h5>📝⌛ ({{ featuresInProgress.length }})</h5>
|
||||
<ul v-if="hasFeaturesInProgress">
|
||||
<li v-for="feature in featuresInProgress" :key="feature.name">
|
||||
<Starport
|
||||
@@ -45,7 +42,7 @@ const isLive = computed(
|
||||
</ul>
|
||||
</section>
|
||||
<section class="done">
|
||||
<h5>📝✅</h5>
|
||||
<h5>📝✅ ({{ featuresDone.length }})</h5>
|
||||
<div
|
||||
v-for="blueBucket in remainingBlueBuckets"
|
||||
:key="blueBucket"
|
||||
@@ -57,7 +54,7 @@ const isLive = computed(
|
||||
<li v-for="feature in featuresDone" :key="feature.name">
|
||||
<Starport
|
||||
:port="feature.name"
|
||||
style="height: var(--feature-item-height)"
|
||||
style="height: calc(var(--feature-item-height) + 0.2rem)"
|
||||
>
|
||||
<FeatureItem :feature="feature" />
|
||||
</Starport>
|
||||
@@ -68,6 +65,22 @@ const isLive = computed(
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@mixin hideScrollbar {
|
||||
// https://blogs.msdn.microsoft.com/kurlak/2013/11/03/hiding-vertical-scrollbars-with-pure-css-in-chrome-ie-6-firefox-opera-and-safari/
|
||||
// There is a CSS rule that can hide scrollbars in Webkit-based browsers (Chrome and Safari).
|
||||
&::-webkit-scrollbar {
|
||||
width: 0 !important;
|
||||
}
|
||||
// There is a CSS rule that can hide scrollbars in IE 10+.
|
||||
-ms-overflow-style: none;
|
||||
|
||||
// Use -ms-autohiding-scrollbar if you wish to display on hover.
|
||||
// -ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
|
||||
// There used to be a CSS rule that could hide scrollbars in Firefox, but it has since been deprecated.
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.feature-step {
|
||||
header {
|
||||
padding: 0.5rem;
|
||||
@@ -76,10 +89,13 @@ const isLive = computed(
|
||||
}
|
||||
|
||||
section {
|
||||
@include hideScrollbar();
|
||||
margin: 1rem 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
max-height: 40vh;
|
||||
}
|
||||
|
||||
h5 {
|
||||
@@ -87,6 +103,7 @@ const isLive = computed(
|
||||
background-color: var(--background-color);
|
||||
padding: 0.35rem;
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
li {
|
||||
@@ -95,7 +112,6 @@ const isLive = computed(
|
||||
|
||||
.done-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,24 +8,35 @@ import { computed, onMounted, ref } from 'vue'
|
||||
|
||||
const featureBoard = createFeatureBoard()
|
||||
|
||||
const totalDays = ref(0)
|
||||
const features = ref<Feature[]>([])
|
||||
|
||||
const meanComplexity = computed(
|
||||
() =>
|
||||
sumElements(features.value.map((feature) => feature.complexity)) /
|
||||
features.value.length
|
||||
Math.round(
|
||||
100 *
|
||||
(sumElements(features.value.map((feature) => feature.complexity)) /
|
||||
features.value.length)
|
||||
) / 100
|
||||
)
|
||||
|
||||
const meanLeadTime = computed(
|
||||
() =>
|
||||
sumElements(features.value.map((feature) => feature.leadTime)) /
|
||||
features.value.length
|
||||
Math.round(
|
||||
100 *
|
||||
(sumElements(features.value.map((feature) => feature.leadTime)) /
|
||||
features.value.length)
|
||||
) / 100
|
||||
)
|
||||
|
||||
onMounted(() => (features.value = featureBoard.initBoard(featureSteps)))
|
||||
|
||||
const nextDay = () => {
|
||||
features.value = featureBoard.nextDay(features.value)
|
||||
totalDays.value++
|
||||
features.value = featureBoard.nextDay(
|
||||
features.value,
|
||||
featureSteps[0].stepIndex
|
||||
)
|
||||
}
|
||||
|
||||
const featuresGroupedByStep = computed(() => {
|
||||
@@ -51,6 +62,7 @@ const featuresGroupedByStep = computed(() => {
|
||||
</div>
|
||||
<div>
|
||||
<button @click="nextDay">next day</button>
|
||||
Total days: {{ totalDays }}
|
||||
</div>
|
||||
</div>
|
||||
<ul class="features-steps">
|
||||
|
||||
@@ -3,6 +3,8 @@ import { FeatureStep } from '@/modules/feature/feature-steps'
|
||||
import { features } from '@/modules/feature/feature.fixture'
|
||||
import { pickRandomElement, popNElement, shuffleArray } from '@/utils'
|
||||
|
||||
const MAX_FEATURES = 30
|
||||
|
||||
const hasQualityIssue = (
|
||||
complexity: number,
|
||||
tasksInParallel: number
|
||||
@@ -10,18 +12,24 @@ const hasQualityIssue = (
|
||||
let probabilityOfQualityIssue = 0
|
||||
|
||||
switch (complexity) {
|
||||
case 0:
|
||||
probabilityOfQualityIssue = 0.99
|
||||
|
||||
case 1:
|
||||
probabilityOfQualityIssue = 0.8
|
||||
probabilityOfQualityIssue = 0.93
|
||||
break
|
||||
case 2:
|
||||
probabilityOfQualityIssue = 0.7
|
||||
probabilityOfQualityIssue = 0.9
|
||||
break
|
||||
case 3:
|
||||
probabilityOfQualityIssue = 0.6
|
||||
probabilityOfQualityIssue = 0.85
|
||||
break
|
||||
case 4:
|
||||
probabilityOfQualityIssue = 0.77
|
||||
break
|
||||
|
||||
default:
|
||||
probabilityOfQualityIssue = 0.5
|
||||
probabilityOfQualityIssue = 0.65
|
||||
break
|
||||
}
|
||||
|
||||
@@ -38,6 +46,8 @@ const hasQualityIssue = (
|
||||
multiplicator = 1.1
|
||||
case 5:
|
||||
multiplicator = 1.15
|
||||
default:
|
||||
multiplicator = 1.25
|
||||
}
|
||||
|
||||
return Math.random() > probabilityOfQualityIssue / multiplicator
|
||||
@@ -58,7 +68,7 @@ export const createFeatureBoard = () => {
|
||||
return initialFeatures
|
||||
}
|
||||
|
||||
const nextDay = (features: Feature[]): Feature[] => {
|
||||
const nextDay = (features: Feature[], initialStep: number): Feature[] => {
|
||||
features.forEach((feature) => {
|
||||
const isFeatureLive = feature.step === 0 && feature.status === 'done'
|
||||
if (isFeatureLive) {
|
||||
@@ -91,6 +101,14 @@ export const createFeatureBoard = () => {
|
||||
}
|
||||
})
|
||||
|
||||
if (features.length < MAX_FEATURES) {
|
||||
const [newFeature] = popNElement(boardFeatures, 1)
|
||||
|
||||
if (newFeature) {
|
||||
features.push({ ...newFeature, step: initialStep })
|
||||
}
|
||||
}
|
||||
|
||||
return features
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ const featureNames = [
|
||||
|
||||
export const features: Feature[] = featureNames.map((name) => ({
|
||||
name,
|
||||
complexity: Math.floor(Math.random() * 5),
|
||||
complexity: Math.floor(Math.random() * 6),
|
||||
leadTime: 0,
|
||||
status: 'doing',
|
||||
step: Infinity,
|
||||
|
||||
Reference in New Issue
Block a user