Update user interface for file import tool
This commit is contained in:
@ -2910,6 +2910,7 @@ export type UploadImportFileSuccess = {
|
||||
};
|
||||
|
||||
export enum UploadImportFileType {
|
||||
Matter = 'MATTER',
|
||||
Pocket = 'POCKET',
|
||||
UrlList = 'URL_LIST'
|
||||
}
|
||||
|
||||
@ -2269,6 +2269,7 @@ type UploadImportFileSuccess {
|
||||
}
|
||||
|
||||
enum UploadImportFileType {
|
||||
MATTER
|
||||
POCKET
|
||||
URL_LIST
|
||||
}
|
||||
|
||||
@ -2309,6 +2309,7 @@ const schema = gql`
|
||||
enum UploadImportFileType {
|
||||
URL_LIST
|
||||
POCKET
|
||||
MATTER
|
||||
}
|
||||
|
||||
enum UploadImportFileErrorCode {
|
||||
|
||||
@ -243,11 +243,14 @@ function onResponseReceived(error, source, destRoot, options) {
|
||||
}
|
||||
|
||||
async function runReadability(source, destPath, metadataDestPath, options) {
|
||||
console.log('running readability')
|
||||
|
||||
var uri = "http://fakehost/test/page.html";
|
||||
var myReader, result, readerable;
|
||||
try {
|
||||
// Use linkedom for isProbablyReaderable because it supports querySelectorAll
|
||||
var dom = parseHTML(source).document;
|
||||
console.log('dom', parseHTML(source).innerHTML)
|
||||
readerable = isProbablyReaderable(dom);
|
||||
// We pass `caption` as a class to check that passing in extra classes works,
|
||||
// given that it appears in some of the test documents.
|
||||
@ -257,6 +260,7 @@ async function runReadability(source, destPath, metadataDestPath, options) {
|
||||
console.error(ex);
|
||||
ex.stack.forEach(console.log.bind(console));
|
||||
}
|
||||
console.log('result', result)
|
||||
if (!result) {
|
||||
console.error("No content generated by readability, not going to write expected.html!");
|
||||
return;
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { gqlFetcher } from '../networkHelpers'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
export type UploadImportFileType = 'URL_LIST' | 'POCKET'
|
||||
export enum UploadImportFileType {
|
||||
URL_LIST = 'URL_LIST',
|
||||
POCKET = 'POCKET',
|
||||
MATTER = 'MATTER',
|
||||
}
|
||||
|
||||
type UploadImportFileResponseData = {
|
||||
uploadImportFile?: UploadImportFileData
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"react-hot-toast": "^2.1.1",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-pro-sidebar": "^0.7.1",
|
||||
"react-spinners": "^0.13.7",
|
||||
"react-super-responsive-table": "^5.2.1",
|
||||
"react-topbar-progress-indicator": "^4.1.1",
|
||||
"react-twitter-widgets": "^1.10.0",
|
||||
|
||||
@ -5,26 +5,40 @@ import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
|
||||
import { applyStoredTheme } from '../../../lib/themeUpdater'
|
||||
|
||||
import {
|
||||
Box,
|
||||
HStack,
|
||||
SpanBox,
|
||||
VStack,
|
||||
} from '../../../components/elements/LayoutPrimitives'
|
||||
|
||||
import 'antd/dist/antd.compact.css'
|
||||
import { StyledText } from '../../../components/elements/StyledText'
|
||||
import { Button } from '../../../components/elements/Button'
|
||||
import { ProfileLayout } from '../../../components/templates/ProfileLayout'
|
||||
import {
|
||||
uploadImportFileRequestMutation,
|
||||
UploadImportFileType,
|
||||
} from '../../../lib/networking/mutations/uploadImportFileMutation'
|
||||
import { Button } from '../../../components/elements/Button'
|
||||
import { FormLabel } from '../../../components/elements/FormElements'
|
||||
import { uploadImportFileRequestMutation } from '../../../lib/networking/mutations/uploadImportFileMutation'
|
||||
import { Loader } from '../../../components/templates/SavingRequest'
|
||||
|
||||
import { SyncLoader } from 'react-spinners'
|
||||
import { theme } from '../../../components/tokens/stitches.config'
|
||||
|
||||
type UploadState = 'none' | 'uploading' | 'completed'
|
||||
|
||||
export default function ImportUploader(): JSX.Element {
|
||||
applyStoredTheme(false)
|
||||
|
||||
const [errorMessage, setErrorMessage] = useState<string | undefined>()
|
||||
const [file, setFile] = useState<File>()
|
||||
const [type, setType] = useState<string>()
|
||||
const [type, setType] = useState<UploadImportFileType>()
|
||||
const [uploadState, setUploadState] = useState<UploadState>('none')
|
||||
|
||||
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const onFinish = (values: unknown) => {
|
||||
console.log(values)
|
||||
}
|
||||
|
||||
const onTypeChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files) {
|
||||
setFile(e.target.files[0])
|
||||
}
|
||||
@ -32,16 +46,19 @@ export default function ImportUploader(): JSX.Element {
|
||||
|
||||
const handleUploadClick = async () => {
|
||||
if (!file) {
|
||||
setErrorMessage('No file selected.')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('file type: ', file.type)
|
||||
if (!type) {
|
||||
setErrorMessage('No file type selected.')
|
||||
return
|
||||
}
|
||||
|
||||
setUploadState('uploading')
|
||||
|
||||
try {
|
||||
const result = await uploadImportFileRequestMutation(
|
||||
'URL_LIST',
|
||||
'text/csv'
|
||||
)
|
||||
const result = await uploadImportFileRequestMutation(type, 'text/csv')
|
||||
|
||||
if (result && result.uploadSignedUrl) {
|
||||
const uploadRes = await fetch(result.uploadSignedUrl, {
|
||||
@ -52,20 +69,26 @@ export default function ImportUploader(): JSX.Element {
|
||||
'content-length': `${file.size}`,
|
||||
},
|
||||
})
|
||||
console.log('upload result: ', uploadRes)
|
||||
setUploadState('completed')
|
||||
} else {
|
||||
setErrorMessage(
|
||||
'Unable to create file upload. Please ensure you are logged in.'
|
||||
)
|
||||
setUploadState('none')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('caught error', error)
|
||||
if (error == 'UPLOAD_DAILY_LIMIT_EXCEEDED') {
|
||||
setErrorMessage('You have exceeded your maximum daily upload limit.')
|
||||
}
|
||||
setUploadState('none')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ProfileLayout>
|
||||
<VStack
|
||||
alignment="center"
|
||||
alignment="start"
|
||||
css={{
|
||||
padding: '16px',
|
||||
background: 'white',
|
||||
@ -76,41 +99,128 @@ export default function ImportUploader(): JSX.Element {
|
||||
boxShadow: 'rgb(224 224 224) 9px 9px 9px -9px',
|
||||
}}
|
||||
>
|
||||
<VStack
|
||||
css={{ width: '100%', minWidth: '320px', gap: '16px', pb: '16px' }}
|
||||
></VStack>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Type</FormLabel>
|
||||
<select
|
||||
onChange={(event) => setType('')}
|
||||
style={{
|
||||
padding: '8px',
|
||||
height: '38px',
|
||||
borderRadius: '6px',
|
||||
minWidth: '196px',
|
||||
}}
|
||||
>
|
||||
<option value="URL_LIST">CSV of URLs</option>
|
||||
<option value="POCKET">Pocket export file</option>
|
||||
</select>
|
||||
</SpanBox>
|
||||
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>File</FormLabel>
|
||||
<HStack css={{ py: '16px' }} distribution="center">
|
||||
<input type="file" onChange={handleFileChange} />
|
||||
<div>{file && `${file.name} - ${file.type}`}</div>
|
||||
</HStack>
|
||||
</SpanBox>
|
||||
|
||||
{errorMessage && <StyledText style="error">{errorMessage}</StyledText>}
|
||||
<Button
|
||||
onClick={handleUploadClick}
|
||||
style="ctaDarkYellow"
|
||||
css={{ my: '$2' }}
|
||||
<StyledText
|
||||
style="modalHeadline"
|
||||
css={{ color: theme.colors.omnivoreGray.toString() }}
|
||||
>
|
||||
Upload File
|
||||
</Button>
|
||||
Upload a file to import
|
||||
</StyledText>
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{ pt: '10px', color: theme.colors.omnivoreGray.toString() }}
|
||||
>
|
||||
Omnivore supports uploading a CSV file with one URL per a Row or a
|
||||
_matter_history.csv file for users migrating from the Matter app
|
||||
</StyledText>
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{ pt: '10px', color: theme.colors.omnivoreGray.toString() }}
|
||||
>
|
||||
<b>Importing from Matter:</b> If you are a Matter user, export your
|
||||
data, unzip the Archive.zip file, select `Matter history` on this
|
||||
page, and upload the _matter_history file that was extracted from the
|
||||
Archive.zip file.
|
||||
</StyledText>
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{ pt: '10px', color: theme.colors.omnivoreGray.toString() }}
|
||||
>
|
||||
<b>Importing from other apps:</b> Most apps allow you to export your
|
||||
saved items as a CSV file. Once you have extracted a file, ensure the
|
||||
first column of each row is a URL, and choose our `CSV of URLs` option
|
||||
and upload your file.
|
||||
</StyledText>
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{ pt: '10px', color: theme.colors.omnivoreGray.toString() }}
|
||||
>
|
||||
<b>Note:</b> Please note you are limited to three import uploads per a
|
||||
day, and the maximum file size is 10MB.
|
||||
</StyledText>
|
||||
<VStack css={{ pt: '36px' }}>
|
||||
{uploadState == 'completed' ? (
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{ pt: '10px', color: theme.colors.omnivoreGray.toString() }}
|
||||
>
|
||||
Your upload has completed. Please note that it can take some time
|
||||
for your library to be updated. You will be sent an email when the
|
||||
process completes.
|
||||
</StyledText>
|
||||
) : (
|
||||
<>
|
||||
<HStack>
|
||||
<StyledText
|
||||
style="caption"
|
||||
css={{
|
||||
height: '38px',
|
||||
width: '88px',
|
||||
fontWeight: 'bold',
|
||||
color: theme.colors.omnivoreGray.toString(),
|
||||
}}
|
||||
>
|
||||
File type:
|
||||
</StyledText>
|
||||
<select
|
||||
onChange={(event) => {
|
||||
var changeType: UploadImportFileType =
|
||||
UploadImportFileType[
|
||||
event.currentTarget
|
||||
.value as keyof typeof UploadImportFileType
|
||||
]
|
||||
setType(changeType)
|
||||
}}
|
||||
style={{
|
||||
padding: '8px',
|
||||
height: '38px',
|
||||
borderRadius: '6px',
|
||||
minWidth: '196px',
|
||||
color: theme.colors.omnivoreGray.toString(),
|
||||
}}
|
||||
>
|
||||
<option value="none">Choose file type</option>
|
||||
<option value="URL_LIST">CSV of URLs</option>
|
||||
<option value="MATTER">Matter history</option>
|
||||
</select>
|
||||
</HStack>
|
||||
|
||||
<HStack css={{ width: '100%' }}>
|
||||
<FormLabel
|
||||
css={{
|
||||
height: '38px',
|
||||
width: '88px',
|
||||
color: theme.colors.omnivoreGray.toString(),
|
||||
}}
|
||||
></FormLabel>
|
||||
<HStack css={{ py: '16px' }} distribution="start">
|
||||
<input type="file" onChange={onTypeChange} />
|
||||
{/* <Box>{file && `${file.name}`}</Box> */}
|
||||
</HStack>
|
||||
</HStack>
|
||||
|
||||
<HStack css={{ width: '100%' }} distribution="start">
|
||||
<FormLabel css={{ height: '38px', width: '88px' }}></FormLabel>
|
||||
{uploadState == 'none' && (
|
||||
<Button onClick={handleUploadClick} style="ctaDarkYellow">
|
||||
Upload
|
||||
</Button>
|
||||
)}
|
||||
{uploadState == 'uploading' && (
|
||||
<SyncLoader
|
||||
color={theme.colors.omnivoreGray.toString()}
|
||||
size={8}
|
||||
/>
|
||||
)}
|
||||
</HStack>
|
||||
</>
|
||||
)}
|
||||
<HStack css={{ width: '100%', pt: '10px' }} distribution="start">
|
||||
<FormLabel css={{ height: '38px', width: '88px' }}></FormLabel>
|
||||
{errorMessage && (
|
||||
<StyledText style="error">{errorMessage}</StyledText>
|
||||
)}
|
||||
</HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</ProfileLayout>
|
||||
)
|
||||
|
||||
10
yarn.lock
10
yarn.lock
@ -19744,11 +19744,6 @@ mocha@^9.0.1:
|
||||
yargs-parser "20.2.4"
|
||||
yargs-unparser "2.0.0"
|
||||
|
||||
modern-random-ua@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/modern-random-ua/-/modern-random-ua-1.0.3.tgz#c6fca366e60ea9a793c9d99021533744d7f58c41"
|
||||
integrity sha1-xvyjZuYOqaeTydmQIVM3RNf1jEE=
|
||||
|
||||
modify-values@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
|
||||
@ -22941,6 +22936,11 @@ react-slidedown@^2.4.5:
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-spinners@^0.13.7:
|
||||
version "0.13.7"
|
||||
resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.13.7.tgz#0f423c415bfa56765ce9fb36ff604e52a92b37a9"
|
||||
integrity sha512-mRamn56bfxWbGcacif5RT3UbeJaXi2AttjtPwSmomuv2IcxjpbfETCzdTvaQpNDk0E33ENJsStsQeKAZFuJcpA==
|
||||
|
||||
react-style-singleton@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
|
||||
|
||||
Reference in New Issue
Block a user