Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advanced event filters #22

Merged
merged 7 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/actions/ModActionPanel/QuickAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ function Form(
}
}
`}</style>
<div className="flex overflow-y-auto scrollable-container">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make room for the ring around the Configure button in the mod event list header.

<div className="flex overflow-y-auto scrollable-container pt-1">
<form
id={FORM_ID}
onSubmit={onFormSubmit}
Expand Down Expand Up @@ -560,7 +560,6 @@ function Form(
id="labels"
name="labels"
formId={FORM_ID}
subject={subject}
defaultLabels={currentLabels.filter(
(label) => !isSelfLabel(label),
)}
Expand Down
2 changes: 1 addition & 1 deletion components/common/FullScreenActionPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function FullScreenActionPanel(props: {
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="max-w-screen-lg w-full sm:w-5/6 h-full md:max-h-3/4 md:my-12 align-bottom bg-white rounded-lg text-left sm:overflow-hidden shadow-xl transform transition-all sm:align-middle flex">
<Dialog.Panel className="max-w-screen-xl w-full sm:w-5/6 h-full md:max-h-3/4 md:my-12 align-bottom bg-white rounded-lg text-left sm:overflow-hidden shadow-xl transform transition-all sm:align-middle flex">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make room for the filter panel's content in the event list

<div className="absolute top-0 right-0 pt-4 pr-4">
<button
type="button"
Expand Down
153 changes: 10 additions & 143 deletions components/common/labels/Grid.tsx
Original file line number Diff line number Diff line change
@@ -1,163 +1,25 @@
import { Fragment, useState, useEffect } from 'react'
import { useState } from 'react'
import Select from 'react-tailwindcss-select'
import { Disclosure, Transition } from '@headlessui/react'
import { LabelChip, LabelListEmpty } from './List'
import {
labelOptions,
displayLabel,
groupLabelList,
getLabelGroupInfo,
isSelfLabel,
buildAllLabelOptions,
unFlagSelfLabel,
} from './util'
import { classNames } from '@/lib/util'

const EMPTY_ARR = []
type SelectProps = React.ComponentProps<typeof Select>

// TODO: Probably redundant
export function LabelsGrid(props: LabelsProps) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just cleaning up unused code.

const {
id,
formId,
name,
className = '',
defaultLabels = EMPTY_ARR,
options = labelOptions,
disabled,
subject,
...others
} = props
const allOptions = buildAllLabelOptions(defaultLabels, options)
const [current, setCurrent] = useState<string[]>(defaultLabels)

// update the current list when the current labels prop changes
// default labels are an array of strings so passing that as dependency to the useEffect hook will
// cause the current state to change everytime some other prop changes. the string conversion shields
// us from that. only caveat is that it won't work when the labels don't change just their order is changed
const defaultLabelsKey = defaultLabels.join('_')
useEffect(() => {
setCurrent(defaultLabels)
}, [defaultLabelsKey, subject])

const handleCheckboxChange = (opt: string) => {
// don't allow self labels to be changed
if (isSelfLabel(opt)) return
setCurrent((prev) => {
if (prev.includes(opt)) {
return prev.filter((item) => item !== opt)
} else {
return [...prev, opt]
}
})
}

const groupedLabelList = groupLabelList(allOptions)
// Sort by number of labels in each group so that the lists of labels take less vertical space in the UI
const sortedLabelList = Object.values(groupedLabelList).sort(
(a, b) => b.labels?.length - a.labels?.length,
)

return (
<Disclosure as="div">
<Disclosure.Button
className={`${disabled ? '' : 'cursor-pointer'} ${className}`}
disabled={disabled}
{...others}
>
{!current.length && <LabelListEmpty>(click to add)</LabelListEmpty>}
{current.map((label) => {
const labelGroup = getLabelGroupInfo(unFlagSelfLabel(label))
return (
<LabelChip key={label} style={{ color: labelGroup.color }}>
{displayLabel(label)}
<input type="hidden" name={name} value={label} />
</LabelChip>
)
})}
</Disclosure.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Disclosure.Panel>
<div
className="flex flex-wrap flex-row gap-x-8 py-3 shadow-sm"
id={`${id}-staged-container`}
>
{sortedLabelList.map((group) => {
const groupTitle = group.strings.settings.en.name
return (
<div
key={`label_group_${groupTitle}`}
className={classNames('flex flex-col py-1 min-w-1/6')}
>
<p style={{ color: group.color }}>{groupTitle}</p>
{group.labels.map((opt, i) => {
const labelText = typeof opt === 'string' ? opt : opt.id
const cantChange = isSelfLabel(labelText)
return (
<div
className={classNames(
`flex flex-row pl-1`,
cantChange ? 'opacity-75' : '',
)}
key={`label_${labelText}`}
>
<div className="flex h-6 items-center">
<input
id={`${id}-${groupTitle}-opt-${i}`}
name={`${name}-staged`}
type="checkbox"
value={labelText}
disabled={cantChange}
checked={current.includes(labelText)}
onChange={() => handleCheckboxChange(labelText)}
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600"
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault() // make sure we don't submit the form
e.currentTarget.click() // simulate a click on the input
}
}}
/>
</div>
<label
htmlFor={`${id}-${groupTitle}-opt-${i}`}
className="ml-1 text-sm leading-6 font-medium text-gray-900"
>
{displayLabel(labelText)}
</label>
</div>
)
})}
</div>
)
})}
</div>
</Disclosure.Panel>
</Transition>
</Disclosure>
)
}

export const LabelSelector = (props: LabelsProps) => {
const {
id,
formId,
name,
className = '',
defaultLabels = EMPTY_ARR,
options = labelOptions,
disabled,
subject,
...others
onChange,
} = props
const [selectedLabels, setSelectedLabels] = useState<SelectProps['value']>(
defaultLabels.map((label) => ({
Expand Down Expand Up @@ -186,6 +48,7 @@ export const LabelSelector = (props: LabelsProps) => {
<input
type="hidden"
name={name}
{...{ id, formId, disabled }}
value={
Array.isArray(selectedLabels)
? selectedLabels.map(({ label }) => label).join(',')
Expand All @@ -209,7 +72,12 @@ export const LabelSelector = (props: LabelsProps) => {
</li>
)
}}
onChange={(value) => setSelectedLabels(value)}
onChange={(value) => {
setSelectedLabels(value)
onChange?.(
Array.isArray(value) ? value.map(({ value }) => value) : [],
)
}}
/>
</>
)
Expand All @@ -220,8 +88,7 @@ type LabelsProps = {
formId: string
name: string
disabled?: boolean
className?: string
defaultLabels?: string[]
options?: string[]
subject?: string
onChange?: (labels: string[]) => void
}
Loading
Loading