mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
chore: Migrate all .js files in studio to .ts (#19601)
* Change the config to only allow TS files. * Rename bunch of files from js to ts. * Add better types to some files. * Rename the big StorageExplorerStore but with no-check flag.
This commit is contained in:
1 parent
87ff576336
commit
8be7d08b6a
16 files changed
+99
-68
No files matched your search
@@ -23,7 +23,7 @@ const TemplatesList = ({
|
||||
>
|
||||
<Menu type="border">
|
||||
{templates.map((template, i) => {
|
||||
const active = selectedTemplate === template
|
||||
const active = selectedTemplate?.id === template?.id
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
|
||||
@@ -7,9 +7,9 @@ import TemplatePreview from './TemplatePreview'
|
||||
import TemplatesList from './TemplatesList'
|
||||
|
||||
interface PolicyTemplatesProps {
|
||||
templates: PolicyTemplate[]
|
||||
templatesNote: string
|
||||
onUseTemplate: (template: PolicyTemplate) => void
|
||||
templates?: PolicyTemplate[]
|
||||
templatesNote?: string
|
||||
onUseTemplate?: (template: PolicyTemplate) => void
|
||||
}
|
||||
|
||||
const PolicyTemplates = ({
|
||||
@@ -17,7 +17,7 @@ const PolicyTemplates = ({
|
||||
templatesNote = '',
|
||||
onUseTemplate = noop,
|
||||
}: PolicyTemplatesProps) => {
|
||||
const [selectedTemplate, setSelectedTemplate] = useState(templates[0])
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<PolicyTemplate>(templates[0])
|
||||
return (
|
||||
<div>
|
||||
<div className="flex justify-between border-t border-default">
|
||||
|
||||
+12
-15
@@ -25,12 +25,12 @@ const StoragePolicies = () => {
|
||||
const { data } = useBucketsQuery({ projectRef })
|
||||
const buckets = data ?? []
|
||||
|
||||
const roles = meta.roles.list((role) => !meta.roles.systemRoles.includes(role.name))
|
||||
const roles = meta.roles.list((role: any) => !meta.roles.systemRoles.includes(role.name))
|
||||
|
||||
const [policies, setPolicies] = useState([])
|
||||
const [policies, setPolicies] = useState<any[]>([])
|
||||
const [selectedPolicyToEdit, setSelectedPolicyToEdit] = useState({})
|
||||
const [selectedPolicyToDelete, setSelectedPolicyToDelete] = useState({})
|
||||
const [isEditingPolicyForBucket, setIsEditingPolicyForBucket] = useState({})
|
||||
const [selectedPolicyToDelete, setSelectedPolicyToDelete] = useState<any>({})
|
||||
const [isEditingPolicyForBucket, setIsEditingPolicyForBucket] = useState<any>({})
|
||||
|
||||
// Only use storage policy editor when creating new policies for buckets
|
||||
const showStoragePolicyEditor =
|
||||
@@ -60,9 +60,7 @@ const StoragePolicies = () => {
|
||||
if (meta) {
|
||||
await meta.policies.load()
|
||||
const storagePolicies =
|
||||
meta?.policies.list((policy) => policy.schema === 'storage', {
|
||||
allSchemas: true,
|
||||
}) ?? []
|
||||
meta?.policies.list((policy: any) => policy.schema === 'storage') ?? []
|
||||
setPolicies(storagePolicies)
|
||||
}
|
||||
}
|
||||
@@ -72,7 +70,7 @@ const StoragePolicies = () => {
|
||||
setIsEditingPolicyForBucket({ bucket: bucketName, table })
|
||||
}
|
||||
|
||||
const onSelectPolicyEdit = (policy, bucketName = '', table = '') => {
|
||||
const onSelectPolicyEdit = (policy: any, bucketName = '', table = '') => {
|
||||
setIsEditingPolicyForBucket({ bucket: bucketName, table })
|
||||
setSelectedPolicyToEdit(policy)
|
||||
}
|
||||
@@ -81,7 +79,7 @@ const StoragePolicies = () => {
|
||||
setIsEditingPolicyForBucket({})
|
||||
}
|
||||
|
||||
const onSelectPolicyDelete = (policy) => setSelectedPolicyToDelete(policy)
|
||||
const onSelectPolicyDelete = (policy: any) => setSelectedPolicyToDelete(policy)
|
||||
const onCancelPolicyDelete = () => setSelectedPolicyToDelete({})
|
||||
|
||||
const onSavePolicySuccess = async () => {
|
||||
@@ -94,7 +92,7 @@ const StoragePolicies = () => {
|
||||
Functions that involve the CRUD for policies
|
||||
For each API call within the Promise.all, return true if an error occurred, else return false
|
||||
*/
|
||||
const onCreatePolicies = async (payloads) => {
|
||||
const onCreatePolicies = async (payloads: any[]) => {
|
||||
return await Promise.all(
|
||||
payloads.map(async (payload) => {
|
||||
const res = await meta.policies.create(payload)
|
||||
@@ -110,7 +108,7 @@ const StoragePolicies = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const onCreatePolicy = async (payload) => {
|
||||
const onCreatePolicy = async (payload: any) => {
|
||||
const res = await meta.policies.create(payload)
|
||||
if (res.error) {
|
||||
ui.setNotification({
|
||||
@@ -122,7 +120,7 @@ const StoragePolicies = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
const onUpdatePolicy = async (payload) => {
|
||||
const onUpdatePolicy = async (payload: any) => {
|
||||
const res = await meta.policies.update(payload.id, payload)
|
||||
if (res.error) {
|
||||
ui.setNotification({
|
||||
@@ -135,8 +133,8 @@ const StoragePolicies = () => {
|
||||
}
|
||||
|
||||
const onDeletePolicy = async () => {
|
||||
const res = await meta.policies.del(selectedPolicyToDelete.id)
|
||||
if (res.error) {
|
||||
const res: any = await meta.policies.del(selectedPolicyToDelete.id)
|
||||
if (res) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to delete policy: ${res.error.message}`,
|
||||
@@ -229,7 +227,6 @@ const StoragePolicies = () => {
|
||||
schema="storage"
|
||||
roles={roles}
|
||||
table={isEditingPolicyForBucket.table}
|
||||
target={isEditingPolicyForBucket.bucket}
|
||||
selectedPolicyToEdit={selectedPolicyToEdit}
|
||||
onSelectCancel={onCancelPolicyEdit}
|
||||
onCreatePolicy={onCreatePolicy}
|
||||
+13
-10
@@ -14,13 +14,21 @@ import {
|
||||
IconTrash,
|
||||
} from 'ui'
|
||||
|
||||
interface PolicyRowProps {
|
||||
policy: any
|
||||
table: any
|
||||
bucketName: string
|
||||
onSelectPolicyEdit: (p: any, s: string, t: any) => void
|
||||
onSelectPolicyDelete: (s: string) => void
|
||||
}
|
||||
|
||||
const PolicyRow = ({
|
||||
policy,
|
||||
table,
|
||||
bucketName,
|
||||
onSelectPolicyEdit = () => {},
|
||||
onSelectPolicyDelete = () => {},
|
||||
}) => {
|
||||
}: PolicyRowProps) => {
|
||||
const { name, command } = policy
|
||||
return (
|
||||
<div className="group">
|
||||
@@ -39,21 +47,16 @@ const PolicyRow = ({
|
||||
icon={<IconMoreVertical />}
|
||||
/>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="bottom" align="end" size="small">
|
||||
<DropdownMenuContent side="bottom" align="end">
|
||||
<DropdownMenuItem
|
||||
className="space-x-2"
|
||||
type="outline"
|
||||
onClick={() => onSelectPolicyEdit(policy, bucketName, table)}
|
||||
>
|
||||
<IconEdit size={14} />
|
||||
<p>Edit</p>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
type="outline"
|
||||
className="space-x-2"
|
||||
onClick={() => onSelectPolicyDelete(policy)}
|
||||
>
|
||||
<DropdownMenuItem className="space-x-2" onClick={() => onSelectPolicyDelete(policy)}>
|
||||
<IconTrash size={14} />
|
||||
<p>Delete</p>
|
||||
</DropdownMenuItem>
|
||||
@@ -72,7 +75,7 @@ const StoragePoliciesBucketRow = ({
|
||||
onSelectPolicyAdd = () => {},
|
||||
onSelectPolicyEdit = () => {},
|
||||
onSelectPolicyDelete = () => {},
|
||||
}) => {
|
||||
}: any) => {
|
||||
const getFooterLabel = () => {
|
||||
if (isEmpty(bucket))
|
||||
return table === 'objects'
|
||||
@@ -106,7 +109,7 @@ const StoragePoliciesBucketRow = ({
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 divide-y [[data-theme*=dark]_&]:divide-dark">
|
||||
{policies.map((policy) => (
|
||||
{policies.map((policy: any) => (
|
||||
<PolicyRow
|
||||
key={policy.name}
|
||||
policy={policy}
|
||||
+14
-14
@@ -11,14 +11,14 @@ import {
|
||||
import { STORAGE_POLICY_TEMPLATES } from './StoragePolicies.constants'
|
||||
|
||||
import {
|
||||
POLICY_MODAL_VIEWS,
|
||||
PolicySelection,
|
||||
PolicyTemplates,
|
||||
POLICY_MODAL_VIEWS,
|
||||
} from 'components/interfaces/Auth/Policies'
|
||||
import StoragePoliciesEditor from './StoragePoliciesEditor'
|
||||
import StoragePoliciesReview from './StoragePoliciesReview'
|
||||
|
||||
const newPolicyTemplate = {
|
||||
const newPolicyTemplate: any = {
|
||||
name: '',
|
||||
roles: [],
|
||||
policyIds: [],
|
||||
@@ -33,13 +33,13 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
onSelectCancel = () => {},
|
||||
onCreatePolicies = () => {},
|
||||
onSaveSuccess = () => {},
|
||||
}) => {
|
||||
}: any) => {
|
||||
const { ui } = useStore()
|
||||
const [previousView, setPreviousView] = useState('') // Mainly to decide which view to show when back from templates
|
||||
const [view, setView] = useState('')
|
||||
|
||||
const [policyFormFields, setPolicyFormFields] = useState(newPolicyTemplate)
|
||||
const [policyStatementsForReview, setPolicyStatementsForReview] = useState([])
|
||||
const [policyStatementsForReview, setPolicyStatementsForReview] = useState<any[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
@@ -50,7 +50,7 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
|
||||
/* Methods to determine which step to show */
|
||||
const onViewIntro = () => setView(POLICY_MODAL_VIEWS.SELECTION)
|
||||
const onViewEditor = (state) => {
|
||||
const onViewEditor = (state?: any) => {
|
||||
if (state === 'new') {
|
||||
setPolicyFormFields({
|
||||
...policyFormFields,
|
||||
@@ -67,7 +67,7 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
|
||||
/* Methods for policy templates */
|
||||
const onSelectBackFromTemplates = () => setView(previousView)
|
||||
const onUseTemplate = (template) => {
|
||||
const onUseTemplate = (template: any) => {
|
||||
// Each template has an id as a unique identifier to refresh the SQL editor
|
||||
// but we don't need this property to be in the policyFormField
|
||||
const { id, ...templateFields } = template
|
||||
@@ -81,7 +81,7 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
}
|
||||
|
||||
/* Methods for policy editor form fields */
|
||||
const onUpdatePolicyName = (name) => {
|
||||
const onUpdatePolicyName = (name: string) => {
|
||||
if (name.length <= 50) {
|
||||
setPolicyFormFields({
|
||||
...policyFormFields,
|
||||
@@ -90,14 +90,14 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
}
|
||||
}
|
||||
|
||||
const onUpdatePolicyDefinition = (definition) => {
|
||||
const onUpdatePolicyDefinition = (definition: any) => {
|
||||
setPolicyFormFields({
|
||||
...policyFormFields,
|
||||
definition,
|
||||
})
|
||||
}
|
||||
|
||||
const onToggleOperation = (operation, isSingleOperation = false) => {
|
||||
const onToggleOperation = (operation: any, isSingleOperation = false) => {
|
||||
if (isSingleOperation) {
|
||||
return setPolicyFormFields({
|
||||
...policyFormFields,
|
||||
@@ -113,7 +113,7 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
})
|
||||
}
|
||||
|
||||
const onUpdatePolicyRoles = (roles) => {
|
||||
const onUpdatePolicyRoles = (roles: any) => {
|
||||
setPolicyFormFields({
|
||||
...policyFormFields,
|
||||
roles,
|
||||
@@ -150,7 +150,7 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
onSavePolicy(payloads)
|
||||
}
|
||||
|
||||
const onSavePolicy = async (payloads) => {
|
||||
const onSavePolicy = async (payloads: any) => {
|
||||
const errors = await onCreatePolicies(payloads)
|
||||
const hasErrors = errors.indexOf(true) !== -1
|
||||
if (hasErrors) {
|
||||
@@ -166,7 +166,7 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
view,
|
||||
bucketName,
|
||||
onSelectBackFromTemplates = () => {},
|
||||
}) => {
|
||||
}: any) => {
|
||||
const getTitle = () => {
|
||||
if (view === POLICY_MODAL_VIEWS.EDITOR || view === POLICY_MODAL_VIEWS.SELECTION) {
|
||||
return `Adding new policy to ${bucketName}`
|
||||
@@ -234,9 +234,9 @@ const StoragePoliciesEditPolicyModal = ({
|
||||
/>
|
||||
) : view === POLICY_MODAL_VIEWS.TEMPLATES ? (
|
||||
<PolicyTemplates
|
||||
templates={STORAGE_POLICY_TEMPLATES}
|
||||
onSelectBackFromTemplates={onSelectBackFromTemplates}
|
||||
templates={STORAGE_POLICY_TEMPLATES as any[]}
|
||||
onUseTemplate={onUseTemplate}
|
||||
templatesNote={''}
|
||||
/>
|
||||
) : view === POLICY_MODAL_VIEWS.REVIEW ? (
|
||||
<StoragePoliciesReview
|
||||
+2
-2
@@ -23,7 +23,7 @@ const PolicyDefinition = ({ definition = '', onUpdatePolicyDefinition = () => {}
|
||||
)
|
||||
}
|
||||
|
||||
const PolicyAllowedOperations = ({ allowedOperations = [], onToggleOperation = () => {} }) => {
|
||||
const PolicyAllowedOperations = ({ allowedOperations = [], onToggleOperation = () => {} }: any) => {
|
||||
const allowedClientLibraryMethods = deriveAllowedClientLibraryMethods(allowedOperations)
|
||||
return (
|
||||
<div className="flex justify-between space-x-12">
|
||||
@@ -114,7 +114,7 @@ const StoragePoliciesEditor = ({
|
||||
onToggleOperation = () => {},
|
||||
onUpdatePolicyRoles = () => {},
|
||||
onReviewPolicy = () => {},
|
||||
}) => {
|
||||
}: any) => {
|
||||
const definition = policyFormFields.definition
|
||||
const selectedRoles = policyFormFields.roles
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { IconArchive } from 'ui'
|
||||
|
||||
const StoragePoliciesPlaceholder = ({ guiHeight }) => (
|
||||
const StoragePoliciesPlaceholder = () => (
|
||||
<Panel
|
||||
title={[
|
||||
<div key="storagePlaceholder" className="flex w-full items-center justify-between">
|
||||
+7
-1
@@ -10,11 +10,17 @@ const ReviewEmptyState = () => {
|
||||
)
|
||||
}
|
||||
|
||||
interface StoragePoliciesReviewProps {
|
||||
policyStatements: any[]
|
||||
onSelectBack: any
|
||||
onSelectSave: any
|
||||
}
|
||||
|
||||
const StoragePoliciesReview = ({
|
||||
policyStatements = [],
|
||||
onSelectBack = () => {},
|
||||
onSelectSave = () => {},
|
||||
}) => {
|
||||
}: StoragePoliciesReviewProps) => {
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
const onSavePolicy = () => {
|
||||
setIsSaving(true)
|
||||
@@ -4,4 +4,4 @@ import StorageSettings from './StorageSettings/StorageSettings'
|
||||
|
||||
import DeleteBucketModal from './DeleteBucketModal'
|
||||
|
||||
export { StorageExplorer, StoragePolicies, StorageSettings, DeleteBucketModal }
|
||||
export { DeleteBucketModal, StorageExplorer, StoragePolicies, StorageSettings }
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
import { TextAreaProps } from '@ui/components/Input/Input'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Input } from 'ui'
|
||||
import React, { useState, useEffect, useRef } from 'react'
|
||||
|
||||
const AutoTextArea = (props) => {
|
||||
const AutoTextArea = (props: TextAreaProps) => {
|
||||
const textAreaRef = useRef(null)
|
||||
const [text, setText] = useState('')
|
||||
const [textAreaHeight, setTextAreaHeight] = useState('auto')
|
||||
+16
-5
@@ -1,7 +1,18 @@
|
||||
import { AutoForm } from 'uniforms-bootstrap4'
|
||||
import Ajv from 'ajv'
|
||||
import { PropsWithChildren } from 'react'
|
||||
import { AutoForm } from 'uniforms-bootstrap4'
|
||||
import { JSONSchemaBridge } from 'uniforms-bridge-json-schema'
|
||||
|
||||
interface SchemaFormProps
|
||||
extends PropsWithChildren<{
|
||||
schema: any
|
||||
model: any
|
||||
disabled: boolean
|
||||
formRef: any
|
||||
onSubmit: any
|
||||
onChangeModel: any
|
||||
}> {}
|
||||
|
||||
const SchemaForm = ({
|
||||
schema,
|
||||
model,
|
||||
@@ -10,7 +21,7 @@ const SchemaForm = ({
|
||||
formRef,
|
||||
onSubmit,
|
||||
onChangeModel = () => {},
|
||||
}) => {
|
||||
}: SchemaFormProps) => {
|
||||
const validatedSchema = new JSONSchemaBridge(schema, createValidator(schema))
|
||||
return (
|
||||
<AutoForm
|
||||
@@ -31,9 +42,9 @@ export default SchemaForm
|
||||
let ajv = new Ajv({ strict: false, allErrors: true, useDefaults: true })
|
||||
ajv = ajv.addFormat('absolute-url', '^(http://|https://)')
|
||||
|
||||
const createValidator = (schema) => {
|
||||
const createValidator = (schema: any) => {
|
||||
const validator = ajv.compile(schema)
|
||||
return (model) => {
|
||||
return (model: any) => {
|
||||
let cleansedModel = { ...model }
|
||||
Object.entries(cleansedModel).map(([k, v]) => {
|
||||
const isRequired = schema.required.indexOf(k) != -1
|
||||
@@ -52,7 +63,7 @@ const createValidator = (schema) => {
|
||||
* JSON Schema doesn't support validation for empty strings.
|
||||
* We want to convert all empty strings to NULL to ensure they get validated
|
||||
*/
|
||||
const nullifyStringIfEmpty = (data) => {
|
||||
const nullifyStringIfEmpty = (data: any) => {
|
||||
if (data.trim() === '') return null
|
||||
else return data
|
||||
}
|
||||
+7
-7
@@ -7,7 +7,7 @@ export default function SchemaFormPanel({
|
||||
title,
|
||||
model,
|
||||
children,
|
||||
onChangeModel = (model) => {},
|
||||
onChangeModel = () => {},
|
||||
onReset = () => {},
|
||||
onSubmit,
|
||||
loading,
|
||||
@@ -16,8 +16,8 @@ export default function SchemaFormPanel({
|
||||
message = '',
|
||||
disabled = false,
|
||||
disabledMessage = '',
|
||||
}) {
|
||||
let formRef
|
||||
}: any) {
|
||||
let formRef: any
|
||||
const [submitButtonLoading, setSubmitButtonLoading] = useState(false)
|
||||
const [hasChanged, setHasChanged] = useState(false)
|
||||
const isLoading = loading !== undefined ? loading : submitButtonLoading
|
||||
@@ -35,7 +35,7 @@ export default function SchemaFormPanel({
|
||||
.then(() => {
|
||||
setSubmitButtonLoading(true)
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
console.error('Error on submitting', error)
|
||||
})
|
||||
}
|
||||
@@ -81,14 +81,14 @@ export default function SchemaFormPanel({
|
||||
<div className="Form section-block--body px-6 py-3">
|
||||
<SchemaForm
|
||||
disabled={disabled}
|
||||
onChangeModel={(model) => {
|
||||
onChangeModel={(model: any) => {
|
||||
setHasChanged(true)
|
||||
if (onChangeModel) onChangeModel(model)
|
||||
}}
|
||||
formRef={(ref) => (formRef = ref)}
|
||||
formRef={(ref: any) => (formRef = ref)}
|
||||
schema={schema}
|
||||
model={model}
|
||||
onSubmit={async (args) => {
|
||||
onSubmit={async (args: any) => {
|
||||
onSubmit(args)
|
||||
.then(() => {
|
||||
setSubmitButtonLoading(false)
|
||||
+14
-3
@@ -3,6 +3,18 @@ import { Button, Form, Modal } from 'ui'
|
||||
|
||||
// [Joshen] As of 280222, let's just use ConfirmationModal as the one and only confirmation modal (Deprecate this)
|
||||
|
||||
interface ConfirmModalProps {
|
||||
visible: boolean
|
||||
danger?: boolean
|
||||
title: string
|
||||
description: string
|
||||
size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge'
|
||||
buttonLabel: string
|
||||
buttonLoadingLabel?: string
|
||||
onSelectCancel: () => void
|
||||
onSelectConfirm: () => void
|
||||
}
|
||||
|
||||
const ConfirmModal = ({
|
||||
visible = false,
|
||||
danger = false,
|
||||
@@ -13,7 +25,7 @@ const ConfirmModal = ({
|
||||
buttonLoadingLabel = '',
|
||||
onSelectCancel = () => {},
|
||||
onSelectConfirm = () => {},
|
||||
}) => {
|
||||
}: ConfirmModalProps) => {
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setLoading(false)
|
||||
@@ -42,8 +54,7 @@ const ConfirmModal = ({
|
||||
validateOnBlur
|
||||
onSubmit={() => onConfirm()}
|
||||
validate={() => {
|
||||
let errors = []
|
||||
return errors
|
||||
return []
|
||||
}}
|
||||
>
|
||||
{() => {
|
||||
@@ -8,7 +8,7 @@ interface PanelProps {
|
||||
hideHeaderStyling?: boolean
|
||||
loading?: boolean
|
||||
noMargin?: boolean
|
||||
title?: JSX.Element | false
|
||||
title?: ReactNode | false
|
||||
wrapWithLoading?: boolean
|
||||
noHideOverflow?: boolean
|
||||
}
|
||||
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { BlobReader, BlobWriter, ZipWriter } from '@zip.js/zip.js'
|
||||
import { chunk, compact, find, findIndex, has, isEqual, some, uniq, uniqBy } from 'lodash'
|
||||
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
Reference in new issue
Block a user