mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-26 04:23:58 +03:00
UBERF-4136: New issues from command palette (#3956)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
d474bbf8a7
commit
6b6ec0b658
@ -212,11 +212,34 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
|
||||
mode: ['browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'create'
|
||||
}
|
||||
},
|
||||
override: [tracker.action.NewIssueGlobal]
|
||||
},
|
||||
tracker.action.NewIssue
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
action: view.actionImpl.ShowPopup,
|
||||
actionProps: {
|
||||
component: tracker.component.CreateIssue,
|
||||
element: 'top'
|
||||
},
|
||||
label: tracker.string.NewIssue,
|
||||
icon: tracker.icon.NewIssue,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
category: tracker.category.Tracker,
|
||||
target: core.class.Doc,
|
||||
context: {
|
||||
mode: [],
|
||||
group: 'create'
|
||||
}
|
||||
},
|
||||
tracker.action.NewIssueGlobal
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ import { Class, DOMAIN_MODEL, Ref, Space } from '@hcengineering/core'
|
||||
import { Builder, Mixin, Model, Prop, TypeRef, UX } from '@hcengineering/model'
|
||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||
import { createAction } from '@hcengineering/model-view'
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import { getEmbeddedLabel, type Asset, type IntlString } from '@hcengineering/platform'
|
||||
import view, { KeyBinding } from '@hcengineering/view'
|
||||
import type {
|
||||
Application,
|
||||
@ -69,6 +69,24 @@ export function createModel (builder: Builder): void {
|
||||
builder.mixin(workbench.class.Application, core.class.Class, view.mixin.IgnoreActions, {
|
||||
actions: [view.action.Delete]
|
||||
})
|
||||
|
||||
createAction(builder, {
|
||||
action: view.actionImpl.ShowPopup,
|
||||
actionProps: {
|
||||
component: workbench.component.ServerManager,
|
||||
element: 'content'
|
||||
},
|
||||
label: getEmbeddedLabel('Server statistics'),
|
||||
icon: view.icon.Configure,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
category: view.category.General,
|
||||
target: core.class.Doc,
|
||||
secured: true,
|
||||
context: {
|
||||
mode: ['workbench']
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default workbench
|
||||
|
@ -24,7 +24,8 @@ export default mergeIds(workbenchId, workbench, {
|
||||
ApplicationPresenter: '' as AnyComponent,
|
||||
Archive: '' as AnyComponent,
|
||||
SpaceBrowser: '' as AnyComponent,
|
||||
SpecialView: '' as AnyComponent
|
||||
SpecialView: '' as AnyComponent,
|
||||
ServerManager: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
Application: '' as IntlString,
|
||||
|
@ -436,6 +436,7 @@
|
||||
}
|
||||
|
||||
const checkSibling = (start: boolean = false): void => {
|
||||
if (separator === null) return
|
||||
if (prevElement === null || start) prevElement = separator.previousElementSibling as HTMLElement
|
||||
if (nextElement === null || start) nextElement = separator.nextElementSibling as HTMLElement
|
||||
if (separators && prevElement && separators[index].float !== undefined) {
|
||||
|
@ -99,10 +99,7 @@ export const uis = plugin(uiId, {
|
||||
metadata: {
|
||||
DefaultApplication: '' as Metadata<AnyComponent>,
|
||||
Routes: '' as Metadata<Map<string, AnyComponent>>,
|
||||
Languages: '' as Metadata<string[]>,
|
||||
|
||||
// Will activate network click button
|
||||
ShowNetwork: '' as Metadata<(evt: MouseEvent) => void>
|
||||
Languages: '' as Metadata<string[]>
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -467,6 +467,7 @@ export default plugin(trackerId, {
|
||||
Duplicate: '' as Ref<Action>,
|
||||
Relations: '' as Ref<Action>,
|
||||
NewIssue: '' as Ref<Action>,
|
||||
NewIssueGlobal: '' as Ref<Action>,
|
||||
NewSubIssue: '' as Ref<Action>,
|
||||
EditWorkflowStatuses: '' as Ref<Action>,
|
||||
EditProject: '' as Ref<Action>,
|
||||
|
@ -1,15 +1,33 @@
|
||||
<script lang="ts">
|
||||
import contact, { PersonAccount } from '@hcengineering/contact'
|
||||
import { metricsToRows } from '@hcengineering/core'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Button, IconArrowRight, Loading, Panel, Scroller, TabItem, TabList, ticker } from '@hcengineering/ui'
|
||||
import login from '@hcengineering/login'
|
||||
import { getEmbeddedLabel, getMetadata } from '@hcengineering/platform'
|
||||
import presentation, { createQuery } from '@hcengineering/presentation'
|
||||
import {
|
||||
Button,
|
||||
IconArrowRight,
|
||||
Loading,
|
||||
Panel,
|
||||
Scroller,
|
||||
TabItem,
|
||||
TabList,
|
||||
closePopup,
|
||||
fetchMetadataLocalStorage,
|
||||
ticker
|
||||
} from '@hcengineering/ui'
|
||||
import EditBox from '@hcengineering/ui/src/components/EditBox.svelte'
|
||||
import Expandable from '@hcengineering/ui/src/components/Expandable.svelte'
|
||||
import { ObjectPresenter } from '@hcengineering/view-resources'
|
||||
import { onDestroy } from 'svelte'
|
||||
|
||||
export let endpoint: string
|
||||
export let token: string
|
||||
const _endpoint: string = fetchMetadataLocalStorage(login.metadata.LoginEndpoint) ?? ''
|
||||
const token: string = getMetadata(presentation.metadata.Token) ?? ''
|
||||
|
||||
let endpoint = _endpoint.replace(/^ws/g, 'http')
|
||||
if (endpoint.endsWith('/')) {
|
||||
endpoint = endpoint.substring(0, endpoint.length - 1)
|
||||
}
|
||||
|
||||
let data: any
|
||||
let admin = false
|
||||
@ -18,6 +36,9 @@
|
||||
fetch(endpoint + `/api/v1/statistics?token=${token}`, {}).then(async (json) => {
|
||||
data = await json.json()
|
||||
admin = data?.admin ?? false
|
||||
if (admin === false) {
|
||||
closePopup()
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
@ -47,6 +68,7 @@
|
||||
string,
|
||||
{
|
||||
userId: string
|
||||
data?: Record<string, any>
|
||||
total: StatisticsElement
|
||||
mins5: StatisticsElement
|
||||
current: StatisticsElement
|
||||
@ -125,33 +147,63 @@
|
||||
{:else if selectedTab === 'users'}
|
||||
<div class="flex-column p-3 h-full" style:overflow="auto">
|
||||
{#each Object.entries(activeSessions) as act}
|
||||
{@const totalFind = act[1].reduce((it, itm) => itm.current.find + it, 0)}
|
||||
{@const totalTx = act[1].reduce((it, itm) => itm.current.tx + it, 0)}
|
||||
{@const employeeGroups = Array.from(new Set(act[1].map((it) => it.userId)))}
|
||||
<span class="flex-col">
|
||||
<div class="fs-title">
|
||||
Workspace: {act[0]}: {act[1].length}
|
||||
Workspace: {act[0]}: {act[1].length} current 5 mins => {totalFind}/{totalTx}
|
||||
</div>
|
||||
|
||||
<div class="flex-col">
|
||||
{#each act[1] as user}
|
||||
{@const employee = employees.get(user.userId)}
|
||||
<div class="p-1 flex-row-center">
|
||||
{#if employee}
|
||||
<ObjectPresenter
|
||||
_class={contact.mixin.Employee}
|
||||
objectId={employee.person}
|
||||
props={{ shouldShowAvatar: true }}
|
||||
/>
|
||||
{:else}
|
||||
{user.userId}
|
||||
{/if}
|
||||
<div class="p-1">
|
||||
Total: {user.total.find}/{user.total.tx}
|
||||
</div>
|
||||
<div class="p-1">
|
||||
Previous 5 mins: {user.mins5.find}/{user.mins5.tx}
|
||||
</div>
|
||||
<div class="p-1">
|
||||
Current 5 mins: {user.current.find}/{user.current.tx}
|
||||
</div>
|
||||
{#each employeeGroups as employeeId}
|
||||
{@const employee = employees.get(employeeId)}
|
||||
{@const connections = act[1].filter((it) => it.userId === employeeId)}
|
||||
|
||||
{@const find = connections.reduce((it, itm) => itm.current.find + it, 0)}
|
||||
{@const txes = connections.reduce((it, itm) => itm.current.tx + it, 0)}
|
||||
<div class="p-1 flex-col">
|
||||
<Expandable>
|
||||
<svelte:fragment slot="title">
|
||||
<div class="flex-row-center p-1">
|
||||
{#if employee}
|
||||
<ObjectPresenter
|
||||
_class={contact.mixin.Employee}
|
||||
objectId={employee.person}
|
||||
props={{ shouldShowAvatar: true }}
|
||||
/>
|
||||
{:else}
|
||||
{employeeId}
|
||||
{/if}
|
||||
: {connections.length}
|
||||
<div class="ml-4">
|
||||
<div class="ml-1">{find}/{txes}</div>
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{#each connections as user, i}
|
||||
<div class="flex-row-center ml-10">
|
||||
#{i}
|
||||
{user.userId}
|
||||
<div class="p-1">
|
||||
Total: {user.total.find}/{user.total.tx}
|
||||
</div>
|
||||
<div class="p-1">
|
||||
Previous 5 mins: {user.mins5.find}/{user.mins5.tx}
|
||||
</div>
|
||||
<div class="p-1">
|
||||
Current 5 mins: {user.current.find}/{user.current.tx}
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-1 flex-col ml-10">
|
||||
{#each Object.entries(user.data ?? {}) as [k, v]}
|
||||
<div class="p-1">
|
||||
{k}: {JSON.stringify(v)}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</Expandable>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import client from '@hcengineering/client'
|
||||
import core, {
|
||||
AccountClient,
|
||||
AccountRole,
|
||||
Client,
|
||||
ClientConnectEvent,
|
||||
Version,
|
||||
@ -12,15 +11,13 @@ import core, {
|
||||
import login, { loginId } from '@hcengineering/login'
|
||||
import { addEventListener, broadcastEvent, getMetadata, getResource, setMetadata } from '@hcengineering/platform'
|
||||
import presentation, { closeClient, refreshClient, setClient } from '@hcengineering/presentation'
|
||||
import ui, {
|
||||
import {
|
||||
fetchMetadataLocalStorage,
|
||||
getCurrentLocation,
|
||||
navigate,
|
||||
networkStatus,
|
||||
setMetadataLocalStorage,
|
||||
showPopup
|
||||
setMetadataLocalStorage
|
||||
} from '@hcengineering/ui'
|
||||
import ServerManager from './components/ServerManager.svelte'
|
||||
import plugin from './plugin'
|
||||
|
||||
export let versionError: string | undefined = ''
|
||||
@ -186,24 +183,6 @@ export async function connect (title: string): Promise<Client | undefined> {
|
||||
document.title = [ws, title].filter((it) => it).join(' - ')
|
||||
_clientSet = true
|
||||
await setClient(_client)
|
||||
|
||||
if (me.role === AccountRole.Owner) {
|
||||
setMetadata(ui.metadata.ShowNetwork, (evt: MouseEvent) => {
|
||||
if (getMetadata(presentation.metadata.Token) == null) {
|
||||
return
|
||||
}
|
||||
if (getCurrentAccount()?.role === AccountRole.Owner) {
|
||||
showPopup(
|
||||
ServerManager,
|
||||
{
|
||||
endpoint: serverEndpoint,
|
||||
token
|
||||
},
|
||||
'content'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
await broadcastEvent(plugin.event.NotifyConnection, getCurrentAccount())
|
||||
|
||||
return _client
|
||||
|
@ -23,6 +23,7 @@ import SpecialView from './components/SpecialView.svelte'
|
||||
import WorkbenchApp from './components/WorkbenchApp.svelte'
|
||||
import { doNavigate } from './utils'
|
||||
import Workbench from './components/Workbench.svelte'
|
||||
import ServerManager from './components/ServerManager.svelte'
|
||||
|
||||
async function hasArchiveSpaces (spaces: Space[]): Promise<boolean> {
|
||||
return spaces.find((sp) => sp.archived) !== undefined
|
||||
@ -41,7 +42,8 @@ export default async (): Promise<Resources> => ({
|
||||
SpacePanel,
|
||||
SpecialView,
|
||||
SpaceBrowser,
|
||||
Workbench
|
||||
Workbench,
|
||||
ServerManager
|
||||
},
|
||||
function: {
|
||||
HasArchiveSpaces: hasArchiveSpaces,
|
||||
|
@ -145,12 +145,18 @@ export function startHttpServer (
|
||||
skipUTF8Validation: true
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
wss.on('connection', async (ws: WebSocket, request: any, token: Token, sessionId?: string) => {
|
||||
wss.on('connection', async (ws: WebSocket, request: IncomingMessage, token: Token, sessionId?: string) => {
|
||||
let buffer: Buffer[] | undefined = []
|
||||
|
||||
const data = {
|
||||
remoteAddress: request.socket.remoteAddress ?? '',
|
||||
userAgent: request.headers['user-agent'] ?? '',
|
||||
language: request.headers['accept-language'] ?? ''
|
||||
}
|
||||
const cs: ConnectionSocket = {
|
||||
id: generateId(),
|
||||
close: () => ws.close(),
|
||||
data: () => data,
|
||||
send: async (ctx: MeasureContext, msg, binary, compression) => {
|
||||
if (ws.readyState !== ws.OPEN) {
|
||||
return
|
||||
|
@ -17,6 +17,7 @@ export function getStatistics (ctx: MeasureContext, sessions: SessionManager, ad
|
||||
for (const [k, v] of sessions.workspaces) {
|
||||
data.statistics.activeSessions[k] = Array.from(v.sessions.entries()).map(([k, v]) => ({
|
||||
userId: v.session.getUser(),
|
||||
data: v.socket.data(),
|
||||
mins5: v.session.mins5,
|
||||
total: v.session.total,
|
||||
current: v.session.current
|
||||
|
@ -88,6 +88,7 @@ export interface ConnectionSocket {
|
||||
id: string
|
||||
close: () => void
|
||||
send: (ctx: MeasureContext, msg: Response<any>, binary: boolean, compression: boolean) => Promise<void>
|
||||
data: () => Record<string, any>
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user