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

stacklok / codegate-ui / 13009890552

28 Jan 2025 11:57AM UTC coverage: 68.399% (+0.09%) from 68.305%
13009890552

Pull #213

github

web-flow
Merge cbe89e304 into 8894ed521
Pull Request #213: feat: quick "go to settings" for workspace selector

348 of 609 branches covered (57.14%)

Branch coverage included in aggregate %.

5 of 6 new or added lines in 2 files covered. (83.33%)

771 of 1027 relevant lines covered (75.07%)

66.59 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 { ChevronDown, Search, Settings } from "lucide-react";
15
import { useState } from "react";
16
import { useMutationActivateWorkspace } from "../hooks/use-mutation-activate-workspace";
17
import clsx from "clsx";
18
import { useActiveWorkspaceName } from "../hooks/use-active-workspace-name";
19
import { hrefs } from "@/lib/hrefs";
20
import { twMerge } from "tailwind-merge";
21

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

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

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

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

37
  const handleWorkspaceClick = (name: string) => {
9✔
38
    activateWorkspace({ body: { name } }).then(() => {
×
39
      queryClient.invalidateQueries({ refetchType: "all" });
×
40
      setIsOpen(false);
×
41
    });
42
  };
43

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

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

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

91
                <LinkButton
92
                  href={hrefs.workspaces.edit(item.name)}
NEW
93
                  onPress={() => setIsOpen(false)}
×
94
                  isIcon
95
                  variant="tertiary"
96
                  className={twMerge(
97
                    "ml-auto size-6 group-hover/selector:opacity-100 opacity-0 transition-opacity",
98
                    item.is_active
4✔
99
                      ? "hover:bg-gray-800 pressed:bg-gray-700"
100
                      : "hover:bg-gray-50 hover:text-primary",
101
                  )}
102
                >
103
                  <Settings
104
                    className={twMerge(
105
                      item.is_active ? "text-gray-25" : "text-secondary",
4✔
106
                    )}
107
                  />
108
                </LinkButton>
109
              </ListBoxItem>
110
            )}
111
          </ListBox>
112
          <Separator className="" />
113
          <LinkButton
114
            href="/workspaces"
115
            onPress={() => setIsOpen(false)}
×
116
            variant="tertiary"
117
            className="text-secondary h-10 pl-2 gap-2 flex mt-2 justify-start"
118
          >
119
            <Settings />
120
            Manage Workspaces
121
          </LinkButton>
122
        </div>
123
      </Popover>
124
    </DialogTrigger>
125
  );
126
}
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