diff --git a/packages/text-editor/src/components/CollaboratorEditor.svelte b/packages/text-editor/src/components/CollaboratorEditor.svelte
index 201efd4e44..c38994a805 100644
--- a/packages/text-editor/src/components/CollaboratorEditor.svelte
+++ b/packages/text-editor/src/components/CollaboratorEditor.svelte
@@ -79,6 +79,8 @@
 
   export let field: string | undefined = undefined
 
+  export let autoOverflow = false
+
   const ydoc = (getContext(CollaborationIds.Doc) as Y.Doc | undefined) ?? new Y.Doc()
   const contextProvider = getContext(CollaborationIds.Provider) as WebsocketProvider | undefined
   const wsProvider =
@@ -464,7 +466,7 @@
   let showDiff = true
 </script>
 
-<div class="ref-container">
+<div class="ref-container" class:autoOverflow>
   <div class="flex">
     {#if isFormatting && !readonly}
       <div class="formatPanel buttons-group xsmall-gap mb-4">
@@ -709,4 +711,7 @@
   span.deletion {
     text-decoration: line-through;
   }
+  .autoOverflow {
+    overflow: auto;
+  }
 </style>
diff --git a/plugins/attachment-resources/src/components/AddAttachment.svelte b/plugins/attachment-resources/src/components/AddAttachment.svelte
index b37c593e47..3a3a756f50 100644
--- a/plugins/attachment-resources/src/components/AddAttachment.svelte
+++ b/plugins/attachment-resources/src/components/AddAttachment.svelte
@@ -13,11 +13,13 @@
 // limitations under the License.
 -->
 <script lang="ts">
-  import { Class, Doc, Ref, Space } from '@hcengineering/core'
+  import { Attachment } from '@hcengineering/attachment'
+  import { Class, Data, Doc, Ref, Space } from '@hcengineering/core'
   import { getClient } from '@hcengineering/presentation'
   import { Button, IconAdd } from '@hcengineering/ui'
   import { createEventDispatcher } from 'svelte'
   import { createAttachments } from '../utils'
+  import attachment from '../plugin'
 
   export let loading: number = 0
   export let inputFile: HTMLInputElement
@@ -25,6 +27,8 @@
   export let objectClass: Ref<Class<Doc>>
   export let objectId: Ref<Doc>
   export let space: Ref<Space>
+  export let attachmentClass: Ref<Class<Attachment>> = attachment.class.Attachment
+  export let attachmentClassOptions: Partial<Data<Attachment>> = {}
 
   const client = getClient()
   const dispatch = createEventDispatcher()
@@ -35,7 +39,7 @@
 
     loading++
     try {
-      await createAttachments(client, list, { objectClass, objectId, space })
+      await createAttachments(client, list, { objectClass, objectId, space }, attachmentClass, attachmentClassOptions)
     } finally {
       loading--
     }
diff --git a/plugins/attachment-resources/src/components/Attachments.svelte b/plugins/attachment-resources/src/components/Attachments.svelte
index de3a2de284..b809a4ec08 100644
--- a/plugins/attachment-resources/src/components/Attachments.svelte
+++ b/plugins/attachment-resources/src/components/Attachments.svelte
@@ -14,9 +14,10 @@
 // limitations under the License.
 -->
 <script lang="ts">
-  import { Class, Doc, DocumentQuery, Ref, Space } from '@hcengineering/core'
-  import { Icon, Label, Spinner, resizeObserver, Scroller } from '@hcengineering/ui'
-  import view from '@hcengineering/view'
+  import { Attachment } from '@hcengineering/attachment'
+  import { Class, Data, Doc, DocumentQuery, Ref, Space } from '@hcengineering/core'
+  import { Icon, Label, resizeObserver, Scroller, Spinner } from '@hcengineering/ui'
+  import view, { BuildModelKey } from '@hcengineering/view'
   import { Table } from '@hcengineering/view-resources'
   import attachment from '../plugin'
   import AddAttachment from './AddAttachment.svelte'
@@ -28,7 +29,11 @@
   export let space: Ref<Space>
   export let _class: Ref<Class<Doc>>
   export let query: DocumentQuery<Doc> = {}
-
+  export let attachmentClass: Ref<Class<Attachment>> = attachment.class.Attachment
+  export let attachmentClassOptions: Partial<Data<Attachment>> = {}
+  export let extraConfig: (BuildModelKey | string)[] = []
+  export let readonly = false
+  export let showHeader = true
   export let attachments: number | undefined = undefined
 
   let inputFile: HTMLInputElement
@@ -40,19 +45,33 @@
 <div class="antiSection" use:resizeObserver={(element) => (wSection = element.clientWidth)}>
   <div class="antiSection-header">
     <div class="antiSection-header__icon">
-      <Icon icon={IconAttachment} size={'small'} />
+      {#if showHeader}
+        <Icon icon={IconAttachment} size={'small'} />
+      {/if}
     </div>
-    <span class="antiSection-header__title"><Label label={attachment.string.Attachments} /></span>
+    <span class="antiSection-header__title">
+      {#if showHeader}
+        <Label label={attachment.string.Attachments} />
+      {/if}
+    </span>
     <div class="buttons-group small-gap">
       {#if loading}
         <Spinner />
-      {:else}
-        <AddAttachment bind:loading bind:inputFile objectClass={_class} {objectId} {space} />
+      {:else if !readonly}
+        <AddAttachment
+          bind:loading
+          bind:inputFile
+          objectClass={_class}
+          {objectId}
+          {space}
+          {attachmentClass}
+          {attachmentClassOptions}
+        />
       {/if}
     </div>
   </div>
 
-  {#if !loading && (attachments === null || attachments === 0)}
+  {#if !loading && (attachments === null || attachments === 0) && !readonly}
     <AttachmentDroppable bind:loading bind:dragover objectClass={_class} {objectId} {space}>
       <div class="antiSection-empty attachments flex-col mt-3" class:solid={dragover}>
         <div class="flex-center content-accent-color">
@@ -74,7 +93,7 @@
   {:else if wSection < 640}
     <Scroller horizontal>
       <Table
-        _class={attachment.class.Attachment}
+        _class={attachmentClass}
         config={[
           '',
           'description',
@@ -84,6 +103,7 @@
             label: attachment.string.Pinned,
             sortingKey: 'pinned'
           },
+          ...extraConfig,
           'lastModified'
         ]}
         options={{ sort: { pinned: -1 } }}
@@ -92,11 +112,12 @@
         on:content={(evt) => {
           attachments = evt.detail.length
         }}
+        {readonly}
       />
     </Scroller>
   {:else}
     <Table
-      _class={attachment.class.Attachment}
+      _class={attachmentClass}
       config={[
         '',
         'description',
@@ -106,6 +127,7 @@
           label: attachment.string.Pinned,
           sortingKey: 'pinned'
         },
+        ...extraConfig,
         'lastModified'
       ]}
       options={{ sort: { pinned: -1 } }}
@@ -114,6 +136,7 @@
       on:content={(evt) => {
         attachments = evt.detail.length
       }}
+      {readonly}
     />
   {/if}
 </div>
diff --git a/plugins/attachment-resources/src/utils.ts b/plugins/attachment-resources/src/utils.ts
index 17f75790a1..e725d9f0be 100644
--- a/plugins/attachment-resources/src/utils.ts
+++ b/plugins/attachment-resources/src/utils.ts
@@ -14,7 +14,8 @@
 // limitations under the License.
 //
 
-import type { Class, Doc, Ref, Space, TxOperations as Client } from '@hcengineering/core'
+import { Attachment } from '@hcengineering/attachment'
+import type { Class, Data, Doc, Ref, Space, TxOperations as Client } from '@hcengineering/core'
 import login from '@hcengineering/login'
 import { getMetadata, setPlatformStatus, unknownError } from '@hcengineering/platform'
 
@@ -77,7 +78,9 @@ export async function deleteFile (id: string): Promise<void> {
 export async function createAttachments (
   client: Client,
   list: FileList,
-  attachTo: { objectClass: Ref<Class<Doc>>, space: Ref<Space>, objectId: Ref<Doc> }
+  attachTo: { objectClass: Ref<Class<Doc>>, space: Ref<Space>, objectId: Ref<Doc> },
+  attachmentClass: Ref<Class<Attachment>> = attachment.class.Attachment,
+  extraData: Partial<Data<Attachment>> = {}
 ): Promise<void> {
   const { objectClass, objectId, space } = attachTo
   try {
@@ -85,7 +88,8 @@ export async function createAttachments (
       const file = list.item(index)
       if (file !== null) {
         const uuid = await uploadFile(file, { space, attachedTo: objectId })
-        await client.addCollection(attachment.class.Attachment, space, objectId, objectClass, 'attachments', {
+        await client.addCollection(attachmentClass, space, objectId, objectClass, 'attachments', {
+          ...extraData,
           name: file.name,
           file: uuid,
           type: file.type,
diff --git a/plugins/view-resources/src/components/ClassAttributeBar.svelte b/plugins/view-resources/src/components/ClassAttributeBar.svelte
index 58f8c07807..8a907b3f41 100644
--- a/plugins/view-resources/src/components/ClassAttributeBar.svelte
+++ b/plugins/view-resources/src/components/ClassAttributeBar.svelte
@@ -29,6 +29,7 @@
   export let showLabel: IntlString | undefined = undefined
   export let defaultCollapsed = false
   export let draft = false
+  export let showHeader: boolean = true
 
   const client = getClient()
   const hierarchy = client.getHierarchy()
@@ -47,42 +48,44 @@
 </script>
 
 <!-- svelte-ignore a11y-click-events-have-key-events -->
-<div
-  class="attrbar-header"
-  class:collapsed
-  on:click={() => {
-    collapsed = !collapsed
-  }}
->
-  <div class="flex-row-center">
-    <span class="overflow-label">
-      <Label {label} />
-    </span>
-    <div class="icon-arrow">
-      <svg fill="var(--dark-color)" viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg">
-        <path d="M0,0L6,3L0,6Z" />
-      </svg>
+{#if showHeader}
+  <div
+    class="attrbar-header"
+    class:collapsed
+    on:click={() => {
+      collapsed = !collapsed
+    }}
+  >
+    <div class="flex-row-center">
+      <span class="overflow-label">
+        <Label {label} />
+      </span>
+      <div class="icon-arrow">
+        <svg fill="var(--dark-color)" viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg">
+          <path d="M0,0L6,3L0,6Z" />
+        </svg>
+      </div>
+    </div>
+    <div class="tool">
+      <Button
+        icon={setting.icon.Setting}
+        kind={'transparent'}
+        showTooltip={{ label: setting.string.ClassSetting }}
+        on:click={(ev) => {
+          ev.stopPropagation()
+          const loc = getCurrentLocation()
+          loc.path[2] = settingId
+          loc.path[3] = 'setting'
+          loc.path[4] = 'classes'
+          loc.path.length = 5
+          loc.query = { _class }
+          loc.fragment = undefined
+          navigate(loc)
+        }}
+      />
     </div>
   </div>
-  <div class="tool">
-    <Button
-      icon={setting.icon.Setting}
-      kind={'transparent'}
-      showTooltip={{ label: setting.string.ClassSetting }}
-      on:click={(ev) => {
-        ev.stopPropagation()
-        const loc = getCurrentLocation()
-        loc.path[2] = settingId
-        loc.path[3] = 'setting'
-        loc.path[4] = 'classes'
-        loc.path.length = 5
-        loc.query = { _class }
-        loc.fragment = undefined
-        navigate(loc)
-      }}
-    />
-  </div>
-</div>
+{/if}
 {#if keys.length}
   <div class="collapsed-container" class:collapsed>
     <AttributesBar {_class} {object} keys={keys.map((p) => p.key)} {readonly} {draft} on:update />
diff --git a/plugins/view-resources/src/components/Table.svelte b/plugins/view-resources/src/components/Table.svelte
index f2dc3f7ad7..dcd2a8213a 100644
--- a/plugins/view-resources/src/components/Table.svelte
+++ b/plugins/view-resources/src/components/Table.svelte
@@ -44,6 +44,7 @@
   export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
   export let config: (BuildModelKey | string)[]
   export let tableId: string | undefined = undefined
+  export let readonly = false
 
   // If defined, will show a number of dummy items before real data will appear.
   export let loadingProps: LoadingProps | undefined = undefined
@@ -243,7 +244,11 @@
             on:mouseover={() => onRow(object)}
             on:focus={() => {}}
             bind:this={refs[row]}
-            on:contextmenu|preventDefault={(ev) => showMenu(ev, object, row)}
+            on:contextmenu|preventDefault={(ev) => {
+              if (!readonly) {
+                showMenu(ev, object, row)
+              }
+            }}
           >
             {#each model as attribute, cell}
               {#if !cell}