mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-29 11:43:49 +00:00
Merge branch 'staging' into develop
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
commit
86494e7fd1
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
"DESKTOP_UPDATES_CHANNEL": "front",
|
"DESKTOP_UPDATES_CHANNEL": "front",
|
||||||
|
|
||||||
"FILES_URL": "https://dl.hc.engineering/blob/:workspace/:blobId",
|
"FILES_URL": "https://dl.hc.engineering/blob/:workspace/:blobId/:filename",
|
||||||
|
|
||||||
"GITHUB_APP": "huly-github-staging",
|
"GITHUB_APP": "huly-github-staging",
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ function defineResource (builder: Builder): void {
|
|||||||
key: '',
|
key: '',
|
||||||
presenter: drive.component.ResourcePresenter,
|
presenter: drive.component.ResourcePresenter,
|
||||||
label: drive.string.Name,
|
label: drive.string.Name,
|
||||||
sortingKey: 'name'
|
sortingKey: 'title'
|
||||||
},
|
},
|
||||||
'$lookup.file.size',
|
'$lookup.file.size',
|
||||||
'comments',
|
'comments',
|
||||||
@ -366,7 +366,7 @@ function defineResource (builder: Builder): void {
|
|||||||
}
|
}
|
||||||
} as FindOptions<Resource>,
|
} as FindOptions<Resource>,
|
||||||
configOptions: {
|
configOptions: {
|
||||||
hiddenKeys: ['name', 'parent', 'path', 'file', 'versions'],
|
hiddenKeys: ['title', 'parent', 'path', 'file', 'versions'],
|
||||||
sortable: true
|
sortable: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -393,7 +393,7 @@ function defineResource (builder: Builder): void {
|
|||||||
viewOptions: {
|
viewOptions: {
|
||||||
groupBy: [],
|
groupBy: [],
|
||||||
orderBy: [
|
orderBy: [
|
||||||
['name', SortingOrder.Ascending],
|
['title', SortingOrder.Ascending],
|
||||||
['$lookup.file.size', SortingOrder.Ascending],
|
['$lookup.file.size', SortingOrder.Ascending],
|
||||||
['$lookup.file.modifiedOn', SortingOrder.Descending]
|
['$lookup.file.modifiedOn', SortingOrder.Descending]
|
||||||
],
|
],
|
||||||
@ -404,14 +404,14 @@ function defineResource (builder: Builder): void {
|
|||||||
key: '',
|
key: '',
|
||||||
presenter: drive.component.ResourcePresenter,
|
presenter: drive.component.ResourcePresenter,
|
||||||
label: drive.string.Name,
|
label: drive.string.Name,
|
||||||
sortingKey: 'name'
|
sortingKey: 'title'
|
||||||
},
|
},
|
||||||
'$lookup.file.size',
|
'$lookup.file.size',
|
||||||
'$lookup.file.modifiedOn',
|
'$lookup.file.modifiedOn',
|
||||||
'createdBy'
|
'createdBy'
|
||||||
],
|
],
|
||||||
configOptions: {
|
configOptions: {
|
||||||
hiddenKeys: ['name', 'parent', 'path', 'file', 'versions'],
|
hiddenKeys: ['title', 'parent', 'path', 'file', 'versions'],
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
|
@ -275,3 +275,19 @@ export interface Storage {
|
|||||||
export interface FulltextStorage {
|
export interface FulltextStorage {
|
||||||
searchFulltext: (query: SearchQuery, options: SearchOptions) => Promise<SearchResult>
|
searchFulltext: (query: SearchQuery, options: SearchOptions) => Promise<SearchResult>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldShowArchived<T extends Doc> (
|
||||||
|
query: DocumentQuery<T>,
|
||||||
|
options: FindOptions<T> | undefined
|
||||||
|
): boolean {
|
||||||
|
if (options?.showArchived !== undefined) {
|
||||||
|
return options.showArchived
|
||||||
|
}
|
||||||
|
if (query._id !== undefined && typeof query._id === 'string') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (query.space !== undefined && typeof query.space === 'string') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -95,13 +95,17 @@
|
|||||||
case 'disabled':
|
case 'disabled':
|
||||||
return { _id: { $nin: ignoreObjects, ..._idExtra } }
|
return { _id: { $nin: ignoreObjects, ..._idExtra } }
|
||||||
case 'fulltext':
|
case 'fulltext':
|
||||||
return { $search: search, _id: { $nin: ignoreObjects, ..._idExtra } }
|
return search !== ''
|
||||||
|
? { $search: search, _id: { $nin: ignoreObjects, ..._idExtra } }
|
||||||
|
: { _id: { $nin: ignoreObjects, ..._idExtra } }
|
||||||
case 'spotlight':
|
case 'spotlight':
|
||||||
return extraItems.length > 0
|
return extraItems.length > 0
|
||||||
? { _id: { $in: extraItems, $nin: ignoreObjects } }
|
? { _id: { $in: extraItems, $nin: ignoreObjects } }
|
||||||
: { _id: { $nin: ignoreObjects, ..._idExtra } }
|
: { _id: { $nin: ignoreObjects, ..._idExtra } }
|
||||||
default:
|
default:
|
||||||
return { [searchField]: { $like: '%' + search + '%' }, _id: { $nin: ignoreObjects, ..._idExtra } }
|
return search !== ''
|
||||||
|
? { [searchField]: { $like: '%' + search + '%' }, _id: { $nin: ignoreObjects, ..._idExtra } }
|
||||||
|
: { _id: { $nin: ignoreObjects, ..._idExtra } }
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// import { Doc } from '@hcengineering/core'
|
// import { Doc } from '@hcengineering/core'
|
||||||
import type { Blob, Ref } from '@hcengineering/core'
|
import type { Blob, Ref } from '@hcengineering/core'
|
||||||
import { Button, Dialog, Label, Spinner } from '@hcengineering/ui'
|
import { Button, Dialog, EmbeddedPDF, Label, Spinner } from '@hcengineering/ui'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import presentation, { getFileUrl } from '..'
|
import presentation, { getFileUrl } from '..'
|
||||||
import ActionContext from './ActionContext.svelte'
|
import ActionContext from './ActionContext.svelte'
|
||||||
@ -45,22 +45,9 @@
|
|||||||
})
|
})
|
||||||
let download: HTMLAnchorElement
|
let download: HTMLAnchorElement
|
||||||
|
|
||||||
$: srcRef = file !== undefined ? getFileUrl(file, name) : undefined
|
$: src = file !== undefined ? getFileUrl(file, name) : undefined
|
||||||
|
|
||||||
$: isImage = contentType !== undefined && contentType.startsWith('image/')
|
$: isImage = contentType !== undefined && contentType.startsWith('image/')
|
||||||
|
|
||||||
let frame: HTMLIFrameElement | undefined = undefined
|
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
|
||||||
$: if (css !== undefined && frame !== undefined && frame !== null) {
|
|
||||||
frame.onload = () => {
|
|
||||||
const head = frame?.contentDocument?.querySelector('head')
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
|
||||||
if (css !== undefined && head !== undefined && head !== null) {
|
|
||||||
head.appendChild(document.createElement('style')).textContent = css
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ActionContext context={{ mode: 'browser' }} />
|
<ActionContext context={{ mode: 'browser' }} />
|
||||||
@ -85,41 +72,37 @@
|
|||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
<svelte:fragment slot="utils">
|
<svelte:fragment slot="utils">
|
||||||
{#await srcRef then src}
|
{#if !isLoading && src !== ''}
|
||||||
{#if !isLoading && src !== ''}
|
<a class="no-line" href={src} download={name} bind:this={download}>
|
||||||
<a class="no-line" href={src} download={name} bind:this={download}>
|
<Button
|
||||||
<Button
|
icon={Download}
|
||||||
icon={Download}
|
kind={'ghost'}
|
||||||
kind={'ghost'}
|
on:click={() => {
|
||||||
on:click={() => {
|
download.click()
|
||||||
download.click()
|
}}
|
||||||
}}
|
showTooltip={{ label: presentation.string.Download }}
|
||||||
showTooltip={{ label: presentation.string.Download }}
|
/>
|
||||||
/>
|
</a>
|
||||||
</a>
|
{/if}
|
||||||
{/if}
|
|
||||||
{/await}
|
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
{#await srcRef then src}
|
{#if !isLoading}
|
||||||
{#if !isLoading}
|
{#if src === '' || src === undefined}
|
||||||
{#if src === '' || src === undefined}
|
|
||||||
<div class="centered">
|
|
||||||
<Label label={presentation.string.FailedToPreview} />
|
|
||||||
</div>
|
|
||||||
{:else if isImage}
|
|
||||||
<div class="pdfviewer-content img">
|
|
||||||
<img class="img-fit" {src} alt="" />
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<iframe bind:this={frame} class="pdfviewer-content" src={src + '#view=FitH&navpanes=0'} title="" />
|
|
||||||
{/if}
|
|
||||||
{:else}
|
|
||||||
<div class="centered">
|
<div class="centered">
|
||||||
<Spinner size="medium" />
|
<Label label={presentation.string.FailedToPreview} />
|
||||||
</div>
|
</div>
|
||||||
|
{:else if isImage}
|
||||||
|
<div class="pdfviewer-content img">
|
||||||
|
<img class="img-fit" {src} alt="" />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<EmbeddedPDF {src} {name} {css} fit />
|
||||||
{/if}
|
{/if}
|
||||||
{/await}
|
{:else}
|
||||||
|
<div class="centered">
|
||||||
|
<Spinner size="medium" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -54,6 +54,7 @@ import core, {
|
|||||||
getObjectValue,
|
getObjectValue,
|
||||||
matchQuery,
|
matchQuery,
|
||||||
reduceCalls,
|
reduceCalls,
|
||||||
|
shouldShowArchived,
|
||||||
toFindResult
|
toFindResult
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { PlatformError } from '@hcengineering/platform'
|
import { PlatformError } from '@hcengineering/platform'
|
||||||
@ -519,8 +520,7 @@ export class LiveQuery implements WithTx, Client {
|
|||||||
if (q.options?.lookup !== undefined) {
|
if (q.options?.lookup !== undefined) {
|
||||||
options.lookup = q.options?.lookup
|
options.lookup = q.options?.lookup
|
||||||
}
|
}
|
||||||
const showArchived: boolean =
|
const showArchived = shouldShowArchived(q.query, q.options)
|
||||||
options?.showArchived ?? (q.query._id !== undefined && typeof q.query._id === 'string')
|
|
||||||
|
|
||||||
options.showArchived = showArchived
|
options.showArchived = showArchived
|
||||||
const docIdKey = _id + JSON.stringify(options ?? {}) + q._class
|
const docIdKey = _id + JSON.stringify(options ?? {}) + q._class
|
||||||
|
88
packages/ui/src/components/EmbeddedPDF.svelte
Normal file
88
packages/ui/src/components/EmbeddedPDF.svelte
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { onDestroy } from 'svelte'
|
||||||
|
import Loading from './Loading.svelte'
|
||||||
|
|
||||||
|
export let src: string
|
||||||
|
export let name: string
|
||||||
|
export let fit: boolean = false
|
||||||
|
export let css: string | undefined = undefined
|
||||||
|
|
||||||
|
let iframeSrc: string | undefined = undefined
|
||||||
|
|
||||||
|
async function loadFile (src: string): Promise<void> {
|
||||||
|
if (iframeSrc !== undefined) {
|
||||||
|
URL.revokeObjectURL(iframeSrc)
|
||||||
|
iframeSrc = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(src)
|
||||||
|
const blob = await response.blob()
|
||||||
|
iframeSrc = URL.createObjectURL(blob)
|
||||||
|
}
|
||||||
|
|
||||||
|
$: void loadFile(src)
|
||||||
|
|
||||||
|
let iframe: HTMLIFrameElement | undefined = undefined
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||||
|
$: if (css !== undefined && iframe !== undefined && iframe !== null) {
|
||||||
|
iframe.onload = () => {
|
||||||
|
const head = iframe?.contentDocument?.querySelector('head')
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||||
|
if (css !== undefined && head !== undefined && head !== null) {
|
||||||
|
head.appendChild(document.createElement('style')).textContent = css
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iframe.contentDocument !== undefined) {
|
||||||
|
const style = iframe.contentDocument?.querySelector('head style')
|
||||||
|
|
||||||
|
if (style != null) {
|
||||||
|
style.textContent = css
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (iframeSrc !== undefined) {
|
||||||
|
URL.revokeObjectURL(iframeSrc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if iframeSrc}
|
||||||
|
<iframe bind:this={iframe} class:fit src={iframeSrc + '#view=FitH&navpanes=0'} title={name} on:load />
|
||||||
|
{:else}
|
||||||
|
<Loading />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&.fit {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
&:not(.fit) {
|
||||||
|
height: 80vh;
|
||||||
|
min-height: 20rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -280,6 +280,7 @@ export { default as CodeForm } from './components/CodeForm.svelte'
|
|||||||
export { default as CodeInput } from './components/CodeInput.svelte'
|
export { default as CodeInput } from './components/CodeInput.svelte'
|
||||||
export { default as TimeLeft } from './components/TimeLeft.svelte'
|
export { default as TimeLeft } from './components/TimeLeft.svelte'
|
||||||
export { default as SectionEmpty } from './components/SectionEmpty.svelte'
|
export { default as SectionEmpty } from './components/SectionEmpty.svelte'
|
||||||
|
export { default as EmbeddedPDF } from './components/EmbeddedPDF.svelte'
|
||||||
|
|
||||||
export { default as Dock } from './components/Dock.svelte'
|
export { default as Dock } from './components/Dock.svelte'
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
bind:viewlet
|
bind:viewlet
|
||||||
bind:preference
|
bind:preference
|
||||||
bind:loading
|
bind:loading
|
||||||
|
ignoreFragment
|
||||||
viewletQuery={{
|
viewletQuery={{
|
||||||
attachTo: contact.class.Contact,
|
attachTo: contact.class.Contact,
|
||||||
descriptor: view.viewlet.Table
|
descriptor: view.viewlet.Table
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
import { type Blob, type Ref } from '@hcengineering/core'
|
import { type Blob, type Ref } from '@hcengineering/core'
|
||||||
import { getMetadata } from '@hcengineering/platform'
|
import { getMetadata } from '@hcengineering/platform'
|
||||||
import presentation, { BlobMetadata, getFileUrl } from '@hcengineering/presentation'
|
import presentation, { BlobMetadata, getFileUrl } from '@hcengineering/presentation'
|
||||||
import { Spinner, themeStore } from '@hcengineering/ui'
|
import { EmbeddedPDF, Spinner, themeStore } from '@hcengineering/ui'
|
||||||
import { convertToHTML } from '@hcengineering/print'
|
import { convertToHTML } from '@hcengineering/print'
|
||||||
|
|
||||||
export let value: Ref<Blob>
|
export let value: Ref<Blob>
|
||||||
@ -55,7 +55,6 @@
|
|||||||
--scrollbar-bar-color: #e0e0e0;
|
--scrollbar-bar-color: #e0e0e0;
|
||||||
--scrollbar-bar-hover: #90959d;
|
--scrollbar-bar-hover: #90959d;
|
||||||
`
|
`
|
||||||
let oldColors = colors
|
|
||||||
|
|
||||||
$: css = `
|
$: css = `
|
||||||
* {
|
* {
|
||||||
@ -262,29 +261,6 @@
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
let frame: HTMLIFrameElement | undefined = undefined
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
|
||||||
$: if (css !== undefined && frame !== undefined && frame !== null) {
|
|
||||||
frame.onload = () => {
|
|
||||||
const head = frame?.contentDocument?.querySelector('head')
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
|
||||||
if (css !== undefined && head !== undefined && head !== null) {
|
|
||||||
head.appendChild(document.createElement('style')).textContent = css
|
|
||||||
oldColors = colors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$: if (oldColors !== colors && css !== undefined && frame != null) {
|
|
||||||
const style = frame?.contentDocument?.querySelector('head style')
|
|
||||||
|
|
||||||
if (style != null) {
|
|
||||||
style.textContent = css
|
|
||||||
oldColors = colors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if src}
|
{#if src}
|
||||||
@ -293,7 +269,7 @@
|
|||||||
<Spinner size="medium" />
|
<Spinner size="medium" />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<iframe bind:this={frame} src={src + '#view=FitH&navpanes=0'} class="w-full h-full" title={name} />
|
<EmbeddedPDF {src} {name} {css} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -236,6 +236,7 @@
|
|||||||
isRegular: true,
|
isRegular: true,
|
||||||
disableLink: true
|
disableLink: true
|
||||||
}}
|
}}
|
||||||
|
searchField={'code'}
|
||||||
excluded={excludedChangeControl}
|
excluded={excludedChangeControl}
|
||||||
kind={'regular'}
|
kind={'regular'}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
<Table
|
<Table
|
||||||
_class={recruit.class.Applicant}
|
_class={recruit.class.Applicant}
|
||||||
config={preference?.config ?? viewlet.config}
|
config={preference?.config ?? viewlet.config}
|
||||||
|
options={{ showArchived: true }}
|
||||||
query={{ attachedTo: objectId, ...(viewlet?.baseQuery ?? {}) }}
|
query={{ attachedTo: objectId, ...(viewlet?.baseQuery ?? {}) }}
|
||||||
loadingProps={{ length: applications }}
|
loadingProps={{ length: applications }}
|
||||||
{readonly}
|
{readonly}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
_class={recruit.class.Applicant}
|
_class={recruit.class.Applicant}
|
||||||
config={['', '$lookup.space.name', '$lookup.space.company', 'status']}
|
config={['', '$lookup.space.name', '$lookup.space.company', 'status']}
|
||||||
query={{ attachedTo: value._id }}
|
query={{ attachedTo: value._id }}
|
||||||
|
options={{ showArchived: true }}
|
||||||
loadingProps={{ length: value.applications ?? 0 }}
|
loadingProps={{ length: value.applications ?? 0 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -198,6 +198,7 @@
|
|||||||
bind:loading
|
bind:loading
|
||||||
bind:viewlet
|
bind:viewlet
|
||||||
bind:preference
|
bind:preference
|
||||||
|
ignoreFragment
|
||||||
viewletQuery={{
|
viewletQuery={{
|
||||||
attachTo: recruit.mixin.VacancyList,
|
attachTo: recruit.mixin.VacancyList,
|
||||||
descriptor: { $in: [view.viewlet.Table, view.viewlet.List] }
|
descriptor: { $in: [view.viewlet.Table, view.viewlet.List] }
|
||||||
|
@ -146,6 +146,7 @@
|
|||||||
bind:loading
|
bind:loading
|
||||||
bind:viewlet
|
bind:viewlet
|
||||||
bind:preference
|
bind:preference
|
||||||
|
ignoreFragment
|
||||||
viewletQuery={{
|
viewletQuery={{
|
||||||
attachTo: recruit.class.Vacancy,
|
attachTo: recruit.class.Vacancy,
|
||||||
descriptor: { $in: [view.viewlet.Table, view.viewlet.List] }
|
descriptor: { $in: [view.viewlet.Table, view.viewlet.List] }
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Doc, Ref } from '@hcengineering/core'
|
import { Doc, Ref } from '@hcengineering/core'
|
||||||
import presentation from '@hcengineering/presentation'
|
import presentation from '@hcengineering/presentation'
|
||||||
import { Button, Icon, IconAdd, Label, showPopup, Scroller } from '@hcengineering/ui'
|
import { Button, Icon, IconAdd, Label, Scroller, showPopup } from '@hcengineering/ui'
|
||||||
import view, { BuildModelKey } from '@hcengineering/view'
|
import view, { BuildModelKey } from '@hcengineering/view'
|
||||||
import { Table } from '@hcengineering/view-resources'
|
import { Table } from '@hcengineering/view-resources'
|
||||||
import recruit from '../plugin'
|
import recruit from '../plugin'
|
||||||
@ -66,6 +66,7 @@
|
|||||||
_class={recruit.class.Vacancy}
|
_class={recruit.class.Vacancy}
|
||||||
{config}
|
{config}
|
||||||
query={{ company: objectId }}
|
query={{ company: objectId }}
|
||||||
|
options={{ showArchived: true }}
|
||||||
{readonly}
|
{readonly}
|
||||||
loadingProps={{ length: vacancies ?? 0 }}
|
loadingProps={{ length: vacancies ?? 0 }}
|
||||||
/>
|
/>
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import core, { Association, Class, Data, Doc, Ref } from '@hcengineering/core'
|
import core, { Association, Class, Data, Doc, Ref } from '@hcengineering/core'
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery, getClient, MessageBox } from '@hcengineering/presentation'
|
||||||
import { Button, Header, Breadcrumb, Separator, defineSeparators, twoPanelsSeparators } from '@hcengineering/ui'
|
import {
|
||||||
|
Button,
|
||||||
|
Header,
|
||||||
|
Breadcrumb,
|
||||||
|
Separator,
|
||||||
|
defineSeparators,
|
||||||
|
twoPanelsSeparators,
|
||||||
|
IconDelete,
|
||||||
|
showPopup
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import settings from '../plugin'
|
import settings from '../plugin'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view-resources/src/plugin'
|
||||||
import AssociationEditor from './AssociationEditor.svelte'
|
import AssociationEditor from './AssociationEditor.svelte'
|
||||||
|
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
|
const client = getClient()
|
||||||
|
|
||||||
let selected: Association | Data<Association> | undefined
|
let selected: Association | Data<Association> | undefined
|
||||||
|
|
||||||
@ -26,12 +36,37 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAssociation (data: Data<Association> | Association | undefined): data is Association {
|
||||||
|
return (data as Association)?._id !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
defineSeparators('workspaceSettings', twoPanelsSeparators)
|
defineSeparators('workspaceSettings', twoPanelsSeparators)
|
||||||
|
|
||||||
|
async function remove (val: Association | Data<Association> | undefined): Promise<void> {
|
||||||
|
if (isAssociation(val)) {
|
||||||
|
showPopup(MessageBox, {
|
||||||
|
label: view.string.DeleteObject,
|
||||||
|
message: view.string.DeleteObjectConfirm,
|
||||||
|
params: { count: 1 },
|
||||||
|
dangerous: true,
|
||||||
|
action: async () => {
|
||||||
|
selected = undefined
|
||||||
|
await client.remove(val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="hulyComponent">
|
<div class="hulyComponent">
|
||||||
<Header adaptive={'disabled'}>
|
<Header adaptive={'disabled'}>
|
||||||
<Breadcrumb icon={settings.icon.Relations} label={core.string.Relations} size={'large'} isCurrent />
|
<Breadcrumb icon={settings.icon.Relations} label={core.string.Relations} size={'large'} isCurrent />
|
||||||
|
|
||||||
|
<svelte:fragment slot="actions">
|
||||||
|
{#if isAssociation(selected)}
|
||||||
|
<Button icon={IconDelete} label={view.string.Delete} kind={'dangerous'} on:click={() => remove(selected)} />
|
||||||
|
{/if}
|
||||||
|
</svelte:fragment>
|
||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
<div class="hulyComponent-content__container columns">
|
<div class="hulyComponent-content__container columns">
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Class, Doc, DocumentQuery, FindOptions, mergeQueries, Ref, Space, WithLookup } from '@hcengineering/core'
|
import { Class, Doc, DocumentQuery, mergeQueries, Ref, Space, WithLookup } from '@hcengineering/core'
|
||||||
import { IntlString } from '@hcengineering/platform'
|
import { IntlString } from '@hcengineering/platform'
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
import { Project, ProjectType, ProjectTypeDescriptor } from '@hcengineering/task'
|
import { Project, ProjectType, ProjectTypeDescriptor } from '@hcengineering/task'
|
||||||
@ -97,6 +97,7 @@
|
|||||||
bind:viewlet
|
bind:viewlet
|
||||||
bind:preference
|
bind:preference
|
||||||
bind:viewlets
|
bind:viewlets
|
||||||
|
ignoreFragment
|
||||||
viewletQuery={{
|
viewletQuery={{
|
||||||
attachTo: _class,
|
attachTo: _class,
|
||||||
variant: { $exists: false },
|
variant: { $exists: false },
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Analytics } from '@hcengineering/analytics'
|
import { Analytics } from '@hcengineering/analytics'
|
||||||
import { AccountRole, Ref, Space, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
import { AccountRole, Ref, Space, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||||
import { MultipleDraftController, getClient } from '@hcengineering/presentation'
|
import { MultipleDraftController, createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { TrackerEvents } from '@hcengineering/tracker'
|
import { TrackerEvents } from '@hcengineering/tracker'
|
||||||
import { ButtonWithDropdown, IconAdd, IconDropdown, SelectPopupValueType, showPopup } from '@hcengineering/ui'
|
import { Button, ButtonWithDropdown, IconAdd, IconDropdown, SelectPopupValueType, showPopup } from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
|
|
||||||
import { onDestroy } from 'svelte'
|
import { onDestroy } from 'svelte'
|
||||||
@ -44,6 +44,14 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const query = createQuery()
|
||||||
|
|
||||||
|
let projectExists = false
|
||||||
|
|
||||||
|
query.query(tracker.class.Project, {}, (res) => {
|
||||||
|
projectExists = res.length > 0
|
||||||
|
})
|
||||||
|
|
||||||
$: label = draftExists || !closed ? tracker.string.ResumeDraft : tracker.string.NewIssue
|
$: label = draftExists || !closed ? tracker.string.ResumeDraft : tracker.string.NewIssue
|
||||||
$: dropdownItems = hasAccountRole(getCurrentAccount(), AccountRole.User)
|
$: dropdownItems = hasAccountRole(getCurrentAccount(), AccountRole.User)
|
||||||
? [
|
? [
|
||||||
@ -82,30 +90,45 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiNav-subheader">
|
<div class="antiNav-subheader">
|
||||||
<ButtonWithDropdown
|
{#if projectExists}
|
||||||
icon={IconAdd}
|
<ButtonWithDropdown
|
||||||
justify={'left'}
|
icon={IconAdd}
|
||||||
kind={'primary'}
|
justify={'left'}
|
||||||
{label}
|
kind={'primary'}
|
||||||
on:click={newIssue}
|
{label}
|
||||||
{dropdownItems}
|
on:click={newIssue}
|
||||||
dropdownIcon={IconDropdown}
|
{dropdownItems}
|
||||||
on:dropdown-selected={(ev) => {
|
dropdownIcon={IconDropdown}
|
||||||
dropdownItemSelected(ev.detail)
|
on:dropdown-selected={(ev) => {
|
||||||
}}
|
dropdownItemSelected(ev.detail)
|
||||||
mainButtonId={'new-issue'}
|
}}
|
||||||
showTooltipMain={{
|
mainButtonId={'new-issue'}
|
||||||
direction: 'bottom',
|
showTooltipMain={{
|
||||||
label,
|
direction: 'bottom',
|
||||||
keys
|
label,
|
||||||
}}
|
keys
|
||||||
>
|
}}
|
||||||
<div slot="content" class="draft-circle-container">
|
>
|
||||||
{#if draftExists}
|
<div slot="content" class="draft-circle-container">
|
||||||
<div class="draft-circle" />
|
{#if draftExists}
|
||||||
{/if}
|
<div class="draft-circle" />
|
||||||
</div>
|
{/if}
|
||||||
</ButtonWithDropdown>
|
</div>
|
||||||
|
</ButtonWithDropdown>
|
||||||
|
{:else}
|
||||||
|
<Button
|
||||||
|
icon={IconAdd}
|
||||||
|
justify="left"
|
||||||
|
kind="primary"
|
||||||
|
label={tracker.string.CreateProject}
|
||||||
|
width="100%"
|
||||||
|
on:click={() => {
|
||||||
|
showPopup(tracker.component.CreateProject, {}, 'top', () => {
|
||||||
|
closed = true
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -326,25 +326,14 @@ async function deleteProject (project: Project | undefined): Promise<void> {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const anyIssue = await client.findOne(tracker.class.Issue, { space: project._id })
|
const anyIssue = await client.findOne(tracker.class.Issue, { space: project._id })
|
||||||
if (anyIssue !== undefined) {
|
showPopup(MessageBox, {
|
||||||
showPopup(MessageBox, {
|
label: tracker.string.ArchiveProjectName,
|
||||||
label: tracker.string.ArchiveProjectName,
|
labelProps: { name: project.name },
|
||||||
labelProps: { name: project.name },
|
message: anyIssue !== undefined ? tracker.string.ProjectHasIssues : tracker.string.ArchiveProjectConfirm,
|
||||||
message: tracker.string.ProjectHasIssues,
|
action: async () => {
|
||||||
action: async () => {
|
await client.update(project, { archived: true })
|
||||||
await client.update(project, { archived: true })
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
} else {
|
|
||||||
showPopup(MessageBox, {
|
|
||||||
label: tracker.string.ArchiveProjectName,
|
|
||||||
labelProps: { name: project.name },
|
|
||||||
message: tracker.string.ArchiveProjectConfirm,
|
|
||||||
action: async () => {
|
|
||||||
await client.update(project, { archived: true })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,12 @@
|
|||||||
(res) => {
|
(res) => {
|
||||||
configurationRaw = res
|
configurationRaw = res
|
||||||
configurationsLoading = false
|
configurationsLoading = false
|
||||||
|
loading = configurationsLoading || preferencesLoading
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchPreferences (viewlet: Viewlet): void {
|
function fetchPreferences (configurationRaw: Viewlet[]): void {
|
||||||
preferencesLoading = preferenceQuery.query(
|
preferencesLoading = preferenceQuery.query(
|
||||||
view.class.ViewletPreference,
|
view.class.ViewletPreference,
|
||||||
{
|
{
|
||||||
@ -56,6 +57,7 @@
|
|||||||
(res) => {
|
(res) => {
|
||||||
preference = res
|
preference = res
|
||||||
preferencesLoading = false
|
preferencesLoading = false
|
||||||
|
loading = configurationsLoading || preferencesLoading
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -81,7 +83,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$: fetchConfigurations(viewlet)
|
$: fetchConfigurations(viewlet)
|
||||||
$: fetchPreferences(viewlet)
|
$: fetchPreferences(configurationRaw)
|
||||||
|
|
||||||
$: updateConfiguration(configurationRaw, preference)
|
$: updateConfiguration(configurationRaw, preference)
|
||||||
|
|
||||||
@ -90,6 +92,8 @@
|
|||||||
|
|
||||||
{#if viewlet?.$lookup?.descriptor?.component}
|
{#if viewlet?.$lookup?.descriptor?.component}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
|
{configurationsLoading}
|
||||||
|
{preferencesLoading}
|
||||||
<Loading />
|
<Loading />
|
||||||
{:else}
|
{:else}
|
||||||
<Component
|
<Component
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
export let preference: ViewletPreference | undefined = undefined
|
export let preference: ViewletPreference | undefined = undefined
|
||||||
export let loading = true
|
export let loading = true
|
||||||
export let hidden = false
|
export let hidden = false
|
||||||
|
export let ignoreFragment = false
|
||||||
|
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
|
|
||||||
@ -29,11 +30,11 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let key = makeViewletKey()
|
let key = makeViewletKey(undefined, ignoreFragment)
|
||||||
|
|
||||||
onDestroy(
|
onDestroy(
|
||||||
resolvedLocationStore.subscribe((loc) => {
|
resolvedLocationStore.subscribe((loc) => {
|
||||||
key = makeViewletKey(loc)
|
key = makeViewletKey(loc, ignoreFragment)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,25 +15,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type Blob, type Ref } from '@hcengineering/core'
|
import { type Blob, type Ref } from '@hcengineering/core'
|
||||||
import { getFileUrl } from '@hcengineering/presentation'
|
import { getFileUrl } from '@hcengineering/presentation'
|
||||||
|
import { EmbeddedPDF } from '@hcengineering/ui'
|
||||||
|
|
||||||
export let value: Ref<Blob>
|
export let value: Ref<Blob>
|
||||||
export let name: string
|
export let name: string
|
||||||
export let fit: boolean = false
|
export let fit: boolean = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<iframe class:fit src={getFileUrl(value, name) + '#view=FitH&navpanes=0'} title={name} />
|
<EmbeddedPDF src={getFileUrl(value, name)} {name} {fit} />
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
iframe {
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
&.fit {
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
&:not(.fit) {
|
|
||||||
height: 80vh;
|
|
||||||
min-height: 20rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -743,11 +743,11 @@ export function categorizeFields (
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeViewletKey (loc?: Location): string {
|
export function makeViewletKey (loc?: Location, ignoreFragment = false): string {
|
||||||
loc = loc != null ? { path: loc.path, fragment: loc.fragment } : getCurrentResolvedLocation()
|
loc = loc != null ? { path: loc.path, fragment: loc.fragment } : getCurrentResolvedLocation()
|
||||||
loc.query = undefined
|
loc.query = undefined
|
||||||
|
|
||||||
if (loc.fragment != null && loc.fragment !== '') {
|
if (!ignoreFragment && loc.fragment != null && loc.fragment !== '') {
|
||||||
const props = decodeURIComponent(loc.fragment).split('|')
|
const props = decodeURIComponent(loc.fragment).split('|')
|
||||||
if (props.length >= 3) {
|
if (props.length >= 3) {
|
||||||
const [panel, , _class] = props
|
const [panel, , _class] = props
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
{#if space}
|
{#if space}
|
||||||
<Header hideActions={createItemDialog === undefined}>
|
<Header hideActions={createItemDialog === undefined}>
|
||||||
<svelte:fragment slot="beforeTitle">
|
<svelte:fragment slot="beforeTitle">
|
||||||
<ViewletSelector {viewletQuery} bind:viewlet bind:viewlets />
|
<ViewletSelector {viewletQuery} ignoreFragment bind:viewlet bind:viewlets />
|
||||||
<ViewletSettingButton bind:viewOptions bind:viewlet />
|
<ViewletSettingButton bind:viewOptions bind:viewlet />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
|
@ -114,6 +114,7 @@
|
|||||||
bind:viewlet
|
bind:viewlet
|
||||||
bind:preference
|
bind:preference
|
||||||
bind:viewlets
|
bind:viewlets
|
||||||
|
ignoreFragment
|
||||||
viewletQuery={{
|
viewletQuery={{
|
||||||
attachTo: _class,
|
attachTo: _class,
|
||||||
variant: { $exists: false },
|
variant: { $exists: false },
|
||||||
|
@ -758,6 +758,11 @@ export async function backup (
|
|||||||
backupInfo.domainHashes = {}
|
backupInfo.domainHashes = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (backupInfo.domainHashes === undefined) {
|
||||||
|
// Migration
|
||||||
|
backupInfo.domainHashes = {}
|
||||||
|
}
|
||||||
|
|
||||||
let lastTx: Tx | undefined
|
let lastTx: Tx | undefined
|
||||||
|
|
||||||
let lastTxChecked = false
|
let lastTxChecked = false
|
||||||
|
@ -43,6 +43,8 @@ import core, {
|
|||||||
WorkspaceEvent,
|
WorkspaceEvent,
|
||||||
clone,
|
clone,
|
||||||
generateId,
|
generateId,
|
||||||
|
shouldShowArchived,
|
||||||
|
systemAccountEmail,
|
||||||
toFindResult,
|
toFindResult,
|
||||||
type SessionData,
|
type SessionData,
|
||||||
type PersonUuid
|
type PersonUuid
|
||||||
@ -537,7 +539,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
|||||||
const account = ctx.contextData.account
|
const account = ctx.contextData.account
|
||||||
const isSpace = this.context.hierarchy.isDerived(_class, core.class.Space)
|
const isSpace = this.context.hierarchy.isDerived(_class, core.class.Space)
|
||||||
const field = this.getKey(domain)
|
const field = this.getKey(domain)
|
||||||
const showArchived: boolean = options?.showArchived ?? (query._id !== undefined && typeof query._id === 'string')
|
const showArchived: boolean = shouldShowArchived(query, options)
|
||||||
|
|
||||||
let clientFilterSpaces: Set<Ref<Space>> | undefined
|
let clientFilterSpaces: Set<Ref<Space>> | undefined
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ import core, {
|
|||||||
type Ref,
|
type Ref,
|
||||||
type ReverseLookups,
|
type ReverseLookups,
|
||||||
type SessionData,
|
type SessionData,
|
||||||
|
shouldShowArchived,
|
||||||
type SortingQuery,
|
type SortingQuery,
|
||||||
type StorageIterator,
|
type StorageIterator,
|
||||||
systemAccountUuid,
|
systemAccountUuid,
|
||||||
@ -662,7 +663,7 @@ abstract class PostgresAdapterBase implements DbAdapter {
|
|||||||
|
|
||||||
const select = `SELECT ${this.getProjection(vars, domain, options?.projection, joins, options?.associations)} FROM ${domain}`
|
const select = `SELECT ${this.getProjection(vars, domain, options?.projection, joins, options?.associations)} FROM ${domain}`
|
||||||
|
|
||||||
const showArchived = options?.showArchived ?? (query._id !== undefined && typeof query._id === 'string')
|
const showArchived = shouldShowArchived(query, options)
|
||||||
const secJoin = this.addSecurity(vars, query, showArchived, domain, ctx.contextData)
|
const secJoin = this.addSecurity(vars, query, showArchived, domain, ctx.contextData)
|
||||||
if (secJoin !== undefined) {
|
if (secJoin !== undefined) {
|
||||||
sqlChunks.push(secJoin)
|
sqlChunks.push(secJoin)
|
||||||
@ -683,7 +684,7 @@ abstract class PostgresAdapterBase implements DbAdapter {
|
|||||||
let total = options?.total === true ? 0 : -1
|
let total = options?.total === true ? 0 : -1
|
||||||
if (options?.total === true) {
|
if (options?.total === true) {
|
||||||
const pvars = new ValuesVariables()
|
const pvars = new ValuesVariables()
|
||||||
const showArchived = options?.showArchived ?? (query._id !== undefined && typeof query._id === 'string')
|
const showArchived = shouldShowArchived(query, options)
|
||||||
const secJoin = this.addSecurity(pvars, query, showArchived, domain, ctx.contextData)
|
const secJoin = this.addSecurity(pvars, query, showArchived, domain, ctx.contextData)
|
||||||
const totalChunks: string[] = []
|
const totalChunks: string[] = []
|
||||||
if (secJoin !== undefined) {
|
if (secJoin !== undefined) {
|
||||||
@ -860,7 +861,12 @@ abstract class PostgresAdapterBase implements DbAdapter {
|
|||||||
if (key === 'data') {
|
if (key === 'data') {
|
||||||
obj[p] = { ...obj[p], ...row[column] }
|
obj[p] = { ...obj[p], ...row[column] }
|
||||||
} else {
|
} else {
|
||||||
if (key === 'attachedTo' && row[column] === 'NULL') {
|
if (key === 'createdOn' || key === 'modifiedOn') {
|
||||||
|
const val = Number.parseInt(row[column])
|
||||||
|
obj[p][key] = Number.isNaN(val) ? null : val
|
||||||
|
} else if (key === '%hash%') {
|
||||||
|
continue
|
||||||
|
} else if (key === 'attachedTo' && row[column] === 'NULL') {
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
obj[p][key] = row[column] === 'NULL' ? null : row[column]
|
obj[p][key] = row[column] === 'NULL' ? null : row[column]
|
||||||
|
@ -216,7 +216,7 @@ export abstract class IssueSyncManagerBase {
|
|||||||
const target: IssueSyncTarget | undefined =
|
const target: IssueSyncTarget | undefined =
|
||||||
milestone !== undefined
|
milestone !== undefined
|
||||||
? {
|
? {
|
||||||
mappings: milestone.mappings,
|
mappings: milestone.mappings ?? [],
|
||||||
project: prj,
|
project: prj,
|
||||||
target: milestone
|
target: milestone
|
||||||
}
|
}
|
||||||
@ -1167,7 +1167,7 @@ export abstract class IssueSyncManagerBase {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
project,
|
project,
|
||||||
mappings: milestone.mappings,
|
mappings: milestone.mappings ?? [],
|
||||||
target: milestone,
|
target: milestone,
|
||||||
prjData: external.projectItems.nodes.find((it) => it.project.id === milestone.projectNodeId)
|
prjData: external.projectItems.nodes.find((it) => it.project.id === milestone.projectNodeId)
|
||||||
}
|
}
|
||||||
@ -1178,7 +1178,7 @@ export abstract class IssueSyncManagerBase {
|
|||||||
getProjectIssueTarget (project: GithubProject, external?: IssueExternalData): IssueSyncTarget {
|
getProjectIssueTarget (project: GithubProject, external?: IssueExternalData): IssueSyncTarget {
|
||||||
return {
|
return {
|
||||||
project,
|
project,
|
||||||
mappings: project.mappings,
|
mappings: project.mappings ?? [],
|
||||||
target: project,
|
target: project,
|
||||||
prjData: external?.projectItems.nodes.find((it) => it.project.id === project.projectNodeId)
|
prjData: external?.projectItems.nodes.find((it) => it.project.id === project.projectNodeId)
|
||||||
}
|
}
|
||||||
|
@ -610,7 +610,7 @@ export class ProjectsSyncManager implements DocSyncManager {
|
|||||||
okit: Octokit
|
okit: Octokit
|
||||||
): Promise<{ projectStructure: GithubProjectV2, wasUpdates: boolean, mappings: GithubFieldMapping[] }> {
|
): Promise<{ projectStructure: GithubProjectV2, wasUpdates: boolean, mappings: GithubFieldMapping[] }> {
|
||||||
let projectStructure = await this.queryProjectStructure(integration, target)
|
let projectStructure = await this.queryProjectStructure(integration, target)
|
||||||
let mappings = target.mappings
|
let mappings = target.mappings ?? []
|
||||||
|
|
||||||
if (projectStructure === undefined) {
|
if (projectStructure === undefined) {
|
||||||
if (this.client.getHierarchy().isDerived(tracker.class.Project, target._class)) {
|
if (this.client.getHierarchy().isDerived(tracker.class.Project, target._class)) {
|
||||||
@ -653,7 +653,7 @@ export class ProjectsSyncManager implements DocSyncManager {
|
|||||||
const mHash = JSON.stringify(mappings)
|
const mHash = JSON.stringify(mappings)
|
||||||
// Create any platform field into matching github field
|
// Create any platform field into matching github field
|
||||||
for (const [, f] of allFields.entries()) {
|
for (const [, f] of allFields.entries()) {
|
||||||
const existingField = (mappings ?? []).find((it) => it._id === f._id)
|
const existingField = mappings.find((it) => it._id === f._id)
|
||||||
if (f.hidden === true) {
|
if (f.hidden === true) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user