add vieweditable for smartviews views

This commit is contained in:
davy-c 2022-02-21 13:45:15 +09:00 committed by Davy
parent d97d14162c
commit f76da8f662
12 changed files with 79 additions and 55 deletions

View File

@ -85,9 +85,11 @@ const StatusSelect = ({
export default StatusSelect
export const StatusSelector = ({
readOnly,
onSelect,
ignoredStatuses = [],
}: {
readOnly?: boolean
ignoredStatuses?: string[]
onSelect: (status: SerializedStatus | null) => void
}) => {
@ -116,9 +118,9 @@ export const StatusSelector = ({
}
})}
onSelect={onSelect}
onCreate={createStatus}
onUpdate={editStatus}
onDelete={removeStatus}
onCreate={!readOnly ? createStatus : undefined}
onUpdate={!readOnly ? editStatus : undefined}
onDelete={!readOnly ? removeStatus : undefined}
type='Status'
allowEmpty={
ignoredStatuses == null ? true : !ignoredStatuses.includes('none')

View File

@ -212,6 +212,7 @@ const CalendarView = ({
[actionsRef, closeLastModal]
)
const isViewEditable = currentUserIsCoreMember || view.smartViewId != null
return (
<Container className='view view--calendar'>
<Flexbox justifyContent='space-between' alignItems='center'>
@ -228,7 +229,7 @@ const CalendarView = ({
teamId={team.id}
watchedProp={watchedProp}
updateWatchedProp={actionsRef.current.updateWatchedProp}
currentUserIsCoreMember={currentUserIsCoreMember}
isViewEditable={isViewEditable}
/>,
{
width: 250,
@ -281,7 +282,7 @@ const CalendarView = ({
view={view}
teamId={team.id}
properties={view.data.props}
currentUserIsCoreMember={currentUserIsCoreMember}
isViewEditable={isViewEditable}
setProperties={actionsRef.current.setViewProperties}
/>,
{

View File

@ -33,7 +33,7 @@ interface CalendarViewPropertiesContextProps {
view: SerializedView<ViewCalendarData>
teamId: string
properties?: Record<string, CalendarViewProp>
currentUserIsCoreMember?: boolean
isViewEditable?: boolean
setProperties: (
props: Record<string, CalendarViewProp>
) => Promise<BulkApiActionRes | undefined>
@ -43,7 +43,7 @@ const CalendarViewPropertiesContext = ({
view,
teamId,
properties = {},
currentUserIsCoreMember,
isViewEditable,
setProperties,
}: CalendarViewPropertiesContextProps) => {
const [formState, setFormState] = useState<'list' | 'add'>('list')
@ -160,7 +160,7 @@ const CalendarViewPropertiesContext = ({
type: 'content',
icon: getIconPathOfPropType(col.id.split(':').pop() as any),
label: <EllipsisText>{col.name}</EllipsisText>,
content: currentUserIsCoreMember ? (
content: isViewEditable ? (
<Flexbox justifyContent='flex-end'>
<LoadingButton
variant='icon'
@ -180,7 +180,7 @@ const CalendarViewPropertiesContext = ({
))}
</>
)}
{currentUserIsCoreMember && (
{isViewEditable && (
<>
{orderedProps.length > 0 && <MetadataContainerBreak />}
<MetadataContainerRow

View File

@ -26,7 +26,7 @@ import { filterIter } from '../../../lib/utils/iterator'
interface CalendarWatchedPropContextProps {
view: SerializedView
teamId: string
currentUserIsCoreMember?: boolean
isViewEditable?: boolean
watchedProp: {
type: PropType
name: string
@ -46,7 +46,7 @@ interface PropertySuggestions {
const CalendarWatchedPropContext = ({
view,
watchedProp,
currentUserIsCoreMember,
isViewEditable,
teamId,
updateWatchedProp,
}: CalendarWatchedPropContextProps) => {
@ -162,8 +162,7 @@ const CalendarWatchedPropContext = ({
</Flexbox>
),
iconPath: getIconPathOfPropType(propSuggestion.type),
disabled:
!currentUserIsCoreMember || sending != null || isSelected,
disabled: !isViewEditable || sending != null || isSelected,
spinning: sending === propSuggestion.name,
id: id,
onClick: () => setNewWatchedProp(propSuggestion),
@ -198,8 +197,7 @@ const CalendarWatchedPropContext = ({
</Flexbox>
),
iconPath: getIconPathOfPropType(propSuggestion.type),
disabled:
!currentUserIsCoreMember || sending != null || isSelected,
disabled: !isViewEditable || sending != null || isSelected,
spinning: sending === propSuggestion.name,
id: id,
onClick: () => setNewWatchedProp(propSuggestion),

View File

@ -33,7 +33,7 @@ interface KanbanViewPropertiesContextProps {
view: SerializedView<KanbanViewData>
teamId: string
properties?: Record<string, KanbanViewProp>
currentUserIsCoreMember?: boolean
isViewEditable?: boolean
setProperties: (
props: Record<string, KanbanViewProp>
) => Promise<BulkApiActionRes | undefined>
@ -43,7 +43,7 @@ const KanbanViewPropertiesContext = ({
view,
teamId,
properties = {},
currentUserIsCoreMember,
isViewEditable,
setProperties,
}: KanbanViewPropertiesContextProps) => {
const [formState, setFormState] = useState<'list' | 'add'>('list')
@ -159,7 +159,7 @@ const KanbanViewPropertiesContext = ({
type: 'content',
icon: getIconPathOfPropType(col.id.split(':').pop() as any),
label: <EllipsisText>{col.name}</EllipsisText>,
content: currentUserIsCoreMember ? (
content: isViewEditable ? (
<Flexbox justifyContent='flex-end'>
<LoadingButton
variant='icon'
@ -179,7 +179,7 @@ const KanbanViewPropertiesContext = ({
))}
</>
)}
{currentUserIsCoreMember && (
{isViewEditable && (
<>
{orderedProps.length > 0 && <MetadataContainerBreak />}
<MetadataContainerRow

View File

@ -73,6 +73,7 @@ const KanbanView = ({
const { createDoc } = useCloudApi()
const { translate } = useI18n()
const { goToDocPreview, openNewDocForm } = useCloudResourceModals()
const isViewEditable = currentUserIsCoreMember || view.smartViewId != null
const addListRef = useRef(addList)
useEffect(() => {
@ -84,6 +85,7 @@ const KanbanView = ({
openContextModal(
ev,
<StatusSelector
readOnly={!currentUserIsCoreMember}
ignoredStatuses={lists.map((list) => list.id)}
onSelect={(status) => {
addListRef.current(status?.id.toString() || 'none')
@ -93,7 +95,7 @@ const KanbanView = ({
{ width: 200, removePadding: true, keepAll: true }
)
},
[openContextModal, closeLastModal, lists]
[openContextModal, closeLastModal, currentUserIsCoreMember, lists]
)
const removeListRef = useRef(removeList)
@ -123,9 +125,9 @@ const KanbanView = ({
name={status?.name || 'No Status'}
backgroundColor={status?.backgroundColor}
/>
{currentUserIsCoreMember && (
{isViewEditable && (
<div className={'kanban__item--action-buttons'}>
{currentWorkspaceId != null && (
{currentWorkspaceId != null && currentUserIsCoreMember && (
<Button
className={'kanban__item--action-button'}
variant={'icon'}
@ -176,6 +178,7 @@ const KanbanView = ({
type='status'
label={status}
onSave={(status) => editStatus(status)}
readOnly={!currentUserIsCoreMember}
/>
<MetadataContainerBreak />
</>
@ -207,6 +210,7 @@ const KanbanView = ({
closeLastModal,
openNewDocForm,
currentUserIsCoreMember,
isViewEditable,
]
)
@ -286,7 +290,7 @@ const KanbanView = ({
{viewsSelector}
<Flexbox flex='0 0 auto'>
<Button
disabled={!currentUserIsCoreMember}
disabled={!isViewEditable}
variant='transparent'
className='view--kanban__prop'
onClick={(event) =>
@ -325,7 +329,7 @@ const KanbanView = ({
view={view}
teamId={team.id}
properties={view.data.props}
currentUserIsCoreMember={currentUserIsCoreMember}
isViewEditable={isViewEditable}
setProperties={setProperties}
/>,
{
@ -352,7 +356,7 @@ const KanbanView = ({
afterItems={renderListFooter}
afterLists={
<Button
disabled={!currentUserIsCoreMember}
disabled={!isViewEditable}
onClick={openSelector}
iconPath={mdiPlus}
variant='transparent'

View File

@ -33,7 +33,7 @@ interface ListViewPropertiesContextProps {
view: SerializedView<ViewListData>
teamId: string
properties?: Record<string, ListViewProp>
currentUserIsCoreMember?: boolean
isViewEditable?: boolean
setProperties: (
view: SerializedView,
props: Record<string, ListViewProp>
@ -44,7 +44,7 @@ const ListViewPropertiesContext = ({
view: currentView,
teamId,
properties = {},
currentUserIsCoreMember,
isViewEditable,
setProperties,
}: ListViewPropertiesContextProps) => {
const [view, setView] = useState(currentView)
@ -163,7 +163,7 @@ const ListViewPropertiesContext = ({
type: 'content',
icon: getIconPathOfPropType(prop.id.split(':').pop() as any),
label: <EllipsisText>{prop.name}</EllipsisText>,
content: currentUserIsCoreMember ? (
content: isViewEditable ? (
<Flexbox justifyContent='flex-end'>
<LoadingButton
variant='icon'
@ -183,7 +183,7 @@ const ListViewPropertiesContext = ({
))}
</>
)}
{currentUserIsCoreMember && (
{isViewEditable && (
<>
{orderedProps.length > 0 && <MetadataContainerBreak />}
<MetadataContainerRow

View File

@ -187,6 +187,7 @@ const ListView = ({
[dropInDocOrFolder]
)
const isViewEditable = currentUserIsCoreMember || view.smartViewId != null
return (
<Container className='view view--table'>
<StyledContentManagerList>
@ -204,7 +205,7 @@ const ListView = ({
view={view}
teamId={team.id}
properties={view.data.props}
currentUserIsCoreMember={currentUserIsCoreMember}
isViewEditable={isViewEditable}
setProperties={actionsRef.current.setProperties}
/>,
{

View File

@ -156,6 +156,7 @@ const TableView = ({
setState(Object.assign({}, view.data as ViewTableData))
}, [view.data])
const isViewEditable = currentUserIsCoreMember || view.smartViewId != null
return (
<Container className='view view--table'>
<StyledContentManagerList>
@ -172,7 +173,7 @@ const TableView = ({
view={view}
teamId={team.id}
columns={view.data.columns}
currentUserIsCoreMember={currentUserIsCoreMember}
isViewEditable={isViewEditable}
setColumns={actionsRef.current.setColumns}
/>,
{
@ -198,12 +199,12 @@ const TableView = ({
id: 'doc-title',
children: <Flexbox style={{ height: '100%' }}>Title</Flexbox>,
width: view.data.titleColumnWidth ?? 300,
onWidthChange: !currentUserIsCoreMember
onWidthChange: !isViewEditable
? undefined
: (newWidth) => {
actionsRef.current.updateTitleColumnWidth(newWidth)
},
onClick: !currentUserIsCoreMember
onClick: !isViewEditable
? undefined
: (ev: any) =>
openContextModal(
@ -234,12 +235,12 @@ const TableView = ({
</Flexbox>
),
width: col.width ?? 200,
onWidthChange: !currentUserIsCoreMember
onWidthChange: !isViewEditable
? undefined
: (newWidth: number) => {
actionsRef.current.updateColumnWidth(col, newWidth)
},
onClick: !currentUserIsCoreMember
onClick: !isViewEditable
? undefined
: (ev: any) =>
openContextModal(
@ -350,9 +351,9 @@ const TableView = ({
],
}
})}
disabledAddColumn={!currentUserIsCoreMember}
disabledAddColumn={!isViewEditable}
onAddColButtonClick={
!currentUserIsCoreMember
!isViewEditable
? undefined
: (ev) =>
openContextModal(

View File

@ -33,7 +33,7 @@ interface TableViewPropertiesContextProps {
view: SerializedView<ViewTableData>
teamId: string
columns?: Record<string, Column>
currentUserIsCoreMember?: boolean
isViewEditable?: boolean
setColumns: (
cols: Record<string, Column>
) => Promise<BulkApiActionRes | undefined>
@ -43,7 +43,7 @@ const TableViewPropertiesContext = ({
view,
teamId,
columns = {},
currentUserIsCoreMember,
isViewEditable,
setColumns,
}: TableViewPropertiesContextProps) => {
const [formState, setFormState] = useState<'list' | 'add'>('list')
@ -160,7 +160,7 @@ const TableViewPropertiesContext = ({
type: 'content',
icon: getIconPathOfPropType(col.id.split(':').pop() as any),
label: <EllipsisText>{col.name}</EllipsisText>,
content: currentUserIsCoreMember ? (
content: isViewEditable ? (
<Flexbox justifyContent='flex-end'>
<LoadingButton
variant='icon'
@ -178,7 +178,7 @@ const TableViewPropertiesContext = ({
))}
</>
)}
{currentUserIsCoreMember && (
{isViewEditable && (
<>
{orderedProps.length > 0 && <MetadataContainerBreak />}
<MetadataContainerRow

View File

@ -701,8 +701,8 @@ export function useCloudSidebarTree() {
},
[] as SidebarTreeChildRow[]
),
controls: currentUserIsCoreMember
? subscription == null && dashboardsMap.size !== 0
controls:
subscription == null && dashboardsMap.size !== 0
? [
{
icon: mdiPlus,
@ -724,8 +724,7 @@ export function useCloudSidebarTree() {
name,
}),
},
]
: undefined,
],
})
tree.push({

View File

@ -23,9 +23,9 @@ export interface LabelLike {
interface LabelManagerProps<T extends LabelLike> {
labels: T[]
onSelect: (label: T | null) => void
onCreate: (label: LabelLike) => void
onUpdate: (label: T) => void
onDelete: (label: T) => void
onCreate?: (label: LabelLike) => void
onUpdate?: (label: T) => void
onDelete?: (label: T) => void
sending?: boolean
type?: string
allowEmpty?: boolean
@ -54,7 +54,7 @@ const LabelManager = <T extends LabelLike>({
const createStatusHandler = useCallback(
async (name: string) => {
if (sending || labelName.trim() === '') {
if (sending || labelName.trim() === '' || onCreate == null) {
return
}
onCreate({ name, backgroundColor: getColorFromString(name) })
@ -74,6 +74,11 @@ const LabelManager = <T extends LabelLike>({
(ev: React.MouseEvent, label: T) => {
ev.stopPropagation()
ev.preventDefault()
if (onDelete == null || onUpdate == null) {
return
}
openContextModal(
ev,
<StatusEditor
@ -103,9 +108,11 @@ const LabelManager = <T extends LabelLike>({
const showCreate = useMemo(() => {
return (
labelName != '' && !labels.some((status) => status.name === labelName)
onCreate != null &&
labelName != '' &&
!labels.some((status) => status.name === labelName)
)
}, [labels, labelName])
}, [onCreate, labels, labelName])
const showNoStatus = useMemo(() => {
return (
@ -173,9 +180,11 @@ const LabelManager = <T extends LabelLike>({
name={label.name}
backgroundColor={label.backgroundColor}
/>
<span onClick={(ev) => openEditor(ev, label)}>
<Icon path={mdiDotsHorizontal} />
</span>
{onUpdate != null && onDelete != null && (
<span onClick={(ev) => openEditor(ev, label)}>
<Icon path={mdiDotsHorizontal} />
</span>
)}
</Flexbox>
</a>
))}
@ -191,6 +200,7 @@ interface StatusEditorProps<T extends LabelLike> {
onDelete?: (status: T) => void
onSave: (status: T) => void
type?: string
readOnly?: boolean
}
export const StatusEditor = <T extends LabelLike>({
@ -198,6 +208,7 @@ export const StatusEditor = <T extends LabelLike>({
onDelete,
onSave,
type = 'label',
readOnly,
}: StatusEditorProps<T>) => {
const [editingStatus, setEditingStatus] = useState(label)
const editingStatusRef = useRef(label)
@ -244,7 +255,13 @@ export const StatusEditor = <T extends LabelLike>({
<MetadataContainerRow
row={{
type: 'content',
content: <FormInput value={editingStatus.name} onChange={setName} />,
content: (
<FormInput
value={editingStatus.name}
onChange={setName}
disabled={readOnly}
/>
),
}}
/>
<MetadataContainerRow row={{ type: 'header', content: 'COLOR' }} />
@ -255,6 +272,7 @@ export const StatusEditor = <T extends LabelLike>({
<FormColorSelect
value={editingStatus.backgroundColor || ''}
onChange={setColor}
disabled={readOnly}
/>
),
}}