Skip to content

Commit

Permalink
Merge branch 'main' into ty/add-cody-pro-links-to-user-nav
Browse files Browse the repository at this point in the history
  • Loading branch information
taras-yemets committed Jun 20, 2024
2 parents 70a6e43 + 345f6b9 commit 5795ca2
Show file tree
Hide file tree
Showing 16 changed files with 155 additions and 71 deletions.
5 changes: 2 additions & 3 deletions client/web-sveltekit/src/lib/KeyboardShortcut.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,11 @@ A component to display the keyboard shortcuts for the application.
line-height: 1;
background-color: var(--secondary-4);
color: var(--text-muted);
color: var(--text-body);
// When inside a selected container, show the selected variant
:global([aria-selected='true']) & {
color: white;
background-color: var(--primary);
color: var(--primary);
}
}
</style>
16 changes: 11 additions & 5 deletions client/web-sveltekit/src/lib/TabsHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
align-items: center;
min-height: 2rem;
padding: 0.25rem 0.75rem;
color: var(--text-body);
color: var(--text-muted);
display: inline-flex;
flex-flow: row nowrap;
justify-content: center;
Expand All @@ -95,16 +95,16 @@
}
&:hover {
--icon-color: currentColor;
color: var(--text-title);
background-color: var(--secondary-2);
}
&[aria-selected='true'] {
--icon-color: currentColor;
font-weight: 500;
color: var(--text-title);
background-color: var(--secondary-2);
color: var(--primary);
&::after {
border-color: var(--primary);
Expand All @@ -119,10 +119,16 @@
&::before {
content: attr(data-tab-title);
display: block;
font-weight: 500;
height: 0;
visibility: hidden;
}
}
&[aria-selected='true'] span,
span::before {
// Hidden rendering of the bold tab title to prevent
// shifting when the tab is selected.
font-weight: 500;
}
}
</style>
1 change: 1 addition & 0 deletions client/web-sveltekit/src/lib/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export {
isLinuxPlatform,
getPlatform,
} from '@sourcegraph/common/src/util/browserDetection'
export { dirname, basename } from '@sourcegraph/common/src/util/path'

let highlightingLoaded = false

Expand Down
104 changes: 80 additions & 24 deletions client/web-sveltekit/src/lib/fuzzyfinder/FuzzyFinder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
import { isMacPlatform } from '@sourcegraph/common'
import { dirname } from '$lib/common'
import { nextSibling, onClickOutside, previousSibling } from '$lib/dom'
import { getGraphQLClient } from '$lib/graphql'
import Icon from '$lib/Icon.svelte'
import FileIcon from '$lib/repo/FileIcon.svelte'
import CodeHostIcon from '$lib/search/CodeHostIcon.svelte'
import EmphasizedLabel from '$lib/search/EmphasizedLabel.svelte'
import SymbolKindIcon from '$lib/search/SymbolKindIcon.svelte'
import { displayRepoName } from '$lib/shared'
import TabsHeader, { type Tab } from '$lib/TabsHeader.svelte'
import { Input } from '$lib/wildcard'
import Button from '$lib/wildcard/Button.svelte'
Expand Down Expand Up @@ -181,6 +183,8 @@
</script>

<dialog bind:this={dialog} on:close>
<!-- We cannot use the `use:onClickOutside` directive on the dialog element itself because the element will take
up the entire viewport and the event will never be triggered. -->
<div class="content" use:onClickOutside on:click-outside={() => dialog?.close()}>
<header>
<TabsHeader
Expand All @@ -193,9 +197,11 @@
input?.focus()
}}
/>
<Button variant="icon" on:click={() => dialog?.close()} size="sm">
<Icon icon={ILucideX} aria-label="Close" inline />
</Button>
<span class="close">
<Button variant="icon" on:click={() => dialog?.close()} size="sm">
<Icon icon={ILucideX} aria-label="Close" />
</Button>
</span>
</header>
<main>
<div class="input">
Expand Down Expand Up @@ -223,41 +229,51 @@
<ul role="listbox" bind:this={listbox} aria-label="Search results">
{#if $source.value}
{#each $source.value as item, index (item.item)}
{@const repo = item.item.repository.name}
{@const displayRepo = displayRepoName(repo)}
<li role="option" aria-selected={selectedOption === index} data-index={index}>
{#if item.item.type === 'repo'}
{@const matchOffset = repo.length - displayRepo.length}
<a href="/{item.item.repository.name}" on:click={handleClick}>
<CodeHostIcon repository={item.item.repository.name} />
<span
<span class="icon"><CodeHostIcon repository={item.item.repository.name} /></span>
<span class="label"
><EmphasizedLabel
label={item.item.repository.name}
label={displayRepo}
matches={item.positions}
offset={matchOffset}
/></span
>
<span class="info">{repo}</span>
</a>
{:else if item.item.type == 'symbol'}
<a href={item.item.symbol.location.url} on:click={handleClick}>
<SymbolKindIcon symbolKind={item.item.symbol.kind} />
<span
<span class="icon"><SymbolKindIcon symbolKind={item.item.symbol.kind} /></span>
<span class="label"
><EmphasizedLabel
label={item.item.symbol.name}
matches={item.positions}
/></span
>
<small>-</small>
<FileIcon file={item.item.file} inline />
<small
>{#if !useScope}{item.item.repository.name}/{/if}{item.item.file.path}</small
<span class="info mono"
>{#if !useScope}{displayRepo} &middot; {/if}{item.item.file.path}</span
>
</a>
{:else if item.item.type == 'file'}
{@const fileName = item.item.file.name}
{@const folderName = dirname(item.item.file.path)}
<a href={item.item.file.url} on:click={handleClick}>
<FileIcon file={item.item.file} inline />
<span
>{#if !useScope}{item.item.repository.name}/{/if}<EmphasizedLabel
label={item.item.file.path}
<span class="icon"><FileIcon file={item.item.file} inline /></span>
<span class="label"
><EmphasizedLabel
label={fileName}
matches={item.positions}
offset={folderName.length + 1}
/></span
>
<span class="info mono">
{#if !useScope}{displayRepo} &middot; {/if}
<EmphasizedLabel label={folderName} matches={item.positions} />
</span>
</a>
{/if}
</li>
Expand All @@ -274,14 +290,17 @@
dialog {
width: 80vw;
height: 80vh;
border: none;
border-radius: 0.75rem;
padding: 0;
overflow: hidden;
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
background-color: var(--body-bg);
background-color: var(--color-bg-1);
box-shadow: var(--fuzzy-finder-shadow);
&::backdrop {
background-color: var(--modal-bg);
background: var(--fuzzy-finder-backdrop);
}
}
Expand Down Expand Up @@ -316,14 +335,18 @@
[role='option'] {
a {
display: flex;
align-items: center;
padding: 0.25rem 1rem;
display: grid;
grid-template-columns: [icon] auto [label] 1fr;
grid-template-rows: auto;
grid-template-areas: 'icon label' '. info';
column-gap: 0.5rem;
cursor: pointer;
color: var(--body-color);
gap: 0.25rem;
padding: 0.25rem 0.75rem;
text-decoration: none;
color: var(--body-color);
font-size: var(--font-size-small);
}
small {
Expand All @@ -334,6 +357,28 @@
a:hover {
background-color: var(--color-bg-2);
}
.icon {
grid-area: icon;
// Centers the icon vertically
display: flex;
align-items: center;
}
.label {
grid-area: label;
}
.info {
grid-area: info;
color: var(--text-muted);
font-size: var(--font-size-extra-small);
&.mono {
font-family: var(--code-font-family);
}
}
}
.empty {
Expand All @@ -358,5 +403,16 @@
bottom: 0;
left: 0;
}
.close {
position: fixed;
right: 2rem;
background-color: var(--color-bg-1);
border-radius: 50%;
&:hover {
background-color: var(--color-bg-2);
}
}
}
</style>
7 changes: 7 additions & 0 deletions client/web-sveltekit/src/routes/svelte-overrides.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ body {
--code-font-family: var(--monospace-font-family);
--font-size-base: 0.9375rem;
--font-size-small: 0.875rem;
--font-size-extra-small: 0.6875rem;
--font-size-tiny: 0.8125rem;
--code-font-size: 13px;
--border-radius: 4px;
Expand Down Expand Up @@ -43,6 +44,7 @@ label {
--code-bg: var(--white);
--modal-bg: rgba(219, 226, 240, 0.5);
--code-selection-bg: rgba(231, 238, 250, 0.8);
--fuzzy-finder-backdrop: rgba(255, 255, 255, 0.96);

// Shadows
--sidebar-shadow: 0 79px 22px 0 rgba(30, 4, 47, 0), 0 51px 20px 0 rgba(30, 4, 47, 0.01),
Expand All @@ -57,6 +59,8 @@ label {
0 -18px 11px 0 rgba(1, 6, 12, 0.02), 0 -8px 8px 0 rgba(1, 6, 12, 0.03), 0 -2px 4px 0 rgba(1, 6, 12, 0.04);
--popover-shadow: 0 174px 49px 0 rgba(0, 0, 0, 0), 0 112px 45px 0 rgba(0, 0, 0, 0.01),
0 63px 38px 0 rgba(0, 0, 0, 0.02), 0 28px 28px 0 rgba(0, 0, 0, 0.03), 0 7px 15px 0 rgba(0, 0, 0, 0.04);
--fuzzy-finder-shadow: 0 186px 52px 0 rgba(0, 0, 0, 0), 0 119px 48px 0 rgba(0, 0, 0, 0.01),
0 67px 40px 0 rgba(0, 0, 0, 0.02), 0 30px 30px 0 rgba(0, 0, 0, 0.03), 0 7px 16px 0 rgba(0, 0, 0, 0.04);
}

// Theme Dark
Expand All @@ -71,6 +75,7 @@ label {
--code-selection-bg: var(--color-bg-2);
--code-bg: var(--gray-12);
--modal-bg: rgba(52, 58, 77, 0.5);
--fuzzy-finder-backdrop: rgba(20, 23, 31, 0.96);

// Shadows
--sidebar-shadow: 0 240px 80px 0 rgba(12, 1, 19, 0.01), 0 160px 80px 0 rgba(12, 1, 19, 0.02),
Expand All @@ -85,4 +90,6 @@ label {
0 -16px 8px 0 rgba(0, 0, 0, 0.08), 0 -8px 4px 0 rgba(0, 0, 0, 0.16), 0 -2px 4px 0 rgba(0, 0, 0, 0.32);
--popover-shadow: 0 174px 49px 0 rgba(0, 0, 0, 0.01), 0 112px 45px 0 rgba(0, 0, 0, 0.05),
0 63px 38px 0 rgba(0, 0, 0, 0.16), 0 28px 28px 0 rgba(0, 0, 0, 0.27), 0 7px 15px 0 rgba(0, 0, 0, 0.31);
--fuzzy-finder-shadow: 0 186px 52px 0 rgba(0, 0, 0, 0.01), 0 119px 48px 0 rgba(0, 0, 0, 0.03),
0 67px 40px 0 rgba(0, 0, 0, 0.06), 0 30px 30px 0 rgba(0, 0, 0, 0.12), 0 7px 16px 0 rgba(0, 0, 0, 0.24);
}
2 changes: 1 addition & 1 deletion client/web/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ ts_project(
"src/cody/dashboard/UpsellImage.tsx",
"src/cody/editorGroups.ts",
"src/cody/invites/AcceptInviteBanner.tsx",
"src/cody/invites/InviteUsers.tsx",
"src/cody/invites/useInviteParams.ts",
"src/cody/invites/useInviteState.ts",
"src/cody/isCodyEnabled.tsx",
Expand Down Expand Up @@ -282,7 +283,6 @@ ts_project(
"src/cody/subscription/queries.tsx",
"src/cody/switch-account/CodySwitchAccountPage.tsx",
"src/cody/team/CodyManageTeamPage.tsx",
"src/cody/team/InviteUsers.tsx",
"src/cody/team/TeamMemberList.tsx",
"src/cody/upsell/ChatBrandIcon.tsx",
"src/cody/upsell/CodyUpsellPage.tsx",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useCallback } from 'react'
import React, { useState, useCallback, useMemo } from 'react'

import { pluralize } from '@sourcegraph/common'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
Expand All @@ -7,21 +7,29 @@ import { ButtonLink, H2, Link, Text, H3, TextArea } from '@sourcegraph/wildcard'
import { CodyAlert } from '../components/CodyAlert'
import { CodyContainer } from '../components/CodyContainer'
import { CodyProBadgeDeck } from '../components/CodyProBadgeDeck'
import { useSendInvite } from '../management/api/react-query/invites'
import { useSendInvite, useTeamInvites } from '../management/api/react-query/invites'
import { useCurrentSubscription, useSubscriptionSummary } from '../management/api/react-query/subscriptions'
import { useTeamMembers } from '../management/api/react-query/teams'
import { isValidEmailAddress } from '../util'

import styles from './InviteUsers.module.scss'

interface InviteUsersProps extends TelemetryV2Props {
teamId: string
remainingInviteCount: number
}
export const InviteUsers: React.FunctionComponent<TelemetryV2Props> = ({ telemetryRecorder }) => {
const subscriptionQueryResult = useCurrentSubscription()
const subscriptionSummaryQueryResult = useSubscriptionSummary()
const isAdmin = subscriptionSummaryQueryResult?.data?.userRole === 'admin'
const teamId = subscriptionSummaryQueryResult?.data?.teamId
const teamMembersQueryResult = useTeamMembers()
const teamMembers = teamMembersQueryResult.data?.members
const teamInvitesQueryResult = useTeamInvites()
const teamInvites = teamInvitesQueryResult.data

const remainingInviteCount = useMemo(() => {
const memberCount = teamMembers?.length ?? 0
const invitesUsed = (teamInvites ?? []).filter(invite => invite.status === 'sent').length
return Math.max((subscriptionQueryResult.data?.maxSeats ?? 0) - (memberCount + invitesUsed), 0)
}, [subscriptionQueryResult.data?.maxSeats, teamMembers, teamInvites])

export const InviteUsers: React.FunctionComponent<InviteUsersProps> = ({
teamId,
remainingInviteCount,
telemetryRecorder,
}) => {
const [emailAddressesString, setEmailAddressesString] = useState<string>('')
const emailAddresses = emailAddressesString.split(',').map(email => email.trim())
const [emailAddressErrorMessage, setEmailAddressErrorMessage] = useState<string | null>(null)
Expand Down Expand Up @@ -92,6 +100,10 @@ export const InviteUsers: React.FunctionComponent<InviteUsersProps> = ({
})
}, [emailAddresses, sendInviteMutation.mutateAsync, teamId, telemetryRecorder, verifyEmailList])

if (!isAdmin || !remainingInviteCount || !subscriptionSummaryQueryResult?.data) {
return null
}

return (
<>
{sendInviteMutation.status === 'success' && (
Expand Down
3 changes: 3 additions & 0 deletions client/web/src/cody/management/CodyManagementPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { CodyAlert } from '../components/CodyAlert'
import { ProIcon } from '../components/CodyIcon'
import { PageHeaderIcon } from '../components/PageHeaderIcon'
import { AcceptInviteBanner } from '../invites/AcceptInviteBanner'
import { InviteUsers } from '../invites/InviteUsers'
import { isCodyEnabled } from '../isCodyEnabled'
import { CodyOnboarding, type IEditor } from '../onboarding/CodyOnboarding'
import { USER_CODY_PLAN, USER_CODY_USAGE } from '../subscription/queries'
Expand Down Expand Up @@ -143,6 +144,8 @@ export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps
</PageHeader.Heading>
</PageHeader>

{isAdmin && <InviteUsers telemetryRecorder={telemetryRecorder} />}

{!isUserOnProTier && <UpgradeToProBanner onClick={onClickUpgradeToProCTA} />}

<div className={classNames('p-4 border bg-1 mt-3', styles.container)}>
Expand Down
Loading

0 comments on commit 5795ca2

Please sign in to comment.