Skip to content

Commit

Permalink
feat: implements dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
aviemet committed Apr 2, 2024
1 parent 0e4b153 commit c3f1e31
Show file tree
Hide file tree
Showing 47 changed files with 469 additions and 100 deletions.
39 changes: 39 additions & 0 deletions app/controllers/api/controls_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class Api::ControlsController < ApplicationController
expose :control
expose :controls, -> { Control.all }

# @route GET /api/options/controls (api_controls_options)
def options
authorize controls
render json: controls.render(view: :options), status: :ok
end

def execute
authorize control

control.create_activity key: :slug, owner: current_user

SendOscCommandsJob.perform_later(control)

render json: control, status: :accepted
end

# @route POST /api/controls (api_controls)
def create
if control.save
render json: control.render, status: :created
else
render json: { errors: control.errors }, status: :not_acceptable
end
end

# @route PATCH /api/controls/:slug (api_control)
# @route PUT /api/controls/:slug (api_control)
def update
if control.save
render json: control.render, status: :created
else
render json: { errors: control.errors }, status: :not_acceptable
end
end
end
28 changes: 28 additions & 0 deletions app/controllers/api/protocols_controller.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
class Api::ProtocolsController < ApplicationController
expose :protocol
expose :protocols, -> { Protocol.all }

# @route GET /api/options/protocols (api_protocols_options)
def options
authorize protocols
render json: protocols.render(view: :options), status: :ok
end

# @route PUT /api/protocol/:id/execute (api_execute_protocol)
def execute
authorize protocol

protocol.create_activity key: :slug, owner: current_user

SendOscCommandsJob.perform_later(protocol)

render json: protocol, status: :accepted
end

# @route POST /api/protocols (api_protocols)
def create
if protocol.save
render json: protocol.render, status: :created
else
render json: { errors: protocol.errors }, status: :not_acceptable
end
end

# @route PATCH /api/protocols/:slug (api_protocol)
# @route PUT /api/protocols/:slug (api_protocol)
def update
if protocol.save
render json: protocol.render, status: :created
else
render json: { errors: protocol.errors }, status: :not_acceptable
end
end
end
1 change: 1 addition & 0 deletions app/controllers/api/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def update
end
end

# @route PATCH /api/users/:id/update_table_preferences (api_update_table_preferences)
def update_table_preferences
authorize user
if user.update(
Expand Down
1 change: 0 additions & 1 deletion app/controllers/commands_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def index
}
end

# @route GET /commands/:id (command)
# def show
# authorize command
# render inertia: "Commands/Show", props: {
Expand Down
1 change: 0 additions & 1 deletion app/controllers/protocols_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def index
}
end

# @route GET /protocols/:id (protocol)
# def show
# authorize protocol
# render inertia: "Protocols/Show", props: {
Expand Down
22 changes: 0 additions & 22 deletions app/frontend/Components/Control/EditButton.tsx

This file was deleted.

30 changes: 25 additions & 5 deletions app/frontend/Components/Dropdowns/ProtocolDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
import React from 'react'
import React, { forwardRef } from 'react'
import { Select } from '@/Components/Form'
import { type IAsyncDropdown } from '.'
import { protocolsOptionsQuery } from '@/queries'

interface ProtocolDropdownProps extends Omit<IAsyncDropdown<Schema.ProtocolsOptions>, 'onSelect'> {
onSelect?: (data: Schema.ProtocolsOptions) => void
}

const ProtocolDropdown = forwardRef<HTMLInputElement, ProtocolDropdownProps>((
{ label = 'Protocol', name = 'protocol_id', initialData = [], value, onSelect, ...props },
ref,
) => {
const { data } = protocolsOptionsQuery()

const ProocolDropdown = () => {
return (
<div>ProocolDropdown</div>
<Select
label={ label }
name={ name }
options={ !data ? [] : data.map(protocol => ({
label: protocol.title,
value: protocol.slug,
})) }
{ ...props }
/>
)
}
})

export default ProocolDropdown
export default ProtocolDropdown
25 changes: 7 additions & 18 deletions app/frontend/Components/Dropdowns/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
import { type ISelectProps } from '../Inputs/Select'
import { type IMultiSelectProps } from '../Inputs/MultiSelect'
import { type ISelectFormProps } from '../Form/Inputs/Select'
import { type IFormDropdownProps } from '../Form/Inputs/MultiSelect'

// export { default as AssetsDropdown } from './AssetsDropdown'
// export { default as CategoriesDropdown } from './CategoriesDropdown'
// export { default as CurrenciesDropdown } from './CurrenciesDropdown'
// export { default as DepartmentsDropdown } from './DepartmentsDropdown'
// export { default as ItemsDropdown } from './ItemsDropdown'
// export { default as LocationsDropdown } from './LocationsDropdown'
// export { default as ManufacturersDropdown } from './ManufacturersDropdown'
// export { default as ModelsDropdown } from './ModelsDropdown'
// export { default as PeopleDropdown } from './PeopleDropdown'
// export { default as PeopleMultiSelect } from './PeopleMultiSelect'
// export { default as StatusLabelsDropdown } from './StatusLabelsDropdown'
// export { default as VendorsDropdown } from './VendorsDropdown'

export interface IAsyncDropdown<T> extends Omit<ISelectProps, 'defaultValue'|'onBlur'> {
name?: string
export interface IAsyncDropdown<T> extends Omit<ISelectFormProps, 'defaultValue'|'onBlur'> {
model?: string
label?: string
fetchOnOpen?: string
Expand All @@ -24,7 +10,10 @@ export interface IAsyncDropdown<T> extends Omit<ISelectProps, 'defaultValue'|'on
initialData?: T[]
}

export interface IAsyncMultiSelect<T> extends Omit<IMultiSelectProps, 'onBlur'> {
export interface IAsyncMultiSelect<T> extends Omit<IFormDropdownProps, 'onBlur'> {
errorKey?: string
initialData?: T[]
}

export { default as ProtocolDropdown } from './ProtocolDropdown'

9 changes: 9 additions & 0 deletions app/frontend/Components/Form/Form.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { vars, theme } from '@/lib/theme'
import { rem } from '@mantine/core'
import { css } from '@linaria/core'

export const form = css`
.field {
margin-bottom: ${vars.spacing.md}
}
`
9 changes: 6 additions & 3 deletions app/frontend/Components/Form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@ import React from 'react'
import { Box } from '@mantine/core'
import cx from 'clsx'
import { Form as InertiaForm, type FormProps, type NestedObject } from 'use-inertia-form'
import * as classes from './Form.css'


interface IFormProps<TForm> extends FormProps<TForm> {
grid?: boolean
}

export interface ExtendableFormProps<TForm> extends Omit<IFormProps<TForm>, 'data'> {}

const Form = <TForm extends NestedObject>(
{ children, data, grid = true, className, railsAttributes = true, ...props }: IFormProps<TForm>,
) => {

return (
<Box>
<Box className={ cx('form') }>
<InertiaForm
data={ data }
className={ cx({ 'format-grid': grid }, className) }
className={ cx({ 'format-grid': grid }, classes.form, className) }
railsAttributes={ railsAttributes }
{ ...props }
>
Expand Down
36 changes: 23 additions & 13 deletions app/frontend/Components/Form/Inputs/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import React from 'react'
import Field from '../Field'
import SelectInput, { type ISelectProps } from '@/Components/Inputs/Select'
import SelectInput, { type SelectProps } from '@/Components/Inputs/Select'
import { ConditionalWrapper, Group } from '@/Components'
import { ModalFormButton } from '@/Components/Button'
import { useInertiaInput, type UseFormProps, NestedObject } from 'use-inertia-form'
import { ComboboxData } from '@mantine/core'

type OmittedDropdownTypes = 'name'|'defaultValue'|'onBlur'|'onChange'|'onDropdownOpen'|'onDropdownClose'
type OmittedDropdownTypes = 'name'|'defaultValue'|'onBlur'|'onChange'|'onDropdownOpen'|'onDropdownClose'|'onSelect'
export interface ISelectFormProps<TForm extends NestedObject = NestedObject>
extends
Omit<ISelectProps, OmittedDropdownTypes>,
Omit<SelectProps, OmittedDropdownTypes>,
IInertiaInputProps {
defaultValue?: string
onChange?: ((value: string|null, form: UseFormProps<TForm>) => void) | undefined
onDropdownOpen?: (form: UseFormProps<any>) => void
onDropdownClose?: (form: UseFormProps<any>) => void
onChange?: (option: ComboboxData|null, form: UseFormProps<TForm>) => void
onClear?: (form: UseFormProps<TForm>) => void
onDropdownOpen?: (form: UseFormProps<TForm>) => void
onDropdownClose?: (form: UseFormProps<TForm>) => void
onSelect?: (form: UseFormProps<TForm>) => void
onOptionSubmit?: (option: ComboboxData|null, form: UseFormProps<TForm>) => void
onSearchChange?: (value: string, form: UseFormProps<TForm>) => void
endpoint?: string
newForm?: React.ReactElement
field?: boolean
Expand All @@ -31,6 +36,7 @@ const Select = <TForm extends NestedObject = NestedObject>(
onBlur,
onDropdownOpen,
onDropdownClose,
onSelect,
fetchOnOpen,
endpoint,
newForm,
Expand All @@ -50,23 +56,28 @@ const Select = <TForm extends NestedObject = NestedObject>(
}

const handleBlur = () => {
if(onBlur) onBlur(String(value), form)
onBlur?.(String(value), form)
}

const handleDropdownOpen = () => {
if(onDropdownOpen) onDropdownOpen(form)
onDropdownOpen?.(form)
}

const handleDropdownClose = () => {
if(onDropdownClose) onDropdownClose(form)
onDropdownClose?.(form)
}

const handleNewFormSuccess = (data: { id: string|number }) => {
setValue(String(data.id))
}

const handleSelect = () => {
onSelect?.(form)
}

return (
<ConditionalWrapper
condition={ newForm !== undefined }
wrapper={ children => (
<Group
grow
Expand All @@ -76,12 +87,11 @@ const Select = <TForm extends NestedObject = NestedObject>(
>
{ children }
</Group>
)
}
condition={ newForm !== undefined }
) }
>
<>
<ConditionalWrapper
condition={ field }
wrapper={ children => (
<Field
type="select"
Expand All @@ -91,7 +101,6 @@ const Select = <TForm extends NestedObject = NestedObject>(
{ children }
</Field>
) }
condition={ field }
>
<SelectInput
// Add "search" suffix to prevent password managers trying to autofill dropdowns
Expand All @@ -104,6 +113,7 @@ const Select = <TForm extends NestedObject = NestedObject>(
onBlur={ handleBlur }
onDropdownClose={ handleDropdownClose }
onDropdownOpen={ handleDropdownOpen }
onSelect={ handleSelect }
defaultValue={ defaultValue ?? String(value) }
error={ error }
options={ options }
Expand Down
3 changes: 3 additions & 0 deletions app/frontend/Components/Form/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { default as DateTime } from './Inputs/DateTime'
export { default as Textarea } from './Inputs/Textarea'
export { default as RichText } from './Inputs/RichText'
export { default as Checkbox } from './Inputs/Checkbox'
export { default as Select } from './Inputs/Select'
export { default as Switch } from './Inputs/Switch'
export { default as RadioButtons } from './Inputs/RadioButtons'
export { default as SearchableDropdown } from './Inputs/SearchableDropdown'
Expand All @@ -17,3 +18,5 @@ export { default as Field } from './Field'
export { default as FieldsFor } from './FieldsFor'
export { default as DynamicInputs } from './DynamicInputs'
export { default as FormConsumer } from './Components/FormConsumer'

export { type ExtendableFormProps } from './Form'
1 change: 1 addition & 0 deletions app/frontend/Components/Icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export {
} from 'react-icons/bs'

export {
FaHome as HomeIcon,
} from 'react-icons/fa'

export {
Expand Down
Loading

0 comments on commit c3f1e31

Please sign in to comment.