mirror of
https://github.com/BoostIO/BoostNote-App.git
synced 2024-10-04 08:07:41 +03:00
add vieweditable for smartviews views
This commit is contained in:
parent
d97d14162c
commit
f76da8f662
@ -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')
|
||||
|
@ -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}
|
||||
/>,
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
/>,
|
||||
{
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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({
|
||||
|
@ -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}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
|
Loading…
Reference in New Issue
Block a user