Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion bwh_hive/bwh_hive/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,6 @@ def get_project_activity(project: str, limit: int = 100):
"start_date",
"completed_on",
"size",
"uat_status",
):
activities.append(
{
Expand Down
30 changes: 0 additions & 30 deletions bwh_hive/bwh_hive/doctype/hive_task/hive_task.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@
"recurring_parent",
"pr_link",
"description",
"uat_section",
"uat_status",
"uat_approved_by",
"uat_date",
"github_issue_url"
],
"fields": [
Expand Down Expand Up @@ -144,32 +140,6 @@
"fieldtype": "Text Editor",
"label": "Description"
},
{
"fieldname": "uat_section",
"fieldtype": "Section Break",
"label": "UAT"
},
{
"default": "Pending",
"fieldname": "uat_status",
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "UAT Status",
"options": "Pending\nApproved\nRejected"
},
{
"fieldname": "uat_approved_by",
"fieldtype": "Link",
"label": "UAT Approved By",
"options": "User",
"read_only": 1
},
{
"fieldname": "uat_date",
"fieldtype": "Date",
"label": "UAT Date",
"read_only": 1
},
{
"fieldname": "github_issue_url",
"fieldtype": "Data",
Expand Down
17 changes: 0 additions & 17 deletions bwh_hive/bwh_hive/doctype/hive_task/hive_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ class HiveTask(Document):
start_date: DF.Date | None
status: DF.Literal["Someday", "Backlog", "To Do", "In Progress", "Done", "Blocked"]
title: DF.Data
uat_approved_by: DF.Link | None
uat_date: DF.Date | None
uat_status: DF.Literal["Pending", "Approved", "Rejected"]
# end: auto-generated types

def validate(self):
Expand Down Expand Up @@ -178,17 +175,3 @@ def _maybe_spawn_recurrence(self):
title="recurring task: assign failed",
message=f"Failed to assign {assignees} to {new_task.name}",
)

@frappe.whitelist()
def approve_uat(self):
self.uat_status = "Approved"
self.uat_approved_by = frappe.session.user
self.uat_date = today()
self.save()

@frappe.whitelist()
def reject_uat(self):
self.uat_status = "Rejected"
self.uat_approved_by = frappe.session.user
self.uat_date = today()
self.save()
2 changes: 1 addition & 1 deletion e2e/tests/app-switcher.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ test.describe("App switcher", () => {

await gotoHive(page, "/");

await page.locator('[data-slot="sidebar-header"] button').click();
await page.getByRole("button", { name: "Hive" }).first().click();
await page.getByRole("menuitem", { name: "Switch app" }).hover();

const desk = page.getByRole("menuitem", { name: "Desk" });
Expand Down
5 changes: 0 additions & 5 deletions e2e/tests/client-experience.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,6 @@ test.describe("Client Experience", () => {
await expect(panel.getByLabel("Title")).toBeVisible();
await expect(panel.getByLabel("Title")).toBeDisabled();
await expect(panel.getByLabel("Assignees")).toBeDisabled();

// UAT is the one thing a client is meant to act on.
await expect(
panel.getByRole("button", { name: /Approve/ }).first(),
).toBeVisible();
});

test("a client can raise a feature request", async ({ page, request }) => {
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/projects/ActivityTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ const FIELD_LABELS: Record<string, string> = {
status: 'status',
target_date: 'target date',
title: 'title',
uat_status: 'UAT status',
}

const DOC_LABELS: Record<string, string> = {
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/projects/ProjectHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@
</div>
</div>

<!-- Clients never see the repo: it is internal, like the
board's UAT column. -->
<!-- Clients never see the repo: it is internal. -->
<div v-if="canEdit" class="space-y-1.5 p-3">
<p class="text-xs font-medium text-ink-gray-5">GitHub</p>
<Combobox
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/components/projects/ProjectTasksTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
:assignees-by-task="assigneesByTask"
:list="list"
:readonly="readonly"
:show-uat="hasClient"
@select="emit('select', $event)"
@changed="emit('changed')"
/>
Expand All @@ -58,10 +57,8 @@ const props = withDefaults(
assigneesByTask?: Record<string, HiveTaskAssignee[]>
loading?: boolean
readonly?: boolean
/** UAT badges only mean something on a project that has a client. */
hasClient?: boolean
}>(),
{ assigneesByTask: () => ({}), loading: false, readonly: false, hasClient: true },
{ assigneesByTask: () => ({}), loading: false, readonly: false },
)

const emit = defineEmits<{ select: [task: HiveTask]; changed: [] }>()
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/components/tasks/TaskBoard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
:task="element"
:assignees="assigneesByTask[element.name]"
:depends-on="dependency(element)"
:show-uat="showUat"
:draggable="!readonly"
@select="emit('select', element)"
/>
Expand Down Expand Up @@ -73,9 +72,8 @@ const props = withDefaults(
list?: TaskListHandle
/** Clients see the board but cannot move cards. */
readonly?: boolean
showUat?: boolean
}>(),
{ assigneesByTask: () => ({}), readonly: false, showUat: true },
{ assigneesByTask: () => ({}), readonly: false },
)

const emit = defineEmits<{ select: [task: HiveTask]; changed: [] }>()
Expand Down
12 changes: 2 additions & 10 deletions frontend/src/components/tasks/TaskBoardCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,6 @@
>
<Badge variant="outline" theme="gray" label="PR" />
</a>
<Badge
v-if="showUat && task.uat_status && task.uat_status !== 'Pending'"
:theme="uatStatusTheme(task.uat_status)"
:label="`UAT ${task.uat_status}`"
variant="subtle"
/>
<Badge
v-if="task.recurrence_frequency"
variant="outline"
Expand Down Expand Up @@ -97,7 +91,7 @@ import AvatarStack from '@/components/common/AvatarStack.vue'
import PriorityBadge from '@/components/common/PriorityBadge.vue'
import { usePinnedTasks } from '@/composables/usePinnedTasks'
import { formatDate, today } from '@/lib/dates'
import { sizeTheme, uatStatusTheme } from '@/lib/status'
import { sizeTheme } from '@/lib/status'
import type { HiveTask, HiveTaskAssignee } from '@/types'

const props = withDefaults(
Expand All @@ -106,12 +100,10 @@ const props = withDefaults(
assignees?: HiveTaskAssignee[]
/** The task this one waits on, when it is on the board too. */
dependsOn?: HiveTask | null
/** Hidden on internal-only boards, where UAT means nothing. */
showUat?: boolean
/** Cursor affordance only — the column owns the drag handle. */
draggable?: boolean
}>(),
{ assignees: () => [], dependsOn: null, showUat: true, draggable: true },
{ assignees: () => [], dependsOn: null, draggable: true },
)

const emit = defineEmits<{ select: [task: HiveTask] }>()
Expand Down
68 changes: 2 additions & 66 deletions frontend/src/components/tasks/TaskPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -209,49 +209,6 @@
<TaskAttachments :task-name="task.doc.name" :read-only="!canEdit" />
</div>

<section
v-if="hasClient"
class="space-y-3 rounded-5 border border-outline-gray-2 p-3"
>
<div class="flex items-center justify-between gap-2">
<span class="text-sm font-medium text-ink-gray-6">UAT status</span>
<Badge
:label="task.doc.uat_status || 'Pending'"
:theme="uatStatusTheme(task.doc.uat_status)"
variant="subtle"
/>
</div>
<p v-if="task.doc.uat_approved_by" class="text-sm text-ink-gray-5">
{{ task.doc.uat_status === 'Approved' ? 'Approved' : 'Rejected' }} by
{{ task.doc.uat_approved_by }}
<template v-if="task.doc.uat_date">
on {{ formatDate(task.doc.uat_date) }}
</template>
</p>
<div class="flex gap-2">
<Button
class="flex-1"
variant="solid"
theme="green"
label="Approve"
icon-left="lucide-circle-check"
:loading="task.approveUat.loading"
:disabled="task.doc.uat_status === 'Approved'"
@click="reviewUat('approve')"
/>
<Button
class="flex-1"
variant="outline"
theme="red"
label="Reject"
icon-left="lucide-circle-x"
:loading="task.rejectUat.loading"
:disabled="task.doc.uat_status === 'Rejected'"
@click="reviewUat('reject')"
/>
</div>
</section>

<!-- Clients comment too; only their own comment can be deleted. -->
<TaskComments :task-name="task.doc.name" :members="members.data ?? []" />
</div>
Expand Down Expand Up @@ -293,7 +250,6 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, reactive, ref, watch } from 'vue'
import {
Badge,
BottomSheet,
Button,
DatePicker,
Expand All @@ -320,8 +276,7 @@ import { useCelebrate } from '@/composables/useCelebrate'
import { usePinnedTasks } from '@/composables/usePinnedTasks'
import { useSession } from '@/composables/useSession'
import { useTaskMutations } from '@/composables/useTaskMutations'
import { formatDate, today } from '@/lib/dates'
import { uatStatusTheme } from '@/lib/status'
import { today } from '@/lib/dates'
import {
TASK_PRIORITIES,
TASK_RECURRENCE_FREQUENCIES,
Expand Down Expand Up @@ -351,15 +306,9 @@ const { isPinned, toggle: togglePinned } = usePinnedTasks()
const { assign, unassign } = useTaskMutations()
const archive = useArchiveWithUndo('Hive Task')

interface TaskDocMethods {
approveUat: () => void
rejectUat: () => void
}

const task = useDoc<HiveTask, TaskDocMethods>({
const task = useDoc<HiveTask>({
doctype: 'Hive Task',
name: () => props.name ?? '',
methods: { approveUat: 'approve_uat', rejectUat: 'reject_uat' },
})

const project = useDoc<Pick<HiveProject, 'name' | 'client' | 'github_repo'>>({
Expand Down Expand Up @@ -410,7 +359,6 @@ const createIssue = useCall<{ issue_url: string }, { task_name: string }>({

const canEdit = computed(() => !isClient.value)
const pinned = computed(() => Boolean(props.name && isPinned(props.name)))
const hasClient = computed(() => Boolean(project.doc?.client))

const form = reactive({
title: '',
Expand Down Expand Up @@ -680,18 +628,6 @@ async function onAssigneesChange(next: unknown) {
}
}

async function reviewUat(action: 'approve' | 'reject') {
try {
if (action === 'approve') await task.approveUat.submit()
else await task.rejectUat.submit()
task.reload()
emit('changed')
toast.success(action === 'approve' ? 'UAT approved' : 'UAT rejected')
} catch {
toast.error(action === 'approve' ? 'Failed to approve UAT' : 'Failed to reject UAT')
}
}

async function convertToIssue() {
if (!props.name) return
try {
Expand Down
11 changes: 0 additions & 11 deletions frontend/src/lib/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type {
TaskPriority,
TaskSize,
TaskStatus,
UATStatus,
} from '@/types'

export type BadgeTheme = NonNullable<BadgeProps['theme']>
Expand Down Expand Up @@ -180,16 +179,6 @@ export function featureRequestPriorityTheme(
return (priority && FEATURE_REQUEST_PRIORITY_THEME[priority]) || 'gray'
}

const UAT_STATUS_THEME: Record<UATStatus, BadgeTheme> = {
Pending: 'amber',
Approved: 'green',
Rejected: 'red',
}

export function uatStatusTheme(status: UATStatus | null | undefined): BadgeTheme {
return (status && UAT_STATUS_THEME[status]) || 'gray'
}

/** Position in a fixed vocabulary; unknown values sort last, not first. */
function rankIn<T>(order: T[], value: T): number {
const index = order.indexOf(value)
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/pages/ProjectDetailPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,6 @@ const tasks = useList<HiveTask>({
'due_date',
'completed_on',
'pr_link',
'uat_status',
'recurrence_frequency',
'recurrence_end_date',
'creation',
Expand Down Expand Up @@ -372,7 +371,6 @@ const panelProps = computed<Record<string, unknown>>(() => {
assigneesByTask: assignees.data ?? {},
loading: tasks.loading && !tasks.data,
readonly: isClient.value,
hasClient: Boolean(project.doc?.client),
}
}
})
Expand Down
1 change: 0 additions & 1 deletion frontend/src/pages/TasksPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ const tasks = useList<HiveTask>({
'due_date',
'completed_on',
'pr_link',
'uat_status',
'recurrence_frequency',
'recurrence_end_date',
'creation',
Expand Down
6 changes: 0 additions & 6 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ export type FeatureRequestStatus = (typeof FEATURE_REQUEST_STATUSES)[number]
export const FEATURE_REQUEST_PRIORITIES = ['Nice to Have', 'Important', 'Critical'] as const
export type FeatureRequestPriority = (typeof FEATURE_REQUEST_PRIORITIES)[number]

export const UAT_STATUSES = ['Pending', 'Approved', 'Rejected'] as const
export type UATStatus = (typeof UAT_STATUSES)[number]

export type Bool = 0 | 1

export interface HiveProjectLink {
Expand Down Expand Up @@ -105,9 +102,6 @@ export interface HiveTask {
completed_on: string | null
pr_link: string | null
github_issue_url: string | null
uat_status: UATStatus
uat_approved_by: string | null
uat_date: string | null
recurrence_frequency: TaskRecurrenceFrequency | '' | null
recurrence_end_date: string | null
recurring_parent: string | null
Expand Down
Loading