Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into staging
Browse files Browse the repository at this point in the history
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
  • Loading branch information
haiodo committed Jan 17, 2025
2 parents 339a62a + 08e4ee5 commit bbdd076
Show file tree
Hide file tree
Showing 63 changed files with 1,147 additions and 176 deletions.
30 changes: 25 additions & 5 deletions dev/tool/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1193,12 +1193,14 @@ export function devTool (

program
.command('copy-s3-datalake')
.description('migrate files from s3 to datalake')
.description('copy files from s3 to datalake')
.option('-w, --workspace <workspace>', 'Selected workspace only', '')
.option('-c, --concurrency <concurrency>', 'Number of files being processed concurrently', '10')
.action(async (cmd: { workspace: string, concurrency: string }) => {
.option('-e, --existing', 'Copy existing blobs', false)
.action(async (cmd: { workspace: string, concurrency: string, existing: boolean }) => {
const params = {
concurrency: parseInt(cmd.concurrency)
concurrency: parseInt(cmd.concurrency),
existing: cmd.existing
}

const storageConfig = storageConfigFromEnv(process.env.STORAGE)
Expand All @@ -1222,14 +1224,32 @@ export function devTool (
workspaces = workspaces
.filter((p) => isActiveMode(p.mode) || isArchivingMode(p.mode))
.filter((p) => cmd.workspace === '' || p.workspace === cmd.workspace)
.sort((a, b) => b.lastVisit - a.lastVisit)
// .sort((a, b) => b.lastVisit - a.lastVisit)
.sort((a, b) => {
if (a.backupInfo !== undefined && b.backupInfo !== undefined) {
return b.backupInfo.blobsSize - a.backupInfo.blobsSize
} else if (b.backupInfo !== undefined) {
return 1
} else if (a.backupInfo !== undefined) {
return -1
} else {
return b.lastVisit - a.lastVisit
}
})
})

const count = workspaces.length
console.log('found workspaces', count)

let index = 0
for (const workspace of workspaces) {
index++
toolCtx.info('processing workspace', { workspace: workspace.workspace, index, count })
toolCtx.info('processing workspace', {
workspace: workspace.workspace,
index,
count,
blobsSize: workspace.backupInfo?.blobsSize ?? 0
})
const workspaceId = getWorkspaceId(workspace.workspace)

for (const config of storages) {
Expand Down
42 changes: 36 additions & 6 deletions dev/tool/src/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ async function retryOnFailure<T> (

export interface CopyDatalakeParams {
concurrency: number
existing: boolean
}

export async function copyToDatalake (
Expand All @@ -281,7 +282,9 @@ export async function copyToDatalake (

let time = Date.now()
let processedCnt = 0
let processedSize = 0
let skippedCnt = 0
let existingCnt = 0
let failedCnt = 0

function printStats (): void {
Expand All @@ -291,14 +294,32 @@ export async function copyToDatalake (
processedCnt,
'skipped',
skippedCnt,
'existing',
existingCnt,
'failed',
failedCnt,
Math.round(duration / 1000) + 's'
Math.round(duration / 1000) + 's',
formatSize(processedSize)
)

time = Date.now()
}

const existing = new Set<string>()

let cursor: string | undefined = ''
let hasMore = true
while (hasMore) {
const res = await datalake.listObjects(ctx, workspaceId, cursor, 1000)
cursor = res.cursor
hasMore = res.cursor !== undefined
for (const blob of res.blobs) {
existing.add(blob.name)
}
}

console.info('found blobs in datalake:', existing.size)

const rateLimiter = new RateLimiter(params.concurrency)

const iterator = await adapter.listStream(ctx, workspaceId)
Expand All @@ -315,6 +336,12 @@ export async function copyToDatalake (
continue
}

if (!params.existing && existing.has(objectName)) {
// TODO handle mutable blobs
existingCnt++
continue
}

await rateLimiter.add(async () => {
try {
await retryOnFailure(
Expand All @@ -323,6 +350,7 @@ export async function copyToDatalake (
async () => {
await copyBlobToDatalake(ctx, workspaceId, blob, config, adapter, datalake)
processedCnt += 1
processedSize += blob.size
},
50
)
Expand Down Expand Up @@ -352,11 +380,6 @@ export async function copyBlobToDatalake (
datalake: DatalakeClient
): Promise<void> {
const objectName = blob._id
const stat = await datalake.statObject(ctx, workspaceId, objectName)
if (stat !== undefined) {
return
}

if (blob.size < 1024 * 1024 * 64) {
// Handle small file
const { endpoint, accessKey: accessKeyId, secretKey: secretAccessKey, region } = config
Expand Down Expand Up @@ -392,3 +415,10 @@ export async function copyBlobToDatalake (
}
}
}

export function formatSize (size: number): string {
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const pow = size === 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
const val = (1.0 * size) / Math.pow(1024, pow)
return `${val.toFixed(2)} ${units[pow]}`
}
11 changes: 11 additions & 0 deletions models/contact/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,17 @@ export function createModel (builder: Builder): void {
contact.channelProvider.Profile
)

builder.createDoc(
contact.class.ChannelProvider,
core.space.Model,
{
label: contact.string.Viber,
icon: contact.icon.Viber,
placeholder: contact.string.ViberPlaceholder
},
contact.channelProvider.Viber
)

builder.createDoc(
contact.class.AvatarProvider,
core.space.Model,
Expand Down
2 changes: 2 additions & 0 deletions models/contact/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ export default mergeIds(contactId, contact, {
SkypePlaceholder: '' as IntlString,
Profile: '' as IntlString,
ProfilePlaceholder: '' as IntlString,
Viber: '' as IntlString,
ViberPlaceholder: '' as IntlString,

CurrentEmployee: '' as IntlString,

Expand Down
18 changes: 18 additions & 0 deletions models/controlled-documents/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,24 @@ export function createModel (builder: Builder): void {
provider: documents.function.DocumentIdentifierProvider
})

createAction(
builder,
{
action: documents.actionImpl.TransferDocument,
label: documents.string.Transfer,
icon: view.icon.Move,
input: 'any',
category: view.category.General,
target: documents.class.ProjectDocument,
visibilityTester: documents.function.CanTransferDocument,
context: {
mode: ['context', 'browser'],
group: 'copy'
}
},
documents.action.TransferDocument
)

createAction(
builder,
{
Expand Down
2 changes: 2 additions & 0 deletions models/controlled-documents/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ export default mergeIds(documentsId, documents, {
CreateChildTemplate: '' as ViewAction,
CreateDocument: '' as ViewAction,
CreateTemplate: '' as ViewAction,
TransferTemplate: '' as ViewAction,
DeleteDocument: '' as ViewAction,
ArchiveDocument: '' as ViewAction,
TransferDocument: '' as ViewAction,
EditDocSpace: '' as ViewAction
},
viewlet: {
Expand Down
21 changes: 20 additions & 1 deletion packages/presentation/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,23 @@ export async function getBlobURL (blob: Blob): Promise<string> {
})
}

/**
* @public
*/
export function copyTextToClipboardOldBrowser (text: string): void {
const textarea = document.createElement('textarea')
textarea.value = text
textarea.classList.add('hulyClipboardArea')
document.body.appendChild(textarea)
textarea.select()
try {
document.execCommand('copy')
} catch (err) {
console.error(err)
}
document.body.removeChild(textarea)
}

/**
* @public
*/
Expand All @@ -562,7 +579,9 @@ export async function copyTextToClipboard (text: string | Promise<string>): Prom
await navigator.clipboard.write([clipboardItem])
} catch {
// Fallback to default clipboard API implementation
await navigator.clipboard.writeText(text instanceof Promise ? await text : text)
if (navigator.clipboard != null && typeof navigator.clipboard.writeText === 'function') {
await navigator.clipboard.writeText(text instanceof Promise ? await text : text)
} else copyTextToClipboardOldBrowser(text instanceof Promise ? await text : text)
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/text/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export * from './nodes'
export * from './marks/code'
export * from './marks/colors'
export * from './marks/noteBase'
export * from './marks/inlineComment'
export * from './markdown'
export * from './markdown/serializer'
export * from './markdown/parser'
Expand Down
2 changes: 2 additions & 0 deletions packages/text/src/kits/server-kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { MermaidExtension, mermaidOptions } from '../nodes/mermaid'
import TextAlign from '@tiptap/extension-text-align'
import TextStyle from '@tiptap/extension-text-style'
import { BackgroundColor, TextColor } from '../marks/colors'
import { InlineCommentMark } from '../marks/inlineComment'

const headingLevels: Level[] = [1, 2, 3, 4, 5, 6]

Expand Down Expand Up @@ -84,6 +85,7 @@ export const ServerKit = Extension.create<ServerKitOptions>({
levels: headingLevels
}
}),
InlineCommentMark.configure({}),
CodeBlockExtension.configure(codeBlockOptions),
CodeExtension.configure(codeOptions),
MermaidExtension.configure(mermaidOptions),
Expand Down
87 changes: 87 additions & 0 deletions packages/text/src/marks/inlineComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

import { Mark } from '@tiptap/core'
import { Fragment, Node, Slice } from '@tiptap/pm/model'
import { Plugin, PluginKey } from '@tiptap/pm/state'

export const InlineCommentMark = Mark.create({
name: 'inline-comment',
excludes: '',

inclusive: false,

parseHTML () {
return [
{
tag: 'span.proseInlineComment[data-inline-comment-thread]'
}
]
},

renderHTML ({ HTMLAttributes, mark }) {
return ['span', { ...HTMLAttributes, class: 'proseInlineComment' }, 0]
},

addAttributes () {
const name = 'data-inline-comment-thread-id'
return {
thread: {
default: undefined,
parseHTML: (element) => {
return element.getAttribute(name)
},
renderHTML: (attributes) => {
return { [name]: attributes.thread }
}
}
}
},

addProseMirrorPlugins () {
return [...(this.parent?.() ?? []), InlineCommentPasteFixPlugin()]
}
})

function removeMarkFromNode (node: Node, name: string): Node {
if (node.isText) {
return node.mark(node.marks.filter((mark) => mark.type.name !== name))
}

if (node.content.size > 0) {
const nodes: Node[] = []
node.content.forEach((child) => {
nodes.push(removeMarkFromNode(child, name))
})
return node.copy(Fragment.fromArray(nodes))
}

return node
}

export function InlineCommentPasteFixPlugin (): Plugin {
return new Plugin({
key: new PluginKey('inline-comment-paste-fix-plugin'),
props: {
transformPasted: (slice) => {
const nodes: Node[] = []
slice.content.forEach((node) => {
nodes.push(removeMarkFromNode(node, 'inline-comment'))
})
return new Slice(Fragment.fromArray(nodes), slice.openStart, slice.openEnd)
}
}
})
}
2 changes: 2 additions & 0 deletions packages/text/src/nodes/codeblock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export const backtickInputRegex = /^```$/
export const tildeInputRegex = /^~~~$/

export const CodeBlockExtension = CodeBlock.extend({
marks: 'inline-comment',

addAttributes () {
return {
language: {
Expand Down
1 change: 1 addition & 0 deletions packages/text/src/nodes/mermaid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const mermaidOptions: CodeBlockOptions = {
export const MermaidExtension = CodeBlock.extend({
name: 'mermaid',
group: 'block',
marks: 'inline-comment',

parseHTML () {
return [
Expand Down
2 changes: 2 additions & 0 deletions packages/theme/styles/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
--theme-text-editor-note-anchor-bg-primary-light: #747C81;

--text-editor-table-border-color: hsl(220, 6%, 40%);
--text-editor-color-picker-outline: rgba(250, 222, 201, 0.3);

--theme-text-editor-palette-text-gray: rgba(155, 155, 155, 1);
--theme-text-editor-palette-text-brown: rgba(186, 133, 111, 1);
Expand Down Expand Up @@ -531,6 +532,7 @@
--theme-text-editor-note-anchor-bg-primary-light: #D5E5F5;

--text-editor-table-border-color: #c9cbcd;
--text-editor-color-picker-outline: rgb(227, 226, 224);

--theme-text-editor-palette-text-gray: rgba(120, 119, 116, 1);
--theme-text-editor-palette-text-brown: rgba(159, 107, 83, 1);
Expand Down
Loading

0 comments on commit bbdd076

Please sign in to comment.