Skip to content

Commit

Permalink
chore(release): Test v7.38.0 (#9921)
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Krick <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Matt Krick <[email protected]>
Co-authored-by: Bartosz Jarocki <[email protected]>
Co-authored-by: Marcus Wermuth <[email protected]>
Co-authored-by: Jordan Husney <[email protected]>
Co-authored-by: Rafa <[email protected]>
Co-authored-by: Georg Bremer <[email protected]>
Co-authored-by: parabol-release-bot[bot] <150284312+parabol-release-bot[bot]@users.noreply.github.com>
Co-authored-by: Rafael Romero <[email protected]>
Co-authored-by: Bruce Tian <[email protected]>
Co-authored-by: Nick O'Ferrall <[email protected]>
Co-authored-by: snyk-bot <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
Co-authored-by: Dale Bumblis <[email protected]>
Co-authored-by: Mohd Muneeb <[email protected]>
Co-authored-by: Muneeb-Ventures <[email protected]>
Co-authored-by: Terry Acker <[email protected]>
Co-authored-by: github-actions <[email protected]>
  • Loading branch information
19 people authored Jul 3, 2024
1 parent ba81227 commit daaaa72
Show file tree
Hide file tree
Showing 39 changed files with 455 additions and 209 deletions.
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "7.37.8"
".": "7.38.0"
}
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ This project adheres to [Semantic Versioning](http://semver.org/).

This CHANGELOG follows conventions [outlined here](http://keepachangelog.com/).

## [7.38.0](https://github.com/ParabolInc/parabol/compare/v7.37.8...v7.38.0) (2024-07-02)


### Added

* Add search template mutation ([#9802](https://github.com/ParabolInc/parabol/issues/9802)) ([486f670](https://github.com/ParabolInc/parabol/commit/486f6703a997c827ffcd157c13e3fa1321e977ed))


### Fixed

* Allow to start recurrence for existing Standups ([#9909](https://github.com/ParabolInc/parabol/issues/9909)) ([ae577e2](https://github.com/ParabolInc/parabol/commit/ae577e28a791350f20dbd29779511f75f439224c))
* Avoid adding embedding jobs without metadata id ([#9881](https://github.com/ParabolInc/parabol/issues/9881)) ([4e2fec1](https://github.com/ParabolInc/parabol/commit/4e2fec1ea0e1b9eb442a799b0d3a2d66ef40772b))
* bugs during upgrade/downgrade ([#9919](https://github.com/ParabolInc/parabol/issues/9919)) ([c67a6a8](https://github.com/ParabolInc/parabol/commit/c67a6a87efc35fcb8f41e388d451b1a784a045e2))
* remove ai from summary url if no ai env var ([#9895](https://github.com/ParabolInc/parabol/issues/9895)) ([4413142](https://github.com/ParabolInc/parabol/commit/4413142e55c94388e1cfe78503cc420d2945c334))
* remove Organization.teams field from gql ([#9918](https://github.com/ParabolInc/parabol/issues/9918)) ([55b2dfb](https://github.com/ParabolInc/parabol/commit/55b2dfb425f89135a39bb38b02b5bc955ea2e5a0))
* speed up team upgrade ([#9902](https://github.com/ParabolInc/parabol/issues/9902)) ([d91f649](https://github.com/ParabolInc/parabol/commit/d91f649918ed471bc37332abdefcc6e07d737e6d))


### Changed

* Fix debug output when retrying after Cloudflare error ([#9912](https://github.com/ParabolInc/parabol/issues/9912)) ([d17345f](https://github.com/ParabolInc/parabol/commit/d17345ff90bc88cba673fbd3a9efb76848556449))
* remove contact us message for team users that want to downgrade ([#9903](https://github.com/ParabolInc/parabol/issues/9903)) ([7e90ac2](https://github.com/ParabolInc/parabol/commit/7e90ac2d1ba2144271779982272160c7c1b0df33))

## [7.37.8](https://github.com/ParabolInc/parabol/compare/v7.37.7...v7.37.8) (2024-06-27)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "An open-source app for building smarter, more agile teams.",
"author": "Parabol Inc. <[email protected]> (http://github.com/ParabolInc)",
"license": "AGPL-3.0",
"version": "7.37.8",
"version": "7.38.0",
"repository": {
"type": "git",
"url": "https://github.com/ParabolInc/parabol"
Expand Down
4 changes: 2 additions & 2 deletions packages/chronos/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chronos",
"version": "7.37.8",
"version": "7.38.0",
"description": "A cron job scheduler",
"author": "Matt Krick <[email protected]>",
"homepage": "https://github.com/ParabolInc/parabol/tree/master/packages/chronos#readme",
Expand All @@ -25,6 +25,6 @@
},
"dependencies": {
"cron": "^2.3.1",
"parabol-server": "7.37.8"
"parabol-server": "7.38.0"
}
}
115 changes: 90 additions & 25 deletions packages/client/components/ActivityLibrary/ActivityLibrary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,28 @@ import * as ScrollArea from '@radix-ui/react-scroll-area'
import graphql from 'babel-plugin-relay/macro'
import clsx from 'clsx'
import React, {Fragment, useEffect, useMemo} from 'react'
import {PreloadedQuery, commitLocalUpdate, usePreloadedQuery} from 'react-relay'
import {
PreloadedQuery,
commitLocalUpdate,
fetchQuery,
usePreloadedQuery,
useRefetchableFragment
} from 'react-relay'
import {Redirect} from 'react-router'
import {Link} from 'react-router-dom'
import {useDebounce} from 'use-debounce'
import {ActivityLibraryQuery} from '~/__generated__/ActivityLibraryQuery.graphql'
import {ActivityLibraryTemplateSearchRefetchQuery} from '~/__generated__/ActivityLibraryTemplateSearchRefetchQuery.graphql'
import {ActivityLibraryTemplateSearch_query$key} from '~/__generated__/ActivityLibraryTemplateSearch_query.graphql'
import {ActivityLibrary_template$data} from '~/__generated__/ActivityLibrary_template.graphql'
import {ActivityLibrary_templateSearchDocument$data} from '~/__generated__/ActivityLibrary_templateSearchDocument.graphql'
import useAtmosphere from '../../hooks/useAtmosphere'
import {useDebouncedSearch} from '../../hooks/useDebouncedSearch'
import useRouter from '../../hooks/useRouter'
import useSearchFilter from '../../hooks/useSearchFilter'
import logoMarkPurple from '../../styles/theme/images/brand/mark-color.svg'
import SendClientSideEvent from '../../utils/SendClientSideEvent'
import IconLabel from '../IconLabel'
import LoadingComponent from '../LoadingComponent/LoadingComponent'
import AISearch from './AISearch'
import ActivityGrid from './ActivityGrid'
import ActivityLibraryEmptyState from './ActivityLibraryEmptyState'
Expand Down Expand Up @@ -75,8 +84,27 @@ graphql`
}
`

const templateSearchFragment = graphql`
fragment ActivityLibraryTemplateSearch_query on Query
@argumentDefinitions(search: {type: "String!"})
@refetchable(queryName: "ActivityLibraryTemplateSearchRefetchQuery") {
viewer {
templateSearch(search: $search) {
...ActivityLibrary_template @relay(mask: false)
}
}
}
`

const templateSearchQuery = graphql`
query ActivityLibraryTemplateSearchQuery($search: String!) {
...ActivityLibraryTemplateSearch_query @arguments(search: $search)
}
`

const query = graphql`
query ActivityLibraryQuery {
...ActivityLibraryTemplateSearch_query @arguments(search: "")
viewer {
...ActivityGrid_user
favoriteTemplates {
Expand Down Expand Up @@ -203,6 +231,12 @@ export const ActivityLibrary = (props: Props) => {
const {availableTemplates, organizations} = viewer
const hasAITemplateFeatureFlag = !!organizations.find((org) => org.featureFlags.aiTemplate)

const [isSearching, setIsSearching] = React.useState(true)
const [templateSearch, refetchTemplateSearch] = useRefetchableFragment<
ActivityLibraryTemplateSearchRefetchQuery,
ActivityLibraryTemplateSearch_query$key
>(templateSearchFragment, data)

const setSearch = (value: string) => {
commitLocalUpdate(atmosphere, (store) => {
const viewer = store.getRoot().getLinkedRecord('viewer')
Expand All @@ -224,13 +258,29 @@ export const ActivityLibrary = (props: Props) => {
onQueryChange,
resetQuery
} = useSearchFilter(templates, getTemplateDocumentValue)
const [debouncedSearchQuery] = useDebounce(searchQuery, 500)
const {debouncedSearch: debouncedSearchQuery, dirty} = useDebouncedSearch(searchQuery)
const showLoading = dirty || isSearching

useEffect(() => {
if (debouncedSearchQuery) {
setIsSearching(true)
// Avoid suspense while refreshing the search results, see
// https://relay.dev/docs/guided-tour/refetching/refetching-fragments-with-different-data/#if-you-need-to-avoid-suspense
fetchQuery(atmosphere, templateSearchQuery, {search: debouncedSearchQuery}).subscribe({
complete: () => {
refetchTemplateSearch({search: debouncedSearchQuery}, {fetchPolicy: 'store-only'})
setIsSearching(false)
},
error: () => {
setIsSearching(false)
}
})
SendClientSideEvent(atmosphere, 'Activity Library Searched', {
debouncedSearchQuery
})
} else {
refetchTemplateSearch({search: ''}, {fetchPolicy: 'store-only'})
setIsSearching(false)
}
}, [debouncedSearchQuery])

Expand All @@ -241,8 +291,21 @@ export const ActivityLibrary = (props: Props) => {

const templatesToRender = useMemo(() => {
if (searchQuery.length > 0) {
// If there's a search query, just use the search filter results
return filteredTemplates
// If there's a search query, combine the filtered templates with the search results
const searchResults = templateSearch.viewer.templateSearch
const doubleMatches = searchResults.filter((searchResult) =>
filteredTemplates.find((template) => template.id === searchResult.id)
)

return [
...doubleMatches,
...filteredTemplates.filter(
(template) => !doubleMatches.find((doubleMatch) => doubleMatch.id === template.id)
),
...searchResults.filter(
(searchResult) => !doubleMatches.find((doubleMatch) => doubleMatch.id === searchResult.id)
)
]
}
if (categoryId === 'favorite') {
return viewer.favoriteTemplates
Expand All @@ -255,7 +318,7 @@ export const ActivityLibrary = (props: Props) => {
? template.scope !== 'PUBLIC'
: template.category === categoryId
)
}, [searchQuery, filteredTemplates, categoryId])
}, [searchQuery, filteredTemplates, templateSearch, categoryId])

const sectionedTemplates = useMemo(() => {
// Show the teams on search as well, because you can search by team name
Expand Down Expand Up @@ -337,7 +400,7 @@ export const ActivityLibrary = (props: Props) => {
(category) => (
<Link
className={clsx(
'flex-shrink-0 cursor-pointer rounded-full py-2 px-4 text-sm text-slate-800',
'flex flex-shrink-0 cursor-pointer items-center rounded-full px-4 text-sm leading-9 text-slate-800',
category === categoryId && searchQuery.length === 0
? [
`${CategoryIDToColorClass[category]}`,
Expand Down Expand Up @@ -373,7 +436,7 @@ export const ActivityLibrary = (props: Props) => {
<AISearch />
</div>
)}
{templatesToRender.length === 0 ? (
{templatesToRender.length === 0 && !showLoading ? (
<ActivityLibraryEmptyState
searchQuery={searchQuery}
categoryId={categoryId as AllCategoryID}
Expand All @@ -382,24 +445,25 @@ export const ActivityLibrary = (props: Props) => {
<>
{sectionedTemplates ? (
<>
{Object.entries(sectionedTemplates).map(
([subCategory, subCategoryTemplates]) =>
subCategoryTemplates.length > 0 && (
<Fragment key={subCategory}>
{subCategory && (
<div className='ml-4 mt-8 text-xl font-bold text-slate-700'>
{subCategory}
</div>
)}
<div className='mt-1 grid auto-rows-fr grid-cols-[repeat(auto-fill,minmax(min(40%,256px),1fr))] gap-4 px-4 md:mt-4'>
<ActivityGrid
templates={subCategoryTemplates}
selectedCategory={categoryId}
viewerRef={viewer}
/>
{Object.entries(sectionedTemplates).map(([subCategory, subCategoryTemplates]) =>
subCategoryTemplates.length > 0 ? (
<Fragment key={subCategory}>
{subCategory && (
<div className='ml-4 mt-8 text-xl font-bold text-slate-700'>
{subCategory}
</div>
</Fragment>
)
)}
<div className='mt-1 grid auto-rows-fr grid-cols-[repeat(auto-fill,minmax(min(40%,256px),1fr))] gap-4 px-4 md:mt-4'>
<ActivityGrid
templates={subCategoryTemplates}
selectedCategory={categoryId}
viewerRef={viewer}
/>
</div>
</Fragment>
) : (
<div className='p-4' />
)
)}
</>
) : (
Expand All @@ -415,6 +479,7 @@ export const ActivityLibrary = (props: Props) => {
)}
</>
)}
{showLoading && <LoadingComponent />}
</ScrollArea.Viewport>
<ScrollArea.Scrollbar
orientation='vertical'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const ActivityLibraryEmptyState = (props: Props) => {
const {categoryId, searchQuery} = props
const showResultsNotFound = categoryId !== 'custom' || searchQuery !== ''

if (categoryId === 'favorite') {
if (!searchQuery && categoryId === 'favorite') {
return (
<div className='relative mx-auto flex justify-center p-2 align-middle text-slate-700'>
<div className='p-4 md:p-0 '>
Expand Down
37 changes: 37 additions & 0 deletions packages/client/hooks/useDebouncedSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {useEffect, useRef, useState} from 'react'

/**
* Debounces a search string. It will wait for the user to stop typing or finishing a word before returning the debounced search string.
*/
export const useDebouncedSearch = (search: string) => {
const wordEndChars = /[\s,.\!?:;\-\(\)\[\]\{\}<>"'\\|&*+=#%@$]/
const timer = useRef<NodeJS.Timeout>()
const [debouncedSearch, setDebouncedSearch] = useState('')

useEffect(() => {
if (!search) {
setDebouncedSearch(search)
return
}
// if they finished a word, send it now
if (wordEndChars.test(search.at(-1)!)) {
setDebouncedSearch(search)
return
}
// assuming 40 wpm with 5 characters per word we get 300ms between characters
// give some wiggle room for slow typers
timer.current = setTimeout(() => {
setDebouncedSearch(search)
timer.current = undefined
}, 500)
return () => {
clearTimeout(timer.current)
timer.current = undefined
}
}, [search])

return {
debouncedSearch,
dirty: !!timer.current
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@ import {
useElements,
useStripe
} from '@stripe/react-stripe-js'
import {StripeElementChangeEvent} from '@stripe/stripe-js'
import React, {useState} from 'react'
import {
StripeCardNumberElement,
StripeCardNumberElementOptions,
StripeElementChangeEvent
} from '@stripe/stripe-js'
import React, {MutableRefObject, useState} from 'react'
import {commitLocalUpdate} from 'relay-runtime'
import {CreateStripeSubscriptionMutation$data} from '../../../../__generated__/CreateStripeSubscriptionMutation.graphql'
import Ellipsis from '../../../../components/Ellipsis/Ellipsis'
import PrimaryButton from '../../../../components/PrimaryButton'
import StyledError from '../../../../components/StyledError'
import useAtmosphere from '../../../../hooks/useAtmosphere'
import useMutationProps from '../../../../hooks/useMutationProps'
import CreateStripeSubscriptionMutation from '../../../../mutations/CreateStripeSubscriptionMutation'
import upgradeToTeamTierSuccessUpdater from '../../../../mutations/handlers/upgradeToTeamTierSuccessUpdater'
import {PALETTE} from '../../../../styles/paletteV3'
import SendClientSideEvent from '../../../../utils/SendClientSideEvent'
import createProxyRecord from '../../../../utils/relay/createProxyRecord'

const ButtonBlock = styled('div')({
display: 'flex',
Expand Down Expand Up @@ -45,7 +52,8 @@ const ErrorMsg = styled(StyledError)({
textTransform: 'none'
})

const CARD_ELEMENT_OPTIONS = {
const CARD_ELEMENT_OPTIONS: StripeCardNumberElementOptions = {
disableLink: true,
style: {
base: {
color: PALETTE.SLATE_800,
Expand All @@ -61,10 +69,11 @@ const CARD_ELEMENT_OPTIONS = {

type Props = {
orgId: string
cardNumberRef: MutableRefObject<StripeCardNumberElement | null>
}

const BillingForm = (props: Props) => {
const {orgId} = props
const {cardNumberRef, orgId} = props
const stripe = useStripe()
const elements = useElements()
const [isLoading, setIsLoading] = useState(false)
Expand Down Expand Up @@ -131,6 +140,11 @@ const BillingForm = (props: Props) => {
setIsLoading(false)
return
}
commitLocalUpdate(atmosphere, (store) => {
const payload = createProxyRecord(store, 'payload', {})
payload.setLinkedRecord(store.get(orgId)!, 'organization')
upgradeToTeamTierSuccessUpdater(payload)
})
onCompleted()
}

Expand Down Expand Up @@ -183,6 +197,9 @@ const BillingForm = (props: Props) => {

<div className='mt-1'>
<CardNumberElement
onReady={(e) => {
cardNumberRef.current = e
}}
className='focus:ring-indigo-500 focus:border-indigo-500 block w-full border-b border-slate-400 bg-slate-200 px-4 py-3 shadow-sm outline-none sm:text-sm'
options={CARD_ELEMENT_OPTIONS}
onChange={handleChange('CardNumber')}
Expand Down
Loading

0 comments on commit daaaa72

Please sign in to comment.