Merge branch 'omnivore-app:main' into flair-icon-alignment

This commit is contained in:
Eduardo Grajeda
2024-03-27 21:57:04 +01:00
committed by GitHub
28 changed files with 435 additions and 378 deletions

File diff suppressed because one or more lines are too long

View File

@ -23,6 +23,8 @@ struct LibraryTabView: View {
@State var isEditMode: EditMode = .inactive
@State var showExpandedAudioPlayer = false
@State var presentPushContainer = true
@State var pushLinkRequest: String?
private let syncManager = LibrarySyncManager()
@ -77,13 +79,34 @@ struct LibraryTabView: View {
var body: some View {
VStack(spacing: 0) {
WindowLink(level: .alert, transition: .move(edge: .bottom), isPresented: $showOperationToast) {
OperationToast(operationMessage: $operationMessage,
OperationToast(operationMessage: $operationMessage,
showOperationToast: $showOperationToast,
operationStatus: $operationStatus)
} label: {
EmptyView()
}.buttonStyle(.plain)
if let pushLinkRequest = pushLinkRequest {
PresentationLink(
transition: PresentationLinkTransition.slide(
options: PresentationLinkTransition.SlideTransitionOptions(
edge: .trailing,
options: PresentationLinkTransition.Options(
modalPresentationCapturesStatusBarAppearance: true,
preferredPresentationBackgroundColor: ThemeManager.currentBgColor
))),
isPresented: $presentPushContainer,
destination: {
WebReaderLoadingContainer(requestID: pushLinkRequest)
.background(ThemeManager.currentBgColor)
.environmentObject(dataService)
.environmentObject(audioController)
}, label: {
EmptyView()
}
)
}
TabView(selection: $selectedTab) {
if !hideFollowingTab {
NavigationView {
@ -145,15 +168,9 @@ struct LibraryTabView: View {
}
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("PushLibraryItem"))) { notification in
guard let folder = notification.userInfo?["libraryItemId"] as? String else { return }
guard let libraryItemId = notification.userInfo?["libraryItemId"] as? String else { return }
if folder == "following" {
selectedTab = "following"
followingViewModel.pushLinkedRequest(request: LinkRequest(id: UUID(), serverID: libraryItemId))
} else {
selectedTab = "inbox"
inboxViewModel.pushLinkedRequest(request: LinkRequest(id: UUID(), serverID: libraryItemId))
}
pushLinkRequest = libraryItemId
presentPushContainer = true
}
.onOpenURL { url in
inboxViewModel.linkRequest = nil

View File

@ -136,6 +136,9 @@ struct ProfileView: View {
#if os(iOS)
Section {
NavigationLink(destination: ReaderSettingsView()) {
Text(LocalText.readerSettingsGeneric)
}
NavigationLink(destination: PushNotificationSettingsView()) {
Text(LocalText.pushNotificationsGeneric)
}

View File

@ -0,0 +1,27 @@
import Services
import SwiftUI
import Views
import Utils
enum OpenLinkIn: String {
case insideApp
case systemBrowser
}
struct ReaderSettingsView: View {
@Environment(\.dismiss) private var dismiss
@AppStorage(UserDefaultKey.openExternalLinksIn.rawValue) var openExternalLinksIn = OpenLinkIn.insideApp.rawValue
var body: some View {
List {
Picker(selection: $openExternalLinksIn, content: {
Text("Inside app").tag(OpenLinkIn.insideApp.rawValue)
Text("Use system browser").tag(OpenLinkIn.systemBrowser.rawValue)
}, label: { Text("Open links:") })
.pickerStyle(MenuPickerStyle())
}.navigationTitle(LocalText.readerSettingsGeneric)
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("ScrollToTop"))) { _ in
dismiss()
}
}
}

View File

@ -414,16 +414,24 @@ struct WebReaderContainerView: View {
titleVisibility: .visible) {
Button(action: {
if let linkToOpen = linkToOpen {
safariWebLink = SafariWebLink(id: UUID(), url: linkToOpen)
if UserDefaults.standard.string(forKey: UserDefaultKey.openExternalLinksIn.rawValue) == OpenLinkIn.systemBrowser.rawValue, UIApplication.shared.canOpenURL(linkToOpen) {
UIApplication.shared.open(linkToOpen)
} else {
safariWebLink = SafariWebLink(id: UUID(), url: linkToOpen)
}
}
}, label: { Text(LocalText.genericOpen) })
Button(action: {
#if os(iOS)
UIPasteboard.general.string = item.unwrappedPageURLString
#else
// Pasteboard.general.string = item.unwrappedPageURLString TODO: fix for mac
#endif
Snackbar.show(message: "Link copied", dismissAfter: 2000)
if let linkToOpen = linkToOpen?.absoluteString {
#if os(iOS)
UIPasteboard.general.string = linkToOpen
#else
// Pasteboard.general.string = item.unwrappedPageURLString TODO: fix for mac
#endif
Snackbar.show(message: "Link copied", dismissAfter: 2000)
} else {
Snackbar.show(message: "Error copying link", dismissAfter: 2000)
}
}, label: { Text(LocalText.readerCopyLink) })
Button(action: {
if let linkToOpen = linkToOpen {

View File

@ -61,8 +61,8 @@ struct WebReaderContent {
-webkit-text-size-adjust: 100%;
}
.is-sticky {
right: 15px !important;
bottom: 40px !important;
right: 20px !important;
bottom: 60px !important;
}
</style>
</head>

View File

@ -0,0 +1,46 @@
import CoreData
import Foundation
import Models
import SwiftGraphQL
public extension DataService {
func deleteRule(ruleID: String) async throws -> Rule {
enum MutationResult {
case result(rule: Rule)
case error(errorMessage: String)
}
let selection = Selection<MutationResult, Unions.DeleteRuleResult> {
try $0.on(
deleteRuleError: .init { .error(errorMessage: try $0.errorCodes().first?.rawValue ?? "Unknown Error") },
deleteRuleSuccess: .init { .result(rule: try $0.rule(selection: ruleSelection)) }
)
}
let mutation = Selection.Mutation {
try $0.deleteRule(
id: ruleID,
selection: selection
)
}
let path = appEnvironment.graphqlPath
let headers = networker.defaultHeaders
return try await withCheckedThrowingContinuation { continuation in
send(mutation, to: path, headers: headers) { queryResult in
guard let payload = try? queryResult.get() else {
continuation.resume(throwing: BasicError.message(messageText: "network error"))
return
}
switch payload.data {
case let .result(rule: rule):
continuation.resume(returning: rule)
case let .error(errorMessage: errorMessage):
continuation.resume(throwing: BasicError.message(messageText: errorMessage))
}
}
}
}
}

View File

@ -35,6 +35,7 @@ public enum UserDefaultKey: String {
case hideFeatureSection
case hideSystemLabels
case justifyText
case openExternalLinksIn
case prefersHideStatusBarInReader
case visibleShareExtensionTab
}

View File

@ -201,4 +201,5 @@ public enum LocalText {
public static let dismissButton = localText(key: "dismissButton")
public static let errorNetwork = localText(key: "errorNetwork")
public static let documentationGeneric = localText(key: "documentationGeneric")
public static let readerSettingsGeneric = localText(key: "readerSettingsGeneric")
}

File diff suppressed because one or more lines are too long

View File

@ -171,7 +171,7 @@
"labelsGeneric" = "Labels";
"emailsGeneric" = "Emails";
"subscriptionsGeneric" = "Subscriptions";
"textToSpeechGeneric" = "Text to Speech";
"textToSpeechGeneric" = "Text to speech";
"privacyPolicyGeneric" = "Privacy Policy";
"termsAndConditionsGeneric" = "Terms and Conditions";
"feedbackGeneric" = "Feedback";
@ -196,7 +196,8 @@
"clubsGeneric" = "Clubs";
"filterGeneric" = "Filters";
"errorGeneric" = "Something went wrong, please try again.";
"pushNotificationsGeneric" = "Push Notifications";
"readerSettingsGeneric" = "Reader settings";
"pushNotificationsGeneric" = "Push notifications";
"dismissButton" = "Dismiss";
"errorNetwork" = "We are having trouble connecting to the internet.";
"documentationGeneric" = "Documentation";

View File

@ -223,7 +223,7 @@ export const addTranscriptPlaceholdReadableContent = async (
async function readStringFromStorage(
bucketName: string,
fileName: string
): Promise<string> {
): Promise<string | undefined> {
try {
const storage = env.fileUpload?.gcsUploadSAKeyFilePath
? new Storage({ keyFilename: env.fileUpload.gcsUploadSAKeyFilePath })
@ -247,12 +247,11 @@ async function readStringFromStorage(
.file(fileName)
.download()
const fileContent = fileContentResponse[0].toString()
console.log(`File '${fileName}' downloaded successfully as string.`)
return fileContent
} catch (error) {
console.error('Error downloading file:', error)
throw error
// This isn't a catastrophic error it just means the file doesn't exist
logger.info('Error downloading file:', error)
return undefined
}
}
@ -284,11 +283,11 @@ const writeStringToStorage = async (
.on('error', reject)
})
console.log(
logger.info(
`File '${fileName}' uploaded successfully to bucket '${bucketName}'.`
)
} catch (error) {
console.error('Error uploading file:', error)
logger.error('Error uploading file:', error)
throw error
}
}
@ -334,6 +333,7 @@ const cacheYouTubeTranscript = async (
export const processYouTubeVideo = async (
jobData: ProcessYouTubeVideoJobData
) => {
let videoURL: URL | undefined
try {
const libraryItem = await authTrx(
async (tx) =>
@ -356,11 +356,11 @@ export const processYouTubeVideo = async (
return
}
const u = new URL(libraryItem.originalUrl)
const videoId = u.searchParams.get('v')
videoURL = new URL(libraryItem.originalUrl)
const videoId = videoURL.searchParams.get('v')
if (!videoId) {
console.warn('no video id for supplied youtube url', {
logger.warn('no video id for supplied youtube url', {
url: libraryItem.originalUrl,
})
return
@ -370,7 +370,7 @@ export const processYouTubeVideo = async (
const youtube = new YouTubeClient()
const video = await youtube.getVideo(videoId)
if (!video) {
console.warn('no video found for youtube url', {
logger.warn('no video found for youtube url', {
url: libraryItem.originalUrl,
})
return
@ -427,11 +427,11 @@ export const processYouTubeVideo = async (
jobData.userId
)
if (!updated) {
console.warn('could not updated library item')
logger.warn('could not updated library item')
}
}
} catch (err) {
console.warn('error creating summary: ', err)
logger.warn('error getting youtube metadata: ', { err, jobData, videoURL })
}
}
@ -470,7 +470,7 @@ export const processYouTubeTranscript = async (
const youtube = new YouTubeClient()
const video = await youtube.getVideo(jobData.videoId)
if (!video) {
logger.warn('no video found for youtube url', {
logger.warning('no video found for youtube url', {
url: libraryItem.originalUrl,
})
return
@ -517,10 +517,10 @@ export const processYouTubeTranscript = async (
jobData.userId
)
if (!updated) {
console.warn('could not updated library item')
logger.warn('could not updated library item')
}
}
} catch (err) {
console.warn('error creating summary: ', err)
logger.warn('error getting youtube transcript: ', { err, jobData })
}
}

View File

@ -1,10 +1,13 @@
import { LiqeQuery } from '@omnivore/liqe'
import { ReadingProgressDataSource } from '../datasources/reading_progress_data_source'
import { LibraryItemState } from '../entity/library_item'
import { LibraryItem, LibraryItemState } from '../entity/library_item'
import { Rule, RuleAction, RuleActionType, RuleEventType } from '../entity/rule'
import { addLabelsToLibraryItem } from '../services/labels'
import {
filterItemEvents,
ItemEvent,
RequiresSearchQueryError,
searchLibraryItems,
softDeleteLibraryItem,
updateLibraryItem,
} from '../services/library_item'
@ -24,7 +27,7 @@ interface RuleActionObj {
libraryItemId: string
userId: string
action: RuleAction
data: ItemEvent
data: ItemEvent | LibraryItem
}
type RuleActionFunc = (obj: RuleActionObj) => Promise<unknown>
@ -107,33 +110,51 @@ const triggerActions = async (
const actionPromises: Promise<unknown>[] = []
for (const rule of rules) {
let filteredData: ItemEvent
let ast: LiqeQuery
let results: (ItemEvent | LibraryItem)[]
try {
const ast = parseSearchQuery(rule.filter)
// filter library item by rule filter
const results = filterItemEvents(ast, [data])
if (results.length === 0) {
logger.info(`No items found for rule ${rule.id}`)
continue
}
filteredData = results[0]
ast = parseSearchQuery(rule.filter)
} catch (error) {
// failed to search for library items, mark rule as failed
logger.error('Error parsing filter in rules', error)
await markRuleAsFailed(rule.id, userId)
continue
}
// filter library item by metadata
try {
results = filterItemEvents(ast, [data])
} catch (error) {
if (error instanceof RequiresSearchQueryError) {
logger.info('Failed to filter items by metadata, running search query')
const searchResult = await searchLibraryItems(
{
query: `includes:${libraryItemId} AND (${rule.filter})`,
size: 1,
},
userId
)
results = searchResult.libraryItems
} else {
logger.error('Error filtering item events', error)
await markRuleAsFailed(rule.id, userId)
continue
}
}
if (results.length === 0) {
logger.info(`No items found for rule ${rule.id}`)
continue
}
for (const action of rule.actions) {
const actionFunc = getRuleAction(action.type)
const actionObj: RuleActionObj = {
libraryItemId,
userId,
action,
data: filteredData,
data: results[0],
}
actionPromises.push(actionFunc(actionObj))

View File

@ -158,7 +158,7 @@ export const createWorker = (connection: ConnectionOptions) =>
case EXPORT_ALL_ITEMS_JOB_NAME:
return exportAllItems(job.data)
default:
logger.warn(`[queue-processor] unhandled job: ${job.name}`)
logger.warning(`[queue-processor] unhandled job: ${job.name}`)
}
},
{

View File

@ -171,7 +171,7 @@ export const recommendResolver = authorized<
member.user.id,
item.id,
{
group: { id: group.id },
group: { id: group.id, name: group.name },
note: input.note,
recommender: { id: uid },
createdAt: new Date(),
@ -278,11 +278,11 @@ export const recommendHighlightsResolver = authorized<
member.user.id,
item.id,
{
id: group.id,
note: input.note,
recommender: { id: uid },
createdAt: new Date(),
libraryItem: { id: item.id },
group: { id: group.id, name: group.name },
},
auth,
input.highlightIds

View File

@ -47,7 +47,7 @@ export const componentsForCachedReadingPositionKey = (
libraryItemID,
}
} catch (error) {
logger.log('exception getting cache key components', { cacheKey, error })
logger.error('exception getting cache key components', { cacheKey, error })
}
return undefined
}

View File

@ -13,6 +13,7 @@ export enum FeatureName {
AISummaries = 'ai-summaries',
YouTubeTranscripts = 'youtube-transcripts',
UltraRealisticVoice = 'ultra-realistic-voice',
Notion = 'notion',
}
export const getFeatureName = (name: string): FeatureName | undefined => {
@ -36,8 +37,11 @@ export const optInFeature = async (
uid,
MAX_YOUTUBE_TRANSCRIPT_USERS
)
case FeatureName.Notion:
return optInLimitedFeature(FeatureName.Notion, uid, 1)
default:
return undefined
}
return undefined
}
const optInLimitedFeature = async (

View File

@ -259,7 +259,7 @@ export const createLabelAndRuleForGroup = async (
},
],
// add a condition to check if the page is created
filter: `event:created recommendedBy:"${groupName}"`,
filter: `recommendedBy:"${groupName}"`,
})
await Promise.all([addLabelPromise, sendNotificationPromise])

View File

@ -43,6 +43,12 @@ export type UpdateItemEvent = Omit<
IgnoredFields
>
export class RequiresSearchQueryError extends Error {
constructor() {
super('Requires a search query')
}
}
enum ReadFilter {
ALL = 'all',
READ = 'read',
@ -869,7 +875,12 @@ export const updateLibraryItem = async (
// send create event if the item was created
await pubsub.entityCreated<CreateItemEvent>(
EntityType.PAGE,
updatedLibraryItem,
{
...updatedLibraryItem,
originalContent: undefined,
readableContent: undefined,
feedContent: undefined,
},
userId,
id
)
@ -879,7 +890,12 @@ export const updateLibraryItem = async (
await pubsub.entityUpdated<UpdateItemEvent>(
EntityType.PAGE,
libraryItem,
{
...libraryItem,
originalContent: undefined,
readableContent: undefined,
feedContent: undefined,
},
userId,
id
)
@ -1043,7 +1059,12 @@ export const createOrUpdateLibraryItem = async (
await pubsub.entityCreated<CreateItemEvent>(
EntityType.PAGE,
newLibraryItem,
{
...newLibraryItem,
originalContent: undefined,
readableContent: undefined,
feedContent: undefined,
},
userId,
newLibraryItem.id
)
@ -1320,7 +1341,7 @@ export const findLibraryItemIdsByLabelId = async (
export const filterItemEvents = (
ast: LiqeQuery,
events: readonly ItemEvent[]
): readonly ItemEvent[] => {
): ItemEvent[] => {
const testNo = (value: string, event: ItemEvent) => {
const keywordRegexMap: Record<string, RegExp> = {
highlightAnnotations: /^highlight(s)?$/i,
@ -1353,28 +1374,10 @@ export const filterItemEvents = (
throw new Error('Expected a literal expression.')
}
const lowercasedValue = expression.value?.toString().toLowerCase()
const lowercasedValue = expression.value?.toString()?.toLowerCase()
if (field.type === 'ImplicitField') {
if (!lowercasedValue) {
return true
}
const textFields = [
'author',
'title',
'description',
'note',
'siteName',
'readableContent',
'originalUrl',
]
const text = textFields
.map((field) => event[field as keyof ItemEvent])
.join(' ')
// TODO: Implement full text search
return text.match(new RegExp(lowercasedValue, 'i'))
throw new RequiresSearchQueryError()
}
if (!lowercasedValue) {
@ -1422,7 +1425,7 @@ export const filterItemEvents = (
}
}
case 'type': {
return event.itemType?.toString().toLowerCase() === lowercasedValue
return event.itemType?.toString()?.toLowerCase() === lowercasedValue
}
case 'label': {
const labels = event.labelNames as string[] | undefined
@ -1430,7 +1433,9 @@ export const filterItemEvents = (
return labelsToTest.some((label) => {
const hasWildcard = label.includes('*')
if (hasWildcard) {
return labels?.some((l) => l.match(new RegExp(label, 'i')))
return labels?.some(
(l) => l.match(new RegExp(label.replace('*', '.*'), 'i')) // match wildcard
)
}
return labels?.some((l) => l.toLowerCase() === label)
@ -1495,7 +1500,7 @@ export const filterItemEvents = (
// get camel case column name
const key = camelCase(columnName) as 'subscription' | 'itemLanguage'
return event[key]?.toString().toLowerCase() === lowercasedValue
return event[key]?.toString()?.toLowerCase() === lowercasedValue
}
// match filters
case 'author':
@ -1512,7 +1517,7 @@ export const filterItemEvents = (
| 'siteName'
// TODO: Implement full text search
return event[key]?.toString().match(new RegExp(lowercasedValue, 'i'))
return event[key]?.toString()?.match(new RegExp(lowercasedValue, 'i'))
}
case 'includes': {
const ids = lowercasedValue.split(',')
@ -1523,16 +1528,17 @@ export const filterItemEvents = (
return event.id && ids.includes(event.id.toString())
}
case 'recommendedby': {
if (lowercasedValue === '*') {
// select all if * is provided
return event.recommenderNames && event.recommenderNames.length > 0
if (!event.recommenderNames) {
return false
}
return (
event.recommenderNames &&
(event.recommenderNames as string[]).some(
(name) => name.toLowerCase() === lowercasedValue
)
if (lowercasedValue === '*') {
// select all if * is provided
return event.recommenderNames.length > 0
}
return (event.recommenderNames as string[]).some(
(name) => name.toLowerCase() === lowercasedValue
)
}
case 'no':

View File

@ -9,6 +9,7 @@ import {
createOrUpdateLibraryItem,
CreateOrUpdateLibraryItemArgs,
findLibraryItemByUrl,
updateLibraryItem,
} from './library_item'
export const addRecommendation = async (
@ -41,6 +42,7 @@ export const addRecommendation = async (
uploadFile: item.uploadFile,
wordCount: item.wordCount,
publishedAt: item.publishedAt,
recommenderNames: [recommendation.group?.name],
}
recommendedItem = await createOrUpdateLibraryItem(newItem, userId)
@ -65,6 +67,15 @@ export const addRecommendation = async (
if (highlights) {
await createHighlights(highlights, userId)
}
} else {
// update the item
await updateLibraryItem(
recommendedItem.id,
{
recommenderNames: [recommendation.group?.name],
},
userId
)
}
await createRecommendation(

View File

@ -15,7 +15,7 @@ import {
parsePreparedContent,
parseUrlMetadata,
} from '../utils/parser'
import { createAndSaveLabelsInLibraryItem } from './labels'
import { createAndAddLabelsToLibraryItem } from './labels'
import {
createOrUpdateLibraryItem,
findLibraryItemByUrl,
@ -79,6 +79,8 @@ export const saveEmail = async (
return updatedLibraryItem
}
const labels = [{ name: 'Newsletter' }]
// start a transaction to create the library item and update the received email
const newLibraryItem = await createOrUpdateLibraryItem(
{
@ -105,6 +107,7 @@ export const saveEmail = async (
wordCount: wordsCount(content),
subscription: input.author,
folder: input.folder,
labelNames: labels.map((label) => label.name),
},
input.userId
)
@ -120,11 +123,11 @@ export const saveEmail = async (
})
}
// save newsletter label in the item
await createAndSaveLabelsInLibraryItem(
// add newsletter label to the item
await createAndAddLabelsToLibraryItem(
newLibraryItem.id,
input.userId,
[{ name: 'Newsletter' }],
labels,
undefined,
'system'
)

View File

@ -119,12 +119,24 @@ export function Article(props: ArticleProps): JSX.Element {
const youtubePlayer = document.getElementById('_omnivore_youtube_video')
const updateScroll = () => {
console.log('scroll y: ', window.scrollY, youtubePlayer)
const YOUTUBE_PLACEHOLDER_ID = 'omnivore-youtube-placeholder'
const youtubePlaceholder = document.getElementById(YOUTUBE_PLACEHOLDER_ID)
if (youtubePlayer) {
if (window.scrollY > 200) {
if (window.scrollY > 400) {
if (!youtubePlaceholder) {
const rect = youtubePlayer.getBoundingClientRect()
const placeholder = document.createElement('div')
placeholder.setAttribute('id', YOUTUBE_PLACEHOLDER_ID)
placeholder.style.width = rect.width + 'px'
placeholder.style.height = rect.height + 'px'
youtubePlayer.parentNode?.insertBefore(placeholder, youtubePlayer)
}
youtubePlayer.classList.add('is-sticky')
} else {
if (youtubePlaceholder) {
youtubePlayer.parentNode?.removeChild(youtubePlaceholder)
}
youtubePlayer.classList.remove('is-sticky')
}
}

View File

@ -1,11 +1,5 @@
import { UserBasicData } from './networking/queries/useGetViewerQuery'
const VIP_USERS = ['jacksonh', 'satindar', 'hongbo', 'nat']
export const isVipUser = (user: UserBasicData): boolean => {
return VIP_USERS.includes(user.profile.username)
}
export const userHasFeature = (
user: UserBasicData | undefined,
feature: string

View File

@ -1,29 +1,15 @@
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Spinner } from 'phosphor-react'
import { useCallback, useMemo, useState } from 'react'
import { Toaster } from 'react-hot-toast'
import { Button } from '../../../components/elements/Button'
import {
Box,
HStack,
SpanBox,
VStack,
} from '../../../components/elements/LayoutPrimitives'
import { HStack, VStack } from '../../../components/elements/LayoutPrimitives'
import { StyledText } from '../../../components/elements/StyledText'
import { SettingsLayout } from '../../../components/templates/SettingsLayout'
import { styled, theme } from '../../../components/tokens/stitches.config'
import { updateEmailMutation } from '../../../lib/networking/mutations/updateEmailMutation'
import { updateUserMutation } from '../../../lib/networking/mutations/updateUserMutation'
import { updateUserProfileMutation } from '../../../lib/networking/mutations/updateUserProfileMutation'
import { useGetLibraryItemsQuery } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { styled } from '../../../components/tokens/stitches.config'
import { optInFeature } from '../../../lib/networking/mutations/optIntoFeatureMutation'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useValidateUsernameQuery } from '../../../lib/networking/queries/useValidateUsernameQuery'
import { applyStoredTheme } from '../../../lib/themeUpdater'
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
import { ConfirmationModal } from '../../../components/patterns/ConfirmationModal'
import { ProgressBar } from '../../../components/elements/ProgressBar'
import { emptyTrashMutation } from '../../../lib/networking/mutations/emptyTrashMutation'
import { ProgressIndicator } from '@radix-ui/react-progress'
import { Spinner } from 'phosphor-react'
import { optInFeature } from '../../../lib/networking/mutations/optIntoFeatureMutation'
const ACCOUNT_LIMIT = 50_000
@ -62,6 +48,10 @@ export default function Account(): JSX.Element {
)
}, [viewerData])
const hasNotion = useMemo(() => {
return (viewerData?.me?.features.indexOf('notion') ?? -1) !== -1
}, [viewerData])
applyStoredTheme()
return (
@ -121,7 +111,8 @@ export default function Account(): JSX.Element {
)
})}
{!hasYouTube /* || !hasAISummaries || !hasDigest */ && (
{(!hasYouTube ||
!hasNotion) /* || !hasAISummaries || !hasDigest */ && (
<StyledLabel css={{ mt: '25px' }}>
Available beta features
</StyledLabel>
@ -154,6 +145,31 @@ export default function Account(): JSX.Element {
</VStack>
)}
{!hasNotion && (
<VStack
alignment="start"
distribution="start"
css={{ width: '100%' }}
>
<StyledText
style="footnote"
css={{ display: 'flex', gap: '5px' }}
>
- Notion integration: Export your items and highlights
to Notion.
</StyledText>
<Button
style="ctaDarkYellow"
onClick={(event) => {
requestFeatureAccess('notion')
event.preventDefault()
}}
>
Request feature
</Button>
</VStack>
)}
{/* <VStack
alignment="start"
distribution="start"

View File

@ -17,6 +17,7 @@ import {
} from '../../components/elements/LayoutPrimitives'
import { SettingsLayout } from '../../components/templates/SettingsLayout'
import { fetchEndpoint } from '../../lib/appConfig'
import { userHasFeature } from '../../lib/featureFlag'
import { deleteIntegrationMutation } from '../../lib/networking/mutations/deleteIntegrationMutation'
import { importFromIntegrationMutation } from '../../lib/networking/mutations/importFromIntegrationMutation'
import {
@ -27,8 +28,8 @@ import {
Integration,
useGetIntegrationsQuery,
} from '../../lib/networking/queries/useGetIntegrationsQuery'
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
import { useGetWebhooksQuery } from '../../lib/networking/queries/useGetWebhooksQuery'
import { applyStoredTheme } from '../../lib/themeUpdater'
import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers'
// Styles
const Header = styled(Box, {
@ -74,7 +75,8 @@ type integrationsCard = {
}
}
export default function Integrations(): JSX.Element {
applyStoredTheme()
const { viewerData } = useGetViewerQuery()
const { integrations, revalidate } = useGetIntegrationsQuery()
const { webhooks } = useGetWebhooksQuery()
@ -202,7 +204,7 @@ export default function Integrations(): JSX.Element {
}, [router])
useEffect(() => {
setIntegrationsArray([
const integrationsArray = [
{
icon: '/static/icons/logseq.svg',
title: 'Logseq',
@ -267,22 +269,6 @@ export default function Integrations(): JSX.Element {
],
},
},
{
icon: '/static/icons/notion.png',
title: 'Notion',
subText:
'Notion is an all-in-one workspace. Use our Notion integration to sync your Omnivore items to Notion.',
button: {
text: isConnected('NOTION') ? 'Settings' : 'Connect',
icon: <Link size={16} weight={'bold'} />,
style: isConnected('NOTION') ? 'ctaWhite' : 'ctaDarkYellow',
action: () => {
isConnected('NOTION')
? router.push('/settings/integrations/notion')
: redirectToIntegration('NOTION')
},
},
},
{
icon: '/static/icons/webhooks.svg',
title: 'Webhooks',
@ -310,7 +296,27 @@ export default function Integrations(): JSX.Element {
},
},
},
])
]
userHasFeature(viewerData?.me, 'notion') &&
integrationsArray.push({
icon: '/static/icons/notion.png',
title: 'Notion',
subText:
'Notion is an all-in-one workspace. Use our Notion integration to sync your Omnivore items to Notion.',
button: {
text: isConnected('NOTION') ? 'Settings' : 'Connect',
icon: <Link size={16} weight={'bold'} />,
style: isConnected('NOTION') ? 'ctaWhite' : 'ctaDarkYellow',
action: () => {
isConnected('NOTION')
? router.push('/settings/integrations/notion')
: redirectToIntegration('NOTION')
},
},
})
setIntegrationsArray(integrationsArray)
}, [pocketConnected, readwiseConnected, webhooks, integrations])
return (

View File

@ -7,7 +7,6 @@ import {
message,
Space,
Spin,
Switch,
} from 'antd'
import 'antd/dist/antd.compact.css'
import { CheckboxValueType } from 'antd/lib/checkbox/Group'
@ -16,7 +15,6 @@ import { useRouter } from 'next/router'
import { useCallback, useEffect, useState } from 'react'
import { HStack, VStack } from '../../../components/elements/LayoutPrimitives'
import { PageMetaData } from '../../../components/patterns/PageMetaData'
import { Beta } from '../../../components/templates/Beta'
import { Header } from '../../../components/templates/settings/SettingsTable'
import { SettingsLayout } from '../../../components/templates/SettingsLayout'
import { deleteIntegrationMutation } from '../../../lib/networking/mutations/deleteIntegrationMutation'
@ -34,7 +32,6 @@ import { showSuccessToast } from '../../../lib/toastHelpers'
type FieldType = {
parentPageId?: string
parentDatabaseId?: string
enabled: boolean
properties?: string[]
}
@ -52,7 +49,6 @@ export default function Notion(): JSX.Element {
form.setFieldsValue({
parentPageId: notion.settings?.parentPageId,
parentDatabaseId: notion.settings?.parentDatabaseId,
enabled: notion.enabled,
properties: notion.settings?.properties,
})
}, [form, notion])
@ -71,7 +67,7 @@ export default function Notion(): JSX.Element {
name: notion.name,
type: notion.type,
token: notion.token,
enabled: values.enabled,
enabled: true,
settings: values,
})
}
@ -159,7 +155,6 @@ export default function Notion(): JSX.Element {
height={75}
/>
<Header>Notion integration settings</Header>
<Beta />
</HStack>
<div style={{ width: '100%', marginTop: '40px' }}>
@ -194,15 +189,6 @@ export default function Notion(): JSX.Element {
<Input disabled />
</Form.Item>
<Form.Item<FieldType>
label="Automatic Sync"
name="enabled"
valuePropName="checked"
help="Once connected all new items will be exported to Notion"
>
<Switch />
</Form.Item>
<Form.Item<FieldType>
label="Properties to Export"
name="properties"

View File

@ -664,4 +664,10 @@
-webkit-transform: none;
transform: none;
}
}
}
.youtubeplaceholder {
border: 2px dashed #aaa;
box-sizing: border-box;
}

320
yarn.lock
View File

@ -2767,11 +2767,6 @@
dependencies:
tslib "^2.1.0"
"@floating-ui/core@^0.7.3":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86"
integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==
"@floating-ui/core@^1.0.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1"
@ -2779,13 +2774,6 @@
dependencies:
"@floating-ui/utils" "^0.2.1"
"@floating-ui/dom@^0.5.3":
version "0.5.4"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1"
integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==
dependencies:
"@floating-ui/core" "^0.7.3"
"@floating-ui/dom@^1.6.1":
version "1.6.3"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.3.tgz#954e46c1dd3ad48e49db9ada7218b0985cee75ef"
@ -2794,14 +2782,6 @@
"@floating-ui/core" "^1.0.0"
"@floating-ui/utils" "^0.2.0"
"@floating-ui/react-dom@0.7.2":
version "0.7.2"
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-0.7.2.tgz#0bf4ceccb777a140fc535c87eb5d6241c8e89864"
integrity sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==
dependencies:
"@floating-ui/dom" "^0.5.3"
use-isomorphic-layout-effect "^1.1.1"
"@floating-ui/react-dom@^2.0.0", "@floating-ui/react-dom@^2.0.8":
version "2.0.8"
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d"
@ -5048,14 +5028,6 @@
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-arrow@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.0.tgz#c461f4c2cab3317e3d42a1ae62910a4cbb0192a1"
integrity sha512-1MUuv24HCdepi41+qfv125EwMuxgQ+U+h0A9K3BjCO/J8nVRREKHHpkD9clwfnjEDk9hgGzCnff4aUKCPiRepw==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-arrow@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz#c24f7968996ed934d57fe6cde5d6ec7266e1d25d"
@ -5091,17 +5063,6 @@
"@radix-ui/react-use-previous" "0.1.1"
"@radix-ui/react-use-size" "0.1.1"
"@radix-ui/react-collection@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.0.tgz#0ec4c72fabd35a03b5787075ac799e3b17ca5710"
integrity sha512-8i1pf5dKjnq90Z8udnnXKzdCEV3/FYrfw0n/b6NvB6piXEn3fO1bOh7HBcpG8XrnIXzxlYu2oCcR38QpyLS/mg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-slot" "1.0.0"
"@radix-ui/react-collection@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159"
@ -5176,13 +5137,6 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"
"@radix-ui/react-direction@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.0.tgz#a2e0b552352459ecf96342c79949dd833c1e6e45"
integrity sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-direction@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"
@ -5190,18 +5144,6 @@
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-dismissable-layer@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz#35b7826fa262fd84370faef310e627161dffa76b"
integrity sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.0"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-escape-keydown" "1.0.0"
"@radix-ui/react-dismissable-layer@1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4"
@ -5214,26 +5156,19 @@
"@radix-ui/react-use-callback-ref" "1.0.1"
"@radix-ui/react-use-escape-keydown" "1.0.3"
"@radix-ui/react-dropdown-menu@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-1.0.0.tgz#687959e1bcdd5e8eb0de406484aff28d0974c593"
integrity sha512-Ptben3TxPWrZLbInO7zjAK73kmjYuStsxfg6ujgt+EywJyREoibhZYnsSNqC+UiOtl4PdW/MOHhxVDtew5fouQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.0"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-id" "1.0.0"
"@radix-ui/react-menu" "1.0.0"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-use-controllable-state" "1.0.0"
"@radix-ui/react-focus-guards@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz#339c1c69c41628c1a5e655f15f7020bf11aa01fa"
integrity sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==
"@radix-ui/react-dropdown-menu@2.0.6":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.6.tgz#cdf13c956c5e263afe4e5f3587b3071a25755b63"
integrity sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-id" "1.0.1"
"@radix-ui/react-menu" "2.0.6"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-controllable-state" "1.0.1"
"@radix-ui/react-focus-guards@1.0.1":
version "1.0.1"
@ -5242,16 +5177,6 @@
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-focus-scope@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.0.tgz#95a0c1188276dc8933b1eac5f1cdb6471e01ade5"
integrity sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-focus-scope@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525"
@ -5270,14 +5195,6 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-layout-effect" "0.1.0"
"@radix-ui/react-id@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e"
integrity sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-layout-effect" "1.0.0"
"@radix-ui/react-id@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0"
@ -5297,30 +5214,30 @@
"@radix-ui/react-id" "0.1.5"
"@radix-ui/react-primitive" "0.1.4"
"@radix-ui/react-menu@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-1.0.0.tgz#f1e07778c0011aa0c5be260fee88491d3aadf261"
integrity sha512-icW4C64T6nHh3Z4Q1fxO1RlSShouFF4UpUmPV8FLaJZfphDljannKErDuALDx4ClRLihAPZ9i+PrLNPoWS2DMA==
"@radix-ui/react-menu@2.0.6":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.6.tgz#2c9e093c1a5d5daa87304b2a2f884e32288ae79e"
integrity sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.0"
"@radix-ui/react-collection" "1.0.0"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-direction" "1.0.0"
"@radix-ui/react-dismissable-layer" "1.0.0"
"@radix-ui/react-focus-guards" "1.0.0"
"@radix-ui/react-focus-scope" "1.0.0"
"@radix-ui/react-id" "1.0.0"
"@radix-ui/react-popper" "1.0.0"
"@radix-ui/react-portal" "1.0.0"
"@radix-ui/react-presence" "1.0.0"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-roving-focus" "1.0.0"
"@radix-ui/react-slot" "1.0.0"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-collection" "1.0.3"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-direction" "1.0.1"
"@radix-ui/react-dismissable-layer" "1.0.5"
"@radix-ui/react-focus-guards" "1.0.1"
"@radix-ui/react-focus-scope" "1.0.4"
"@radix-ui/react-id" "1.0.1"
"@radix-ui/react-popper" "1.1.3"
"@radix-ui/react-portal" "1.0.4"
"@radix-ui/react-presence" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-roving-focus" "1.0.4"
"@radix-ui/react-slot" "1.0.2"
"@radix-ui/react-use-callback-ref" "1.0.1"
aria-hidden "^1.1.1"
react-remove-scroll "2.5.4"
react-remove-scroll "2.5.5"
"@radix-ui/react-popover@1.0.7":
version "1.0.7"
@ -5344,22 +5261,6 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"
"@radix-ui/react-popper@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.0.0.tgz#fb4f937864bf39c48f27f55beee61fa9f2bef93c"
integrity sha512-k2dDd+1Wl0XWAMs9ZvAxxYsB9sOsEhrFQV4CINd7IUZf0wfdye4OHen9siwxvZImbzhgVeKTJi68OQmPRvVdMg==
dependencies:
"@babel/runtime" "^7.13.10"
"@floating-ui/react-dom" "0.7.2"
"@radix-ui/react-arrow" "1.0.0"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-use-layout-effect" "1.0.0"
"@radix-ui/react-use-rect" "1.0.0"
"@radix-ui/react-use-size" "1.0.0"
"@radix-ui/rect" "1.0.0"
"@radix-ui/react-popper@1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.3.tgz#24c03f527e7ac348fabf18c89795d85d21b00b42"
@ -5377,14 +5278,6 @@
"@radix-ui/react-use-size" "1.0.1"
"@radix-ui/rect" "1.0.1"
"@radix-ui/react-portal@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.0.tgz#7220b66743394fabb50c55cb32381395cc4a276b"
integrity sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-portal@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15"
@ -5410,15 +5303,6 @@
"@radix-ui/react-compose-refs" "0.1.0"
"@radix-ui/react-use-layout-effect" "0.1.0"
"@radix-ui/react-presence@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz#814fe46df11f9a468808a6010e3f3ca7e0b2e84a"
integrity sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-use-layout-effect" "1.0.0"
"@radix-ui/react-presence@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba"
@ -5444,14 +5328,6 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-slot" "0.1.2"
"@radix-ui/react-primitive@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz#376cd72b0fcd5e0e04d252ed33eb1b1f025af2b0"
integrity sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-slot" "1.0.0"
"@radix-ui/react-primitive@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz#c1ebcce283dd2f02e4fbefdaa49d1cb13dbc990a"
@ -5485,21 +5361,21 @@
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-primitive" "1.0.1"
"@radix-ui/react-roving-focus@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.0.tgz#aadeb65d5dbcdbdd037078156ae1f57c2ff754ee"
integrity sha512-lHvO4MhvoWpeNbiJAoyDsEtbKqP2jkkdwsMVJ3kfqbkC71J/aXE6Th6gkZA1xHEqSku+t+UgoDjvE7Z3gsBpcg==
"@radix-ui/react-roving-focus@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz#e90c4a6a5f6ac09d3b8c1f5b5e81aab2f0db1974"
integrity sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.0"
"@radix-ui/react-collection" "1.0.0"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-direction" "1.0.0"
"@radix-ui/react-id" "1.0.0"
"@radix-ui/react-primitive" "1.0.0"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-controllable-state" "1.0.0"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-collection" "1.0.3"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-direction" "1.0.1"
"@radix-ui/react-id" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-callback-ref" "1.0.1"
"@radix-ui/react-use-controllable-state" "1.0.1"
"@radix-ui/react-separator@^0.1.0":
version "0.1.3"
@ -5535,14 +5411,6 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "0.1.0"
"@radix-ui/react-slot@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.0.tgz#7fa805b99891dea1e862d8f8fbe07f4d6d0fd698"
integrity sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-slot@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.1.tgz#e7868c669c974d649070e9ecbec0b367ee0b4d81"
@ -5618,14 +5486,6 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-callback-ref" "1.0.1"
"@radix-ui/react-use-escape-keydown@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz#aef375db4736b9de38a5a679f6f49b45a060e5d1"
integrity sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-escape-keydown@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755"
@ -5676,14 +5536,6 @@
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-rect@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz#b040cc88a4906b78696cd3a32b075ed5b1423b3e"
integrity sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/rect" "1.0.0"
"@radix-ui/react-use-rect@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2"
@ -5715,13 +5567,6 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-layout-effect" "1.0.1"
"@radix-ui/rect@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.0.tgz#0dc8e6a829ea2828d53cbc94b81793ba6383bf3c"
integrity sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/rect@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.1.tgz#bf8e7d947671996da2e30f4904ece343bc4a883f"
@ -6706,6 +6551,11 @@
resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20"
integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==
"@sqltools/formatter@^1.2.5":
version "1.2.5"
resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12"
integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==
"@stitches/react@^1.2.5":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@stitches/react/-/react-1.2.8.tgz#954f8008be8d9c65c4e58efa0937f32388ce3a38"
@ -8558,7 +8408,7 @@
dependencies:
undici-types "~5.26.4"
"@types/node@^20.8.4":
"@types/node@^20.11.0", "@types/node@^20.8.4":
version "20.11.30"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f"
integrity sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==
@ -10126,6 +9976,11 @@ app-root-path@^3.0.0:
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad"
integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==
app-root-path@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86"
integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==
apparatus@^0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/apparatus/-/apparatus-0.0.10.tgz#81ea756772ada77863db54ceee8202c109bdca3e"
@ -13604,7 +13459,7 @@ dateformat@^3.0.0, dateformat@^3.0.3:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
dayjs@1.x, dayjs@^1.10.4, dayjs@^1.11.7:
dayjs@1.x, dayjs@^1.10.4, dayjs@^1.11.7, dayjs@^1.11.9:
version "1.11.10"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
@ -14340,7 +14195,7 @@ dotenv@^16.0.1:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d"
integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==
dotenv@^16.3.1:
dotenv@^16.0.3, dotenv@^16.3.1:
version "16.4.5"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
@ -17032,7 +16887,7 @@ glob@7.2.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glo
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^10.2.2:
glob@^10.2.2, glob@^10.3.10:
version "10.3.10"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
@ -22808,6 +22663,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
mkdirp@^2.1.3:
version "2.1.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
mkdirp@~0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7"
@ -26970,17 +26830,6 @@ react-remove-scroll-bar@^2.3.3:
react-style-singleton "^2.2.1"
tslib "^2.0.0"
react-remove-scroll@2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz#afe6491acabde26f628f844b67647645488d2ea0"
integrity sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==
dependencies:
react-remove-scroll-bar "^2.3.3"
react-style-singleton "^2.2.1"
tslib "^2.1.0"
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"
react-remove-scroll@2.5.5:
version "2.5.5"
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77"
@ -27212,6 +27061,14 @@ read-pkg@^7.1.0:
parse-json "^5.2.0"
type-fest "^2.0.0"
read-yaml-file@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/read-yaml-file/-/read-yaml-file-2.1.0.tgz#c5866712db9ef5343b4d02c2413bada53c41c4a9"
integrity sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==
dependencies:
js-yaml "^4.0.0"
strip-bom "^4.0.0"
read@1, read@^1.0.7, read@~1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
@ -27366,6 +27223,11 @@ reflect-metadata@^0.1.13:
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
reflect-metadata@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.1.tgz#8d5513c0f5ef2b4b9c3865287f3c0940c1f67f74"
integrity sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==
reflect.getprototypeof@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3"
@ -30653,6 +30515,27 @@ typeorm-naming-strategies@^4.1.0:
resolved "https://registry.yarnpkg.com/typeorm-naming-strategies/-/typeorm-naming-strategies-4.1.0.tgz#1ec6eb296c8d7b69bb06764d5b9083ff80e814a9"
integrity sha512-vPekJXzZOTZrdDvTl1YoM+w+sUIfQHG4kZTpbFYoTsufyv9NIBRe4Q+PdzhEAFA2std3D9LZHEb1EjE9zhRpiQ==
typeorm@^0.3.19:
version "0.3.20"
resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.20.tgz#4b61d737c6fed4e9f63006f88d58a5e54816b7ab"
integrity sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==
dependencies:
"@sqltools/formatter" "^1.2.5"
app-root-path "^3.1.0"
buffer "^6.0.3"
chalk "^4.1.2"
cli-highlight "^2.1.11"
dayjs "^1.11.9"
debug "^4.3.4"
dotenv "^16.0.3"
glob "^10.3.10"
mkdirp "^2.1.3"
reflect-metadata "^0.2.1"
sha.js "^2.4.11"
tslib "^2.5.0"
uuid "^9.0.0"
yargs "^17.6.2"
typeorm@^0.3.4:
version "0.3.7"
resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.7.tgz#5776ed5058f0acb75d64723b39ff458d21de64c1"
@ -30691,6 +30574,11 @@ typescript@^4.4.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
typescript@^5.3.3:
version "5.4.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff"
integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==
ua-parser-js@^0.7.30:
version "0.7.33"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532"
@ -31193,7 +31081,7 @@ use-composed-ref@^1.0.0:
resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849"
integrity sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==
use-isomorphic-layout-effect@^1.0.0, use-isomorphic-layout-effect@^1.1.1:
use-isomorphic-layout-effect@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==