We are using a clone of the Polkadot-JS/apps. Our users will need to have several contracts loaded to the UI in order to use the apps. We want our users to be able to add an existing contract to their UI without having to locate the file, drag and drop, etc. In a perfect world, we would love to have one button that auto-uploads the contract to the UI... but until we can figure that out...
Is there a way to pre-populate the metadata.json file in the modal used to add an existing contract? We have a button that says "load the app" which brings up a modal from Add.tsx to process the contract and add it to the UI.
We have narrowed it down to the InputFile.tsx file that governs the Dropzone in that modal. We plant to have the metadata.json local to the UI files. Is there a way to set the default file in the Dropzone? Here is the current file code...
// Copyright 2017-2023 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React, { createRef, useCallback, useState } from 'react';
import Dropzone, { DropzoneRef } from 'react-dropzone';
import styled from 'styled-components';
import { formatNumber, hexToU8a, isHex, u8aToString } from '@polkadot/util';
import Labelled from './Labelled';
import { useTranslation } from './translate';
export interface InputFilePropsBase {
className?: string;
clearContent?: boolean;
isDisabled?: boolean;
isError?: boolean;
isFull?: boolean;
label: React.ReactNode;
labelExtra?: React.ReactNode;
placeholder?: React.ReactNode | null | false;
withEllipsis?: boolean;
withLabel?: boolean;
}
export interface InputFileProps extends InputFilePropsBase {
// Reference Example Usage: https://github.com/react-dropzone/react-dropzone/tree/master/examples/Accept
// i.e. MIME types: 'application/json, text/plain', or '.json, .txt'
accept?: string;
onChange?: (contents: Uint8Array, name: string) => void;
}
interface FileState {
name: string;
size: number;
}
const BYTE_STR_0 = '0'.charCodeAt(0);
const BYTE_STR_X = 'x'.charCodeAt(0);
const STR_NL = '\n';
const NOOP = (): void => undefined;
function convertResult (result: ArrayBuffer): Uint8Array {
const data = new Uint8Array(result);
// this converts the input (if detected as hex), via the hex conversion route
if (data[0] === BYTE_STR_0 && data[1] === BYTE_STR_X) {
let hex = u8aToString(data);
while (hex[hex.length - 1] === STR_NL) {
hex = hex.substring(0, hex.length - 1);
}
if (isHex(hex)) {
return hexToU8a(hex);
}
}
return data;
}
function InputFile ({ accept, className = '', clearContent, isDisabled, isError = false, isFull, label, labelExtra, onChange, placeholder, withEllipsis, withLabel }: InputFileProps): React.ReactElement<InputFileProps> {
const { t } = useTranslation();
const dropRef = createRef<DropzoneRef>();
const [file, setFile] = useState<FileState | undefined>();
const _onDrop = useCallback(
(files: File[]): void => {
files.forEach((file): void => {
const reader = new FileReader();
reader.onabort = NOOP;
reader.onerror = NOOP;
reader.onload = ({ target }: ProgressEvent<FileReader>): void => {
if (target && target.result) {
const name = file.name;
const data = convertResult(target.result as ArrayBuffer);
onChange && onChange(data, name);
dropRef && setFile({
name,
size: data.length
});
}
};
reader.readAsArrayBuffer(file);
});
},
[dropRef, onChange]
);
const dropZone = (
<Dropzone
accept={accept}
disabled={isDisabled}
multiple={false}
onDrop={_onDrop}
ref={dropRef}
>
{({ getInputProps, getRootProps }): JSX.Element => (
<StyledDiv {...getRootProps({ className: `${className} ui--InputFile ${isError ? 'error' : ''}` })}>
<input {...getInputProps()} />
<em className='label'>
{
!file || clearContent
? placeholder || t<string>('click to select or drag and drop the file here')
: placeholder || t<string>('{{name}} ({{size}} bytes)', {
replace: {
name: file.name,
size: formatNumber(file.size)
}
})
}
</em>
</StyledDiv>
)}
</Dropzone>
);
return label
? (
<Labelled
isFull={isFull}
label={label}
labelExtra={labelExtra}
withEllipsis={withEllipsis}
withLabel={withLabel}
>
{dropZone}
</Labelled>
)
: dropZone;
}
const StyledDiv = styled.div`
background: var(--bg-input);
border: 1px solid var(--border-input);
border-radius: 0.28571429rem;
font-size: var(--font-size-base);
margin: 0.25rem 0;
padding: 0.67857143em 1em;
width: 100% !important;
&.error {
background: var(--bg-input-error);
border-color: #e0b4b4;
}
&:hover {
cursor: pointer;
}
`;
export default React.memo(InputFile);