From 783e25b63ac709dc580c8604e1f6a45de9f8b01a Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Fri, 7 Oct 2022 12:48:02 +0800 Subject: [PATCH 01/17] Remove text to speech feature flag, its enabled for everyone now --- .../Sources/App/Views/WebReader/WebReaderContainer.swift | 4 +--- apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift index b2d883adb..31f50f7a8 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift @@ -132,9 +132,7 @@ struct WebReaderContainerView: View { .scaleEffect(navBarVisibilityRatio) Spacer() #endif - if FeatureFlag.enableTextToSpeechButton { - audioNavbarItem - } + audioNavbarItem Button( action: { showPreferencesPopover.toggle() }, label: { diff --git a/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift b/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift index 5c8ac8803..622ded52e 100644 --- a/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift +++ b/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift @@ -14,6 +14,5 @@ public enum FeatureFlag { public static let enableShareButton = false public static let enableSnooze = false public static let enableGridCardsOnPhone = false - public static let enableTextToSpeechButton = true public static let enableHighlightsView = true } From 7267f078806c4c680d8b10823c7361f88101f52f Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Mon, 10 Oct 2022 22:06:52 +0800 Subject: [PATCH 02/17] Use a new modal for search --- .../App/Views/AudioPlayer/MiniPlayer.swift | 6 +- .../App/Views/Home/HomeFeedViewIOS.swift | 345 ++++++------ .../App/Views/Home/HomeFeedViewModel.swift | 3 + .../Sources/App/Views/Home/HomeView.swift | 14 +- .../App/Views/Home/LibrarySearchView.swift | 152 +++++ .../Views/Home/LibrarySearchViewModel.swift | 91 +++ .../CoreDataModel.xcdatamodel/contents | 5 + .../Models/DataModels/RecentSearchItem.swift | 10 + .../Services/DataService/OfflineSync.swift | 1 - .../Queries/TypeAheadSearchQuery.swift | 65 +++ .../Sources/Utils/UserDefaultKeys.swift | 1 + .../OmnivoreKit/Sources/Views/TextChip.swift | 12 +- packages/web/package.json | 1 + packages/web/pages/settings/api.tsx | 45 +- yarn.lock | 533 +++++++++++++++++- 15 files changed, 1111 insertions(+), 173 deletions(-) create mode 100644 apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift create mode 100644 apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchViewModel.swift create mode 100644 apple/OmnivoreKit/Sources/Models/DataModels/RecentSearchItem.swift create mode 100644 apple/OmnivoreKit/Sources/Services/DataService/Queries/TypeAheadSearchQuery.swift diff --git a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift index f4ccce43b..32f065178 100644 --- a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift @@ -239,10 +239,12 @@ public struct MiniPlayer: View { } }) .onChange(of: audioController.currentAudioIndex, perform: { index in + if index >= (audioController.textItems?.count ?? 0) { + return + } + if self.audioController.state != .reachedEnd { tabIndex = index - } else { - tabIndex = (self.audioController.textItems?.count ?? 0) + 1 } }) .frame(width: geom.size.width) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 0154e4eff..d31a30ca7 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -12,6 +12,7 @@ import Views struct HomeFeedContainerView: View { @State var hasHighlightMutations = false + @State var searchPresented = false @EnvironmentObject var dataService: DataService @EnvironmentObject var audioController: AudioController @@ -67,6 +68,13 @@ import Views HighlightsListView(itemObjectID: item.objectID, hasHighlightMutations: $hasHighlightMutations) } .toolbar { + ToolbarItem(placement: .barLeading) { + Image.smallOmnivoreLogo + .renderingMode(.template) + .resizable() + .frame(width: 24, height: 24) + .foregroundColor(.appGrayTextContrast) + } ToolbarItem(placement: .barTrailing) { Button("", action: {}) .disabled(true) @@ -88,15 +96,28 @@ import Views EmptyView() } } + ToolbarItem(placement: .barTrailing) { + Button( + action: { searchPresented = true }, + label: { + Image(systemName: "magnifyingglass") + .resizable() + .frame(width: 18, height: 18) + .padding(.vertical) + .foregroundColor(.appGrayTextContrast) + } + ) + } ToolbarItem(placement: .barTrailing) { if UIDevice.isIPhone { NavigationLink( destination: { ProfileView() }, label: { - Image.profile + Image(systemName: "person.circle") .resizable() - .frame(width: 26, height: 26) - .padding(.vertical) + .frame(width: 22, height: 22) + .padding(.vertical, 16) + .foregroundColor(.appGrayTextContrast) } ) } else { @@ -105,8 +126,6 @@ import Views } } } - .navigationTitle("Home") - .navigationBarTitleDisplayMode(.inline) .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in loadItems(isRefresh: true) } @@ -148,6 +167,9 @@ import Views } } } + .fullScreenCover(isPresented: $searchPresented) { + LibrarySearchView(homeFeedViewModel: self.viewModel) + } .task { if viewModel.items.isEmpty { loadItems(isRefresh: true) @@ -159,75 +181,26 @@ import Views struct HomeFeedView: View { @EnvironmentObject var dataService: DataService @Binding var prefersListLayout: Bool - @State private var showLabelsSheet = false @ObservedObject var viewModel: HomeFeedViewModel var body: some View { VStack(spacing: 0) { - SearchBar(searchTerm: $viewModel.searchTerm) - - ZStack(alignment: .bottom) { - ScrollView(.horizontal, showsIndicators: false) { - HStack { - Menu( - content: { - ForEach(LinkedItemFilter.allCases, id: \.self) { filter in - Button(filter.displayName, action: { viewModel.appliedFilter = filter.rawValue }) - } - }, - label: { - TextChipButton.makeMenuButton( - title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter" - ) - } - ) - Menu( - content: { - ForEach(LinkedItemSort.allCases, id: \.self) { sort in - Button(sort.displayName, action: { viewModel.appliedSort = sort.rawValue }) - } - }, - label: { - TextChipButton.makeMenuButton( - title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort" - ) - } - ) - TextChipButton.makeAddLabelButton { - showLabelsSheet = true - } - ForEach(viewModel.selectedLabels, id: \.self) { label in - TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) { - viewModel.selectedLabels.removeAll { $0.id == label.id } - } - } - ForEach(viewModel.negatedLabels, id: \.self) { label in - TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: true) { - viewModel.negatedLabels.removeAll { $0.id == label.id } - } - } - Spacer() - } - .padding(.horizontal) - .sheet(isPresented: $showLabelsSheet) { - FilterByLabelsView( - initiallySelected: viewModel.selectedLabels, - initiallyNegated: viewModel.negatedLabels - ) { - self.viewModel.selectedLabels = $0 - self.viewModel.negatedLabels = $1 - } - } - } - if viewModel.showLoadingBar { - ShimmeringLoader() - } - } +// if viewModel.showLoadingBar { +// ShimmeringLoader() +// } if prefersListLayout || !enableGrid { HomeFeedListView(prefersListLayout: $prefersListLayout, viewModel: viewModel) } else { HomeFeedGridView(viewModel: viewModel) } + }.sheet(isPresented: $viewModel.showLabelsSheet) { + FilterByLabelsView( + initiallySelected: viewModel.selectedLabels, + initiallyNegated: viewModel.negatedLabels + ) { + self.viewModel.selectedLabels = $0 + self.viewModel.negatedLabels = $1 + } } } } @@ -243,6 +216,59 @@ import Views @ObservedObject var viewModel: HomeFeedViewModel + var filtersHeader: some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack { + if viewModel.searchTerm.count > 0 { + TextChipButton.makeSearchFilterButton(title: viewModel.searchTerm) { + viewModel.searchTerm = "" + } + } else { + Menu( + content: { + ForEach(LinkedItemFilter.allCases, id: \.self) { filter in + Button(filter.displayName, action: { viewModel.appliedFilter = filter.rawValue }) + } + }, + label: { + TextChipButton.makeMenuButton( + title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter" + ) + } + ) + } + Menu( + content: { + ForEach(LinkedItemSort.allCases, id: \.self) { sort in + Button(sort.displayName, action: { viewModel.appliedSort = sort.rawValue }) + } + }, + label: { + TextChipButton.makeMenuButton( + title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort" + ) + } + ) + TextChipButton.makeAddLabelButton { + viewModel.showLabelsSheet = true + } + ForEach(viewModel.selectedLabels, id: \.self) { label in + TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) { + viewModel.selectedLabels.removeAll { $0.id == label.id } + } + } + ForEach(viewModel.negatedLabels, id: \.self) { label in + TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: true) { + viewModel.negatedLabels.removeAll { $0.id == label.id } + } + } + Spacer() + } + .padding(0) + } + .listRowSeparator(.hidden) + } + var body: some View { ZStack { NavigationLink( @@ -252,113 +278,116 @@ import Views EmptyView() } List { - Section { - ForEach(viewModel.items) { item in - FeedCardNavigationLink( - item: item, - viewModel: viewModel + if viewModel.items.count > 0 { + filtersHeader + } + + ForEach(viewModel.items) { item in + FeedCardNavigationLink( + item: item, + viewModel: viewModel + ) + .contextMenu { + Button( + action: { viewModel.itemForHighlightsView = item }, + label: { Label("View Highlights", systemImage: "highlighter") } ) - .contextMenu { - Button( - action: { viewModel.itemForHighlightsView = item }, - label: { Label("View Highlights", systemImage: "highlighter") } - ) - Button( - action: { viewModel.itemUnderTitleEdit = item }, - label: { Label("Edit Title/Description", systemImage: "textbox") } - ) - Button( - action: { viewModel.itemUnderLabelEdit = item }, - label: { Label("Edit Labels", systemImage: "tag") } - ) - Button(action: { - withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived( - dataService: dataService, - objectID: item.objectID, - archived: !item.isArchived - ) - } - }, label: { - Label( - item.isArchived ? "Unarchive" : "Archive", - systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" + Button( + action: { viewModel.itemUnderTitleEdit = item }, + label: { Label("Edit Title/Description", systemImage: "textbox") } + ) + Button( + action: { viewModel.itemUnderLabelEdit = item }, + label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") } + ) + Button(action: { + withAnimation(.linear(duration: 0.4)) { + viewModel.setLinkArchived( + dataService: dataService, + objectID: item.objectID, + archived: !item.isArchived ) - }) - Button( - action: { - itemToRemove = item - confirmationShown = true - }, - label: { Label("Delete", systemImage: "trash") } - ) - if FeatureFlag.enableSnooze { - Button { - viewModel.itemToSnoozeID = item.id - viewModel.snoozePresented = true - } label: { - Label { Text("Snooze") } icon: { Image.moon } - } } - Button( - action: { viewModel.downloadAudio(audioController: audioController, item: item) }, - label: { Label("Download Audio", systemImage: "icloud.and.arrow.down") } + }, label: { + Label( + item.isArchived ? "Unarchive" : "Archive", + systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" ) - } - .swipeActions(edge: .trailing, allowsFullSwipe: true) { - if !item.isArchived { - Button { - withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: true) - } - } label: { - Label("Archive", systemImage: "archivebox") - }.tint(.green) - } else { - Button { - withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: false) - } - } label: { - Label("Unarchive", systemImage: "tray.and.arrow.down.fill") - }.tint(.indigo) + }) + Button( + action: { + itemToRemove = item + confirmationShown = true + }, + label: { Label("Delete", systemImage: "trash") } + ) + if FeatureFlag.enableSnooze { + Button { + viewModel.itemToSnoozeID = item.id + viewModel.snoozePresented = true + } label: { + Label { Text("Snooze") } icon: { Image.moon } } } - .swipeActions(edge: .trailing, allowsFullSwipe: true) { - Button( - role: .destructive, - action: { - itemToRemove = item - confirmationShown = true - }, - label: { - Image(systemName: "trash") + Button( + action: { viewModel.downloadAudio(audioController: audioController, item: item) }, + label: { Label("Download Audio", systemImage: "icloud.and.arrow.down") } + ) + } + .swipeActions(edge: .trailing, allowsFullSwipe: true) { + if !item.isArchived { + Button { + withAnimation(.linear(duration: 0.4)) { + viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: true) } - ) - }.alert("Are you sure?", isPresented: $confirmationShown) { - Button("Remove Link", role: .destructive) { - if let itemToRemove = itemToRemove { - withAnimation { - viewModel.removeLink(dataService: dataService, objectID: itemToRemove.objectID) - } + } label: { + Label("Archive", systemImage: "archivebox") + }.tint(.green) + } else { + Button { + withAnimation(.linear(duration: 0.4)) { + viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: false) } - self.itemToRemove = nil - } - Button("Cancel", role: .cancel) { self.itemToRemove = nil } + } label: { + Label("Unarchive", systemImage: "tray.and.arrow.down.fill") + }.tint(.indigo) } - .swipeActions(edge: .leading, allowsFullSwipe: true) { - if FeatureFlag.enableSnooze { - Button { - viewModel.itemToSnoozeID = item.id - viewModel.snoozePresented = true - } label: { - Label { Text("Snooze") } icon: { Image.moon } - }.tint(.appYellow48) + } + .swipeActions(edge: .trailing, allowsFullSwipe: true) { + Button( + role: .destructive, + action: { + itemToRemove = item + confirmationShown = true + }, + label: { + Image(systemName: "trash") } + ) + }.alert("Are you sure?", isPresented: $confirmationShown) { + Button("Remove Link", role: .destructive) { + if let itemToRemove = itemToRemove { + withAnimation { + viewModel.removeLink(dataService: dataService, objectID: itemToRemove.objectID) + } + } + self.itemToRemove = nil + } + Button("Cancel", role: .cancel) { self.itemToRemove = nil } + } + .swipeActions(edge: .leading, allowsFullSwipe: true) { + if FeatureFlag.enableSnooze { + Button { + viewModel.itemToSnoozeID = item.id + viewModel.snoozePresented = true + } label: { + Label { Text("Snooze") } icon: { Image.moon } + }.tint(.appYellow48) } } } } + .padding(.top, 0) .listStyle(PlainListStyle()) } } diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift index 65d4f4d75..7e5d23189 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift @@ -19,6 +19,7 @@ import Views @Published var itemUnderTitleEdit: LinkedItem? @Published var itemForHighlightsView: LinkedItem? @Published var searchTerm = "" + @Published var scopeSelection = 0 @Published var selectedLabels = [LinkedItemLabel]() @Published var negatedLabels = [LinkedItemLabel]() @Published var snoozePresented = false @@ -30,6 +31,8 @@ import Views @Published var selectedItem: LinkedItem? @Published var linkIsActive = false + @Published var showLabelsSheet = false + @AppStorage(UserDefaultKey.lastSelectedLinkedItemFilter.rawValue) var appliedFilter = LinkedItemFilter.inbox.rawValue @AppStorage(UserDefaultKey.lastItemSyncTime.rawValue) var lastItemSyncTime = DateFormatter.formatterISO8601.string( diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift index b025250da..d7f6781a9 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift @@ -3,14 +3,18 @@ import SwiftUI struct HomeView: View { @StateObject private var viewModel = HomeFeedViewModel() + var navView: some View { + NavigationView { + HomeFeedContainerView(viewModel: viewModel) + } + .navigationViewStyle(.stack) + .accentColor(.appGrayTextContrast) + } + var body: some View { #if os(iOS) if UIDevice.isIPhone { - NavigationView { - HomeFeedContainerView(viewModel: viewModel) - } - .navigationViewStyle(.stack) - .accentColor(.appGrayTextContrast) + navView } else { HomeFeedContainerView(viewModel: viewModel) } diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift new file mode 100644 index 000000000..9e636f894 --- /dev/null +++ b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift @@ -0,0 +1,152 @@ +import Introspect +import Models +import Services +import SwiftUI +import UIKit +import Views + +struct LibrarySearchView: View { + @State private var searchBar: UISearchBar? + @State private var recents: [String] = [] + @StateObject var viewModel = LibrarySearchViewModel() + + @EnvironmentObject var dataService: DataService + @Environment(\.isSearching) var isSearching + @Environment(\.dismiss) private var dismiss + + let homeFeedViewModel: HomeFeedViewModel + + init(homeFeedViewModel: HomeFeedViewModel) { + self.homeFeedViewModel = homeFeedViewModel + } + + func performTypeahead(_ searchTerm: String) { + Task { await viewModel.search(dataService: self.dataService, searchTerm: searchTerm) } + } + + func performSearch(_ searchTerm: String) { + let term = searchTerm.trimmingCharacters(in: Foundation.CharacterSet.whitespacesAndNewlines) + viewModel.saveRecentSearch(dataService: dataService, searchTerm: term) + recents = viewModel.recentSearches(dataService: dataService) + homeFeedViewModel.searchTerm = term + + dismiss() + } + + func recentSearchRow(_ term: String) -> some View { + HStack { + HStack { + Image(systemName: "clock.arrow.circlepath") + Text(term).foregroundColor(.appGrayText) + }.onTapGesture { + performSearch(term) + } + + Spacer() + +// Image(systemName: "arrow.up.backward") +// .onTapGesture { +// viewModel.searchTerm += (viewModel.searchTerm.count > 0 ? " " : "") + term +// searchBar?.becomeFirstResponder() +// } +// .searchCompletion(term) + }.swipeActions(edge: .trailing, allowsFullSwipe: true) { + Button { + withAnimation(.linear(duration: 0.4)) { + viewModel.removeRecentSearch(dataService: dataService, searchTerm: term) + self.recents = viewModel.recentSearches(dataService: dataService) + } + } label: { + Label("Remove", systemImage: "trash") + }.tint(.red) + } + } + + var body: some View { + NavigationView { + innerBody + } + } + + var innerBody: some View { + ZStack { + if let linkRequest = viewModel.linkRequest { + NavigationLink( + destination: WebReaderLoadingContainer(requestID: linkRequest.serverID), + tag: linkRequest, + selection: $viewModel.linkRequest + ) { + EmptyView() + } + } + listBody + .navigationTitle("Search") + .navigationBarItems(trailing: Button(action: { dismiss() }) { + Text("Close") + }) + .navigationBarTitleDisplayMode(NavigationBarItem.TitleDisplayMode.inline) + .searchable(text: $viewModel.searchTerm, placement: .navigationBarDrawer(displayMode: .always)) { + ForEach(viewModel.items) { item in + HStack { + Text(item.title) + Spacer() + Image(systemName: "chevron.right") + }.onTapGesture { + viewModel.linkRequest = LinkRequest(id: UUID(), serverID: item.id) + } + } + } + .onAppear { + self.recents = viewModel.recentSearches(dataService: dataService) + } + .onSubmit(of: .search) { + performSearch(viewModel.searchTerm) + } + .onChange(of: viewModel.searchTerm) { term in + performTypeahead(term) + } + } + } + + var listBody: some View { + VStack { + List { + if viewModel.searchTerm.count == 0 { + Section("Recent Searches") { + ForEach(recents, id: \.self) { term in + recentSearchRow(term) + } + } + Section("Narrow with advanced search") { + (Text("**site:** ") + Text("site or domain (eg omnivore.app)")) + .foregroundColor(.appGrayText) + .onTapGesture { viewModel.searchTerm = "site:" } + + (Text("**author:** ") + Text("author name")) + .foregroundColor(.appGrayText) + .onTapGesture { viewModel.searchTerm = "author:" } + + (Text("**is:** ") + Text("read or unread")) + .foregroundColor(.appGrayText) + .onTapGesture { viewModel.searchTerm = "is:" } + + Button(action: {}, label: { + Text("[More on Advanced Search](https://omnivore.app/help/search)") + .underline() + .padding(.top, 25) + }) + } + } + }.listStyle(PlainListStyle()) + } + } +} + +extension AnyTransition { + static var moveAndFade: AnyTransition { + .asymmetric( + insertion: .move(edge: .trailing).combined(with: .opacity), + removal: .scale.combined(with: .opacity) + ) + } +} diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchViewModel.swift new file mode 100644 index 000000000..f092b1979 --- /dev/null +++ b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchViewModel.swift @@ -0,0 +1,91 @@ +// +// LibrarySearchViewModel.swift +// +// +// Created by Jackson Harper on 10/10/22. +// + +import CoreData +import Models +import Services +import SwiftUI +import UserNotifications +import Utils +import Views + +@MainActor final class LibrarySearchViewModel: NSObject, ObservableObject { + @Published var items = [TypeaheadSearchItem]() + @Published var isLoading = false + @Published var cursor: String? + @Published var searchTerm = "" + @Published var linkRequest: LinkRequest? + + // These are used to make sure we handle search result + // responses in the right order + var searchIdx = 0 + var receivedIdx = 0 + + @AppStorage(UserDefaultKey.recentSearchTerms.rawValue) var recentSearchTerms: String = "" + + func recentSearches(dataService: DataService) -> [String] { + var results: [String] = [] + dataService.viewContext.performAndWait { + let request = RecentSearchItem.fetchRequest() + let sort = NSSortDescriptor(key: #keyPath(RecentSearchItem.savedAt), ascending: false) + request.sortDescriptors = [sort] + request.fetchLimit = 20 + + results = (try? dataService.viewContext.fetch(request))?.map { $0.term ?? "" } ?? [] + } + return results + } + + func saveRecentSearch(dataService: DataService, searchTerm: String) { + let fetchRequest: NSFetchRequest = RecentSearchItem.fetchRequest() + fetchRequest.predicate = NSPredicate(format: "term == %@", searchTerm) + + let item = ((try? dataService.viewContext.fetch(fetchRequest))?.first) ?? RecentSearchItem(context: dataService.viewContext) + item.term = searchTerm + item.savedAt = Date() + + try? dataService.viewContext.save() + } + + func removeRecentSearch(dataService: DataService, searchTerm: String) { + let fetchRequest: NSFetchRequest = RecentSearchItem.fetchRequest() + fetchRequest.predicate = NSPredicate(format: "term == %@", searchTerm) + + let objects = try? dataService.viewContext.fetch(fetchRequest) + for object in objects ?? [] { + dataService.viewContext.delete(object) + } + + try? dataService.viewContext.save() + } + + func search(dataService: DataService, searchTerm: String, isRefresh _: Bool = false) async { + isLoading = true + let thisSearchIdx = searchIdx + searchIdx += 1 + + let queryResult = try? await dataService.typeaheadSearch(searchTerm: searchTerm) + + // Search results aren't guaranteed to return in order so this + // will discard old results that are returned while a user is typing. + // For example if a user types 'Canucks', often the search results + // for 'C' are returned after 'Canucks' because it takes the backend + // much longer to compute. + if thisSearchIdx > 0, thisSearchIdx <= receivedIdx { + return + } + + if let queryResult = queryResult { + items = queryResult + + isLoading = false + receivedIdx = thisSearchIdx + } + + isLoading = false + } +} diff --git a/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents b/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents index 03a45ee30..8dec2a378 100644 --- a/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents +++ b/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents @@ -81,6 +81,11 @@ + + + + + diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/RecentSearchItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/RecentSearchItem.swift new file mode 100644 index 000000000..47b7b473d --- /dev/null +++ b/apple/OmnivoreKit/Sources/Models/DataModels/RecentSearchItem.swift @@ -0,0 +1,10 @@ +// +// RecentSearch.swift +// +// +// Created by Jackson Harper on 10/10/22. +// + +import Foundation + +extension RecentSearchItem {} diff --git a/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift b/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift index be0294a82..60e85ac67 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift @@ -53,7 +53,6 @@ public extension DataService { try await updateLinkedItemStatus(id: id, newId: nil, status: .isSyncing) let uploadRequest = try await uploadFileRequest(id: id, url: url) - print("UPLOAD REQUEST, ORIGINAL ID, NEW ID", id, uploadRequest.pageId) if let urlString = uploadRequest.urlString, let uploadUrl = URL(string: urlString) { try await uploadFile(id: uploadRequest.pageId, localPdfURL: localPdfURL, url: uploadUrl) } else { diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/TypeAheadSearchQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/TypeAheadSearchQuery.swift new file mode 100644 index 000000000..c3aa87ba9 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/TypeAheadSearchQuery.swift @@ -0,0 +1,65 @@ +import CoreData +import Foundation +import Models +import SwiftGraphQL +import Utils + +public struct TypeaheadSearchItem: Identifiable { + public let id: String + public let title: String + let slug: String + let siteName: String? +} + +public extension DataService { + // swiftlint:disable:next function_body_length + func typeaheadSearch(searchTerm: String) async throws -> [TypeaheadSearchItem] { + enum QueryResult { + case success(result: [TypeaheadSearchItem]) + case error(error: String) + } + + let typeaheadSelection = Selection.TypeaheadSearchItem { + TypeaheadSearchItem( + id: try $0.id(), + title: try $0.title(), + slug: try $0.slug(), + siteName: try $0.siteName() + ) + } + + let selection = Selection { + try $0.on( + typeaheadSearchError: .init { + QueryResult.error(error: try $0.errorCodes().description) + }, + typeaheadSearchSuccess: .init { + QueryResult.success(result: try $0.items(selection: typeaheadSelection.list)) + } + ) + } + + let query = Selection.Query { + try $0.typeaheadSearch(query: searchTerm, selection: selection) + } + + let path = appEnvironment.graphqlPath + let headers = networker.defaultHeaders + + return try await withCheckedThrowingContinuation { continuation in + send(query, to: path, headers: headers) { queryResult in + guard let payload = try? queryResult.get() else { + continuation.resume(throwing: ContentFetchError.network) + return + } + + switch payload.data { + case let .success(result: result): + continuation.resume(returning: result) + case .error: + continuation.resume(throwing: ContentFetchError.badData) + } + } + } + } +} diff --git a/apple/OmnivoreKit/Sources/Utils/UserDefaultKeys.swift b/apple/OmnivoreKit/Sources/Utils/UserDefaultKeys.swift index caef28d45..5abfe6c5f 100644 --- a/apple/OmnivoreKit/Sources/Utils/UserDefaultKeys.swift +++ b/apple/OmnivoreKit/Sources/Utils/UserDefaultKeys.swift @@ -17,4 +17,5 @@ public enum UserDefaultKey: String { case textToSpeechPreferredVoice case textToSpeechDefaultLanguage case textToSpeechPreloadEnabled + case recentSearchTerms } diff --git a/apple/OmnivoreKit/Sources/Views/TextChip.swift b/apple/OmnivoreKit/Sources/Views/TextChip.swift index 01320f242..845a0810f 100644 --- a/apple/OmnivoreKit/Sources/Views/TextChip.swift +++ b/apple/OmnivoreKit/Sources/Views/TextChip.swift @@ -75,6 +75,10 @@ public struct TextChipButton: View { TextChipButton(title: title, color: .systemGray6, actionType: .show, negated: false, onTap: {}) } + public static func makeSearchFilterButton(title: String, onTap: @escaping () -> Void) -> TextChipButton { + TextChipButton(title: "Search: \(title)", color: .appCtaYellow, actionType: .clear, negated: false, onTap: onTap) + } + public static func makeShowOptionsButton(title: String, onTap: @escaping () -> Void) -> TextChipButton { TextChipButton(title: title, color: .appButtonBackground, actionType: .add, negated: false, onTap: onTap) } @@ -97,10 +101,11 @@ public struct TextChipButton: View { case remove case add case show + case clear var systemIconName: String { switch self { - case .remove: + case .clear, .remove: return "xmark" case .add: return "plus" @@ -144,9 +149,10 @@ public struct TextChipButton: View { .font(.appFootnote) .foregroundColor(foregroundColor) .lineLimit(1) - .background(Capsule().fill(color)) + .background(Rectangle().fill(color)) + .cornerRadius(8) } - .padding(.vertical, 12) + .padding(.vertical, 0) .contentShape(Rectangle()) .onTapGesture { onTap() } } diff --git a/packages/web/package.json b/packages/web/package.json index 3610ecbf3..2a968798f 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -29,6 +29,7 @@ "@segment/analytics-next": "^1.33.5", "@sentry/nextjs": "^6.16.1", "@stitches/react": "^1.2.5", + "antd": "^4.23.4", "color2k": "^2.0.0", "cookie": "^0.5.0", "diff-match-patch": "^1.0.5", diff --git a/packages/web/pages/settings/api.tsx b/packages/web/pages/settings/api.tsx index a78b2b285..783b0b322 100644 --- a/packages/web/pages/settings/api.tsx +++ b/packages/web/pages/settings/api.tsx @@ -9,12 +9,15 @@ import { generateApiKeyMutation } from '../../lib/networking/mutations/generateA import { revokeApiKeyMutation } from '../../lib/networking/mutations/revokeApiKeyMutation' import { PrimaryLayout } from '../../components/templates/PrimaryLayout' -import { Table } from '../../components/elements/Table' +// import { Table } from '../../components/elements/Table' import { FormInputProps } from '../../components/elements/FormElements' import { FormModal } from '../../components/patterns/FormModal' import { ConfirmationModal } from '../../components/patterns/ConfirmationModal' +import { Table } from 'antd'; +import 'antd/dist/antd.css'; + interface ApiKey { name: string scopes: string @@ -140,6 +143,40 @@ export default function Api(): JSX.Element { ]) } + const dataSource = [ + { + key: '1', + name: 'Mike', + age: 32, + address: '10 Downing Street', + }, + { + key: '2', + name: 'John', + age: 42, + address: '10 Downing Street', + }, + ]; + + const columns = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + }, + { + title: 'Age', + dataIndex: 'age', + key: 'age', + }, + { + title: 'Address', + dataIndex: 'address', + key: 'address', + }, + ]; + + return ( + ; + {addModalOpen && ( )} -
+ /> */} ) } diff --git a/yarn.lock b/yarn.lock index ebf984f5a..58f1d5bd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,6 +16,40 @@ dependencies: "@jridgewell/trace-mapping" "^0.3.0" +"@ant-design/colors@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-6.0.0.tgz#9b9366257cffcc47db42b9d0203bb592c13c0298" + integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ== + dependencies: + "@ctrl/tinycolor" "^3.4.0" + +"@ant-design/icons-svg@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a" + integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw== + +"@ant-design/icons@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-4.7.0.tgz#8c3cbe0a556ba92af5dc7d1e70c0b25b5179af0f" + integrity sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g== + dependencies: + "@ant-design/colors" "^6.0.0" + "@ant-design/icons-svg" "^4.2.1" + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-util "^5.9.4" + +"@ant-design/react-slick@~0.29.1": + version "0.29.2" + resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-0.29.2.tgz#53e6a7920ea3562eebb304c15a7fc2d7e619d29c" + integrity sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA== + dependencies: + "@babel/runtime" "^7.10.4" + classnames "^2.2.5" + json2mq "^0.2.0" + lodash "^4.17.21" + resize-observer-polyfill "^1.5.1" + "@apollo/protobufjs@1.2.4": version "1.2.4" resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.4.tgz#d913e7627210ec5efd758ceeb751c776c68ba133" @@ -1919,6 +1953,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" + integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -2089,6 +2130,11 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@ctrl/tinycolor@^3.4.0": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32" + integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw== + "@cypress/request@^2.88.10": version "2.88.10" resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce" @@ -9087,6 +9133,56 @@ ansi-to-html@^0.6.11: dependencies: entities "^2.0.0" +antd@^4.23.4: + version "4.23.4" + resolved "https://registry.yarnpkg.com/antd/-/antd-4.23.4.tgz#fafe315f1761ab80258d5569462025cc238422d5" + integrity sha512-2VdDSPXEjCc2m2qBgv6DKpKnsKIGyQtJBdcGn223EqHxDWHqCaRxeJIA9bcW50ntHFkwdeBa+IeWLBor377dkA== + dependencies: + "@ant-design/colors" "^6.0.0" + "@ant-design/icons" "^4.7.0" + "@ant-design/react-slick" "~0.29.1" + "@babel/runtime" "^7.18.3" + "@ctrl/tinycolor" "^3.4.0" + classnames "^2.2.6" + copy-to-clipboard "^3.2.0" + lodash "^4.17.21" + memoize-one "^6.0.0" + moment "^2.29.2" + rc-cascader "~3.7.0" + rc-checkbox "~2.3.0" + rc-collapse "~3.3.0" + rc-dialog "~8.9.0" + rc-drawer "~5.1.0" + rc-dropdown "~4.0.0" + rc-field-form "~1.27.0" + rc-image "~5.7.0" + rc-input "~0.1.2" + rc-input-number "~7.3.9" + rc-mentions "~1.9.1" + rc-menu "~9.6.3" + rc-motion "^2.6.1" + rc-notification "~4.6.0" + rc-pagination "~3.1.17" + rc-picker "~2.6.10" + rc-progress "~3.3.2" + rc-rate "~2.9.0" + rc-resize-observer "^1.2.0" + rc-segmented "~2.1.0" + rc-select "~14.1.13" + rc-slider "~10.0.0" + rc-steps "~4.1.0" + rc-switch "~3.2.0" + rc-table "~7.26.0" + rc-tabs "~12.1.0-alpha.1" + rc-textarea "~0.3.0" + rc-tooltip "~5.2.0" + rc-tree "~5.7.0" + rc-tree-select "~5.5.0" + rc-trigger "^5.2.10" + rc-upload "~4.3.0" + rc-util "^5.22.5" + scroll-into-view-if-needed "^2.2.25" + any-observable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" @@ -9379,6 +9475,11 @@ array-slice@^1.0.0: resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== +array-tree-filter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" + integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== + array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -9566,6 +9667,11 @@ async-retry@^1.2.1, async-retry@^1.3.3: dependencies: retry "0.13.1" +async-validator@^4.1.0: + version "4.2.5" + resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" + integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== + async@^2.6.2: version "2.6.4" resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" @@ -10867,6 +10973,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" + integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== + classnames@^2.2.6: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" @@ -11507,6 +11618,13 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copy-to-clipboard@^3.2.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz#5b263ec2366224b100181dded7ce0579b340c107" + integrity sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg== + dependencies: + toggle-selection "^1.0.6" + copy-to-clipboard@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" @@ -11953,6 +12071,11 @@ date-and-time@^2.0.0: resolved "https://registry.yarnpkg.com/date-and-time/-/date-and-time-2.0.0.tgz#99f5fb6b6c7bcd4d1f6dcbeb37553dc0ff797b65" integrity sha512-HJSzj25iPm8E01nt+rSmCIlwjsmjvKfUivG/kXBglpymcHF1FolWAqWwTEV4FvN1Lx5UjPf0J1W4H8yQsVBfFg== +date-fns@2.x: + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + date-fns@^1.27.2: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" @@ -11968,6 +12091,11 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +dayjs@1.x: + version "1.11.5" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.5.tgz#00e8cc627f231f9499c19b38af49f56dc0ac5e93" + integrity sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA== + dayjs@^1.10.4: version "1.11.0" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.0.tgz#009bf7ef2e2ea2d5db2e6583d2d39a4b5061e805" @@ -12424,6 +12552,11 @@ dom-accessibility-api@^0.5.9: resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.13.tgz#102ee5f25eacce09bdf1cfa5a298f86da473be4b" integrity sha512-R305kwb5CcMDIpSHUnLyIAp7SrSPBx6F0VfQFB3M75xVMHhXJJIdePYgbPPh1o57vCHNu5QztokWUPsLjWzFqw== +dom-align@^1.7.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.3.tgz#a36d02531dae0eefa2abb0c4db6595250526f103" + integrity sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA== + dom-converter@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -17267,6 +17400,13 @@ json-to-pretty-yaml@^1.2.2: remedial "^1.0.7" remove-trailing-spaces "^1.0.6" +json2mq@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" + integrity sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA== + dependencies: + string-convert "^0.2.0" + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -18419,6 +18559,11 @@ memfs@^3.1.2, memfs@^3.2.2, memfs@^3.4.1: dependencies: fs-monkey "1.0.3" +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + memoizerific@^1.11.3: version "1.11.3" resolved "https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" @@ -18958,6 +19103,11 @@ module-details-from-path@^1.0.3: resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" integrity sha1-EUyUlnPiqKNenTV4hSeqN7Z52is= +moment@^2.24.0, moment@^2.29.2: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== + moo@^0.5.0, moo@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" @@ -21450,6 +21600,375 @@ raw-loader@^4.0.2: loader-utils "^2.0.0" schema-utils "^3.0.0" +rc-align@^4.0.0: + version "4.0.12" + resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.12.tgz#065b5c68a1cc92a00800c9239320d9fdf5f16207" + integrity sha512-3DuwSJp8iC/dgHzwreOQl52soj40LchlfUHtgACOUtwGuoFIOVh6n/sCpfqCU8kO5+iz6qR0YKvjgB8iPdE3aQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + dom-align "^1.7.0" + lodash "^4.17.21" + rc-util "^5.3.0" + resize-observer-polyfill "^1.5.1" + +rc-cascader@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.7.0.tgz#98134df578ce1cca22be8fb4319b04df4f3dca36" + integrity sha512-SFtGpwmYN7RaWEAGTS4Rkc62ZV/qmQGg/tajr/7mfIkleuu8ro9Hlk6J+aA0x1YS4zlaZBtTcSaXM01QMiEV/A== + dependencies: + "@babel/runtime" "^7.12.5" + array-tree-filter "^2.1.0" + classnames "^2.3.1" + rc-select "~14.1.0" + rc-tree "~5.7.0" + rc-util "^5.6.1" + +rc-checkbox@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/rc-checkbox/-/rc-checkbox-2.3.2.tgz#f91b3678c7edb2baa8121c9483c664fa6f0aefc1" + integrity sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + +rc-collapse@~3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-3.3.1.tgz#fc66d4c9cfeaf41e932b2de6da2d454874aee55a" + integrity sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.3.4" + rc-util "^5.2.1" + shallowequal "^1.1.0" + +rc-dialog@~8.9.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-8.9.0.tgz#04dc39522f0321ed2e06018d4a7e02a4c32bd3ea" + integrity sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-motion "^2.3.0" + rc-util "^5.21.0" + +rc-drawer@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-5.1.0.tgz#c1b8a46e5c064ba46a16233fbcfb1ccec6a73c10" + integrity sha512-pU3Tsn99pxGdYowXehzZbdDVE+4lDXSGb7p8vA9mSmr569oc2Izh4Zw5vLKSe/Xxn2p5MSNbLVqD4tz+pK6SOw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-motion "^2.6.1" + rc-util "^5.21.2" + +rc-dropdown@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/rc-dropdown/-/rc-dropdown-4.0.1.tgz#f65d9d3d89750241057db59d5a75e43cd4576b68" + integrity sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g== + dependencies: + "@babel/runtime" "^7.18.3" + classnames "^2.2.6" + rc-trigger "^5.3.1" + rc-util "^5.17.0" + +rc-field-form@~1.27.0: + version "1.27.2" + resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-1.27.2.tgz#5123282cf1561ba34f3197c37b8b9a8b710dd7dd" + integrity sha512-NaTjkSB8JsHRgm52wkDorsDzFf2HH6GmCQ2AqkwO8zo+zIqybw8K1lkzDBMDJI8nw1pFuD46U5QsYZv4blYvdw== + dependencies: + "@babel/runtime" "^7.18.0" + async-validator "^4.1.0" + rc-util "^5.8.0" + +rc-image@~5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-5.7.1.tgz#678dc014845954c30237808c00c7b12e5f2a0b07" + integrity sha512-QyMfdhoUfb5W14plqXSisaYwpdstcLYnB0MjX5ccIK2rydQM9sDPuekQWu500DDGR2dBaIF5vx9XbWkNFK17Fg== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-dialog "~8.9.0" + rc-util "^5.0.6" + +rc-input-number@~7.3.9: + version "7.3.9" + resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-7.3.9.tgz#bc6560376ea595e3bf8fbd3137711cbc158800b5" + integrity sha512-u0+miS+SATdb6DtssYei2JJ1WuZME+nXaG6XGtR8maNyW5uGDytfDu60OTWLQEb0Anv/AcCzehldV8CKmKyQfA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.23.0" + +rc-input@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/rc-input/-/rc-input-0.1.2.tgz#7d6a0858a5f1fd89f78020cf6f13d672778481b1" + integrity sha512-ZPmwcFspgfYpUfbSx3KnLk9gImBcLOrlQCr4oTJ4jBoIXgJLTfm26yelzRgBJewhkvD8uJbgX0sQ/yOzuOHnJg== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-util "^5.18.1" + +rc-mentions@~1.9.1: + version "1.9.2" + resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-1.9.2.tgz#f264ebc4ec734dad9edc8e078b65ab3586d94a7b" + integrity sha512-uxb/lzNnEGmvraKWNGE6KXMVXvt8RQv9XW8R0Dqi3hYsyPiAZeHRCHQKdLARuk5YBhFhZ6ga55D/8XuY367g3g== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-menu "~9.6.0" + rc-textarea "^0.3.0" + rc-trigger "^5.0.4" + rc-util "^5.22.5" + +rc-menu@~9.6.0, rc-menu@~9.6.3: + version "9.6.4" + resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.6.4.tgz#033e7b8848c17a09a81b68b8d4c3fa457605f4f6" + integrity sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.4.3" + rc-overflow "^1.2.0" + rc-trigger "^5.1.2" + rc-util "^5.12.0" + shallowequal "^1.1.0" + +rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.2.0, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.3, rc-motion@^2.4.4, rc-motion@^2.6.1, rc-motion@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.6.2.tgz#3d31f97e41fb8e4f91a4a4189b6a98ac63342869" + integrity sha512-4w1FaX3dtV749P8GwfS4fYnFG4Rb9pxvCYPc/b2fw1cmlHJWNNgOFIz7ysiD+eOrzJSvnLJWlNQQncpNMXwwpg== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-util "^5.21.0" + +rc-notification@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-4.6.0.tgz#4e76fc2d0568f03cc93ac18c9e20763ebe29fa46" + integrity sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.2.0" + rc-util "^5.20.1" + +rc-overflow@^1.0.0, rc-overflow@^1.2.0: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.2.8.tgz#40f140fabc244118543e627cdd1ef750d9481a88" + integrity sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-resize-observer "^1.0.0" + rc-util "^5.19.2" + +rc-pagination@~3.1.17: + version "3.1.17" + resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-3.1.17.tgz#91e690aa894806e344cea88ea4a16d244194a1bd" + integrity sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + +rc-picker@~2.6.10: + version "2.6.10" + resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-2.6.10.tgz#8d0a473c079388bdb2d7358a2a54c7d5095893b4" + integrity sha512-9wYtw0DFWs9FO92Qh2D76P0iojUr8ZhLOtScUeOit6ks/F+TBLrOC1uze3IOu+u9gbDAjmosNWLKbBzx/Yuv2w== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + date-fns "2.x" + dayjs "1.x" + moment "^2.24.0" + rc-trigger "^5.0.4" + rc-util "^5.4.0" + shallowequal "^1.1.0" + +rc-progress@~3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-3.3.3.tgz#eb9bffbacab1534f2542f9f6861ce772254362b1" + integrity sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-util "^5.16.1" + +rc-rate@~2.9.0: + version "2.9.2" + resolved "https://registry.yarnpkg.com/rc-rate/-/rc-rate-2.9.2.tgz#4a58965d1ecf91896ebae01d458b59056df0b4ea" + integrity sha512-SaiZFyN8pe0Fgphv8t3+kidlej+cq/EALkAJAc3A0w0XcPaH2L1aggM8bhe1u6GAGuQNAoFvTLjw4qLPGRKV5g== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.0.1" + +rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0, rc-resize-observer@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz#9f46052f81cdf03498be35144cb7c53fd282c4c7" + integrity sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.15.0" + resize-observer-polyfill "^1.5.1" + +rc-segmented@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.1.0.tgz#0e0afe646c1a0e44a0e18785f518c42633ec8efc" + integrity sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-motion "^2.4.4" + rc-util "^5.17.0" + +rc-select@~14.1.0, rc-select@~14.1.13: + version "14.1.13" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.1.13.tgz#7eb53d00be82fb8e5050de3094e72edcf27ce6f6" + integrity sha512-WMEsC3gTwA1dbzWOdVIXDmWyidYNLq68AwvvUlRROw790uGUly0/vmqDozXrIr0QvN/A3CEULx12o+WtLCAefg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-overflow "^1.0.0" + rc-trigger "^5.0.4" + rc-util "^5.16.1" + rc-virtual-list "^3.2.0" + +rc-slider@~10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.0.1.tgz#7058c68ff1e1aa4e7c3536e5e10128bdbccb87f9" + integrity sha512-igTKF3zBet7oS/3yNiIlmU8KnZ45npmrmHlUUio8PNbIhzMcsh+oE/r2UD42Y6YD2D/s+kzCQkzQrPD6RY435Q== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.18.1" + shallowequal "^1.1.0" + +rc-steps@~4.1.0: + version "4.1.4" + resolved "https://registry.yarnpkg.com/rc-steps/-/rc-steps-4.1.4.tgz#0ba82db202d59ca52d0693dc9880dd145b19dc23" + integrity sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w== + dependencies: + "@babel/runtime" "^7.10.2" + classnames "^2.2.3" + rc-util "^5.0.1" + +rc-switch@~3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/rc-switch/-/rc-switch-3.2.2.tgz#d001f77f12664d52595b4f6fb425dd9e66fba8e8" + integrity sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.0.1" + +rc-table@~7.26.0: + version "7.26.0" + resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.26.0.tgz#9d517e7fa512e7571fdcc453eb1bf19edfac6fbc" + integrity sha512-0cD8e6S+DTGAt5nBZQIPFYEaIukn17sfa5uFL98faHlH/whZzD8ii3dbFL4wmUDEL4BLybhYop+QUfZJ4CPvNQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-resize-observer "^1.1.0" + rc-util "^5.22.5" + shallowequal "^1.1.0" + +rc-tabs@~12.1.0-alpha.1: + version "12.1.0-alpha.1" + resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-12.1.0-alpha.1.tgz#00f45b9dffa9bc6aff8ce2aff4a1a0764caada54" + integrity sha512-M+B88WEnGSuE+mR54fpgPbZLAakzxa/H6FmEetLBl5WG4I3AcwSk9amuIPC/tu0KXBl+H6Bg5ZwrrEUOBUvgzg== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "2.x" + rc-dropdown "~4.0.0" + rc-menu "~9.6.0" + rc-motion "^2.6.2" + rc-resize-observer "^1.0.0" + rc-util "^5.5.0" + +rc-textarea@^0.3.0, rc-textarea@~0.3.0: + version "0.3.7" + resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-0.3.7.tgz#987142891efdedb774883c07e2f51b318fde5a11" + integrity sha512-yCdZ6binKmAQB13hc/oehh0E/QRwoPP1pjF21aHBxlgXO3RzPF6dUu4LG2R4FZ1zx/fQd2L1faktulrXOM/2rw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-resize-observer "^1.0.0" + rc-util "^5.7.0" + shallowequal "^1.1.0" + +rc-tooltip@~5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-5.2.2.tgz#e5cafa8ecebf78108936a0bcb93c150fa81ac93b" + integrity sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "^2.3.1" + rc-trigger "^5.0.0" + +rc-tree-select@~5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-5.5.0.tgz#96d935ec994a0f6b0fecc4c18f22f472fe8530a3" + integrity sha512-XS0Jvw4OjFz/Xvb2byEkBWv55JFKFz0HVvTBa/cPOHJaQh/3EaYwymEMnCCvGEzS1+5CfDVwMtA8j/v4rt1DHw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-select "~14.1.0" + rc-tree "~5.7.0" + rc-util "^5.16.1" + +rc-tree@~5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-5.7.0.tgz#d0e316eeeac2ba4a1c36b2b2201d84884f1c76a1" + integrity sha512-F+Ewkv/UcutshnVBMISP+lPdHDlcsL+YH/MQDVWbk+QdkfID7vXiwrHMEZn31+2Rbbm21z/HPceGS8PXGMmnQg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-util "^5.16.1" + rc-virtual-list "^3.4.8" + +rc-trigger@^5.0.0, rc-trigger@^5.0.4, rc-trigger@^5.1.2, rc-trigger@^5.2.10, rc-trigger@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.3.1.tgz#acafadf3eaf384e7f466c303bfa0f34c8137d7b8" + integrity sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ== + dependencies: + "@babel/runtime" "^7.18.3" + classnames "^2.2.6" + rc-align "^4.0.0" + rc-motion "^2.0.0" + rc-util "^5.19.2" + +rc-upload@~4.3.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.3.4.tgz#83ff7d3867631c37adbfd72ea3d1fd7e97ca84af" + integrity sha512-uVbtHFGNjHG/RyAfm9fluXB6pvArAGyAx8z7XzXXyorEgVIWj6mOlriuDm0XowDHYz4ycNK0nE0oP3cbFnzxiQ== + dependencies: + "@babel/runtime" "^7.18.3" + classnames "^2.2.5" + rc-util "^5.2.0" + +rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.12.0, rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.2, rc-util@^5.2.0, rc-util@^5.2.1, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.21.2, rc-util@^5.22.5, rc-util@^5.23.0, rc-util@^5.3.0, rc-util@^5.4.0, rc-util@^5.5.0, rc-util@^5.6.1, rc-util@^5.7.0, rc-util@^5.8.0, rc-util@^5.9.4: + version "5.24.4" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.24.4.tgz#a4126f01358c86f17c1bf380a1d83d6c9155ae65" + integrity sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q== + dependencies: + "@babel/runtime" "^7.18.3" + react-is "^16.12.0" + shallowequal "^1.1.0" + +rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.8: + version "3.4.8" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.8.tgz#c24c10c6940546b7e2a5e9809402c6716adfd26c" + integrity sha512-qSN+Rv4i/E7RCTvTMr1uZo7f3crJJg/5DekoCagydo9zsXrxj07zsFSxqizqW+ldGA16lwa8So/bIbV9Ofjddg== + dependencies: + classnames "^2.2.6" + rc-resize-observer "^1.0.0" + rc-util "^5.15.0" + rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -21554,7 +22073,7 @@ react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -22571,6 +23090,13 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" +scroll-into-view-if-needed@^2.2.25: + version "2.2.29" + resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885" + integrity sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg== + dependencies: + compute-scroll-into-view "^1.0.17" + scuid@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/scuid/-/scuid-1.1.0.tgz#d3f9f920956e737a60f72d0e4ad280bf324d5dab" @@ -23347,6 +23873,11 @@ strict-uri-encode@^2.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== +string-convert@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" + integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== + string-env-interpolation@1.0.1, string-env-interpolation@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152" From 7bd8250e1e75f5e9936f47a2b1d133d5d737b6f0 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 11:27:29 +0800 Subject: [PATCH 03/17] Rebasing --- packages/web/package.json | 1 - packages/web/pages/settings/api.tsx | 45 +-- yarn.lock | 533 +--------------------------- 3 files changed, 4 insertions(+), 575 deletions(-) diff --git a/packages/web/package.json b/packages/web/package.json index 2a968798f..3610ecbf3 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -29,7 +29,6 @@ "@segment/analytics-next": "^1.33.5", "@sentry/nextjs": "^6.16.1", "@stitches/react": "^1.2.5", - "antd": "^4.23.4", "color2k": "^2.0.0", "cookie": "^0.5.0", "diff-match-patch": "^1.0.5", diff --git a/packages/web/pages/settings/api.tsx b/packages/web/pages/settings/api.tsx index 783b0b322..a78b2b285 100644 --- a/packages/web/pages/settings/api.tsx +++ b/packages/web/pages/settings/api.tsx @@ -9,15 +9,12 @@ import { generateApiKeyMutation } from '../../lib/networking/mutations/generateA import { revokeApiKeyMutation } from '../../lib/networking/mutations/revokeApiKeyMutation' import { PrimaryLayout } from '../../components/templates/PrimaryLayout' -// import { Table } from '../../components/elements/Table' +import { Table } from '../../components/elements/Table' import { FormInputProps } from '../../components/elements/FormElements' import { FormModal } from '../../components/patterns/FormModal' import { ConfirmationModal } from '../../components/patterns/ConfirmationModal' -import { Table } from 'antd'; -import 'antd/dist/antd.css'; - interface ApiKey { name: string scopes: string @@ -143,40 +140,6 @@ export default function Api(): JSX.Element { ]) } - const dataSource = [ - { - key: '1', - name: 'Mike', - age: 32, - address: '10 Downing Street', - }, - { - key: '2', - name: 'John', - age: 42, - address: '10 Downing Street', - }, - ]; - - const columns = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name', - }, - { - title: 'Age', - dataIndex: 'age', - key: 'age', - }, - { - title: 'Address', - dataIndex: 'address', - key: 'address', - }, - ]; - - return ( -
; - {addModalOpen && ( )} - {/*
*/} + /> ) } diff --git a/yarn.lock b/yarn.lock index 58f1d5bd8..ebf984f5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,40 +16,6 @@ dependencies: "@jridgewell/trace-mapping" "^0.3.0" -"@ant-design/colors@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-6.0.0.tgz#9b9366257cffcc47db42b9d0203bb592c13c0298" - integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ== - dependencies: - "@ctrl/tinycolor" "^3.4.0" - -"@ant-design/icons-svg@^4.2.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a" - integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw== - -"@ant-design/icons@^4.7.0": - version "4.7.0" - resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-4.7.0.tgz#8c3cbe0a556ba92af5dc7d1e70c0b25b5179af0f" - integrity sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g== - dependencies: - "@ant-design/colors" "^6.0.0" - "@ant-design/icons-svg" "^4.2.1" - "@babel/runtime" "^7.11.2" - classnames "^2.2.6" - rc-util "^5.9.4" - -"@ant-design/react-slick@~0.29.1": - version "0.29.2" - resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-0.29.2.tgz#53e6a7920ea3562eebb304c15a7fc2d7e619d29c" - integrity sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA== - dependencies: - "@babel/runtime" "^7.10.4" - classnames "^2.2.5" - json2mq "^0.2.0" - lodash "^4.17.21" - resize-observer-polyfill "^1.5.1" - "@apollo/protobufjs@1.2.4": version "1.2.4" resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.4.tgz#d913e7627210ec5efd758ceeb751c776c68ba133" @@ -1953,13 +1919,6 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" - integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== - dependencies: - regenerator-runtime "^0.13.4" - "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -2130,11 +2089,6 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@ctrl/tinycolor@^3.4.0": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32" - integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw== - "@cypress/request@^2.88.10": version "2.88.10" resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce" @@ -9133,56 +9087,6 @@ ansi-to-html@^0.6.11: dependencies: entities "^2.0.0" -antd@^4.23.4: - version "4.23.4" - resolved "https://registry.yarnpkg.com/antd/-/antd-4.23.4.tgz#fafe315f1761ab80258d5569462025cc238422d5" - integrity sha512-2VdDSPXEjCc2m2qBgv6DKpKnsKIGyQtJBdcGn223EqHxDWHqCaRxeJIA9bcW50ntHFkwdeBa+IeWLBor377dkA== - dependencies: - "@ant-design/colors" "^6.0.0" - "@ant-design/icons" "^4.7.0" - "@ant-design/react-slick" "~0.29.1" - "@babel/runtime" "^7.18.3" - "@ctrl/tinycolor" "^3.4.0" - classnames "^2.2.6" - copy-to-clipboard "^3.2.0" - lodash "^4.17.21" - memoize-one "^6.0.0" - moment "^2.29.2" - rc-cascader "~3.7.0" - rc-checkbox "~2.3.0" - rc-collapse "~3.3.0" - rc-dialog "~8.9.0" - rc-drawer "~5.1.0" - rc-dropdown "~4.0.0" - rc-field-form "~1.27.0" - rc-image "~5.7.0" - rc-input "~0.1.2" - rc-input-number "~7.3.9" - rc-mentions "~1.9.1" - rc-menu "~9.6.3" - rc-motion "^2.6.1" - rc-notification "~4.6.0" - rc-pagination "~3.1.17" - rc-picker "~2.6.10" - rc-progress "~3.3.2" - rc-rate "~2.9.0" - rc-resize-observer "^1.2.0" - rc-segmented "~2.1.0" - rc-select "~14.1.13" - rc-slider "~10.0.0" - rc-steps "~4.1.0" - rc-switch "~3.2.0" - rc-table "~7.26.0" - rc-tabs "~12.1.0-alpha.1" - rc-textarea "~0.3.0" - rc-tooltip "~5.2.0" - rc-tree "~5.7.0" - rc-tree-select "~5.5.0" - rc-trigger "^5.2.10" - rc-upload "~4.3.0" - rc-util "^5.22.5" - scroll-into-view-if-needed "^2.2.25" - any-observable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" @@ -9475,11 +9379,6 @@ array-slice@^1.0.0: resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== -array-tree-filter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" - integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== - array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -9667,11 +9566,6 @@ async-retry@^1.2.1, async-retry@^1.3.3: dependencies: retry "0.13.1" -async-validator@^4.1.0: - version "4.2.5" - resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" - integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== - async@^2.6.2: version "2.6.4" resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" @@ -10973,11 +10867,6 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" - integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== - classnames@^2.2.6: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" @@ -11618,13 +11507,6 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-to-clipboard@^3.2.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz#5b263ec2366224b100181dded7ce0579b340c107" - integrity sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg== - dependencies: - toggle-selection "^1.0.6" - copy-to-clipboard@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" @@ -12071,11 +11953,6 @@ date-and-time@^2.0.0: resolved "https://registry.yarnpkg.com/date-and-time/-/date-and-time-2.0.0.tgz#99f5fb6b6c7bcd4d1f6dcbeb37553dc0ff797b65" integrity sha512-HJSzj25iPm8E01nt+rSmCIlwjsmjvKfUivG/kXBglpymcHF1FolWAqWwTEV4FvN1Lx5UjPf0J1W4H8yQsVBfFg== -date-fns@2.x: - version "2.29.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" - integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== - date-fns@^1.27.2: version "1.30.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" @@ -12091,11 +11968,6 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -dayjs@1.x: - version "1.11.5" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.5.tgz#00e8cc627f231f9499c19b38af49f56dc0ac5e93" - integrity sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA== - dayjs@^1.10.4: version "1.11.0" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.0.tgz#009bf7ef2e2ea2d5db2e6583d2d39a4b5061e805" @@ -12552,11 +12424,6 @@ dom-accessibility-api@^0.5.9: resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.13.tgz#102ee5f25eacce09bdf1cfa5a298f86da473be4b" integrity sha512-R305kwb5CcMDIpSHUnLyIAp7SrSPBx6F0VfQFB3M75xVMHhXJJIdePYgbPPh1o57vCHNu5QztokWUPsLjWzFqw== -dom-align@^1.7.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.3.tgz#a36d02531dae0eefa2abb0c4db6595250526f103" - integrity sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA== - dom-converter@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -17400,13 +17267,6 @@ json-to-pretty-yaml@^1.2.2: remedial "^1.0.7" remove-trailing-spaces "^1.0.6" -json2mq@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" - integrity sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA== - dependencies: - string-convert "^0.2.0" - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -18559,11 +18419,6 @@ memfs@^3.1.2, memfs@^3.2.2, memfs@^3.4.1: dependencies: fs-monkey "1.0.3" -memoize-one@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" - integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== - memoizerific@^1.11.3: version "1.11.3" resolved "https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" @@ -19103,11 +18958,6 @@ module-details-from-path@^1.0.3: resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" integrity sha1-EUyUlnPiqKNenTV4hSeqN7Z52is= -moment@^2.24.0, moment@^2.29.2: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - moo@^0.5.0, moo@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" @@ -21600,375 +21450,6 @@ raw-loader@^4.0.2: loader-utils "^2.0.0" schema-utils "^3.0.0" -rc-align@^4.0.0: - version "4.0.12" - resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.12.tgz#065b5c68a1cc92a00800c9239320d9fdf5f16207" - integrity sha512-3DuwSJp8iC/dgHzwreOQl52soj40LchlfUHtgACOUtwGuoFIOVh6n/sCpfqCU8kO5+iz6qR0YKvjgB8iPdE3aQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - dom-align "^1.7.0" - lodash "^4.17.21" - rc-util "^5.3.0" - resize-observer-polyfill "^1.5.1" - -rc-cascader@~3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.7.0.tgz#98134df578ce1cca22be8fb4319b04df4f3dca36" - integrity sha512-SFtGpwmYN7RaWEAGTS4Rkc62ZV/qmQGg/tajr/7mfIkleuu8ro9Hlk6J+aA0x1YS4zlaZBtTcSaXM01QMiEV/A== - dependencies: - "@babel/runtime" "^7.12.5" - array-tree-filter "^2.1.0" - classnames "^2.3.1" - rc-select "~14.1.0" - rc-tree "~5.7.0" - rc-util "^5.6.1" - -rc-checkbox@~2.3.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/rc-checkbox/-/rc-checkbox-2.3.2.tgz#f91b3678c7edb2baa8121c9483c664fa6f0aefc1" - integrity sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.1" - -rc-collapse@~3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-3.3.1.tgz#fc66d4c9cfeaf41e932b2de6da2d454874aee55a" - integrity sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-motion "^2.3.4" - rc-util "^5.2.1" - shallowequal "^1.1.0" - -rc-dialog@~8.9.0: - version "8.9.0" - resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-8.9.0.tgz#04dc39522f0321ed2e06018d4a7e02a4c32bd3ea" - integrity sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-motion "^2.3.0" - rc-util "^5.21.0" - -rc-drawer@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-5.1.0.tgz#c1b8a46e5c064ba46a16233fbcfb1ccec6a73c10" - integrity sha512-pU3Tsn99pxGdYowXehzZbdDVE+4lDXSGb7p8vA9mSmr569oc2Izh4Zw5vLKSe/Xxn2p5MSNbLVqD4tz+pK6SOw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-motion "^2.6.1" - rc-util "^5.21.2" - -rc-dropdown@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/rc-dropdown/-/rc-dropdown-4.0.1.tgz#f65d9d3d89750241057db59d5a75e43cd4576b68" - integrity sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g== - dependencies: - "@babel/runtime" "^7.18.3" - classnames "^2.2.6" - rc-trigger "^5.3.1" - rc-util "^5.17.0" - -rc-field-form@~1.27.0: - version "1.27.2" - resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-1.27.2.tgz#5123282cf1561ba34f3197c37b8b9a8b710dd7dd" - integrity sha512-NaTjkSB8JsHRgm52wkDorsDzFf2HH6GmCQ2AqkwO8zo+zIqybw8K1lkzDBMDJI8nw1pFuD46U5QsYZv4blYvdw== - dependencies: - "@babel/runtime" "^7.18.0" - async-validator "^4.1.0" - rc-util "^5.8.0" - -rc-image@~5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-5.7.1.tgz#678dc014845954c30237808c00c7b12e5f2a0b07" - integrity sha512-QyMfdhoUfb5W14plqXSisaYwpdstcLYnB0MjX5ccIK2rydQM9sDPuekQWu500DDGR2dBaIF5vx9XbWkNFK17Fg== - dependencies: - "@babel/runtime" "^7.11.2" - classnames "^2.2.6" - rc-dialog "~8.9.0" - rc-util "^5.0.6" - -rc-input-number@~7.3.9: - version "7.3.9" - resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-7.3.9.tgz#bc6560376ea595e3bf8fbd3137711cbc158800b5" - integrity sha512-u0+miS+SATdb6DtssYei2JJ1WuZME+nXaG6XGtR8maNyW5uGDytfDu60OTWLQEb0Anv/AcCzehldV8CKmKyQfA== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.5" - rc-util "^5.23.0" - -rc-input@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/rc-input/-/rc-input-0.1.2.tgz#7d6a0858a5f1fd89f78020cf6f13d672778481b1" - integrity sha512-ZPmwcFspgfYpUfbSx3KnLk9gImBcLOrlQCr4oTJ4jBoIXgJLTfm26yelzRgBJewhkvD8uJbgX0sQ/yOzuOHnJg== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-util "^5.18.1" - -rc-mentions@~1.9.1: - version "1.9.2" - resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-1.9.2.tgz#f264ebc4ec734dad9edc8e078b65ab3586d94a7b" - integrity sha512-uxb/lzNnEGmvraKWNGE6KXMVXvt8RQv9XW8R0Dqi3hYsyPiAZeHRCHQKdLARuk5YBhFhZ6ga55D/8XuY367g3g== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-menu "~9.6.0" - rc-textarea "^0.3.0" - rc-trigger "^5.0.4" - rc-util "^5.22.5" - -rc-menu@~9.6.0, rc-menu@~9.6.3: - version "9.6.4" - resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.6.4.tgz#033e7b8848c17a09a81b68b8d4c3fa457605f4f6" - integrity sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-motion "^2.4.3" - rc-overflow "^1.2.0" - rc-trigger "^5.1.2" - rc-util "^5.12.0" - shallowequal "^1.1.0" - -rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.2.0, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.3, rc-motion@^2.4.4, rc-motion@^2.6.1, rc-motion@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.6.2.tgz#3d31f97e41fb8e4f91a4a4189b6a98ac63342869" - integrity sha512-4w1FaX3dtV749P8GwfS4fYnFG4Rb9pxvCYPc/b2fw1cmlHJWNNgOFIz7ysiD+eOrzJSvnLJWlNQQncpNMXwwpg== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-util "^5.21.0" - -rc-notification@~4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-4.6.0.tgz#4e76fc2d0568f03cc93ac18c9e20763ebe29fa46" - integrity sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-motion "^2.2.0" - rc-util "^5.20.1" - -rc-overflow@^1.0.0, rc-overflow@^1.2.0: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.2.8.tgz#40f140fabc244118543e627cdd1ef750d9481a88" - integrity sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-resize-observer "^1.0.0" - rc-util "^5.19.2" - -rc-pagination@~3.1.17: - version "3.1.17" - resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-3.1.17.tgz#91e690aa894806e344cea88ea4a16d244194a1bd" - integrity sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.1" - -rc-picker@~2.6.10: - version "2.6.10" - resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-2.6.10.tgz#8d0a473c079388bdb2d7358a2a54c7d5095893b4" - integrity sha512-9wYtw0DFWs9FO92Qh2D76P0iojUr8ZhLOtScUeOit6ks/F+TBLrOC1uze3IOu+u9gbDAjmosNWLKbBzx/Yuv2w== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.1" - date-fns "2.x" - dayjs "1.x" - moment "^2.24.0" - rc-trigger "^5.0.4" - rc-util "^5.4.0" - shallowequal "^1.1.0" - -rc-progress@~3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-3.3.3.tgz#eb9bffbacab1534f2542f9f6861ce772254362b1" - integrity sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-util "^5.16.1" - -rc-rate@~2.9.0: - version "2.9.2" - resolved "https://registry.yarnpkg.com/rc-rate/-/rc-rate-2.9.2.tgz#4a58965d1ecf91896ebae01d458b59056df0b4ea" - integrity sha512-SaiZFyN8pe0Fgphv8t3+kidlej+cq/EALkAJAc3A0w0XcPaH2L1aggM8bhe1u6GAGuQNAoFvTLjw4qLPGRKV5g== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.5" - rc-util "^5.0.1" - -rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0, rc-resize-observer@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz#9f46052f81cdf03498be35144cb7c53fd282c4c7" - integrity sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.1" - rc-util "^5.15.0" - resize-observer-polyfill "^1.5.1" - -rc-segmented@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.1.0.tgz#0e0afe646c1a0e44a0e18785f518c42633ec8efc" - integrity sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-motion "^2.4.4" - rc-util "^5.17.0" - -rc-select@~14.1.0, rc-select@~14.1.13: - version "14.1.13" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.1.13.tgz#7eb53d00be82fb8e5050de3094e72edcf27ce6f6" - integrity sha512-WMEsC3gTwA1dbzWOdVIXDmWyidYNLq68AwvvUlRROw790uGUly0/vmqDozXrIr0QvN/A3CEULx12o+WtLCAefg== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-motion "^2.0.1" - rc-overflow "^1.0.0" - rc-trigger "^5.0.4" - rc-util "^5.16.1" - rc-virtual-list "^3.2.0" - -rc-slider@~10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.0.1.tgz#7058c68ff1e1aa4e7c3536e5e10128bdbccb87f9" - integrity sha512-igTKF3zBet7oS/3yNiIlmU8KnZ45npmrmHlUUio8PNbIhzMcsh+oE/r2UD42Y6YD2D/s+kzCQkzQrPD6RY435Q== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.5" - rc-util "^5.18.1" - shallowequal "^1.1.0" - -rc-steps@~4.1.0: - version "4.1.4" - resolved "https://registry.yarnpkg.com/rc-steps/-/rc-steps-4.1.4.tgz#0ba82db202d59ca52d0693dc9880dd145b19dc23" - integrity sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w== - dependencies: - "@babel/runtime" "^7.10.2" - classnames "^2.2.3" - rc-util "^5.0.1" - -rc-switch@~3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/rc-switch/-/rc-switch-3.2.2.tgz#d001f77f12664d52595b4f6fb425dd9e66fba8e8" - integrity sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.1" - rc-util "^5.0.1" - -rc-table@~7.26.0: - version "7.26.0" - resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.26.0.tgz#9d517e7fa512e7571fdcc453eb1bf19edfac6fbc" - integrity sha512-0cD8e6S+DTGAt5nBZQIPFYEaIukn17sfa5uFL98faHlH/whZzD8ii3dbFL4wmUDEL4BLybhYop+QUfZJ4CPvNQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.5" - rc-resize-observer "^1.1.0" - rc-util "^5.22.5" - shallowequal "^1.1.0" - -rc-tabs@~12.1.0-alpha.1: - version "12.1.0-alpha.1" - resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-12.1.0-alpha.1.tgz#00f45b9dffa9bc6aff8ce2aff4a1a0764caada54" - integrity sha512-M+B88WEnGSuE+mR54fpgPbZLAakzxa/H6FmEetLBl5WG4I3AcwSk9amuIPC/tu0KXBl+H6Bg5ZwrrEUOBUvgzg== - dependencies: - "@babel/runtime" "^7.11.2" - classnames "2.x" - rc-dropdown "~4.0.0" - rc-menu "~9.6.0" - rc-motion "^2.6.2" - rc-resize-observer "^1.0.0" - rc-util "^5.5.0" - -rc-textarea@^0.3.0, rc-textarea@~0.3.0: - version "0.3.7" - resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-0.3.7.tgz#987142891efdedb774883c07e2f51b318fde5a11" - integrity sha512-yCdZ6binKmAQB13hc/oehh0E/QRwoPP1pjF21aHBxlgXO3RzPF6dUu4LG2R4FZ1zx/fQd2L1faktulrXOM/2rw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.1" - rc-resize-observer "^1.0.0" - rc-util "^5.7.0" - shallowequal "^1.1.0" - -rc-tooltip@~5.2.0: - version "5.2.2" - resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-5.2.2.tgz#e5cafa8ecebf78108936a0bcb93c150fa81ac93b" - integrity sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg== - dependencies: - "@babel/runtime" "^7.11.2" - classnames "^2.3.1" - rc-trigger "^5.0.0" - -rc-tree-select@~5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-5.5.0.tgz#96d935ec994a0f6b0fecc4c18f22f472fe8530a3" - integrity sha512-XS0Jvw4OjFz/Xvb2byEkBWv55JFKFz0HVvTBa/cPOHJaQh/3EaYwymEMnCCvGEzS1+5CfDVwMtA8j/v4rt1DHw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-select "~14.1.0" - rc-tree "~5.7.0" - rc-util "^5.16.1" - -rc-tree@~5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-5.7.0.tgz#d0e316eeeac2ba4a1c36b2b2201d84884f1c76a1" - integrity sha512-F+Ewkv/UcutshnVBMISP+lPdHDlcsL+YH/MQDVWbk+QdkfID7vXiwrHMEZn31+2Rbbm21z/HPceGS8PXGMmnQg== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-motion "^2.0.1" - rc-util "^5.16.1" - rc-virtual-list "^3.4.8" - -rc-trigger@^5.0.0, rc-trigger@^5.0.4, rc-trigger@^5.1.2, rc-trigger@^5.2.10, rc-trigger@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.3.1.tgz#acafadf3eaf384e7f466c303bfa0f34c8137d7b8" - integrity sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ== - dependencies: - "@babel/runtime" "^7.18.3" - classnames "^2.2.6" - rc-align "^4.0.0" - rc-motion "^2.0.0" - rc-util "^5.19.2" - -rc-upload@~4.3.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.3.4.tgz#83ff7d3867631c37adbfd72ea3d1fd7e97ca84af" - integrity sha512-uVbtHFGNjHG/RyAfm9fluXB6pvArAGyAx8z7XzXXyorEgVIWj6mOlriuDm0XowDHYz4ycNK0nE0oP3cbFnzxiQ== - dependencies: - "@babel/runtime" "^7.18.3" - classnames "^2.2.5" - rc-util "^5.2.0" - -rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.12.0, rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.2, rc-util@^5.2.0, rc-util@^5.2.1, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.21.2, rc-util@^5.22.5, rc-util@^5.23.0, rc-util@^5.3.0, rc-util@^5.4.0, rc-util@^5.5.0, rc-util@^5.6.1, rc-util@^5.7.0, rc-util@^5.8.0, rc-util@^5.9.4: - version "5.24.4" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.24.4.tgz#a4126f01358c86f17c1bf380a1d83d6c9155ae65" - integrity sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q== - dependencies: - "@babel/runtime" "^7.18.3" - react-is "^16.12.0" - shallowequal "^1.1.0" - -rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.8: - version "3.4.8" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.8.tgz#c24c10c6940546b7e2a5e9809402c6716adfd26c" - integrity sha512-qSN+Rv4i/E7RCTvTMr1uZo7f3crJJg/5DekoCagydo9zsXrxj07zsFSxqizqW+ldGA16lwa8So/bIbV9Ofjddg== - dependencies: - classnames "^2.2.6" - rc-resize-observer "^1.0.0" - rc-util "^5.15.0" - rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -22073,7 +21554,7 @@ react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -23090,13 +22571,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" -scroll-into-view-if-needed@^2.2.25: - version "2.2.29" - resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885" - integrity sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg== - dependencies: - compute-scroll-into-view "^1.0.17" - scuid@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/scuid/-/scuid-1.1.0.tgz#d3f9f920956e737a60f72d0e4ad280bf324d5dab" @@ -23873,11 +23347,6 @@ strict-uri-encode@^2.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== -string-convert@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" - integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== - string-env-interpolation@1.0.1, string-env-interpolation@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152" From 2d5bc567121aefba986f4da8fb65a1dc97cad0e0 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 11:33:09 +0800 Subject: [PATCH 04/17] Remove old code --- apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index d31a30ca7..e77364510 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -185,9 +185,6 @@ import Views var body: some View { VStack(spacing: 0) { -// if viewModel.showLoadingBar { -// ShimmeringLoader() -// } if prefersListLayout || !enableGrid { HomeFeedListView(prefersListLayout: $prefersListLayout, viewModel: viewModel) } else { From 015167af602dc2db8731a97f232e379bcf1a8549 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 11:33:53 +0800 Subject: [PATCH 05/17] Remove old code --- .../Sources/App/Views/Home/LibrarySearchView.swift | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift index 9e636f894..fd6cd50ef 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift @@ -141,12 +141,3 @@ struct LibrarySearchView: View { } } } - -extension AnyTransition { - static var moveAndFade: AnyTransition { - .asymmetric( - insertion: .move(edge: .trailing).combined(with: .opacity), - removal: .scale.combined(with: .opacity) - ) - } -} From a1fabcc564b07797b5f651e993dceb940d8332e1 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 12:01:46 +0800 Subject: [PATCH 06/17] Set the searchbar to first responder when advanced search or term updates are used --- .../App/Views/Home/LibrarySearchView.swift | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift index fd6cd50ef..2fe81163c 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift @@ -24,6 +24,11 @@ struct LibrarySearchView: View { Task { await viewModel.search(dataService: self.dataService, searchTerm: searchTerm) } } + func setSearchTerm(_ searchTerm: String) { + viewModel.searchTerm = searchTerm + searchBar?.becomeFirstResponder() + } + func performSearch(_ searchTerm: String) { let term = searchTerm.trimmingCharacters(in: Foundation.CharacterSet.whitespacesAndNewlines) viewModel.saveRecentSearch(dataService: dataService, searchTerm: term) @@ -44,12 +49,11 @@ struct LibrarySearchView: View { Spacer() -// Image(systemName: "arrow.up.backward") -// .onTapGesture { -// viewModel.searchTerm += (viewModel.searchTerm.count > 0 ? " " : "") + term -// searchBar?.becomeFirstResponder() -// } -// .searchCompletion(term) + Image(systemName: "arrow.up.backward") + .onTapGesture { + setSearchTerm(viewModel.searchTerm + (viewModel.searchTerm.count > 0 ? " " : "") + term) + } + .searchCompletion(term) }.swipeActions(edge: .trailing, allowsFullSwipe: true) { Button { withAnimation(.linear(duration: 0.4)) { @@ -65,6 +69,8 @@ struct LibrarySearchView: View { var body: some View { NavigationView { innerBody + }.introspectViewController { controller in + searchBar = Introspect.findChild(ofType: UISearchBar.self, in: controller.view) } } @@ -81,9 +87,7 @@ struct LibrarySearchView: View { } listBody .navigationTitle("Search") - .navigationBarItems(trailing: Button(action: { dismiss() }) { - Text("Close") - }) + .navigationBarItems(trailing: Button(action: { dismiss() }, label: { Text("Close") })) .navigationBarTitleDisplayMode(NavigationBarItem.TitleDisplayMode.inline) .searchable(text: $viewModel.searchTerm, placement: .navigationBarDrawer(displayMode: .always)) { ForEach(viewModel.items) { item in @@ -120,15 +124,15 @@ struct LibrarySearchView: View { Section("Narrow with advanced search") { (Text("**site:** ") + Text("site or domain (eg omnivore.app)")) .foregroundColor(.appGrayText) - .onTapGesture { viewModel.searchTerm = "site:" } + .onTapGesture { setSearchTerm("site:") } (Text("**author:** ") + Text("author name")) .foregroundColor(.appGrayText) - .onTapGesture { viewModel.searchTerm = "author:" } + .onTapGesture { setSearchTerm("author:") } (Text("**is:** ") + Text("read or unread")) .foregroundColor(.appGrayText) - .onTapGesture { viewModel.searchTerm = "is:" } + .onTapGesture { setSearchTerm("is:") } Button(action: {}, label: { Text("[More on Advanced Search](https://omnivore.app/help/search)") From bca7b650d69dfc4c9d85a9905519abf7b42408e5 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 12:32:46 +0800 Subject: [PATCH 07/17] We still need to show the filtersheader if there is a search term but no results --- .../Sources/App/Views/Home/HomeFeedViewIOS.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index e77364510..4ebb27a19 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -275,10 +275,12 @@ import Views EmptyView() } List { - if viewModel.items.count > 0 { + if viewModel.showLoadingBar { + ShimmeringLoader() + } + if viewModel.items.count > 0 || viewModel.searchTerm.count > 0 { filtersHeader } - ForEach(viewModel.items) { item in FeedCardNavigationLink( item: item, From 4149299b68380369745767285a5f075925aa2d38 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 12:47:55 +0800 Subject: [PATCH 08/17] Move the shimmer out of the library list --- .../App/Views/Home/HomeFeedViewIOS.swift | 202 +++++++++--------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 4ebb27a19..965acc0d4 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -274,120 +274,122 @@ import Views ) { EmptyView() } - List { + VStack { if viewModel.showLoadingBar { ShimmeringLoader() } - if viewModel.items.count > 0 || viewModel.searchTerm.count > 0 { - filtersHeader - } - ForEach(viewModel.items) { item in - FeedCardNavigationLink( - item: item, - viewModel: viewModel - ) - .contextMenu { - Button( - action: { viewModel.itemForHighlightsView = item }, - label: { Label("View Highlights", systemImage: "highlighter") } + List { + if viewModel.items.count > 0 || viewModel.searchTerm.count > 0 { + filtersHeader + } + ForEach(viewModel.items) { item in + FeedCardNavigationLink( + item: item, + viewModel: viewModel ) - Button( - action: { viewModel.itemUnderTitleEdit = item }, - label: { Label("Edit Title/Description", systemImage: "textbox") } - ) - Button( - action: { viewModel.itemUnderLabelEdit = item }, - label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") } - ) - Button(action: { - withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived( - dataService: dataService, - objectID: item.objectID, - archived: !item.isArchived - ) - } - }, label: { - Label( - item.isArchived ? "Unarchive" : "Archive", - systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" + .contextMenu { + Button( + action: { viewModel.itemForHighlightsView = item }, + label: { Label("View Highlights", systemImage: "highlighter") } ) - }) - Button( - action: { - itemToRemove = item - confirmationShown = true - }, - label: { Label("Delete", systemImage: "trash") } - ) - if FeatureFlag.enableSnooze { - Button { - viewModel.itemToSnoozeID = item.id - viewModel.snoozePresented = true - } label: { - Label { Text("Snooze") } icon: { Image.moon } - } - } - Button( - action: { viewModel.downloadAudio(audioController: audioController, item: item) }, - label: { Label("Download Audio", systemImage: "icloud.and.arrow.down") } - ) - } - .swipeActions(edge: .trailing, allowsFullSwipe: true) { - if !item.isArchived { - Button { + Button( + action: { viewModel.itemUnderTitleEdit = item }, + label: { Label("Edit Title/Description", systemImage: "textbox") } + ) + Button( + action: { viewModel.itemUnderLabelEdit = item }, + label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") } + ) + Button(action: { withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: true) + viewModel.setLinkArchived( + dataService: dataService, + objectID: item.objectID, + archived: !item.isArchived + ) } - } label: { - Label("Archive", systemImage: "archivebox") - }.tint(.green) - } else { - Button { - withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: false) - } - } label: { - Label("Unarchive", systemImage: "tray.and.arrow.down.fill") - }.tint(.indigo) - } - } - .swipeActions(edge: .trailing, allowsFullSwipe: true) { - Button( - role: .destructive, - action: { - itemToRemove = item - confirmationShown = true - }, - label: { - Image(systemName: "trash") - } - ) - }.alert("Are you sure?", isPresented: $confirmationShown) { - Button("Remove Link", role: .destructive) { - if let itemToRemove = itemToRemove { - withAnimation { - viewModel.removeLink(dataService: dataService, objectID: itemToRemove.objectID) + }, label: { + Label( + item.isArchived ? "Unarchive" : "Archive", + systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" + ) + }) + Button( + action: { + itemToRemove = item + confirmationShown = true + }, + label: { Label("Delete", systemImage: "trash") } + ) + if FeatureFlag.enableSnooze { + Button { + viewModel.itemToSnoozeID = item.id + viewModel.snoozePresented = true + } label: { + Label { Text("Snooze") } icon: { Image.moon } } } - self.itemToRemove = nil + Button( + action: { viewModel.downloadAudio(audioController: audioController, item: item) }, + label: { Label("Download Audio", systemImage: "icloud.and.arrow.down") } + ) } - Button("Cancel", role: .cancel) { self.itemToRemove = nil } - } - .swipeActions(edge: .leading, allowsFullSwipe: true) { - if FeatureFlag.enableSnooze { - Button { - viewModel.itemToSnoozeID = item.id - viewModel.snoozePresented = true - } label: { - Label { Text("Snooze") } icon: { Image.moon } - }.tint(.appYellow48) + .swipeActions(edge: .trailing, allowsFullSwipe: true) { + if !item.isArchived { + Button { + withAnimation(.linear(duration: 0.4)) { + viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: true) + } + } label: { + Label("Archive", systemImage: "archivebox") + }.tint(.green) + } else { + Button { + withAnimation(.linear(duration: 0.4)) { + viewModel.setLinkArchived(dataService: dataService, objectID: item.objectID, archived: false) + } + } label: { + Label("Unarchive", systemImage: "tray.and.arrow.down.fill") + }.tint(.indigo) + } + } + .swipeActions(edge: .trailing, allowsFullSwipe: true) { + Button( + role: .destructive, + action: { + itemToRemove = item + confirmationShown = true + }, + label: { + Image(systemName: "trash") + } + ) + }.alert("Are you sure?", isPresented: $confirmationShown) { + Button("Remove Link", role: .destructive) { + if let itemToRemove = itemToRemove { + withAnimation { + viewModel.removeLink(dataService: dataService, objectID: itemToRemove.objectID) + } + } + self.itemToRemove = nil + } + Button("Cancel", role: .cancel) { self.itemToRemove = nil } + } + .swipeActions(edge: .leading, allowsFullSwipe: true) { + if FeatureFlag.enableSnooze { + Button { + viewModel.itemToSnoozeID = item.id + viewModel.snoozePresented = true + } label: { + Label { Text("Snooze") } icon: { Image.moon } + }.tint(.appYellow48) + } } } } + .padding(.top, 0) + .listStyle(PlainListStyle()) } - .padding(.top, 0) - .listStyle(PlainListStyle()) } } } From 188b51b293990a6fb5c3cfbdc6405c5d836d61bc Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 13:13:49 +0800 Subject: [PATCH 09/17] Fix the spacing on top of the library list On iPad the navigation bar size was set too larger without specifying inline. Without the spacer we get some re-layout glitches after loading completes. --- .../Sources/App/Views/Home/HomeFeedViewIOS.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 965acc0d4..e6a508038 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -67,6 +67,7 @@ import Views .sheet(item: $viewModel.itemForHighlightsView) { item in HighlightsListView(itemObjectID: item.objectID, hasHighlightMutations: $hasHighlightMutations) } + .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .barLeading) { Image.smallOmnivoreLogo @@ -274,10 +275,13 @@ import Views ) { EmptyView() } - VStack { + VStack(spacing: 0) { if viewModel.showLoadingBar { ShimmeringLoader() + } else { + Spacer(minLength: 2) } + List { if viewModel.items.count > 0 || viewModel.searchTerm.count > 0 { filtersHeader From 3709628a936316c66f57a57fa7ee9f7d9bfb9752 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 14:57:09 +0800 Subject: [PATCH 10/17] Update the advanced search suggestions + typeahead when selected --- .../App/Views/Home/LibrarySearchView.swift | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift index 2fe81163c..6369f9ac4 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/LibrarySearchView.swift @@ -21,12 +21,15 @@ struct LibrarySearchView: View { } func performTypeahead(_ searchTerm: String) { - Task { await viewModel.search(dataService: self.dataService, searchTerm: searchTerm) } + Task { + await viewModel.search(dataService: self.dataService, searchTerm: searchTerm) + } } func setSearchTerm(_ searchTerm: String) { viewModel.searchTerm = searchTerm searchBar?.becomeFirstResponder() + performTypeahead(searchTerm) } func performSearch(_ searchTerm: String) { @@ -116,23 +119,26 @@ struct LibrarySearchView: View { VStack { List { if viewModel.searchTerm.count == 0 { - Section("Recent Searches") { - ForEach(recents, id: \.self) { term in - recentSearchRow(term) + if recents.count > 0 { + Section("Recent Searches") { + ForEach(recents, id: \.self) { term in + recentSearchRow(term) + } } } + Section("Narrow with advanced search") { - (Text("**site:** ") + Text("site or domain (eg omnivore.app)")) + (Text("**in:** ") + Text("filter to inbox, archive, or all")) + .foregroundColor(.appGrayText) + .onTapGesture { setSearchTerm("is:") } + + (Text("**title:** ") + Text("search for a specific title")) .foregroundColor(.appGrayText) .onTapGesture { setSearchTerm("site:") } - (Text("**author:** ") + Text("author name")) + (Text("**has:highlights** ") + Text("any saved read with highlights")) .foregroundColor(.appGrayText) - .onTapGesture { setSearchTerm("author:") } - - (Text("**is:** ") + Text("read or unread")) - .foregroundColor(.appGrayText) - .onTapGesture { setSearchTerm("is:") } + .onTapGesture { setSearchTerm("has:highlights") } Button(action: {}, label: { Text("[More on Advanced Search](https://omnivore.app/help/search)") From 08c06a6dff2deb3106509c73d578117ef4d1eff2 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 15:12:22 +0800 Subject: [PATCH 11/17] Add a button to reset read location This will be more useful when text to speech updates read position while listening, gives the user more control and makes it easier to handle scrolling back in an article. --- .../Sources/App/Views/WebReader/WebReaderContainer.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift index 31f50f7a8..f40ca22d5 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift @@ -175,6 +175,12 @@ struct WebReaderContainerView: View { ) } ) + Button( + action: { + dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0) + }, + label: { Label("Reset Read Location", systemImage: "arrow.counterclockwise.circle") } + ) Button( action: { shareActionID = UUID() }, label: { Label("Share Original", systemImage: "square.and.arrow.up") } From 68f9d9d1da8a016420842211c0c6144e3928abab Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 16:20:04 +0800 Subject: [PATCH 12/17] Give the audio controller access to the dataService so it can update read positions --- apple/OmnivoreKit/Sources/App/Services.swift | 2 +- .../AudioSession/AudioController.swift | 30 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Services.swift b/apple/OmnivoreKit/Sources/App/Services.swift index bad6a6fea..10f0a0467 100644 --- a/apple/OmnivoreKit/Sources/App/Services.swift +++ b/apple/OmnivoreKit/Sources/App/Services.swift @@ -18,7 +18,7 @@ public final class Services { let networker = Networker(appEnvironment: appEnvironment) self.authenticator = Authenticator(networker: networker) self.dataService = DataService(appEnvironment: appEnvironment, networker: networker) - self.audioController = AudioController(appEnvironment: appEnvironment, networker: networker) + self.audioController = AudioController(dataService: dataService) } } diff --git a/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift b/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift index 345fce5d6..eed306bda 100644 --- a/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift +++ b/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift @@ -66,7 +66,10 @@ class SpeechPlayerItem: AVPlayerItem { } } - NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self, queue: OperationQueue.main) { [weak self] _ in + NotificationCenter.default.addObserver( + forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, + object: self, queue: OperationQueue.main + ) { [weak self] _ in guard let self = self else { return } self.completed() } @@ -209,8 +212,7 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate @Published public var durationString: String? @Published public var voiceList: [(name: String, key: String, category: VoiceCategory, selected: Bool)]? - let appEnvironment: AppEnvironment - let networker: Networker + let dataService: DataService var timer: Timer? var player: AVQueuePlayer? @@ -218,10 +220,10 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate var document: SpeechDocument? var synthesizer: SpeechSynthesizer? var durations: [Double]? + var lastReadUpdate = 0.0 - public init(appEnvironment: AppEnvironment, networker: Networker) { - self.appEnvironment = appEnvironment - self.networker = networker + public init(dataService: DataService) { + self.dataService = dataService super.init() self.voiceList = generateVoiceList() @@ -262,6 +264,7 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate player = nil observer = nil synthesizer = nil + lastReadUpdate = 0 itemAudioProperties = nil state = .stopped @@ -292,7 +295,7 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate for itemID in itemIDs { if let document = try? await downloadSpeechFile(itemID: itemID, priority: .low) { - let synthesizer = SpeechSynthesizer(appEnvironment: appEnvironment, networker: networker, document: document) + let synthesizer = SpeechSynthesizer(appEnvironment: dataService.appEnvironment, networker: dataService.networker, document: document) do { try await synthesizer.preload() return true @@ -306,7 +309,7 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate public func downloadForOffline(itemID: String) async -> Bool { if let document = try? await downloadSpeechFile(itemID: itemID, priority: .low) { - let synthesizer = SpeechSynthesizer(appEnvironment: appEnvironment, networker: networker, document: document) + let synthesizer = SpeechSynthesizer(appEnvironment: dataService.appEnvironment, networker: dataService.networker, document: document) for item in synthesizer.createPlayerItems(from: 0) { do { _ = try await SpeechSynthesizer.download(speechItem: item, redownloadCached: true) @@ -550,11 +553,11 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate if let itemID = itemAudioProperties?.itemID { Task { - let document = try? await downloadSpeechFile(itemID: itemID, priority: .high) + let document = try? await self.downloadSpeechFile(itemID: itemID, priority: .high) DispatchQueue.main.async { if let document = document { - let synthesizer = SpeechSynthesizer(appEnvironment: self.appEnvironment, networker: self.networker, document: document) + let synthesizer = SpeechSynthesizer(appEnvironment: self.dataService.appEnvironment, networker: self.dataService.networker, document: document) self.setTextItems() self.durations = synthesizer.estimatedDurations(forSpeed: self.playbackRate) @@ -687,7 +690,7 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate } } - let synthesizer = SpeechSynthesizer(appEnvironment: appEnvironment, networker: networker, document: document) + let synthesizer = SpeechSynthesizer(appEnvironment: dataService.appEnvironment, networker: dataService.networker, document: document) durations = synthesizer.estimatedDurations(forSpeed: playbackRate) self.synthesizer = synthesizer @@ -754,6 +757,7 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate func startTimer() { if timer == nil { + lastReadUpdate = 0 timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true) timer?.fire() } @@ -908,13 +912,13 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate } let path = "/api/article/\(itemID)/speech?voice=\(currentVoice)&secondaryVoice=\(secondaryVoice)&priority=\(priority)\(isoLangForCurrentVoice())" - guard let url = URL(string: path, relativeTo: appEnvironment.serverBaseURL) else { + guard let url = URL(string: path, relativeTo: dataService.appEnvironment.serverBaseURL) else { throw BasicError.message(messageText: "Invalid audio URL") } var request = URLRequest(url: url) request.httpMethod = "GET" - for (header, value) in networker.defaultHeaders { + for (header, value) in dataService.networker.defaultHeaders { request.setValue(value, forHTTPHeaderField: header) } From 476d44fbb4024f2929be33ab4e747c5ab1a9dfd0 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 16:34:52 +0800 Subject: [PATCH 13/17] Try to prevent index out of bounds issues with the tab controller --- .../App/Views/AudioPlayer/MiniPlayer.swift | 433 +++++++++--------- 1 file changed, 217 insertions(+), 216 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift index 32f065178..1f7621f94 100644 --- a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift @@ -155,226 +155,227 @@ public struct MiniPlayer: View { } } - // swiftlint:disable:next function_body_length - func playerContent(_ itemAudioProperties: LinkedItemAudioProperties) -> some View { - GeometryReader { geom in - VStack(spacing: 0) { - if expanded { - ZStack { - closeButton - .padding(.top, 24) - .padding(.leading, 16) - .frame(maxWidth: .infinity, alignment: .leading) - - Capsule() - .fill(.gray) - .frame(width: 60, height: 4) - .padding(.top, 8) - .transition(.opacity) - } - } else { - HStack(alignment: .center, spacing: 8) { - let dim = 64.0 - - if let imageURL = itemAudioProperties.imageURL { - AsyncImage(url: imageURL) { phase in - if let image = phase.image { - image - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: dim, height: dim) - .cornerRadius(6) - } else if phase.error != nil { - defaultArtwork(forDimensions: dim) - } else { - Color.appButtonBackground - .frame(width: dim, height: dim) - .cornerRadius(6) - } - } - } else { - defaultArtwork(forDimensions: dim) - } - - VStack { - Text(itemAudioProperties.title) - .font(.appCallout) - .foregroundColor(.appGrayTextContrast) - .fixedSize(horizontal: false, vertical: false) - .frame(maxWidth: .infinity, alignment: .leading) - - if let byline = itemAudioProperties.byline { - Text(byline) - .font(.appCaption) - .lineSpacing(1.25) - .foregroundColor(.appGrayText) - .fixedSize(horizontal: false, vertical: false) - .frame(maxWidth: .infinity, alignment: .leading) - } - } - - playPauseButtonItem - .frame(width: 28, height: 28) - - stopButton - .frame(width: 28, height: 28) - } - .padding(16) - .frame(maxHeight: .infinity) - } - - if expanded { - ZStack { - TabView(selection: $tabIndex) { - ForEach(0 ..< (self.audioController.textItems?.count ?? 0), id: \.self) { id in - SpeechCard(id: id) - .frame(width: geom.size.width) - .tag(id) - } - } - .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - .onChange(of: tabIndex, perform: { index in - if index != audioController.currentAudioIndex, index < (audioController.textItems?.count ?? 0) { - audioController.seek(toUtterance: index) - } - }) - .onChange(of: audioController.currentAudioIndex, perform: { index in - if index >= (audioController.textItems?.count ?? 0) { - return - } - - if self.audioController.state != .reachedEnd { - tabIndex = index - } - }) - .frame(width: geom.size.width) - - if audioController.state == .reachedEnd { - // If we have reached the end display a replay button - Button( - action: { - tabIndex = 0 - audioController.unpause() - audioController.seek(to: 0.0) - }, - label: { - Image(systemName: "gobackward") - .font(.appCallout) - .tint(.appGrayTextContrast) - Text("Replay") - } - ) - } - } - - Spacer() - - Group { - ScrubberView(value: $audioController.timeElapsed, - minValue: 0, maxValue: self.audioController.duration, - onEditingChanged: { scrubStarted in - if scrubStarted { - self.audioController.scrubState = .scrubStarted - } else { - self.audioController.scrubState = .scrubEnded(self.audioController.timeElapsed) - } - }) - - HStack { - Text(audioController.timeElapsedString ?? "0:00") - .font(.appCaptionTwo) - .foregroundColor(.appGrayText) - Spacer() - Text(audioController.durationString ?? "0:00") - .font(.appCaptionTwo) - .foregroundColor(.appGrayText) - } - } - .padding(.leading, 16) - .padding(.trailing, 16) - - HStack(alignment: .center, spacing: 36) { - Menu { - playbackRateButton(rate: 1.0, title: "1.0×", selected: audioController.playbackRate == 1.0) - playbackRateButton(rate: 1.1, title: "1.1×", selected: audioController.playbackRate == 1.1) - playbackRateButton(rate: 1.2, title: "1.2×", selected: audioController.playbackRate == 1.2) - playbackRateButton(rate: 1.5, title: "1.5×", selected: audioController.playbackRate == 1.5) - playbackRateButton(rate: 1.7, title: "1.7×", selected: audioController.playbackRate == 1.7) - playbackRateButton(rate: 2.0, title: "2.0×", selected: audioController.playbackRate == 2.0) - } label: { - VStack { - Text(String(format: "%.1f×", audioController.playbackRate)) - .font(.appCallout) - .lineLimit(0) - } - .contentShape(Rectangle()) - } - .padding(8) - - Button( - action: { self.audioController.skipBackwards(seconds: 30) }, - label: { - Image(systemName: "gobackward.30") - .font(.appTitleTwo) - } - ) - - playPauseButtonItem - .frame(width: 56, height: 56) - - Button( - action: { self.audioController.skipForward(seconds: 30) }, - label: { - Image(systemName: "goforward.30") - .font(.appTitleTwo) - } - ) - - Menu { - Button("View Article", action: { viewArticle() }) - Button("Change Voice", action: { showVoiceSheet = true }) - } label: { - VStack { - Image(systemName: "ellipsis") - .font(.appCallout) - .frame(width: 20, height: 20) - } - .contentShape(Rectangle()) - } - .padding(8) - }.padding(.bottom, 16) + var audioCards: some View { + ZStack { + let textItems = self.audioController.textItems ?? [] + TabView(selection: $tabIndex) { + ForEach(0 ..< textItems.count, id: \.self) { id in + SpeechCard(id: id) + .tag(id) } } - .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) - .background( - Color.systemBackground - .shadow(color: expanded ? .clear : .gray.opacity(0.33), radius: 8, x: 0, y: 4) - .mask(Rectangle().padding(.top, -20)) - ) - .onTapGesture { - withAnimation(.easeIn(duration: 0.08)) { expanded = true } - }.sheet(isPresented: $showVoiceSheet) { - NavigationView { - TextToSpeechVoiceSelectionView(forLanguage: audioController.currentVoiceLanguage, showLanguageChanger: true) - .navigationBarTitle("Voice") - .navigationBarTitleDisplayMode(.inline) - .navigationBarItems(leading: Button(action: { self.showVoiceSheet = false }) { - Image(systemName: "chevron.backward") - .font(.appNavbarIcon) - .tint(.appGrayTextContrast) - }) + .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) + .onChange(of: tabIndex, perform: { index in + if index != audioController.currentAudioIndex, index < (audioController.textItems?.count ?? 0) { + audioController.seek(toUtterance: index) } - }.sheet(isPresented: $showLanguageSheet) { - NavigationView { - TextToSpeechLanguageView() - .navigationBarTitle("Language") - .navigationBarTitleDisplayMode(.inline) - .navigationBarItems(leading: Button(action: { self.showLanguageSheet = false }) { - Image(systemName: "chevron.backward") - .font(.appNavbarIcon) - .tint(.appGrayTextContrast) - }) + }) + .onChange(of: audioController.currentAudioIndex, perform: { index in + if index >= textItems.count { + return } + + if self.audioController.state != .reachedEnd { + tabIndex = index + } + }) + + if audioController.state == .reachedEnd { + // If we have reached the end display a replay button + Button( + action: { + tabIndex = 0 + audioController.unpause() + audioController.seek(to: 0.0) + }, + label: { + Image(systemName: "gobackward") + .font(.appCallout) + .tint(.appGrayTextContrast) + Text("Replay") + } + ) + } + } + } + + // swiftlint:disable:next function_body_length + func playerContent(_ itemAudioProperties: LinkedItemAudioProperties) -> some View { + VStack(spacing: 0) { + if expanded { + ZStack { + closeButton + .padding(.top, 24) + .padding(.leading, 16) + .frame(maxWidth: .infinity, alignment: .leading) + + Capsule() + .fill(.gray) + .frame(width: 60, height: 4) + .padding(.top, 8) + .transition(.opacity) + } + } else { + HStack(alignment: .center, spacing: 8) { + let dim = 64.0 + + if let imageURL = itemAudioProperties.imageURL { + AsyncImage(url: imageURL) { phase in + if let image = phase.image { + image + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: dim, height: dim) + .cornerRadius(6) + } else if phase.error != nil { + defaultArtwork(forDimensions: dim) + } else { + Color.appButtonBackground + .frame(width: dim, height: dim) + .cornerRadius(6) + } + } + } else { + defaultArtwork(forDimensions: dim) + } + + VStack { + Text(itemAudioProperties.title) + .font(.appCallout) + .foregroundColor(.appGrayTextContrast) + .fixedSize(horizontal: false, vertical: false) + .frame(maxWidth: .infinity, alignment: .leading) + + if let byline = itemAudioProperties.byline { + Text(byline) + .font(.appCaption) + .lineSpacing(1.25) + .foregroundColor(.appGrayText) + .fixedSize(horizontal: false, vertical: false) + .frame(maxWidth: .infinity, alignment: .leading) + } + } + + playPauseButtonItem + .frame(width: 28, height: 28) + + stopButton + .frame(width: 28, height: 28) + } + .padding(16) + .frame(maxHeight: .infinity) + } + + if expanded { + audioCards + + Spacer() + + Group { + ScrubberView(value: $audioController.timeElapsed, + minValue: 0, maxValue: self.audioController.duration, + onEditingChanged: { scrubStarted in + if scrubStarted { + self.audioController.scrubState = .scrubStarted + } else { + self.audioController.scrubState = .scrubEnded(self.audioController.timeElapsed) + } + }) + + HStack { + Text(audioController.timeElapsedString ?? "0:00") + .font(.appCaptionTwo) + .foregroundColor(.appGrayText) + Spacer() + Text(audioController.durationString ?? "0:00") + .font(.appCaptionTwo) + .foregroundColor(.appGrayText) + } + } + .padding(.leading, 16) + .padding(.trailing, 16) + + HStack(alignment: .center, spacing: 36) { + Menu { + playbackRateButton(rate: 1.0, title: "1.0×", selected: audioController.playbackRate == 1.0) + playbackRateButton(rate: 1.1, title: "1.1×", selected: audioController.playbackRate == 1.1) + playbackRateButton(rate: 1.2, title: "1.2×", selected: audioController.playbackRate == 1.2) + playbackRateButton(rate: 1.5, title: "1.5×", selected: audioController.playbackRate == 1.5) + playbackRateButton(rate: 1.7, title: "1.7×", selected: audioController.playbackRate == 1.7) + playbackRateButton(rate: 2.0, title: "2.0×", selected: audioController.playbackRate == 2.0) + } label: { + VStack { + Text(String(format: "%.1f×", audioController.playbackRate)) + .font(.appCallout) + .lineLimit(0) + } + .contentShape(Rectangle()) + } + .padding(8) + + Button( + action: { self.audioController.skipBackwards(seconds: 30) }, + label: { + Image(systemName: "gobackward.30") + .font(.appTitleTwo) + } + ) + + playPauseButtonItem + .frame(width: 56, height: 56) + + Button( + action: { self.audioController.skipForward(seconds: 30) }, + label: { + Image(systemName: "goforward.30") + .font(.appTitleTwo) + } + ) + + Menu { + Button("View Article", action: { viewArticle() }) + Button("Change Voice", action: { showVoiceSheet = true }) + } label: { + VStack { + Image(systemName: "ellipsis") + .font(.appCallout) + .frame(width: 20, height: 20) + } + .contentShape(Rectangle()) + } + .padding(8) + }.padding(.bottom, 16) + } + } + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + .background( + Color.systemBackground + .shadow(color: expanded ? .clear : .gray.opacity(0.33), radius: 8, x: 0, y: 4) + .mask(Rectangle().padding(.top, -20)) + ) + .onTapGesture { + withAnimation(.easeIn(duration: 0.08)) { expanded = true } + }.sheet(isPresented: $showVoiceSheet) { + NavigationView { + TextToSpeechVoiceSelectionView(forLanguage: audioController.currentVoiceLanguage, showLanguageChanger: true) + .navigationBarTitle("Voice") + .navigationBarTitleDisplayMode(.inline) + .navigationBarItems(leading: Button(action: { self.showVoiceSheet = false }, label: { + Image(systemName: "chevron.backward") + .font(.appNavbarIcon) + .tint(.appGrayTextContrast) + })) + } + }.sheet(isPresented: $showLanguageSheet) { + NavigationView { + TextToSpeechLanguageView() + .navigationBarTitle("Language") + .navigationBarTitleDisplayMode(.inline) + .navigationBarItems(leading: Button(action: { self.showLanguageSheet = false }) { + Image(systemName: "chevron.backward") + .font(.appNavbarIcon) + .tint(.appGrayTextContrast) + }) } } } From f047775532e67ee24f5c6ebf8a2bdec7deb658ea Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 16:41:23 +0800 Subject: [PATCH 14/17] Improve the replay button, give an overlay behind so its easier to see --- .../App/Views/AudioPlayer/MiniPlayer.swift | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift index 1f7621f94..69f1b45de 100644 --- a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/MiniPlayer.swift @@ -181,7 +181,16 @@ public struct MiniPlayer: View { }) if audioController.state == .reachedEnd { - // If we have reached the end display a replay button + // If we have reached the end display a replay button with an overlay behind + Color.systemBackground.opacity(0.85) + .frame( + minWidth: 0, + maxWidth: .infinity, + minHeight: 0, + maxHeight: .infinity, + alignment: .topLeading + ) + Button( action: { tabIndex = 0 @@ -189,12 +198,14 @@ public struct MiniPlayer: View { audioController.seek(to: 0.0) }, label: { - Image(systemName: "gobackward") - .font(.appCallout) - .tint(.appGrayTextContrast) - Text("Replay") + HStack { + Image(systemName: "gobackward") + .font(.appCallout) + .tint(.appGrayTextContrast) + Text("Replay") + } } - ) + ).buttonStyle(RoundedRectButtonStyle()) } } } From 25055598e323b2a62797191a93e2f44acf5f1165 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 17:22:40 +0800 Subject: [PATCH 15/17] Update read position while listening to audio --- .../Services/AudioSession/AudioController.swift | 11 +++++++++++ packages/web/components/templates/article/Article.tsx | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift b/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift index eed306bda..aea393b20 100644 --- a/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift +++ b/apple/OmnivoreKit/Sources/Services/AudioSession/AudioController.swift @@ -804,6 +804,17 @@ public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate } } } + + if timeElapsed - 10 > lastReadUpdate { + let percentProgress = timeElapsed / duration + let anchorIndex = Int((player?.currentItem as? SpeechPlayerItem)?.speechItem.htmlIdx ?? "") ?? 0 + + if let itemID = itemAudioProperties?.itemID { + dataService.updateLinkReadingProgress(itemID: itemID, readingProgress: percentProgress, anchorIndex: anchorIndex) + } + + lastReadUpdate = timeElapsed + } } func clearNowPlayingInfo() { diff --git a/packages/web/components/templates/article/Article.tsx b/packages/web/components/templates/article/Article.tsx index 4dd39a5fe..a9e17f885 100644 --- a/packages/web/components/templates/article/Article.tsx +++ b/packages/web/components/templates/article/Article.tsx @@ -48,7 +48,6 @@ export function Article(props: ArticleProps): JSX.Element { const debouncedSetReadingProgress = useMemo( () => debounce((readingProgress: number) => { - console.log('setReadingProgress', readingProgress) setReadingProgress(readingProgress) }, 2000), [] From 706021de779c7a14f26c6fb4fbb58e0bc03758fc Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 11 Oct 2022 21:38:28 +0800 Subject: [PATCH 16/17] Add highlighted filter option to see all items with highlights --- .../Sources/Models/LinkedItemFilter.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift b/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift index 62669a63c..abb5f387b 100644 --- a/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift +++ b/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift @@ -6,6 +6,7 @@ public enum LinkedItemFilter: String, CaseIterable { case newsletters case all case archived + case hasHighlights case files } @@ -22,6 +23,8 @@ public extension LinkedItemFilter { return "All" case .archived: return "Archived" + case .hasHighlights: + return "Highlighted" case .files: return "Files" } @@ -39,6 +42,8 @@ public extension LinkedItemFilter { return "in:all" case .archived: return "in:archive" + case .hasHighlights: + return "has:highlights" case .files: return "type:file" } @@ -84,6 +89,13 @@ public extension LinkedItemFilter { format: "%K == %@", #keyPath(LinkedItem.contentReader), "PDF" ) return NSCompoundPredicate(andPredicateWithSubpredicates: [undeletedPredicate, isPDFPredicate]) + case .hasHighlights: + let hasHighlightsPredicate = NSPredicate( + format: "highlights.@count > 0" + ) + return NSCompoundPredicate(andPredicateWithSubpredicates: [ + hasHighlightsPredicate, notInArchivePredicate + ]) } } } From 5278fdd4a157fcb9f418b39805a1275013f4c7f2 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 12 Oct 2022 12:46:10 +0800 Subject: [PATCH 17/17] Set the X-OmnivoreClient request header --- .../Services/DataService/Networking/ServerResource.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift b/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift index 4bf7f11df..0c4698cbb 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Networking/ServerResource.swift @@ -65,7 +65,8 @@ extension URLRequest { var headers = [ "content-type": "application/json", "user-agent": userAgent, - "app-language": Locale.preferredLanguages[0] + "app-language": Locale.preferredLanguages[0], + "X-OmnivoreClient": "ios" ] if let deviceLanguage = NSLocale.current.languageCode {