mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
add visualize federation
This commit is contained in:
parent
47fe739c77
commit
a1b8be4329
@ -33,6 +33,7 @@
|
|||||||
"bootstrap": "4.3.1",
|
"bootstrap": "4.3.1",
|
||||||
"bootstrap-vue": "^2.21.2",
|
"bootstrap-vue": "^2.21.2",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"date-fns": "^2.29.3",
|
||||||
"dotenv-webpack": "^7.0.3",
|
"dotenv-webpack": "^7.0.3",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"graphql": "^15.6.1",
|
"graphql": "^15.6.1",
|
||||||
|
|||||||
76
admin/src/components/Fedaration/FederationVisualizeItem.vue
Normal file
76
admin/src/components/Fedaration/FederationVisualizeItem.vue
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<template>
|
||||||
|
<div class="federation-visualize-item">
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="1"><b-icon :icon="icon" :variant="variant" class="mr-4"></b-icon></b-col>
|
||||||
|
<b-col>
|
||||||
|
<div>{{ item.url }}</div>
|
||||||
|
<small>{{ `${item.publicKey.substring(0, 26)}…` }}</small>
|
||||||
|
</b-col>
|
||||||
|
<b-col cols="2">{{ lastAnnouncedAt }}</b-col>
|
||||||
|
<b-col cols="2">{{ createdAt }}</b-col>
|
||||||
|
</b-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { formatDistanceToNow } from 'date-fns'
|
||||||
|
import { de, en, fr, es, nl } from 'date-fns/locale'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FederationVisualizeItem',
|
||||||
|
props: {
|
||||||
|
item: { type: Object },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
oldPublicKey: '',
|
||||||
|
formatDistanceToNow,
|
||||||
|
locale: this.$i18n.locale,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
verified() {
|
||||||
|
return new Date(this.item.verifiedAt) >= new Date(this.item.lastAnnouncedAt)
|
||||||
|
},
|
||||||
|
icon() {
|
||||||
|
return this.verified ? 'check' : 'x-circle'
|
||||||
|
},
|
||||||
|
variant() {
|
||||||
|
return this.verified ? 'success' : 'danger'
|
||||||
|
},
|
||||||
|
fnsLocale() {
|
||||||
|
switch (this.locale) {
|
||||||
|
case 'de':
|
||||||
|
return de
|
||||||
|
case 'es':
|
||||||
|
return es
|
||||||
|
case 'fr':
|
||||||
|
return fr
|
||||||
|
case 'nl':
|
||||||
|
return nl
|
||||||
|
default:
|
||||||
|
return en
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lastAnnouncedAt() {
|
||||||
|
if (this.item.lastAnnouncedAt) {
|
||||||
|
return formatDistanceToNow(new Date(this.item.lastAnnouncedAt), {
|
||||||
|
includeSecond: true,
|
||||||
|
addSuffix: true,
|
||||||
|
locale: this.fnsLocale,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
createdAt() {
|
||||||
|
if (this.item.createdAt) {
|
||||||
|
return formatDistanceToNow(new Date(this.item.createdAt), {
|
||||||
|
includeSecond: true,
|
||||||
|
addSuffix: true,
|
||||||
|
locale: this.fnsLocale,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import FederationVisualizeItem from './FederationVisualizeItem.vue'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$t: (key) => key,
|
||||||
|
$i18n: {
|
||||||
|
locale: 'de',
|
||||||
|
t: (key) => key,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('FederationVisualizeItem', () => {
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
const propsData = {
|
||||||
|
item: {
|
||||||
|
id: 7590,
|
||||||
|
foreign: false,
|
||||||
|
publicKey: 'eaf6a426b24fd54f8fbae11c17700fc595080ca25159579c63d38dbc64284ba7',
|
||||||
|
url: 'http://localhost/api/api/2_0',
|
||||||
|
lastAnnouncedAt: null,
|
||||||
|
verifiedAt: null,
|
||||||
|
lastErrorAt: null,
|
||||||
|
createdAt: '2023-03-29T04:46:38.823Z',
|
||||||
|
updatedAt: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(FederationVisualizeItem, { localVue, mocks, propsData })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the component', () => {
|
||||||
|
expect(wrapper.find('div.federation-visualize-item').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -62,8 +62,12 @@ describe('NavBar', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('has a link to /federation', () => {
|
||||||
|
expect(wrapper.findAll('.nav-item').at(3).find('a').attributes('href')).toBe('/federation')
|
||||||
|
})
|
||||||
|
|
||||||
it('has a link to /statistic', () => {
|
it('has a link to /statistic', () => {
|
||||||
expect(wrapper.findAll('.nav-item').at(3).find('a').attributes('href')).toBe('/statistic')
|
expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe('/statistic')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -72,7 +76,7 @@ describe('NavBar', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
delete window.location
|
delete window.location
|
||||||
window.location = ''
|
window.location = ''
|
||||||
await wrapper.findAll('.nav-item').at(4).find('a').trigger('click')
|
await wrapper.findAll('.nav-item').at(5).find('a').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -97,7 +101,7 @@ describe('NavBar', () => {
|
|||||||
window.location = {
|
window.location = {
|
||||||
assign: windowLocationMock,
|
assign: windowLocationMock,
|
||||||
}
|
}
|
||||||
await wrapper.findAll('.nav-item').at(5).find('a').trigger('click')
|
await wrapper.findAll('.nav-item').at(6).find('a').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="component-nabvar">
|
<div class="component-nabvar">
|
||||||
<b-navbar toggleable="md" type="dark" variant="success">
|
<b-navbar toggleable="lg" type="dark" class="bg-dark">
|
||||||
<b-navbar-brand class="mb-2" to="/">
|
<b-navbar-brand class="mb-2" to="/">
|
||||||
<img src="img/brand/gradido_logo_w.png" class="navbar-brand-img pl-2" alt="..." />
|
<img src="img/brand/gradido_logo_w.png" class="navbar-brand-img pl-2" alt="..." />
|
||||||
</b-navbar-brand>
|
</b-navbar-brand>
|
||||||
@ -19,6 +19,9 @@
|
|||||||
<b-nav-item to="/contribution-links">
|
<b-nav-item to="/contribution-links">
|
||||||
{{ $t('navbar.automaticContributions') }}
|
{{ $t('navbar.automaticContributions') }}
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
|
<b-nav-item to="/federation">
|
||||||
|
{{ $t('navbar.instances') }}
|
||||||
|
</b-nav-item>
|
||||||
<b-nav-item to="/statistic">{{ $t('navbar.statistic') }}</b-nav-item>
|
<b-nav-item to="/statistic">{{ $t('navbar.statistic') }}</b-nav-item>
|
||||||
<b-nav-item @click="wallet">{{ $t('navbar.my-account') }}</b-nav-item>
|
<b-nav-item @click="wallet">{{ $t('navbar.my-account') }}</b-nav-item>
|
||||||
<b-nav-item @click="logout">{{ $t('navbar.logout') }}</b-nav-item>
|
<b-nav-item @click="logout">{{ $t('navbar.logout') }}</b-nav-item>
|
||||||
|
|||||||
17
admin/src/graphql/getCommunities.js
Normal file
17
admin/src/graphql/getCommunities.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const getCommunities = gql`
|
||||||
|
query {
|
||||||
|
getCommunities {
|
||||||
|
id
|
||||||
|
foreign
|
||||||
|
publicKey
|
||||||
|
url
|
||||||
|
lastAnnouncedAt
|
||||||
|
verifiedAt
|
||||||
|
lastErrorAt
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -76,6 +76,13 @@
|
|||||||
},
|
},
|
||||||
"short_hash": "({shortHash})"
|
"short_hash": "({shortHash})"
|
||||||
},
|
},
|
||||||
|
"federation": {
|
||||||
|
"gradidoInstances":"Gradido Instanzen",
|
||||||
|
"verified":"Verifiziert",
|
||||||
|
"url":"Url",
|
||||||
|
"lastAnnouncedAt":"letzte Bekanntgabe",
|
||||||
|
"createdAt":"Erstellt am"
|
||||||
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"submit": "Senden"
|
"submit": "Senden"
|
||||||
@ -104,6 +111,7 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"navbar": {
|
"navbar": {
|
||||||
"automaticContributions": "Automatische Beiträge",
|
"automaticContributions": "Automatische Beiträge",
|
||||||
|
"instances":"Instanzen",
|
||||||
"logout": "Abmelden",
|
"logout": "Abmelden",
|
||||||
"my-account": "Mein Konto",
|
"my-account": "Mein Konto",
|
||||||
"statistic": "Statistik",
|
"statistic": "Statistik",
|
||||||
|
|||||||
@ -76,6 +76,13 @@
|
|||||||
},
|
},
|
||||||
"short_hash": "({shortHash})"
|
"short_hash": "({shortHash})"
|
||||||
},
|
},
|
||||||
|
"federation": {
|
||||||
|
"gradidoInstances":"Gradido Instances",
|
||||||
|
"verified":"Verified",
|
||||||
|
"url":"Url",
|
||||||
|
"lastAnnouncedAt":"Last Announced",
|
||||||
|
"createdAt":"Created At "
|
||||||
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"submit": "Send"
|
"submit": "Send"
|
||||||
@ -104,6 +111,7 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"navbar": {
|
"navbar": {
|
||||||
"automaticContributions": "Automatic Contributions",
|
"automaticContributions": "Automatic Contributions",
|
||||||
|
"instances":"Instances",
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"my-account": "My Account",
|
"my-account": "My Account",
|
||||||
"statistic": "Statistic",
|
"statistic": "Statistic",
|
||||||
|
|||||||
30
admin/src/pages/FederationVisualize.spec.js
Normal file
30
admin/src/pages/FederationVisualize.spec.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import FederationVisualize from './FederationVisualize'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$t: (key) => key,
|
||||||
|
$i18n: {
|
||||||
|
locale: 'de',
|
||||||
|
t: (key) => key,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Overview', () => {
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(FederationVisualize, { localVue, mocks })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a DIV element with the class.component-confirm-register-mail', () => {
|
||||||
|
expect(wrapper.find('div.federation-visualize').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
68
admin/src/pages/FederationVisualize.vue
Normal file
68
admin/src/pages/FederationVisualize.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<div class="federation-visualize">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<span class="h2">{{ $t('federation.gradidoInstances') }}</span>
|
||||||
|
<b-button>
|
||||||
|
<b-icon
|
||||||
|
icon="arrow-clockwise"
|
||||||
|
font-scale="2"
|
||||||
|
:animation="animation"
|
||||||
|
@click="$apollo.queries.GetCommunities.refresh()"
|
||||||
|
></b-icon>
|
||||||
|
</b-button>
|
||||||
|
</div>
|
||||||
|
<b-list-group>
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="1" class="ml-1">{{ $t('federation.verified') }}</b-col>
|
||||||
|
<b-col class="ml-3">{{ $t('federation.url') }}</b-col>
|
||||||
|
<b-col cols="2">{{ $t('federation.lastAnnouncedAt') }}</b-col>
|
||||||
|
<b-col cols="2">{{ $t('federation.createdAt') }}</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-list-group-item
|
||||||
|
v-for="item in communities"
|
||||||
|
:key="item.id"
|
||||||
|
:variant="!item.foreign ? 'primary' : 'warning'"
|
||||||
|
>
|
||||||
|
<federation-visualize-item :item="item" />
|
||||||
|
</b-list-group-item>
|
||||||
|
</b-list-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { getCommunities } from '@/graphql/getCommunities'
|
||||||
|
|
||||||
|
import FederationVisualizeItem from '../components/Fedaration/FederationVisualizeItem.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FederationVisualize',
|
||||||
|
components: {
|
||||||
|
FederationVisualizeItem,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
oldPublicKey: '',
|
||||||
|
communities: [],
|
||||||
|
icon: '',
|
||||||
|
animation: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
apollo: {
|
||||||
|
GetCommunities: {
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
query() {
|
||||||
|
this.animation = 'spin'
|
||||||
|
|
||||||
|
return getCommunities
|
||||||
|
},
|
||||||
|
update({ getCommunities }) {
|
||||||
|
this.communities = getCommunities
|
||||||
|
this.animation = ''
|
||||||
|
},
|
||||||
|
error({ message }) {
|
||||||
|
this.toastError(message)
|
||||||
|
this.animation = ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -45,7 +45,7 @@ describe('router', () => {
|
|||||||
|
|
||||||
describe('routes', () => {
|
describe('routes', () => {
|
||||||
it('has nine routes defined', () => {
|
it('has nine routes defined', () => {
|
||||||
expect(routes).toHaveLength(8)
|
expect(routes).toHaveLength(9)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has "/overview" as default', async () => {
|
it('has "/overview" as default', async () => {
|
||||||
@ -88,6 +88,13 @@ describe('router', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('federation', () => {
|
||||||
|
it('loads the "FederationVisualize" page', async () => {
|
||||||
|
const component = await routes.find((r) => r.path === '/federation').component()
|
||||||
|
expect(component.default.name).toBe('FederationVisualize')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('not found page', () => {
|
describe('not found page', () => {
|
||||||
it('renders the "NotFound" component', async () => {
|
it('renders the "NotFound" component', async () => {
|
||||||
const component = await routes.find((r) => r.path === '*').component()
|
const component = await routes.find((r) => r.path === '*').component()
|
||||||
|
|||||||
@ -31,6 +31,10 @@ const routes = [
|
|||||||
path: '*',
|
path: '*',
|
||||||
component: () => import('@/components/NotFoundPage.vue'),
|
component: () => import('@/components/NotFoundPage.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/federation',
|
||||||
|
component: () => import('@/pages/FederationVisualize.vue'),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
|||||||
@ -5038,6 +5038,11 @@ data-urls@^2.0.0:
|
|||||||
whatwg-mimetype "^2.3.0"
|
whatwg-mimetype "^2.3.0"
|
||||||
whatwg-url "^8.0.0"
|
whatwg-url "^8.0.0"
|
||||||
|
|
||||||
|
date-fns@^2.29.3:
|
||||||
|
version "2.29.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8"
|
||||||
|
integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==
|
||||||
|
|
||||||
de-indent@^1.0.2:
|
de-indent@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
|
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user