mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-27 06:01:08 +08:00
bunch of unfinished stuff
This commit is contained in:
parent
7b25ae4b95
commit
e67b897535
16
frontend/components/Editor.vue
Normal file
16
frontend/components/Editor.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- todo editor -->
|
||||
{{ $route.name }}
|
||||
hur dur am a editor
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
|
||||
@Component
|
||||
export default class Editor extends Vue {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
12
frontend/components/MemberList.vue
Normal file
12
frontend/components/MemberList.vue
Normal file
@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<!-- todo memberlist -->
|
||||
<div>Memberlist</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
@Component({})
|
||||
export default class MemberList extends Vue {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
33
frontend/components/Tag.vue
Normal file
33
frontend/components/Tag.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="tags" :class="{ 'has-addons': data }">
|
||||
<span
|
||||
:style="{
|
||||
color: color.foreground,
|
||||
background: color.background,
|
||||
'border-color': color.background,
|
||||
}"
|
||||
class="tag"
|
||||
>
|
||||
{{ name }}
|
||||
</span>
|
||||
<span v-if="data" class="tag">{{ data }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import { Prop } from 'vue-property-decorator';
|
||||
@Component({})
|
||||
export default class DocsPage extends Vue {
|
||||
@Prop()
|
||||
name!: String;
|
||||
|
||||
@Prop()
|
||||
data!: String;
|
||||
|
||||
@Prop()
|
||||
color!: Object;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
121
frontend/components/donation/DonationModal.vue
Normal file
121
frontend/components/donation/DonationModal.vue
Normal file
@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<!-- todo fix the layout of this modal, some buttons and shit, also i18n, also am tired -->
|
||||
<v-dialog v-model="show">
|
||||
<template #activator="{ on, attrs }">
|
||||
<slot name="activator" :on="on" :attrs="attrs" />
|
||||
</template>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<h4>Donate to ....</h4>
|
||||
<v-btn @click="show = false">×</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<button type="button" :class="'btn ' + (monthly ? 'btn-primary' : 'btn-default')" @click="monthly = true">Monthly</button>
|
||||
<button type="button" :class="'btn ' + (monthly ? 'btn-default' : 'btn-primary')" @click="monthly = false">One-Time</button>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<form action="https://sandbox.paypal.com/cgi-bin/webscr" method="post" @submit="popup($el)">
|
||||
<!-- https://developer.paypal.com/docs/paypal-payments-standard/integration-guide/Appx-websitestandard-htmlvariables/ -->
|
||||
<input type="hidden" name="business" :value="donationEmail" />
|
||||
<input type="hidden" name="return" :value="returnUrl" />
|
||||
<input type="hidden" name="cancel_return" :value="cancelReturnUrl" />
|
||||
<!-- return method, 2 = POST, with all variables -->
|
||||
<input type="hidden" name="rm" value="1" />
|
||||
<input type="hidden" name="item_name" :value="'Hangar: ' + (monthly ? 'Monthly ' : 'One-Time ') + 'Donation to ' + donationTarget" />
|
||||
<input type="hidden" name="quantity" value="1" />
|
||||
<!-- locale -->
|
||||
<input type="hidden" name="lc" value="US" />
|
||||
<input type="hidden" name="currency_code" value="USD" />
|
||||
<input type="hidden" name="charset" value="utf-8" />
|
||||
<input type="hidden" name="notify_url" value="https://hangar.minidigger.me/paypal/ipn" />
|
||||
<input type="hidden" name="custom" value="idk, maybe hangar user id?" />
|
||||
|
||||
<template v-if="monthly">
|
||||
<input type="hidden" name="cmd" value="_xclick-subscriptions" />
|
||||
<input type="hidden" name="bn" :value="'Hangar_Subscribe_' + donationTarget + 'US'" />
|
||||
<input type="hidden" name="no_note" value="1" />
|
||||
<!-- 1 = do not prompt for an address -->
|
||||
<input type="hidden" name="no_shipping" value="1" />
|
||||
<!-- recurring -->
|
||||
<input type="hidden" name="src" value="1" />
|
||||
<!-- p3 + t3 = 1 month -->
|
||||
<input type="hidden" name="p3" value="1" />
|
||||
<input type="hidden" name="t3" value="M" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<input type="hidden" name="cmd" value="_donations" />
|
||||
<input type="hidden" name="bn" :value="'Hangar_Donate_' + donationTarget + 'US'" />
|
||||
</template>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<button
|
||||
v-for="a in monthly ? monthlyAmounts : oneTimeAmounts"
|
||||
:key="a"
|
||||
:class="'btn ' + (amount === a ? 'btn-primary' : 'btn-default')"
|
||||
@click.prevent="amount = a"
|
||||
>
|
||||
${{ a }}
|
||||
</button>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<div>Select an amount above or enter an amount below</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<div class="input-group mb-3">
|
||||
<input v-model="amount" type="number" class="form-control" :name="monthly ? 'a3' : 'amount'" />
|
||||
<span class="input-group-text">USD</span>
|
||||
</div>
|
||||
<small class="form-text">By donating to X you agree to Y and that tacos are delicious</small>
|
||||
<div>
|
||||
<input type="submit" :value="'Donate ' + (monthly ? 'Monthly ' : 'One-Time ')" class="btn btn-primary" />
|
||||
<img alt="" width="1" height="1" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" />
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn @click="show = false">Close</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import { Prop } from 'vue-property-decorator';
|
||||
|
||||
@Component({})
|
||||
export default class DonationModal extends Vue {
|
||||
monthly: boolean = true;
|
||||
amount: number = 20;
|
||||
show: boolean = false;
|
||||
|
||||
@Prop({ required: true })
|
||||
donationTarget!: String;
|
||||
|
||||
@Prop({ required: true })
|
||||
donationEmail!: String;
|
||||
|
||||
@Prop({ required: true })
|
||||
returnUrl!: String;
|
||||
|
||||
@Prop({ required: true })
|
||||
cancelReturnUrl!: String;
|
||||
|
||||
oneTimeAmounts: Array<number> = [10, 20, 30];
|
||||
monthlyAmounts: Array<number> = [5, 10, 15, 20];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
39
frontend/components/donation/DonationResult.vue
Normal file
39
frontend/components/donation/DonationResult.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div v-if="qs['donation']" class="row">
|
||||
<div class="col-12">
|
||||
<Announcement :announcement="announcement"></Announcement>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import Announcement from '~/components/layouts/Announcement.vue';
|
||||
|
||||
@Component({
|
||||
components: { Announcement },
|
||||
})
|
||||
export default class DonationResult extends Vue {
|
||||
get qs() {
|
||||
return this.$route.query;
|
||||
}
|
||||
|
||||
get announcement() {
|
||||
let text = '';
|
||||
if (this.qs.donation && this.qs.donation === 'success' && this.qs.st && this.qs.st === 'Completed') {
|
||||
text = 'Donation successful! You donated ' + this.qs.amt + ' ' + this.qs.cc + ' ' + this.qs.item_name;
|
||||
} else if (this.qs.donation && this.qs.donation === 'failure') {
|
||||
text = 'Donation failed.';
|
||||
} else {
|
||||
text = JSON.stringify(this.qs);
|
||||
}
|
||||
|
||||
return {
|
||||
text,
|
||||
color: '#093962',
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -12,6 +12,9 @@
|
||||
</template>
|
||||
<Dropdown :controls="dropdown" />
|
||||
</v-menu>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-menu v-if="$util.isLoggedIn()" bottom offset-y transition="slide-y-transition">
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn v-bind="attrs" color="primary" v-on="on">
|
||||
@ -21,8 +24,6 @@
|
||||
<Dropdown :controls="newControls" />
|
||||
</v-menu>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-btn icon to="/authors" nuxt v-on="on"><v-icon>mdi-account-group</v-icon></v-btn>
|
||||
|
50
frontend/components/modals/NewPageModal.vue
Normal file
50
frontend/components/modals/NewPageModal.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- todo fix this -->
|
||||
<div class="modal-header">
|
||||
<h4 v-show="!newPage.error" id="new-page-label" class="modal-title" v-text="$t('page.new.title')"></h4>
|
||||
<h4 v-show="newPage.error" id="new-page-label-error" class="modal-title" v-text="$t('page.new.error')"></h4>
|
||||
<button type="button" class="close" data-dismiss="modal" :aria-label="$t('general.close')">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body input-group">
|
||||
<div class="setting">
|
||||
<div class="setting-description">
|
||||
<h4 v-text="$t('project.page.name._')"></h4>
|
||||
<p v-text="$t('project.page.name.info')"></p>
|
||||
</div>
|
||||
<div class="setting-content">
|
||||
<label for="page-name" class="sr-only">Page Name</label>
|
||||
<input id="page-name" v-model="newPage.pageName" class="form-control" type="text" />
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="setting setting-no-border">
|
||||
<div class="setting-description">
|
||||
<h4 v-text="$t('project.page.parent._')"></h4>
|
||||
<p v-text="$t('project.page.parent.info')"></p>
|
||||
</div>
|
||||
<div class="setting-content">
|
||||
<label for="new-page-parent-select" class="sr-only"></label>
|
||||
<select id="new-page-parent-select" v-model="newPage.parentPage" class="form-control select-parent">
|
||||
<option disabled hidden :value="null"><none></option>
|
||||
<option v-for="pg in noHomePage(rootPages)" :key="pg.id" :value="{ id: pg.id, slug: pg.slug }" v-text="pg.name"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" v-text="$t('general.close')"></button>
|
||||
<button id="continue-page" type="button" class="btn btn-primary" @click="createPage" v-text="$t('general.continue')"></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
|
||||
@Component
|
||||
export default class NewPageModal extends Vue {}
|
||||
</script>
|
@ -5,6 +5,7 @@
|
||||
<v-container>
|
||||
<Announcement v-for="(announcement, idx) in announcements" :key="idx" :announcement="announcement" />
|
||||
|
||||
<DonationResult />
|
||||
<nuxt />
|
||||
</v-container>
|
||||
</v-main>
|
||||
@ -19,9 +20,11 @@ import Header from '~/components/layouts/Header.vue';
|
||||
import Footer from '~/components/layouts/Footer.vue';
|
||||
import Announcement from '~/components/layouts/Announcement.vue';
|
||||
import HangarSnackbar from '~/components/layouts/HangarSnackbar.vue';
|
||||
import DonationResult from '~/components/donation/DonationResult.vue';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
DonationResult,
|
||||
Header,
|
||||
Footer,
|
||||
Announcement,
|
||||
|
@ -5,6 +5,7 @@ const msgs: LocaleMessageObject = {
|
||||
close: 'Close',
|
||||
submit: 'Submit',
|
||||
comment: 'Comment',
|
||||
donate: 'Donate',
|
||||
},
|
||||
hangar: {
|
||||
projectSearch: {
|
||||
@ -50,6 +51,7 @@ const msgs: LocaleMessageObject = {
|
||||
},
|
||||
project: {
|
||||
category: {
|
||||
info: 'Category: {0}',
|
||||
admin_tools: 'Admin Tools',
|
||||
chat: 'Chat',
|
||||
dev_tools: 'Developer Tools',
|
||||
@ -136,6 +138,16 @@ const msgs: LocaleMessageObject = {
|
||||
error: 'There was an error creating the project',
|
||||
},
|
||||
sendForApproval: 'Send for approval',
|
||||
info: 'Information',
|
||||
publishDate: 'Published on {0}',
|
||||
views: '{0} views',
|
||||
promotedVersions: 'Promoted Versions',
|
||||
license: {
|
||||
link: 'Licensed under ',
|
||||
},
|
||||
},
|
||||
page: {
|
||||
plural: 'Pages',
|
||||
},
|
||||
organization: {
|
||||
new: {
|
||||
|
@ -154,7 +154,6 @@ export default class ProjectPage extends Vue {
|
||||
const tabs = [] as Tab[];
|
||||
tabs.push({ title: this.$t('project.tabs.docs') as String, icon: 'mdi-book', link: this.slug, external: false });
|
||||
tabs.push({ title: this.$t('project.tabs.versions') as String, icon: 'mdi-download', link: this.slug + '/versions', external: false });
|
||||
// todo check if has a discussion
|
||||
if (this.project.settings.forumSync) {
|
||||
tabs.push({ title: this.$t('project.tabs.discuss') as String, icon: 'mdi-account-group', link: this.slug + '/discuss', external: false });
|
||||
}
|
||||
|
@ -1,14 +1,162 @@
|
||||
<template>
|
||||
<div>
|
||||
{{ $route.name }}
|
||||
</div>
|
||||
<v-row>
|
||||
<v-col cols="12" md="8">
|
||||
<Editor />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-card>
|
||||
<v-card-title v-text="$t('project.info')"></v-card-title>
|
||||
<v-card-text>
|
||||
<!-- todo where do we get this from? -->
|
||||
<v-btn-toggle v-if="project.recommendedVersionId">
|
||||
<v-btn>
|
||||
<v-icon>mdi-download-outline</v-icon>
|
||||
{{ $t('general.download') }}
|
||||
</v-btn>
|
||||
|
||||
<v-btn>
|
||||
<v-icon>mdi-content-copy</v-icon>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
|
||||
<!-- todo: make donation button toggleable in settings, get email and stuff into modal, translate -->
|
||||
<div v-if="true">
|
||||
<DonationModal
|
||||
donation-email="minidigger-author@hangar.minidigger.me"
|
||||
donation-target="paper/Test"
|
||||
return-url="http://localhost:8080/paper/Test?donation=success"
|
||||
cancel-return-url="http://localhost:8080/paper/Test?donation=failure"
|
||||
>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn v-bind="attrs" v-on="on">
|
||||
<v-icon>mdi-currency-usd</v-icon>
|
||||
{{ $t('general.donate') }}
|
||||
</v-btn>
|
||||
</template>
|
||||
</DonationModal>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p>{{ $t('project.category.info', [formatCategory(project.category)]) }}</p>
|
||||
<p>{{ $t('project.publishDate', [$util.prettyDate(project.createdAt)]) }}</p>
|
||||
<p v-if="project">
|
||||
<span id="view-count">{{ $t('project.views', [project.stats.views]) }}</span>
|
||||
</p>
|
||||
<p v-if="project">
|
||||
<span id="star-count">{{ project.stats.stars }}</span>
|
||||
<NuxtLink :to="project.namespace.slug + '/stars'">
|
||||
{{ project.stats.views !== 1 ? ' stars' : ' star' }}
|
||||
</NuxtLink>
|
||||
</p>
|
||||
<p v-if="project">
|
||||
<span id="watcher-count">{{ project.stats.watchers }}</span>
|
||||
<NuxtLink :to="project.namespace.slug + '/watchers'">
|
||||
{{ project.stats.views !== 1 ? ' watchers' : ' watcher' }}
|
||||
</NuxtLink>
|
||||
</p>
|
||||
<p v-if="project">
|
||||
<span id="download-count">{{ project.stats.downloads }} total download{{ project.stats.downloads !== 1 ? 's' : '' }}</span>
|
||||
</p>
|
||||
<p v-if="project && project.settings.license">
|
||||
{{ $t('project.license.link') }}
|
||||
<a ref="noopener" :href="project.settings.license.url" target="_blank">{{ project.settings.license.name }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-card>
|
||||
<v-card-title v-text="$t('project.promotedVersions')"></v-card-title>
|
||||
<v-card-text>
|
||||
<v-list v-if="project">
|
||||
<v-list-item v-for="(version, index) in project.promotedVersions" :key="`${index}-${version.version}`">
|
||||
{{ version.version.substring(0, version.version.lastIndexOf('.')) }}
|
||||
<Tag v-for="(tag, idx) in version.tags" :key="idx" :color="tag.color" :data="tag.displayData" :name="tag.name"></Tag>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<div v-else class="text-center py-4">
|
||||
<v-progress-circular indeterminate />
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
{{ $t('page.plural') }}
|
||||
<!-- todo new page modal -->
|
||||
<v-btn icon><v-icon>mdi-plus</v-icon></v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-list v-if="rootPages">
|
||||
<v-list-item v-for="page in rootPages" :key="page.id"> </v-list-item>
|
||||
</v-list>
|
||||
<div v-else class="text-center py-4">
|
||||
<v-progress-circular indeterminate />
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<!-- todo member list -->
|
||||
<v-col cols="12">
|
||||
<MemberList />
|
||||
<!-- <MemberList-->
|
||||
<!-- :filtered-members-prop="filteredMembers"-->
|
||||
<!-- :can-manage-members="canManageMembers"-->
|
||||
<!-- :settings-call="ROUTES.parse('PROJECTS_SHOW_SETTINGS', project.ownerName, project.slug)"-->
|
||||
<!-- ></MemberList>-->
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import { Page, Project } from 'hangar-api';
|
||||
import { HangarProject } from 'hangar-internal';
|
||||
import { Context } from '@nuxt/types';
|
||||
import Editor from '~/components/Editor.vue';
|
||||
import Tag from '~/components/Tag.vue';
|
||||
import DonationModal from '~/components/donation/DonationModal.vue';
|
||||
import MemberList from '~/components/MemberList.vue';
|
||||
@Component({
|
||||
components: { MemberList, DonationModal, Editor, Tag },
|
||||
})
|
||||
export default class DocsPage extends Vue {
|
||||
project!: Project;
|
||||
rootPages: Array<Page> = [];
|
||||
|
||||
@Component
|
||||
export default class DocsPage extends Vue {}
|
||||
async asyncData({ $api, params, $util }: Context) {
|
||||
const project = await $api
|
||||
.requestInternal<HangarProject>(`projects/project/${params.author}/${params.slug}`, false)
|
||||
.catch($util.handlePageRequestError);
|
||||
// todo add new route
|
||||
// const rootPages = await $api
|
||||
// .requestInternal<HangarProject>(`projects/project/${params.author}/${params.slug}`, false)
|
||||
// .catch($util.handlePageRequestError);
|
||||
return {
|
||||
project,
|
||||
// rootPages,
|
||||
};
|
||||
}
|
||||
|
||||
formatCategory(apiName: string) {
|
||||
const formatted = apiName.replace('_', ' ');
|
||||
return this.capitalize(formatted);
|
||||
}
|
||||
|
||||
capitalize(input: string) {
|
||||
return input
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.map((s: string) => s.charAt(0).toUpperCase() + s.substring(1))
|
||||
.join(' ');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
20
frontend/types/api.d.ts
vendored
20
frontend/types/api.d.ts
vendored
@ -65,7 +65,7 @@ declare module 'hangar-api' {
|
||||
recentViews: number;
|
||||
recentDownloads: number;
|
||||
stars: number;
|
||||
waters: number;
|
||||
watchers: number;
|
||||
}
|
||||
|
||||
interface UserActions {
|
||||
@ -73,12 +73,17 @@ declare module 'hangar-api' {
|
||||
watching: boolean;
|
||||
}
|
||||
|
||||
interface Licence {
|
||||
name: string | null;
|
||||
url: string | null;
|
||||
}
|
||||
|
||||
interface ProjectSettings {
|
||||
homepage: string | null;
|
||||
issues: string | null;
|
||||
sources: string | null;
|
||||
support: string | null;
|
||||
license: string | null;
|
||||
license: Licence | null;
|
||||
forumSync: boolean;
|
||||
}
|
||||
|
||||
@ -134,4 +139,15 @@ declare module 'hangar-api' {
|
||||
permissionBinString: string;
|
||||
permissions: IPermission[];
|
||||
}
|
||||
|
||||
interface Page {
|
||||
id: number;
|
||||
createdAt: string;
|
||||
projectId: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
isDeletable: false;
|
||||
contents: string;
|
||||
children: Array<Page>;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user