) => {
ev.preventDefault()
setLoading(true)
setError(undefined)
+ if (!file) {
+ return
+ }
const endpoint = `${Ctx.path}@upload/image`
const req = await Ctx.client.upload(endpoint, file)
if (req.status !== 200) {
@@ -69,7 +74,7 @@ export function IImageAttachment({ properties, values }: Props) {
}
}
- setFile(undefined)
+ setFile(null)
setLoading(false)
Ctx.flash(intl.formatMessage(genericFileMessages.image_uploaded), 'success')
Ctx.refresh()
@@ -119,7 +124,7 @@ export function IImageAttachment({ properties, values }: Props) {
field={'image'}
value={values['image']}
ns="guillotina.behaviors.behaviors.IImageAttachment"
- schema={properties['image']}
+ schema={properties['image'] as GuillotinaSchemaProperty}
modifyContent={false}
/>
diff --git a/src/guillo-gmi/components/behaviors/imultiattachment.tsx b/src/guillo-gmi/components/behaviors/imultiattachment.tsx
index e8c33be..d6d31dc 100644
--- a/src/guillo-gmi/components/behaviors/imultiattachment.tsx
+++ b/src/guillo-gmi/components/behaviors/imultiattachment.tsx
@@ -17,7 +17,9 @@ import { LightFile } from '../../types/global'
import {
GuillotinaFile,
GuillotinaSchemaProperties,
+ GuillotinaSchemaProperty,
} from '../../types/guillotina'
+import { get } from '../../lib/utils'
interface Props {
properties: GuillotinaSchemaProperties
@@ -31,14 +33,16 @@ export function IMultiAttachment({ properties, values }: Props) {
const intl = useIntl()
const [fileKey, setFileKey] = useState('')
const [file, setFile] = useState
(undefined)
- const [fileKeyToDelete, setFileKeyToDelete] = useState(undefined)
+ const [fileKeyToDelete, setFileKeyToDelete] = useState(
+ undefined
+ )
const [loading, setLoading] = useState(false)
- const [error, setError] = useState(undefined)
+ const [error, setError] = useState(undefined)
const { Ctx } = useCrudContext()
const modifyContent = Ctx.hasPerm('guillotina.ModifyContent')
- const uploadFile = async (ev) => {
+ const uploadFile = async (ev: React.MouseEvent) => {
ev.preventDefault()
if (!fileKey && !file) {
setError(intl.formatMessage(genericFileMessages.error_file_key_name))
@@ -46,6 +50,9 @@ export function IMultiAttachment({ properties, values }: Props) {
}
setLoading(true)
setError(undefined)
+ if (!file) {
+ return
+ }
const endpoint = `${Ctx.path}@upload/files/${fileKey}`
const req = await Ctx.client.upload(endpoint, file)
if (req.status !== 200) {
@@ -106,7 +113,13 @@ export function IMultiAttachment({ properties, values }: Props) {
field={`files/${key}`}
value={values['files'][key]}
ns="guillotina.behaviors.attachment.IMultiAttachment.files"
- schema={properties['files']['additionalProperties']}
+ schema={
+ get(
+ properties,
+ 'files.additionalProperties',
+ {}
+ ) as GuillotinaSchemaProperty
+ }
modifyContent={false}
/>
diff --git a/src/guillo-gmi/components/behaviors/imultiimageattachment.tsx b/src/guillo-gmi/components/behaviors/imultiimageattachment.tsx
index dff68d9..6170424 100644
--- a/src/guillo-gmi/components/behaviors/imultiimageattachment.tsx
+++ b/src/guillo-gmi/components/behaviors/imultiimageattachment.tsx
@@ -17,7 +17,10 @@ import {
import {
GuillotinaFile,
GuillotinaSchemaProperties,
+ GuillotinaSchemaProperty,
} from '../../types/guillotina'
+import { LightFile } from '../../types/global'
+import { get } from '../../lib/utils'
const _sizesImages = ['large', 'preview', 'mini', 'thumb']
@@ -33,16 +36,18 @@ export function IMultiImageAttachment({ properties, values }: Props) {
const intl = useIntl()
const cfg = useConfig()
const [fileKey, setFileKey] = useState('')
- const [file, setFile] = useState(null)
- const [fileKeyToDelete, setFileKeyToDelete] = useState(undefined)
+ const [file, setFile] = useState(undefined)
+ const [fileKeyToDelete, setFileKeyToDelete] = useState(
+ undefined
+ )
const [loading, setLoading] = useState(false)
- const [error, setError] = useState(undefined)
+ const [error, setError] = useState(undefined)
const { Ctx } = useCrudContext()
const modifyContent = Ctx.hasPerm('guillotina.ModifyContent')
const sizesImages = cfg.SizeImages || _sizesImages
- const uploadFile = async (ev) => {
+ const uploadFile = async (ev: React.MouseEvent) => {
ev.preventDefault()
if (!fileKey && !file) {
setError(intl.formatMessage(genericFileMessages.error_file_key_name))
@@ -50,6 +55,9 @@ export function IMultiImageAttachment({ properties, values }: Props) {
}
setLoading(true)
setError(undefined)
+ if (!file) {
+ return
+ }
const endpoint = `${Ctx.path}@upload/images/${fileKey}`
const req = await Ctx.client.upload(endpoint, file)
if (req.status !== 200) {
@@ -132,7 +140,13 @@ export function IMultiImageAttachment({ properties, values }: Props) {
field={`images/${key}`}
value={values['images'][key]}
ns="guillotina.contrib.image.behaviors.IMultiImageAttachment.images"
- schema={properties['images']['additionalProperties']}
+ schema={
+ get(
+ properties,
+ 'images.additionalProperties',
+ {}
+ ) as GuillotinaSchemaProperty
+ }
modifyContent={false}
required={false}
/>
diff --git a/src/guillo-gmi/components/behaviors/imultiimageorderedattachment.tsx b/src/guillo-gmi/components/behaviors/imultiimageorderedattachment.tsx
index 24ebfab..8255cab 100644
--- a/src/guillo-gmi/components/behaviors/imultiimageorderedattachment.tsx
+++ b/src/guillo-gmi/components/behaviors/imultiimageorderedattachment.tsx
@@ -9,6 +9,7 @@ import { useEffect, useState } from 'react'
import {
DragDropContext,
Draggable,
+ DropResult,
Droppable,
DroppableProvided,
DroppableStateSnapshot,
@@ -22,7 +23,10 @@ import {
import {
GuillotinaFile,
GuillotinaSchemaProperties,
+ GuillotinaSchemaProperty,
} from '../../types/guillotina'
+import { get } from '../../lib/utils'
+import { LightFile } from '../../types/global'
interface StrictModeDroppableProps {
children(
@@ -49,7 +53,7 @@ const StrictModeDroppable = ({
return {children}
}
-const reorder = (list, startIndex, endIndex) => {
+const reorder = (list: string[], startIndex: number, endIndex: number) => {
const result: string[] = Array.from(list)
const [removed] = result.splice(startIndex, 1)
result.splice(endIndex, 0, removed)
@@ -72,7 +76,9 @@ const messages = defineMessages({
interface Props {
properties: GuillotinaSchemaProperties
values: {
- images: GuillotinaFile[]
+ images: {
+ [key: string]: GuillotinaFile
+ }
}
}
export function IMultiImageOrderedAttachment({ properties, values }: Props) {
@@ -81,17 +87,19 @@ export function IMultiImageOrderedAttachment({ properties, values }: Props) {
const [sortedList, setSortedList] = useState(
Object.keys(values['images'])
)
- const [file, setFile] = useState(null)
- const [fileKeyToDelete, setFileKeyToDelete] = useState(undefined)
+ const [file, setFile] = useState(undefined)
+ const [fileKeyToDelete, setFileKeyToDelete] = useState(
+ undefined
+ )
const [loading, setLoading] = useState(false)
- const [error, setError] = useState(undefined)
+ const [error, setError] = useState(undefined)
const { Ctx } = useCrudContext()
const modifyContent = Ctx.hasPerm('guillotina.ModifyContent')
const sizesImages = cfg.SizeImages || _sizesImages
- async function onDragEnd(result) {
+ async function onDragEnd(result: DropResult) {
if (!result.destination) {
return
}
@@ -121,7 +129,7 @@ export function IMultiImageOrderedAttachment({ properties, values }: Props) {
Ctx.refresh()
}
- const uploadFile = async (ev) => {
+ const uploadFile = async (ev: React.MouseEvent) => {
ev.preventDefault()
if (!file) {
setError(intl.formatMessage(genericFileMessages.error_file_key_name))
@@ -216,7 +224,13 @@ export function IMultiImageOrderedAttachment({ properties, values }: Props) {
field={`images/${key}`}
value={values['images'][key]}
ns="guillotina.contrib.image.behaviors.IMultiImageAttachment.images"
- schema={properties['images']['additionalProperties']}
+ schema={
+ get(
+ properties,
+ 'images.additionalProperties',
+ {}
+ ) as GuillotinaSchemaProperty
+ }
modifyContent={false}
required={false}
/>
diff --git a/src/guillo-gmi/components/behaviors/iworkflow.tsx b/src/guillo-gmi/components/behaviors/iworkflow.tsx
index db1aa93..7009dc2 100644
--- a/src/guillo-gmi/components/behaviors/iworkflow.tsx
+++ b/src/guillo-gmi/components/behaviors/iworkflow.tsx
@@ -1,12 +1,12 @@
import { useTraversal } from '../../contexts'
import { Confirm } from '../modal'
import { useCrudContext } from '../../hooks/useCrudContext'
-import { ItemModel } from '../../models'
import { defineMessages, useIntl } from 'react-intl'
import { useEffect, useState } from 'react'
import { useVocabulary } from '../../hooks/useVocabulary'
import { get } from '../../lib/utils'
+import { Workflow } from '../../types/guillotina'
const messages = defineMessages({
status_changed_ok: {
id: 'status_changed_ok',
@@ -33,16 +33,16 @@ const messages = defineMessages({
export function IWorkflow() {
const intl = useIntl()
const Ctx = useTraversal()
- const { post, loading } = useCrudContext()
+ const { post, loading } = useCrudContext()
const modifyContent = Ctx.hasPerm('guillotina.ModifyContent')
- const [definition, setDefinition] = useState(undefined)
- const [workflowAction, setWorkflowAction] = useState(null)
- const model = new ItemModel(Ctx.context)
+ const [definition, setDefinition] = useState(undefined)
+ const [workflowAction, setWorkflowAction] = useState(
+ undefined
+ )
const vocabulary = useVocabulary('workflow_states')
- const currentState =
- model.item['guillotina.contrib.workflows.interfaces.IWorkflowBehavior'][
- 'review_state'
- ]
+ const currentState = Ctx.context[
+ 'guillotina.contrib.workflows.interfaces.IWorkflowBehavior'
+ ]!['review_state']
async function loadDefinition() {
const response = await Ctx.client.get(`${Ctx.path}/@workflow`)
@@ -73,11 +73,12 @@ export function IWorkflow() {
}
Ctx.refresh()
- setWorkflowAction(null)
+ setWorkflowAction(undefined)
}
+
const getStateTitle = () => {
- if (vocabulary.data?.items?.length > 0) {
- const vocabularyValue = vocabulary.data.items.find(
+ if ((vocabulary.data?.items ?? []).length > 0) {
+ const vocabularyValue = vocabulary?.data?.items.find(
(item) => item.token === currentState
)
if (vocabularyValue) {
@@ -109,7 +110,7 @@ export function IWorkflow() {
{workflowAction && (
setWorkflowAction(null)}
+ onCancel={() => setWorkflowAction(undefined)}
onConfirm={doWorkflowAction}
message={intl.formatMessage(messages.confirm_message, {
title: Ctx.context.title || Ctx.context['@name'],
diff --git a/src/guillo-gmi/components/context_toolbar.tsx b/src/guillo-gmi/components/context_toolbar.tsx
index 60d115b..bbcb43f 100644
--- a/src/guillo-gmi/components/context_toolbar.tsx
+++ b/src/guillo-gmi/components/context_toolbar.tsx
@@ -10,12 +10,13 @@ import { useLocation } from '../hooks/useLocation'
import { Select } from './input/select'
import { useIntl } from 'react-intl'
import { genericMessages } from '../locales/generic_messages'
+import { FilterFormElement } from '../types/global'
interface State {
- types?: string[]
+ types: string[]
isActive?: boolean
}
-const initialState = { types: undefined }
+const initialState = { types: [] }
export function CreateButton() {
const intl = useIntl()
@@ -24,7 +25,7 @@ export function CreateButton() {
const Config = useConfig()
useEffect(() => {
async function anyNameFunction() {
- const types = await Ctx.client.getTypes(Ctx.path)
+ const types: string[] = await Ctx.client.getTypes(Ctx.path)
setState({
types: types.filter((item) => !Config.DisabledTypes.includes(item)),
})
@@ -32,7 +33,7 @@ export function CreateButton() {
anyNameFunction()
}, [Ctx.path])
- const doAction = (item) => {
+ const doAction = (item: string) => {
Ctx.doAction('addItem', { type: item })
setState({ isActive: false })
}
@@ -77,7 +78,7 @@ export function ContextToolbar({ AddButton }: Props) {
const [location, setLocation, del] = useLocation()
const traversal = useTraversal()
const Config = useConfig()
- const searchText = location.get('q')
+ const searchText = location.get('q') || ''
const [searchValue, setSearchValue] = useState(searchText || '')
useEffect(() => {
@@ -89,19 +90,22 @@ export function ContextToolbar({ AddButton }: Props) {
}, [searchText])
async function loadTypes() {
- const types = await traversal.client.getTypes(traversal.path)
+ const types: string[] = await traversal.client.getTypes(traversal.path)
setState({
types: types.filter((item) => !Config.DisabledTypes.includes(item)),
})
}
- const onSearchQuery = (ev) => {
- const search = ev.target[0].value
- setLocation({ q: search, tab: 'Items', page: 0 })
- ev.preventDefault()
+ const onSearchQuery = (event: React.FormEvent) => {
+ event.preventDefault()
+ setLocation({
+ q: event.currentTarget.elements.filterInput.value,
+ tab: 'Items',
+ page: 0,
+ })
}
- const onSearchByType = (typeText) => {
+ const onSearchByType = (typeText: string) => {
if (typeText && typeText !== '') {
setLocation({ type: typeText, tab: 'Items', page: 0 })
} else {
@@ -122,6 +126,7 @@ export function ContextToolbar({ AddButton }: Props) {
className="input is-size-7"
placeholder={intl.formatMessage(genericMessages.search)}
data-test="inputFilterTest"
+ id="filterInput"
/>
@@ -145,7 +150,7 @@ export function ContextToolbar({ AddButton }: Props) {
text: item,
value: item,
}))}
- onChange={onSearchByType}
+ onChange={(value) => onSearchByType(value as string)}
/>
{traversal.hasPerm('guillotina.AddContent') && (
diff --git a/src/guillo-gmi/components/error_boundary.tsx b/src/guillo-gmi/components/error_boundary.tsx
index ebd71d8..a2e23ac 100644
--- a/src/guillo-gmi/components/error_boundary.tsx
+++ b/src/guillo-gmi/components/error_boundary.tsx
@@ -1,11 +1,11 @@
-import { Component } from 'react'
+import { Component, ErrorInfo } from 'react'
import { IntlShape, injectIntl } from 'react-intl'
const style = { color: '#F44336', fontSize: 20, paddingBottom: 20 }
class ErrorBoundaryComponent extends Component<
{ intl: IntlShape; children: React.ReactNode },
- { hasError: boolean; errorMsg: string; errorStack: string }
+ { hasError: boolean; errorMsg: string; errorStack: string | null | undefined }
> {
state = {
hasError: false,
@@ -13,7 +13,7 @@ class ErrorBoundaryComponent extends Component<
errorStack: '',
}
- componentDidCatch(error, errorInfo) {
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
this.setState({
hasError: true,
errorMsg: error.message,
diff --git a/src/guillo-gmi/components/fields/downloadField.tsx b/src/guillo-gmi/components/fields/downloadField.tsx
index b742956..cddd132 100644
--- a/src/guillo-gmi/components/fields/downloadField.tsx
+++ b/src/guillo-gmi/components/fields/downloadField.tsx
@@ -16,7 +16,7 @@ export const DownloadField = ({ value }: DownloadFieldProps) => {
const Ctx = useTraversal()
const { data, field } = value
- const getField = async (downloadFile) => {
+ const getField = async (downloadFile: boolean) => {
const endpoint = `${Ctx.path}@download/${field}`
const res = await Ctx.client.download(endpoint)
const text = await res.blob()
diff --git a/src/guillo-gmi/components/fields/editComponent.tsx b/src/guillo-gmi/components/fields/editComponent.tsx
index be219cd..f040268 100644
--- a/src/guillo-gmi/components/fields/editComponent.tsx
+++ b/src/guillo-gmi/components/fields/editComponent.tsx
@@ -10,13 +10,20 @@ import { SearchInputList } from '../input/search_input_list'
import { SearchInput } from '../input/search_input'
import { useTraversal } from '../../contexts'
import { Ref, forwardRef } from 'react'
-import { GuillotinaItemsProperty } from '../../types/guillotina'
-import { IndexSignature } from '../../types/global'
+import {
+ GuillotinaFile,
+ GuillotinaSchemaProperty,
+} from '../../types/guillotina'
+import {
+ EditableFieldValue,
+ IndexSignature,
+ LightFile,
+} from '../../types/global'
interface Props {
- schema: GuillotinaItemsProperty
- val: any
- setValue: (value: any) => void
+ schema: GuillotinaSchemaProperty
+ val: EditableFieldValue
+ setValue: (value: EditableFieldValue) => void
dataTest?: string
className?: string
placeholder?: string
@@ -45,7 +52,7 @@ export const EditComponent = forwardRef(
<>
{placeholder && }
setValue(ev)}
queryCondition={
@@ -55,7 +62,7 @@ export const EditComponent = forwardRef(
labelProperty={
schema?.labelProperty ? schema.labelProperty : 'title'
}
- typeNameQuery={schema?.typeNameQuery ? schema.typeNameQuery : null}
+ typeNameQuery={schema?.typeNameQuery}
/>
>
)
@@ -64,7 +71,7 @@ export const EditComponent = forwardRef(
<>
{placeholder && }
setValue(ev)}
queryCondition={
@@ -74,14 +81,14 @@ export const EditComponent = forwardRef(
labelProperty={
schema?.labelProperty ? schema.labelProperty : 'title'
}
- typeNameQuery={schema?.typeNameQuery ? schema.typeNameQuery : null}
+ typeNameQuery={schema?.typeNameQuery}
/>
>
)
} else if (schema?.widget === 'textarea' || schema?.widget === 'richtext') {
return (
- {!required && fieldHaveDeleteButton(schema) && (
+ {!required && schema && fieldHaveDeleteButton(schema) && (
diff --git a/src/guillo-gmi/components/panel/properties.tsx b/src/guillo-gmi/components/panel/properties.tsx
index ce20803..1758c2f 100644
--- a/src/guillo-gmi/components/panel/properties.tsx
+++ b/src/guillo-gmi/components/panel/properties.tsx
@@ -14,6 +14,7 @@ import {
GuillotinaSchema,
GuillotinaSchemaProperty,
} from '../../types/guillotina'
+import { get } from '../../lib/utils'
const _showProperties = ['@id', '@name', '@uid']
const _ignoreFields = [
@@ -33,9 +34,9 @@ const _ignoreFields = [
]
interface State {
- data: GuillotinaSchema
+ data?: GuillotinaSchema
loading: boolean
- error: string
+ error: string | unknown
}
export function PanelProperties() {
@@ -52,7 +53,7 @@ export function PanelProperties() {
const model = new ItemModel(Ctx.context)
- const showProperties =
+ const showProperties: string[] =
Ctx.registry.getProperties(Ctx.context['@type']).default ||
cfg.properties_default ||
_showProperties
@@ -66,7 +67,7 @@ export function PanelProperties() {
.filter((key) => !ignoreFields.includes(key))
.map((key) => ({
key,
- value: schema.data.properties[key] as GuillotinaSchemaProperty,
+ value: schema?.data?.properties[key] as GuillotinaSchemaProperty,
}))
useEffect(() => {
@@ -74,7 +75,10 @@ export function PanelProperties() {
if (!schema.loading && !schema.data && !schema.error) {
try {
setSchema({ loading: true })
- const dataJson = await Ctx.client.getTypeSchema(Ctx.path, model.type)
+ const dataJson = await Ctx.client.getTypeSchema(
+ Ctx.path,
+ Ctx.context.type_name
+ )
setSchema({ loading: false, data: dataJson })
} catch (err) {
setSchema({ loading: false, error: err })
@@ -121,7 +125,7 @@ export function PanelProperties() {
|
@@ -149,7 +153,7 @@ export function PanelProperties() {
{segments.map((item, indx) => {
const path = links[indx]
- const onClick = (e) => {
+ const onClick = (e: React.MouseEvent) => {
if (e.ctrlKey || e.metaKey) return
e.preventDefault()
navigate({ path }, true)
@@ -52,9 +52,9 @@ export function Path() {
)
}
-const buildPaths = (segments) => {
+const buildPaths = (segments: string[]) => {
let current = ''
- const results = []
+ const results: string[] = []
segments.map((item, indx) => {
if (indx === 0) {
current += '/'
diff --git a/src/guillo-gmi/components/search_options_labels.tsx b/src/guillo-gmi/components/search_options_labels.tsx
index fe84492..44906f5 100644
--- a/src/guillo-gmi/components/search_options_labels.tsx
+++ b/src/guillo-gmi/components/search_options_labels.tsx
@@ -8,12 +8,12 @@ interface Props {
}
export function SearchOptionsLabels({ query = 'q', options }: Props) {
const [location, , del] = useLocation()
- const [renderValue, setRenderValue] = useState(undefined)
- const defaultRenderValue = location.get(query)
+ const [renderValue, setRenderValue] = useState(undefined)
+ const defaultRenderValue = location.get(query) || ''
useEffect(() => {
let value = defaultRenderValue
- if ((options ?? []).length > 0) {
+ if (options && (options ?? []).length > 0) {
const option = options.find((item) => item.value === value)
if (option) {
value = option.text
diff --git a/src/guillo-gmi/components/search_vocabulary_labels.tsx b/src/guillo-gmi/components/search_vocabulary_labels.tsx
index 98a70eb..edad3ae 100644
--- a/src/guillo-gmi/components/search_vocabulary_labels.tsx
+++ b/src/guillo-gmi/components/search_vocabulary_labels.tsx
@@ -5,20 +5,20 @@ import { useVocabulary } from '../hooks/useVocabulary'
interface Props {
query?: string
- vocabularyName?: string
+ vocabularyName: string
}
export function SearchVocabularyLabels({ query = 'q', vocabularyName }: Props) {
const [location, , del] = useLocation()
- const [renderValue, setRenderValue] = useState(undefined)
+ const [renderValue, setRenderValue] = useState(undefined)
const vocabulary = useVocabulary(vocabularyName)
- const defaultRenderValue = location.get(query)
+ const defaultRenderValue = location.get(query) || ''
useEffect(() => {
let value: string = defaultRenderValue
if ((vocabulary?.data?.items ?? []).length > 0) {
- const vocabularyValue = vocabulary.data.items.find(
+ const vocabularyValue = vocabulary?.data?.items.find(
(item) => item.token === value
)
if (vocabularyValue) {
diff --git a/src/guillo-gmi/components/selected_items_actions.tsx b/src/guillo-gmi/components/selected_items_actions.tsx
index 6521092..e8d5cc6 100644
--- a/src/guillo-gmi/components/selected_items_actions.tsx
+++ b/src/guillo-gmi/components/selected_items_actions.tsx
@@ -7,7 +7,7 @@ import { getActionsObject } from '../lib/helpers'
import { SearchItem } from '../types/guillotina'
const ItemsActionsCtx = createContext<{
- selected?: {
+ selected: {
all: boolean
[key: string]: boolean
}
@@ -35,22 +35,27 @@ export function ItemsActionsProvider({
const intl = useIntl()
const actions = getActionsObject(intl, true)
const traversal = useTraversal()
- const [selected, setSelected] = useState({
+ const [selected, setSelected] = useState<{
+ all: boolean
+ [key: string]: boolean
+ }>({
all: false,
})
- function onSelectAllItems(checked) {
+ function onSelectAllItems(checked: boolean) {
setSelected(
items.reduce(
(obj, item) => {
- obj[`${item.path}/${item.id}`] = checked
- return obj
+ return {
+ ...obj,
+ [`${item.path}/${item.id}`]: checked,
+ }
},
{ all: checked }
)
)
}
- function onSelectOneItem(item) {
+ function onSelectOneItem(item: SearchItem) {
setSelected((state) => ({
...state,
all: false,
@@ -58,7 +63,7 @@ export function ItemsActionsProvider({
}))
}
- function onAction(actionKey) {
+ function onAction(actionKey: string) {
traversal.doAction(actions[actionKey].action, {
items: items.filter((item) => selected[`${item.path}/${item.id}`]),
})
@@ -78,12 +83,21 @@ export function ItemsActionsProvider({
)
}
+const useItemsActions = () => {
+ const { onAction, onSelectOneItem, onSelectAllItems, selected } = useContext(
+ ItemsActionsCtx
+ )
+ if (!onAction || !onSelectOneItem || !onSelectAllItems || !selected) {
+ throw new Error('useItemsActions must be used inside ItemsActionsProvider')
+ }
+ return { onAction, onSelectOneItem, onSelectAllItems, selected }
+}
/**
* Checkbox component without props that consume the ItemsActionsContext
* and it select/unselect all items of the page.
*/
export function AllItemsCheckbox({ dataTest }: { dataTest?: string }) {
- const { onSelectAllItems, selected } = useContext(ItemsActionsCtx)
+ const { onSelectAllItems, selected } = useItemsActions()
return (
!v)
const options = Object.keys(ACTIONS_OBJECT).map((action) => ({
text: ACTIONS_OBJECT[action].text,
diff --git a/src/guillo-gmi/components/tabs.tsx b/src/guillo-gmi/components/tabs.tsx
index a0b909d..f0b25b9 100644
--- a/src/guillo-gmi/components/tabs.tsx
+++ b/src/guillo-gmi/components/tabs.tsx
@@ -8,9 +8,9 @@ function FallbackTab({ title }: { title: string }) {
interface Props {
tabs: IndexSignature
- currentTab?: string
+ currentTab: string
rightToolbar?: React.ReactNode
- fallback?: React.ComponentType
+ fallback?: React.ComponentType<{ title: string }>
}
export function TabsPanel({
@@ -21,12 +21,7 @@ export function TabsPanel({
}: Props) {
const [location, setLocation] = useLocation()
- if (location.get('tab')) {
- currentTab = location.get('tab')
- } else {
- currentTab = currentTab || Object.keys(tabs)[0]
- }
-
+ currentTab = location.get('tab') || Object.keys(tabs)[0]
/*if (!Object.keys(tabs).includes(currentTab)) {
setLocation(defaultTab)
currentTab = defaultTab
@@ -42,7 +37,7 @@ export function TabsPanel({
}
}, [currentTab, tabs])
- const changeTab = (tab) => {
+ const changeTab = (tab: string) => {
setLocation({ tab: tab })
}
diff --git a/src/guillo-gmi/components/ui/icon.tsx b/src/guillo-gmi/components/ui/icon.tsx
index 9983582..882525c 100644
--- a/src/guillo-gmi/components/ui/icon.tsx
+++ b/src/guillo-gmi/components/ui/icon.tsx
@@ -6,7 +6,7 @@ interface Props {
align?: string
}
-export const Icon = ({ icon, className, align }: Props) => {
+export const Icon = ({ icon, className = '', align }: Props) => {
const addClass = className ? className.split(' ') : [className]
align = align || 'is-right'
diff --git a/src/guillo-gmi/components/widgets/tags.tsx b/src/guillo-gmi/components/widgets/tags.tsx
index 8cc78c3..b663333 100644
--- a/src/guillo-gmi/components/widgets/tags.tsx
+++ b/src/guillo-gmi/components/widgets/tags.tsx
@@ -3,20 +3,25 @@ import { Tag } from '../ui/tag'
import { Loading } from '../ui/loading'
import { useRef, useState } from 'react'
-const prepareAvailable = (items, already, title) => {
+const prepareAvailable = (
+ items: {
+ value: string
+ text: string
+ }[],
+ already: string[],
+ title: string
+) => {
const def = { value: '', text: `Add ${title}` }
if (items.length === 0) return []
- if (items[0] && typeof items[0] === 'string') {
- return [def]
- .concat(items.map((x) => ({ value: x, text: x })))
- .filter((item) => !already.includes(item.value))
- }
return [def].concat(items).filter((item) => !already.includes(item.value))
}
interface Props {
items: string[]
- available?: string[]
+ available?: {
+ value: string
+ text: string
+ }[]
title: string
noData: string
onChange: (items: string[]) => void
@@ -30,18 +35,18 @@ export function TagsWidget({
onChange,
loading,
}: Props) {
- const selectRef = useRef()
+ const selectRef = useRef(null)
const [result, setResult] = useState(items)
const availableData = prepareAvailable(available || [], result, title)
- const remove = (value) => {
+ const remove = (value: string) => {
const items = result.filter((item) => item !== value)
setResult(items)
onChange(items)
}
- const addItem = (value) => {
+ const addItem = (value: string) => {
if (value === '') return
const items = result.concat([value])
setResult(items)
@@ -66,13 +71,13 @@ export function TagsWidget({
{result.length === 0 && (
{noData}
)}
- {available.length > 1 && (
+ {(available ?? []).length > 1 && (
|