mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-10 11:47:42 +02:00
UBERF-5603 (#4754)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -31,9 +31,10 @@ import {
|
||||
selectionStore,
|
||||
selectionLimit
|
||||
} from './selection'
|
||||
import { deleteObjects, getObjectLinkFragment } from './utils'
|
||||
import { deleteObjects, getObjectLinkFragment, restrictionStore } from './utils'
|
||||
import contact from '@hcengineering/contact'
|
||||
import { locationToUrl } from '@hcengineering/ui'
|
||||
import { get } from 'svelte/store'
|
||||
|
||||
/**
|
||||
* Action to be used for copying text to clipboard.
|
||||
@@ -206,6 +207,7 @@ const MoveRight = (doc: Doc | undefined, evt: Event): void => {
|
||||
}
|
||||
|
||||
function ShowActions (doc: Doc | Doc[] | undefined, evt: Event): void {
|
||||
if (get(restrictionStore).disableActions) return
|
||||
evt.preventDefault()
|
||||
|
||||
showPopup(view.component.ActionsPopup, { viewContext: $contextStore.getLastContext() }, 'top')
|
||||
|
||||
@@ -27,6 +27,7 @@ import core, {
|
||||
} from '@hcengineering/core'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { getEventPositionElement, showPopup } from '@hcengineering/ui'
|
||||
import {
|
||||
type Action,
|
||||
type ActionGroup,
|
||||
@@ -34,8 +35,10 @@ import {
|
||||
type ViewActionInput,
|
||||
type ViewContextType
|
||||
} from '@hcengineering/view'
|
||||
import Menu from './components/Menu.svelte'
|
||||
import view from './plugin'
|
||||
import { type FocusSelection, type SelectionStore } from './selection'
|
||||
import { restrictionStore } from './utils'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -226,3 +229,16 @@ export function filterActions (
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
let disableActions: boolean = false
|
||||
|
||||
restrictionStore.subscribe((v) => {
|
||||
disableActions = v.disableActions
|
||||
})
|
||||
|
||||
export function showMenu (ev: MouseEvent, props: any, onClose?: (result: any) => void | Promise<void>): void {
|
||||
ev.stopPropagation()
|
||||
ev.preventDefault()
|
||||
if (disableActions) return
|
||||
showPopup(Menu, props, getEventPositionElement(ev), onClose)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import { fly } from 'svelte/transition'
|
||||
import { getContextActions, getSelection } from '../actions'
|
||||
import { ListSelectionProvider, SelectionStore, focusStore, previewDocument, selectionStore } from '../selection'
|
||||
import { getObjectPreview } from '../utils'
|
||||
import { getObjectPreview, restrictionStore } from '../utils'
|
||||
|
||||
const client = getClient()
|
||||
|
||||
@@ -128,7 +128,10 @@
|
||||
docs: selectionDocs
|
||||
})
|
||||
|
||||
$: disableActions = $restrictionStore.disableActions
|
||||
|
||||
async function handleKeys (evt: KeyboardEvent): Promise<void> {
|
||||
if (disableActions) return
|
||||
const targetTagName = (evt.target as any)?.tagName?.toLowerCase()
|
||||
|
||||
let elm = evt.target as HTMLElement
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
import { AttributesBar, KeyedAttribute, getAttribute, getClient } from '@hcengineering/presentation'
|
||||
import setting, { settingId } from '@hcengineering/setting'
|
||||
import { Button, Label, getCurrentResolvedLocation, navigate } from '@hcengineering/ui'
|
||||
import { getFiltredKeys, isCollectionAttr } from '../utils'
|
||||
import { getFiltredKeys, isCollectionAttr, restrictionStore } from '../utils'
|
||||
|
||||
export let object: Doc | Record<string, any>
|
||||
export let _class: Ref<Class<Doc>>
|
||||
@@ -75,23 +75,25 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool">
|
||||
<Button
|
||||
icon={setting.icon.Setting}
|
||||
kind={'link'}
|
||||
size={'medium'}
|
||||
showTooltip={{ label: setting.string.ClassSetting }}
|
||||
on:click={(ev) => {
|
||||
ev.stopPropagation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[2] = settingId
|
||||
loc.path[3] = 'setting'
|
||||
loc.path[4] = 'classes'
|
||||
loc.path.length = 5
|
||||
loc.query = { _class }
|
||||
loc.fragment = undefined
|
||||
navigate(loc)
|
||||
}}
|
||||
/>
|
||||
{#if !$restrictionStore.disableNavigation}
|
||||
<Button
|
||||
icon={setting.icon.Setting}
|
||||
kind={'link'}
|
||||
size={'medium'}
|
||||
showTooltip={{ label: setting.string.ClassSetting }}
|
||||
on:click={(ev) => {
|
||||
ev.stopPropagation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[2] = settingId
|
||||
loc.path[3] = 'setting'
|
||||
loc.path[4] = 'classes'
|
||||
loc.path.length = 5
|
||||
loc.query = { _class }
|
||||
loc.fragment = undefined
|
||||
navigate(loc)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
export let ignoreKeys: string[]
|
||||
export let allowedCollections: string[] = []
|
||||
export let showHeader: boolean = true
|
||||
export let readonly: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
@@ -36,6 +37,7 @@
|
||||
to={undefined}
|
||||
{allowedCollections}
|
||||
{showHeader}
|
||||
{readonly}
|
||||
on:update
|
||||
/>
|
||||
{#each mixins as mixin}
|
||||
@@ -47,6 +49,7 @@
|
||||
object={hierarchy.as(object, mixin._id)}
|
||||
{ignoreKeys}
|
||||
{to}
|
||||
{readonly}
|
||||
{allowedCollections}
|
||||
{showHeader}
|
||||
on:update
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
import { NavLink, getClient } from '@hcengineering/presentation'
|
||||
import { AnyComponent, getPanelURI, locationToUrl } from '@hcengineering/ui'
|
||||
import view from '../plugin'
|
||||
import { getObjectLinkFragment } from '../utils'
|
||||
import { getObjectLinkFragment, restrictionStore } from '../utils'
|
||||
|
||||
export let object: Doc | undefined
|
||||
export let disabled = false
|
||||
export let disabled: boolean = false
|
||||
export let onClick: ((event: MouseEvent) => void) | undefined = undefined
|
||||
export let noUnderline = disabled
|
||||
export let inline = false
|
||||
@@ -31,6 +31,9 @@
|
||||
export let accent: boolean = false
|
||||
export let noOverflow: boolean = false
|
||||
|
||||
let _disabled = disabled || $restrictionStore.disableNavigation
|
||||
$: _disabled = disabled || $restrictionStore.disableNavigation
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
@@ -40,7 +43,7 @@
|
||||
: undefined
|
||||
|
||||
async function getHref (object: Doc): Promise<void> {
|
||||
if (disabled) {
|
||||
if (_disabled) {
|
||||
href = undefined
|
||||
return
|
||||
}
|
||||
@@ -53,6 +56,6 @@
|
||||
$: if (object !== undefined) getHref(object)
|
||||
</script>
|
||||
|
||||
<NavLink {disabled} {onClick} {noUnderline} {inline} {shrink} {href} {colorInherit} {accent} {noOverflow}>
|
||||
<NavLink disabled={_disabled} {onClick} {noUnderline} {inline} {shrink} {href} {colorInherit} {accent} {noOverflow}>
|
||||
<slot />
|
||||
</NavLink>
|
||||
|
||||
@@ -14,32 +14,33 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import { Class, Doc, Mixin, Ref } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { Panel } from '@hcengineering/panel'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import {
|
||||
ActionContext,
|
||||
AttributeCategory,
|
||||
AttributeCategoryOrder,
|
||||
AttributesBar,
|
||||
KeyedAttribute,
|
||||
ActionContext,
|
||||
createQuery,
|
||||
getAttributePresenterClass,
|
||||
getClient,
|
||||
hasResource
|
||||
} from '@hcengineering/presentation'
|
||||
import { AnyComponent, Button, Component, IconMixin, IconMoreH, showPopup } from '@hcengineering/ui'
|
||||
import { AnyComponent, Button, Component, IconMixin, IconMoreH } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
|
||||
import { ContextMenu, ParentsNavigator, DocNavLink, getDocLabel, getDocMixins } from '..'
|
||||
import { DocNavLink, ParentsNavigator, getDocLabel, getDocMixins, showMenu } from '..'
|
||||
import { categorizeFields, getCollectionCounter, getFiltredKeys } from '../utils'
|
||||
import DocAttributeBar from './DocAttributeBar.svelte'
|
||||
|
||||
export let _id: Ref<Doc>
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let embedded: boolean = false
|
||||
export let readonly: boolean = false
|
||||
|
||||
let realObjectClass: Ref<Class<Doc>> = _class
|
||||
let lastId: Ref<Doc> = _id
|
||||
@@ -227,11 +228,6 @@
|
||||
let panelWidth: number = 0
|
||||
let innerWidth: number = 0
|
||||
|
||||
function showMenu (ev?: Event): void {
|
||||
if (object !== undefined) {
|
||||
showPopup(ContextMenu, { object, excludedActions: [view.action.Open] }, (ev as MouseEvent).target as HTMLElement)
|
||||
}
|
||||
}
|
||||
function handleOpen (ev: CustomEvent): void {
|
||||
ignoreKeys = ev.detail.ignoreKeys
|
||||
activityOptions = ev.detail.activityOptions ?? activityOptions
|
||||
@@ -259,6 +255,7 @@
|
||||
<Panel
|
||||
{object}
|
||||
isHeader={mainEditor?.pinned ?? false}
|
||||
allowClose={!embedded}
|
||||
isAside={true}
|
||||
{embedded}
|
||||
bind:content
|
||||
@@ -272,7 +269,7 @@
|
||||
dispatch('close')
|
||||
}}
|
||||
withoutActivity={!activityOptions.enabled}
|
||||
withoutInput={!activityOptions.showInput}
|
||||
withoutInput={!activityOptions.showInput || readonly}
|
||||
>
|
||||
<svelte:fragment slot="title">
|
||||
{#if !embedded}<ParentsNavigator element={object} />{/if}
|
||||
@@ -284,7 +281,16 @@
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="utils">
|
||||
<Button icon={IconMoreH} iconProps={{ size: 'medium' }} kind={'icon'} on:click={showMenu} />
|
||||
{#if !readonly}
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
on:click={(e) => {
|
||||
showMenu(e, { object, excludedActions: [view.action.Open] })
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<Button
|
||||
icon={IconMixin}
|
||||
iconProps={{ size: 'medium' }}
|
||||
@@ -301,19 +307,29 @@
|
||||
{#if headerEditor !== undefined}
|
||||
<Component
|
||||
is={headerEditor}
|
||||
props={{ object, keys, mixins, ignoreKeys, vertical: dir === 'column', allowedCollections, embedded }}
|
||||
props={{
|
||||
object,
|
||||
keys,
|
||||
mixins,
|
||||
ignoreKeys,
|
||||
vertical: dir === 'column',
|
||||
allowedCollections,
|
||||
embedded,
|
||||
readonly
|
||||
}}
|
||||
on:update={updateKeys}
|
||||
/>
|
||||
{:else if dir === 'column'}
|
||||
<DocAttributeBar
|
||||
{object}
|
||||
{mixins}
|
||||
{readonly}
|
||||
ignoreKeys={[...ignoreKeys, ...collectionArrays, ...inplaceAttributes]}
|
||||
{allowedCollections}
|
||||
on:update={updateKeys}
|
||||
/>
|
||||
{:else}
|
||||
<AttributesBar {object} _class={realObjectClass} {keys} />
|
||||
<AttributesBar {object} _class={realObjectClass} {keys} {readonly} />
|
||||
{/if}
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
@@ -321,14 +337,14 @@
|
||||
<svelte:fragment slot="header">
|
||||
{#if mainEditor && mainEditor.editor && mainEditor.pinned}
|
||||
<div class="flex-col flex-grow my-4">
|
||||
<Component is={mainEditor.editor} props={{ object }} on:open={handleOpen} />
|
||||
<Component is={mainEditor.editor} props={{ object, readonly }} on:open={handleOpen} />
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
{#if mainEditor && mainEditor.editor && !mainEditor.pinned}
|
||||
<div class="flex-col flex-grow flex-no-shrink step-tb-6">
|
||||
<Component is={mainEditor.editor} props={{ object }} on:open={handleOpen} />
|
||||
<Component is={mainEditor.editor} props={{ object, readonly }} on:open={handleOpen} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -343,6 +359,7 @@
|
||||
object,
|
||||
space: object.space,
|
||||
key: collection.key,
|
||||
readonly,
|
||||
[collection.key.key]: getCollectionCounter(hierarchy, object, collection.key)
|
||||
}}
|
||||
/>
|
||||
@@ -352,7 +369,7 @@
|
||||
|
||||
{#if editorFooter}
|
||||
<div class="step-tb-6">
|
||||
<Component is={editorFooter.footer} props={{ object, _class, ...editorFooter.props }} />
|
||||
<Component is={editorFooter.footer} props={{ object, _class, ...editorFooter.props, readonly }} />
|
||||
</div>
|
||||
{/if}
|
||||
</Panel>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let size: ButtonSize = 'large'
|
||||
export let allowDeselect: boolean = false
|
||||
export let readonly: boolean = false
|
||||
|
||||
let items: DropdownTextItem[] = []
|
||||
|
||||
@@ -56,6 +57,7 @@
|
||||
{kind}
|
||||
width={'100%'}
|
||||
{allowDeselect}
|
||||
disabled={readonly}
|
||||
autoSelect={false}
|
||||
on:selected={(e) => {
|
||||
onChange(e.detail)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import view from '../plugin'
|
||||
|
||||
export let value: string = ''
|
||||
export let value: string | undefined = ''
|
||||
export let editable: boolean | undefined = true
|
||||
|
||||
const placeholder: IntlString = view.string.HyperlinkPlaceholder
|
||||
@@ -33,7 +33,9 @@
|
||||
if (input) input.focus()
|
||||
})
|
||||
const copyLink = (): void => {
|
||||
copyTextToClipboard(value)
|
||||
if (value !== undefined) {
|
||||
copyTextToClipboard(value)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -92,6 +94,7 @@
|
||||
kind={'ghost'}
|
||||
size={'small'}
|
||||
icon={IconCopy}
|
||||
disabled={value === undefined || value === ''}
|
||||
showTooltip={{ label: view.string.CopyToClipboard }}
|
||||
on:click={() => {
|
||||
copyLink()
|
||||
@@ -102,6 +105,7 @@
|
||||
kind={'ghost'}
|
||||
size={'small'}
|
||||
icon={IconArrowRight}
|
||||
disabled={value === undefined || value === ''}
|
||||
showTooltip={{ label: view.string.Open }}
|
||||
on:click={() => {
|
||||
dispatch('update', value)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { AttachedDoc, Doc } from '@hcengineering/core'
|
||||
import { Breadcrumbs, BreadcrumbsModel, getClient } from '@hcengineering/presentation'
|
||||
import { getObjectPresenter, isAttachedDoc } from '../utils'
|
||||
import { getObjectPresenter, isAttachedDoc, restrictionStore } from '../utils'
|
||||
import { AttributeModel } from '@hcengineering/view'
|
||||
|
||||
export let element: Doc | AttachedDoc
|
||||
@@ -77,6 +77,6 @@
|
||||
|
||||
{#await getBreadcrumbsModels(element) then models}
|
||||
{#if models.length > 0}
|
||||
<Breadcrumbs {models} />
|
||||
<Breadcrumbs {models} disabled={$restrictionStore.disableNavigation} />
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import core, {
|
||||
AnyAttribute,
|
||||
Class,
|
||||
@@ -24,9 +22,9 @@
|
||||
FindOptions,
|
||||
Lookup,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
TxOperations,
|
||||
getObjectValue,
|
||||
SortingOrder
|
||||
getObjectValue
|
||||
} from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { createQuery, getClient, updateAttribute } from '@hcengineering/presentation'
|
||||
@@ -34,19 +32,19 @@
|
||||
Button,
|
||||
CheckBox,
|
||||
Component,
|
||||
getEventPositionElement,
|
||||
Label,
|
||||
Loading,
|
||||
mouseAttractor,
|
||||
resizeObserver,
|
||||
showPopup,
|
||||
Spinner,
|
||||
lazyObserver
|
||||
lazyObserver,
|
||||
mouseAttractor,
|
||||
resizeObserver
|
||||
} from '@hcengineering/ui'
|
||||
import { AttributeModel, BuildModelKey, BuildModelOptions } from '@hcengineering/view'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { showMenu } from '../actions'
|
||||
import view from '../plugin'
|
||||
import { buildConfigLookup, buildModel, LoadingProps } from '../utils'
|
||||
import Menu from './Menu.svelte'
|
||||
import { LoadingProps, buildConfigLookup, buildModel, restrictionStore } from '../utils'
|
||||
import IconUpDown from './icons/UpDown.svelte'
|
||||
|
||||
export let _class: Ref<Class<Doc>>
|
||||
@@ -160,14 +158,14 @@
|
||||
{ sort: getSort(_sortKey), limit: 1, ...options, lookup, total: true }
|
||||
)
|
||||
|
||||
const showMenu = async (ev: MouseEvent, object: Doc, row: number): Promise<void> => {
|
||||
const showContextMenu = async (ev: MouseEvent, object: Doc, row: number): Promise<void> => {
|
||||
selection = row
|
||||
if (!checkedSet.has(object._id)) {
|
||||
check(objects, false)
|
||||
checked = []
|
||||
}
|
||||
const items = checked.length > 0 ? checked : object
|
||||
showPopup(Menu, { object: items, baseMenuClass }, getEventPositionElement(ev))
|
||||
showMenu(ev, { object: items, baseMenuClass })
|
||||
}
|
||||
|
||||
function changeSorting (key: string | string[]): void {
|
||||
@@ -217,14 +215,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
const joinProps = (attribute: AttributeModel, object: Doc) => {
|
||||
const joinProps = (attribute: AttributeModel, object: Doc, readonly: boolean) => {
|
||||
const readonlyParams = readonly
|
||||
? {
|
||||
readonly: true,
|
||||
editable: false,
|
||||
disabled: true
|
||||
}
|
||||
: {}
|
||||
if (attribute.collectionAttr) {
|
||||
return { object, ...attribute.props }
|
||||
return { object, ...attribute.props, ...readonlyParams }
|
||||
}
|
||||
if (attribute.attribute?.type._class === core.class.EnumOf) {
|
||||
return { ...attribute.props, type: attribute.attribute.type }
|
||||
return { ...attribute.props, type: attribute.attribute.type, ...readonlyParams }
|
||||
}
|
||||
return { ...attribute.props, space: object.space }
|
||||
return { ...attribute.props, space: object.space, ...readonlyParams }
|
||||
}
|
||||
function getValue (attribute: AttributeModel, object: Doc): any {
|
||||
if (attribute.castRequest) {
|
||||
@@ -300,7 +305,7 @@
|
||||
function contextHandler (object: Doc, row: number): (ev: MouseEvent) => void {
|
||||
return (ev) => {
|
||||
if (!readonly) {
|
||||
showMenu(ev, object, row)
|
||||
showContextMenu(ev, object, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,7 +384,7 @@
|
||||
})}
|
||||
on:focus={() => {}}
|
||||
bind:this={refs[row]}
|
||||
on:contextmenu|preventDefault={contextHandler(object, row)}
|
||||
on:contextmenu={contextHandler(object, row)}
|
||||
use:lazyObserver={(val) => {
|
||||
if (val && row >= rowLimit) {
|
||||
rowLimit = row + 10
|
||||
@@ -430,7 +435,7 @@
|
||||
this={attribute.presenter}
|
||||
value={getValue(attribute, object)}
|
||||
onChange={getOnChange(object, attribute)}
|
||||
{...joinProps(attribute, object)}
|
||||
{...joinProps(attribute, object, $restrictionStore.readonly)}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
export let viewlet: Viewlet | undefined
|
||||
export let kind: ButtonKind = 'regular'
|
||||
export let viewOptions: ViewOptions
|
||||
export let disabled: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
@@ -110,6 +111,7 @@
|
||||
<Button
|
||||
icon={view.icon.ViewButton}
|
||||
label={view.string.View}
|
||||
{disabled}
|
||||
{kind}
|
||||
adaptiveShrink={'sm'}
|
||||
showTooltip={{ label: view.string.CustomizeView, direction: 'bottom' }}
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
import { getViewOptions, viewOptionStore } from '../viewOptions'
|
||||
import ViewOptionsButton from './ViewOptionsButton.svelte'
|
||||
import ViewletSetting from './ViewletSetting.svelte'
|
||||
import { restrictionStore } from '../utils'
|
||||
|
||||
export let kind: ButtonKind = 'regular'
|
||||
export let viewOptions: ViewOptions | undefined = undefined
|
||||
export let viewlet: Viewlet | undefined = undefined
|
||||
export let disabled: boolean = false
|
||||
|
||||
let btn: HTMLButtonElement
|
||||
|
||||
@@ -31,6 +33,8 @@
|
||||
}
|
||||
|
||||
$: viewOptions = getViewOptions(viewlet, $viewOptionStore)
|
||||
|
||||
$: disabled = $restrictionStore.readonly
|
||||
</script>
|
||||
|
||||
{#if viewlet}
|
||||
@@ -41,6 +45,7 @@
|
||||
<Button
|
||||
icon={view.icon.Configure}
|
||||
label={view.string.Show}
|
||||
{disabled}
|
||||
{kind}
|
||||
shrink={1}
|
||||
adaptiveShrink={'sm'}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import { getViewOptions, viewOptionStore } from '../viewOptions'
|
||||
import ViewOptionsButton from './ViewOptionsButton.svelte'
|
||||
import ViewletSetting from './ViewletSetting.svelte'
|
||||
import { restrictionStore } from '../utils'
|
||||
|
||||
export let viewletQuery: DocumentQuery<Viewlet> = {}
|
||||
export let kind: ButtonKind = 'regular'
|
||||
@@ -31,6 +32,7 @@
|
||||
export let viewlets: Array<WithLookup<Viewlet>> = []
|
||||
export let preference: ViewletPreference | undefined = undefined
|
||||
export let loading = true
|
||||
export let disabled: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -76,18 +78,21 @@
|
||||
} else {
|
||||
preferenceQuery.unsubscribe()
|
||||
}
|
||||
|
||||
$: disabled = $restrictionStore.readonly
|
||||
</script>
|
||||
|
||||
{#if viewlet}
|
||||
<div class="flex-row-center gap-2 reverse">
|
||||
{#if viewOptions}
|
||||
<ViewOptionsButton {viewlet} {kind} {viewOptions} />
|
||||
<ViewOptionsButton {viewlet} {kind} {viewOptions} {disabled} />
|
||||
{/if}
|
||||
<Button
|
||||
icon={view.icon.Configure}
|
||||
label={view.string.Show}
|
||||
{kind}
|
||||
shrink={1}
|
||||
{disabled}
|
||||
adaptiveShrink={'sm'}
|
||||
showTooltip={{ label: view.string.CustomizeView, direction: 'bottom' }}
|
||||
bind:input={btn}
|
||||
|
||||
@@ -30,21 +30,14 @@
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { DocWithRank, calcRank } from '@hcengineering/task'
|
||||
import {
|
||||
AnyComponent,
|
||||
AnySvelteComponent,
|
||||
ExpandCollapse,
|
||||
getEventPositionElement,
|
||||
mouseAttractor,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { AnyComponent, AnySvelteComponent, ExpandCollapse, mouseAttractor } from '@hcengineering/ui'
|
||||
import { AttributeModel, BuildModelKey, ViewOptionModel, ViewOptions, Viewlet } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { FocusSelection, SelectionFocusProvider, focusStore } from '../../selection'
|
||||
import Menu from '../Menu.svelte'
|
||||
import ListHeader from './ListHeader.svelte'
|
||||
import ListItem from './ListItem.svelte'
|
||||
import { showMenu } from '../../actions'
|
||||
|
||||
export let category: PrimitiveType | AggregateValue
|
||||
export let headerComponent: AttributeModel | undefined
|
||||
@@ -169,7 +162,6 @@
|
||||
$: selectedObjectIdsSet = new Set<Ref<Doc>>(selectedObjectIds.map((it) => it._id))
|
||||
|
||||
const handleMenuOpened = async (event: MouseEvent, object: Doc) => {
|
||||
event.preventDefault()
|
||||
handleRowFocused(object)
|
||||
|
||||
if (!selectedObjectIdsSet.has(object._id)) {
|
||||
@@ -177,8 +169,7 @@
|
||||
}
|
||||
|
||||
const items = selectedObjectIds.length > 0 ? selectedObjectIds : object
|
||||
|
||||
showPopup(Menu, { object: items, baseMenuClass }, getEventPositionElement(event))
|
||||
showMenu(event, { object: items, baseMenuClass })
|
||||
}
|
||||
|
||||
$: _newObjectProps = (doc: Doc | undefined): Record<string, any> | undefined => {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import view from '../../plugin'
|
||||
import GrowPresenter from './GrowPresenter.svelte'
|
||||
import ListPresenter from './ListPresenter.svelte'
|
||||
import { restrictionStore } from '../../utils'
|
||||
|
||||
export let docObject: Doc
|
||||
export let model: AttributeModel[]
|
||||
@@ -65,6 +66,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getProps (props: Record<string, any>, readonly: boolean): Record<string, any> {
|
||||
if (readonly) {
|
||||
return {
|
||||
...props,
|
||||
readonly: true,
|
||||
disabled: true,
|
||||
editable: false,
|
||||
isEditable: false
|
||||
}
|
||||
}
|
||||
return props
|
||||
}
|
||||
|
||||
$: mobile = $deviceInfo.isMobile
|
||||
|
||||
onMount(() => {
|
||||
@@ -124,7 +138,7 @@
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
{props}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
{compactMode}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
@@ -138,7 +152,7 @@
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
{props}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
/>
|
||||
@@ -148,7 +162,7 @@
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
{props}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
/>
|
||||
@@ -158,7 +172,7 @@
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
{attributeModel}
|
||||
{props}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
value={getObjectValue(attributeModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attributeModel)}
|
||||
hideDivider={i === 0}
|
||||
@@ -187,7 +201,7 @@
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
{props}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
{compactMode}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
@@ -202,7 +216,7 @@
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
{attributeModel}
|
||||
{props}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
value={getObjectValue(attributeModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attributeModel)}
|
||||
hideDivider={j === 0}
|
||||
@@ -220,7 +234,7 @@
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
{attributeModel}
|
||||
{props}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
value={getObjectValue(attributeModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attributeModel)}
|
||||
/>
|
||||
|
||||
@@ -116,7 +116,7 @@ import {
|
||||
import { IndexedDocumentPreview } from '@hcengineering/presentation'
|
||||
import { showEmptyGroups } from './viewOptions'
|
||||
import { AggregationMiddleware, AnalyticsMiddleware } from './middleware'
|
||||
export { getActions, invokeAction, getContextActions } from './actions'
|
||||
export { getActions, invokeAction, getContextActions, showMenu } from './actions'
|
||||
export { default as ActionButton } from './components/ActionButton.svelte'
|
||||
export { default as ActionHandler } from './components/ActionHandler.svelte'
|
||||
export { default as FilterButton } from './components/filter/FilterButton.svelte'
|
||||
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
hasResource,
|
||||
type KeyedAttribute
|
||||
} from '@hcengineering/presentation'
|
||||
import { type Restrictions } from '@hcengineering/guest'
|
||||
import {
|
||||
type AnyComponent,
|
||||
type AnySvelteComponent,
|
||||
@@ -1223,3 +1224,10 @@ export function getDocMixins (
|
||||
export function classIcon (client: Client, _class: Ref<Class<Obj>>): Asset | undefined {
|
||||
return client.getHierarchy().getClass(_class).icon
|
||||
}
|
||||
|
||||
export const restrictionStore = writable<Restrictions>({
|
||||
readonly: false,
|
||||
disableComments: false,
|
||||
disableNavigation: false,
|
||||
disableActions: false
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user