mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-26 06:12:23 +02:00
Move services to public (#6156)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
<script lang="ts">
|
||||
import { AttachedDoc, Ref, WithLookup } from '@hcengineering/core'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import presentation, { NavLink, getClient, isAdminUser } from '@hcengineering/presentation'
|
||||
import MessageBox from '@hcengineering/presentation/src/components/MessageBox.svelte'
|
||||
import tracker, { Project } from '@hcengineering/tracker'
|
||||
import ui, {
|
||||
Action,
|
||||
Button,
|
||||
Expandable,
|
||||
Icon,
|
||||
IconColStar,
|
||||
IconMoreV,
|
||||
Label,
|
||||
Menu,
|
||||
SearchEdit,
|
||||
TimeSince,
|
||||
getEventPositionElement,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { ObjectPresenter } from '@hcengineering/view-resources'
|
||||
import { GithubIntegration, GithubIntegrationRepository, GithubProject } from '@hcengineering/github'
|
||||
import github from '../plugin'
|
||||
import ConnectProject from './ConnectProject.svelte'
|
||||
import { githubLanguageColors } from './languageColors'
|
||||
import { sendGHServiceRequest } from './utils'
|
||||
|
||||
export let integration: WithLookup<GithubIntegration>
|
||||
export let projects: Project[] = []
|
||||
export let giProjects: GithubProject[] = []
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const asRepos = (docs: AttachedDoc[]) => docs as GithubIntegrationRepository[]
|
||||
let search: string = ''
|
||||
|
||||
let limit = 5
|
||||
|
||||
async function disconnect (prj: GithubProject, repository: GithubIntegrationRepository): Promise<void> {
|
||||
// We need to disable repository first
|
||||
await client.update(repository, {
|
||||
enabled: false,
|
||||
githubProject: null
|
||||
})
|
||||
await client.update(prj, {
|
||||
$pull: { repositories: repository._id }
|
||||
})
|
||||
// // We need to delete all issues related to repository
|
||||
// const ops = client.apply('cleanup:' + repository._id)
|
||||
// const issuesQuery = await client.findAll(
|
||||
// github.mixin.GithubIssue,
|
||||
// {
|
||||
// space: prj._id as Ref<Project>,
|
||||
// repository: repository._id
|
||||
// },
|
||||
// { projection: { _id: 1, _class: 1 } }
|
||||
// )
|
||||
// for (const i of issuesQuery) {
|
||||
// await ops.removeDoc(i._class, prj._id, i._id)
|
||||
// }
|
||||
// const docInfo = await client.findAll(
|
||||
// github.class.DocSyncInfo,
|
||||
// {
|
||||
// space: prj._id as Ref<Project>,
|
||||
// repository: repository._id
|
||||
// },
|
||||
// { projection: { _id: 1, _class: 1 } }
|
||||
// )
|
||||
// for (const i of docInfo) {
|
||||
// await ops.removeDoc(i._class, prj._id, i._id)
|
||||
// }
|
||||
// await ops.commit()
|
||||
}
|
||||
|
||||
async function onDisconnect (
|
||||
event: MouseEvent,
|
||||
prj: GithubProject,
|
||||
repository: GithubIntegrationRepository
|
||||
): Promise<void> {
|
||||
const issuesQuery = await client.findAll(
|
||||
github.mixin.GithubIssue,
|
||||
{
|
||||
space: prj._id as Ref<Project>,
|
||||
repository: repository._id
|
||||
},
|
||||
{ total: true, limit: 1 }
|
||||
)
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
label: github.string.UnlinkRepository,
|
||||
message: github.string.UnlinkMessage,
|
||||
params: { repositoryName: repository.name, prjName: prj.name, total: issuesQuery.total },
|
||||
richMessage: true
|
||||
},
|
||||
undefined,
|
||||
async (res) => {
|
||||
if (res === true) {
|
||||
void disconnect(prj, repository)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
$: repos = asRepos(integration.$lookup?.repositories ?? [])
|
||||
.filter((it) => it.name.toLowerCase().includes(search))
|
||||
.sort((a, b) => {
|
||||
const aprj = giProjects.find((it) => it.repositories.includes(a._id))
|
||||
const bprj = giProjects.find((it) => it.repositories.includes(b._id))
|
||||
|
||||
if (aprj !== undefined && bprj === undefined) {
|
||||
return -1
|
||||
}
|
||||
if (bprj !== undefined && aprj === undefined) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return (b.updatedAt ?? 0) - (a.updatedAt ?? 0)
|
||||
})
|
||||
|
||||
async function showMenu (evt: MouseEvent, prj: GithubProject, repository: GithubIntegrationRepository): Promise<void> {
|
||||
if (isAdminUser()) {
|
||||
const actions: Action[] = [
|
||||
{
|
||||
label: !repository.enabled ? github.string.Enable : github.string.Disable,
|
||||
action: async (props: any, ev: Event) => {
|
||||
void client.update(repository, { enabled: !repository.enabled })
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
showPopup(
|
||||
Menu,
|
||||
{
|
||||
actions
|
||||
},
|
||||
getEventPositionElement(evt),
|
||||
() => {}
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Expandable expanded={true}>
|
||||
<svelte:fragment slot="title">
|
||||
<span class="fs-title flex-row-center flex-between flex-grow flex">
|
||||
<div class="ml-2 mr-2">
|
||||
<img class="svg-large" src={integration.name.replace('github.com', 'avatars.githubusercontent.com')} />
|
||||
</div>
|
||||
{#if integration.name.length > 0}
|
||||
{integration.name}
|
||||
{#if (integration.type ?? '') !== ''}
|
||||
({integration.type})
|
||||
{/if}
|
||||
{:else}
|
||||
<Label label={github.string.ConnectionPending} />
|
||||
{/if}
|
||||
{#if !integration.alive}
|
||||
<Label label={github.string.Closed} />
|
||||
{/if}
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="tools">
|
||||
<Button
|
||||
kind={'dangerous'}
|
||||
label={github.string.RemoveInstallation}
|
||||
on:click={() => {
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
label: github.string.UnlinkInstallationTitle,
|
||||
message: github.string.UnlinkInstallation,
|
||||
params: {},
|
||||
richMessage: true
|
||||
},
|
||||
undefined,
|
||||
async (res) => {
|
||||
if (res !== null) {
|
||||
await sendGHServiceRequest('installation-remove', {
|
||||
installationId: integration.installationId,
|
||||
token: getMetadata(presentation.metadata.Token) ?? ''
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<div class="flex flex-row-center flex-between m-0-5">
|
||||
<SearchEdit bind:value={search} width={'100%'} />
|
||||
</div>
|
||||
{#each repos.slice(0, limit) as repository}
|
||||
{@const prj = giProjects.find((it) => it.repositories.includes(repository._id))}
|
||||
<div
|
||||
class="repository-card flex-col m-0-5"
|
||||
class:selected={prj !== undefined}
|
||||
class:disabled={prj !== undefined && !repository.enabled}
|
||||
>
|
||||
<div class="flex flex-row-center flex-between">
|
||||
<div class="flex-row-center">
|
||||
<NavLink href={repository.htmlURL}>{repository.name}</NavLink>
|
||||
<div class="ml-2 visibility">
|
||||
{repository.visibility}
|
||||
</div>
|
||||
{#if !repository.enabled && prj !== undefined}
|
||||
<div class="ml-2 visibility">
|
||||
<Label label={github.string.Disabled} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row-center">
|
||||
{#if prj !== undefined}
|
||||
<div class="mr-2">
|
||||
<Label label={github.string.LinkedWith} />
|
||||
</div>
|
||||
<ObjectPresenter _class={prj._class} objectId={prj._id} value={prj} />
|
||||
<div class="ml-2">
|
||||
<Button
|
||||
kind={'dangerous'}
|
||||
label={github.string.UnlinkFromProject}
|
||||
size={'medium'}
|
||||
on:click={(evt) => {
|
||||
void onDisconnect(evt, prj, repository)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-2">
|
||||
<Button
|
||||
icon={IconMoreV}
|
||||
size={'small'}
|
||||
on:click={(evt) => {
|
||||
void showMenu(evt, prj, repository)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<ConnectProject {integration} {repository} {projects} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
{repository.description ?? ''}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row-center mt-4">
|
||||
{#if repository.language != null}
|
||||
<div class="flex-row-center mr-4">
|
||||
<div class="lcolor-pin mr-1" style:background-color={githubLanguageColors[repository.language] ?? ''} />
|
||||
{repository.language}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex-row-center">
|
||||
<Icon icon={IconColStar} fill={'none'} size={'small'} />
|
||||
<span class="ml-1">{repository.stargazers ?? 0}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-row-center ml-4">
|
||||
<Icon icon={github.icon.Forks} size={'small'} />
|
||||
<span class="ml-1">{repository.forks ?? 0}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-row-center ml-4">
|
||||
<Icon icon={tracker.icon.Issue} size={'small'} />
|
||||
<span class="ml-1">{repository.openIssues ?? 0}</span>
|
||||
</div>
|
||||
|
||||
{#if repository.updatedAt !== undefined}
|
||||
<div class="flex-row-center ml-4">
|
||||
<Label label={github.string.Updated} />
|
||||
<span class="ml-2">
|
||||
<TimeSince value={repository.updatedAt} />
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{#if repos.length > limit}
|
||||
<Button
|
||||
label={ui.string.ShowMore}
|
||||
on:click={() => {
|
||||
limit = limit + 10
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</Expandable>
|
||||
|
||||
<style lang="scss">
|
||||
.bordered {
|
||||
border: 1px dashed var(--theme-divider-color);
|
||||
}
|
||||
.repository-card {
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
&.selected {
|
||||
background-color: var(--theme-divider-color);
|
||||
}
|
||||
&.disabled {
|
||||
border-color: red;
|
||||
}
|
||||
}
|
||||
.visibility {
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 2em;
|
||||
padding: 0 7px;
|
||||
height: fit-content;
|
||||
}
|
||||
.lcolor-pin {
|
||||
border-radius: 50%;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: var(--theme-divider-color);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user