You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
4.0 KiB

  1. <template>
  2. <v-card>
  3. <v-toolbar color="primary white--text" flat>
  4. <v-toolbar-title>Assign examples to members</v-toolbar-title>
  5. </v-toolbar>
  6. <v-card-text>
  7. <v-container fluid>
  8. <v-row>
  9. <v-card-title class="pb-0 pl-3">Select assignment strategy</v-card-title>
  10. <v-col cols="12">
  11. <v-select
  12. v-model="selectedStrategy"
  13. :items="strategies"
  14. item-text="displayName"
  15. item-value="value"
  16. outlined
  17. dense
  18. hide-details
  19. ></v-select>
  20. {{ strategies.find((strategy) => strategy.value === selectedStrategy)?.description }}
  21. The project managers have access to all examples, regardless of whether they are
  22. assigned or not.
  23. </v-col>
  24. </v-row>
  25. <v-row>
  26. <v-card-title class="pb-0 pl-3">Allocate weights</v-card-title>
  27. <v-col v-for="(member, i) in members" :key="member.id" cols="12" class="pt-0 pb-0">
  28. <v-subheader class="pl-0">{{ member.username }}</v-subheader>
  29. <v-slider v-model="workloadAllocation[i]" :max="100" class="align-center">
  30. <template #append>
  31. <v-text-field
  32. v-model="workloadAllocation[i]"
  33. class="mt-0 pt-0"
  34. type="number"
  35. style="width: 60px"
  36. ></v-text-field>
  37. </template>
  38. </v-slider>
  39. </v-col>
  40. </v-row>
  41. </v-container>
  42. </v-card-text>
  43. <v-card-actions>
  44. <v-spacer />
  45. <v-btn class="text-capitalize" text color="primary" data-test="cancel-button" @click="cancel">
  46. Cancel
  47. </v-btn>
  48. <v-btn
  49. class="text-none"
  50. text
  51. :disabled="!validateWeight || isWaiting"
  52. data-test="delete-button"
  53. @click="agree"
  54. >
  55. Assign
  56. </v-btn>
  57. </v-card-actions>
  58. <v-overlay :value="isWaiting">
  59. <v-progress-circular indeterminate size="64" />
  60. </v-overlay>
  61. </v-card>
  62. </template>
  63. <script lang="ts">
  64. import Vue from 'vue'
  65. import { MemberItem } from '~/domain/models/member/member'
  66. export default Vue.extend({
  67. data() {
  68. return {
  69. members: [] as MemberItem[],
  70. workloadAllocation: [] as number[],
  71. selectedStrategy: 'weighted_sequential',
  72. isWaiting: false
  73. }
  74. },
  75. async fetch() {
  76. this.members = await this.$repositories.member.list(this.projectId)
  77. this.workloadAllocation = this.members.map(() => Math.round(100 / this.members.length))
  78. },
  79. computed: {
  80. projectId() {
  81. return this.$route.params.id
  82. },
  83. strategies() {
  84. return [
  85. {
  86. displayName: 'Weighted sequential',
  87. value: 'weighted_sequential',
  88. description:
  89. 'Assign examples to members in order of their workload. The total weight must equal 100.'
  90. },
  91. {
  92. displayName: 'Weighted random',
  93. value: 'weighted_random',
  94. description:
  95. 'Assign examples to members randomly based on their workload. The total weight must equal 100.'
  96. },
  97. {
  98. displayName: 'Sampling without replacement',
  99. value: 'sampling_without_replacement',
  100. description: 'Assign examples to members randomly without replacement.'
  101. }
  102. ]
  103. },
  104. validateWeight(): boolean {
  105. if (this.selectedStrategy === 'sampling_without_replacement') {
  106. return true
  107. } else {
  108. return this.workloadAllocation.reduce((acc, cur) => acc + cur, 0) === 100
  109. }
  110. }
  111. },
  112. methods: {
  113. async agree() {
  114. this.isWaiting = true
  115. const workloads = this.workloadAllocation.map((weight, i) => ({
  116. weight,
  117. member_id: this.members[i].id
  118. }))
  119. await this.$repositories.assignment.bulkAssign(this.projectId, {
  120. strategy_name: this.selectedStrategy,
  121. workloads
  122. })
  123. this.isWaiting = false
  124. this.$emit('assigned')
  125. },
  126. cancel() {
  127. this.$emit('cancel')
  128. }
  129. }
  130. })
  131. </script>