• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacklok / codegate-ui / 13162444531

05 Feb 2025 04:52PM UTC coverage: 70.24% (+0.8%) from 69.459%
13162444531

Pull #268

github

web-flow
Merge 04c4eade5 into ba35ff48a
Pull Request #268: feat: enforce sensible defaults for react-query

378 of 603 branches covered (62.69%)

Branch coverage included in aggregate %.

20 of 22 new or added lines in 11 files covered. (90.91%)

2 existing lines in 2 files now uncovered.

821 of 1104 relevant lines covered (74.37%)

77.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.78
/src/features/workspace/components/workspaces-selection.tsx
1
import { useListWorkspaces } from "@/features/workspace/hooks/use-list-workspaces";
2
import {
3
  Button,
4
  DialogTrigger,
5
  Input,
6
  LinkButton,
7
  ListBox,
8
  ListBoxItem,
9
  Popover,
10
  SearchField,
11
  Separator,
12
} from "@stacklok/ui-kit";
13
import { useQueryClient } from "@tanstack/react-query";
14
import { useState } from "react";
15
import { useMutationActivateWorkspace } from "../hooks/use-mutation-activate-workspace";
16
import clsx from "clsx";
17
import { useActiveWorkspaceName } from "../hooks/use-active-workspace-name";
18
import { hrefs } from "@/lib/hrefs";
19
import { twMerge } from "tailwind-merge";
20
import ChevronDown from "@untitled-ui/icons-react/build/cjs/ChevronDown";
21
import { SearchMd, Settings01 } from "@untitled-ui/icons-react";
22

23
export function WorkspacesSelection() {
24
  const queryClient = useQueryClient();
9✔
25

26
  const { data: workspacesResponse } = useListWorkspaces();
9✔
27
  const { mutateAsync: activateWorkspace } = useMutationActivateWorkspace();
9✔
28

29
  const { data: activeWorkspaceName } = useActiveWorkspaceName();
9✔
30

31
  const [isOpen, setIsOpen] = useState(false);
9✔
32
  const [searchWorkspace, setSearchWorkspace] = useState("");
9✔
33
  const workspaces = workspacesResponse?.workspaces ?? [];
9✔
34
  const filteredWorkspaces = workspaces.filter((workspace) =>
9✔
35
    workspace.name.toLowerCase().includes(searchWorkspace.toLowerCase()),
20✔
36
  );
37

38
  const handleWorkspaceClick = (name: string) => {
9✔
39
    activateWorkspace({ body: { name } }).then(() => {
×
40
      // eslint-disable-next-line no-restricted-syntax
NEW
41
      queryClient.invalidateQueries({ refetchType: "all" }); // Global setting, refetch **everything**
×
UNCOV
42
      setIsOpen(false);
×
43
    });
44
  };
45

46
  return (
47
    <DialogTrigger isOpen={isOpen} onOpenChange={(test) => setIsOpen(test)}>
1✔
48
      <Button variant="tertiary" className="flex cursor-pointer">
49
        Workspace {activeWorkspaceName ?? "default"}
13✔
50
        <ChevronDown />
51
      </Button>
52

53
      <Popover className="w-[32rem] p-3" placement="bottom left">
54
        <div>
55
          <div>
56
            <SearchField
57
              onChange={setSearchWorkspace}
58
              autoFocus
59
              aria-label="search"
60
            >
61
              <Input icon={<SearchMd />} />
62
            </SearchField>
63
          </div>
64

65
          <ListBox
66
            aria-label="Workspaces"
67
            items={filteredWorkspaces}
68
            selectedKeys={activeWorkspaceName ? [activeWorkspaceName] : []}
9✔
69
            onAction={(v) => {
70
              handleWorkspaceClick(v?.toString());
×
71
            }}
72
            className="-mx-1 my-2 max-h-80 overflow-auto"
73
            renderEmptyState={() => (
74
              <p className="text-center">No workspaces found</p>
75
            )}
76
          >
77
            {(item) => (
78
              <ListBoxItem
79
                id={item.name}
80
                key={item.name}
81
                textValue={item.name}
82
                data-is-selected={item.name === activeWorkspaceName}
83
                className={clsx(
84
                  "grid grid-cols-[auto_1.5rem] group/selector cursor-pointer py-2 m-1 text-base hover:bg-gray-200 rounded-sm",
85
                  {
86
                    "!bg-gray-900 hover:bg-gray-900 !text-gray-25 hover:!text-gray-25":
87
                      item.is_active,
88
                  },
89
                )}
90
              >
91
                <span className="block truncate">{item.name}</span>
92

93
                <LinkButton
94
                  href={hrefs.workspaces.edit(item.name)}
95
                  onPress={() => setIsOpen(false)}
×
96
                  isIcon
97
                  variant="tertiary"
98
                  className={twMerge(
99
                    "ml-auto size-6 group-hover/selector:opacity-100 opacity-0 transition-opacity",
100
                    item.is_active
4✔
101
                      ? "hover:bg-gray-800 pressed:bg-gray-700"
102
                      : "hover:bg-gray-50 hover:text-primary",
103
                  )}
104
                >
105
                  <Settings01
106
                    className={twMerge(
107
                      item.is_active ? "text-gray-25" : "text-secondary",
4✔
108
                    )}
109
                  />
110
                </LinkButton>
111
              </ListBoxItem>
112
            )}
113
          </ListBox>
114
          <Separator className="" />
115
          <LinkButton
116
            href="/workspaces"
117
            onPress={() => setIsOpen(false)}
×
118
            variant="tertiary"
119
            className="text-secondary h-10 pl-2 gap-2 flex mt-2 justify-start"
120
          >
121
            <Settings01 />
122
            Manage Workspaces
123
          </LinkButton>
124
        </div>
125
      </Popover>
126
    </DialogTrigger>
127
  );
128
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc