Merge branch 'fix-settings-menu' into 'master'

Fix settings menu

See merge request framasoft/mobilizon!494
This commit is contained in:
Thomas Citharel 2020-06-25 12:51:09 +02:00
commit 97c153ada3
33 changed files with 2911 additions and 2830 deletions

View File

@ -39,6 +39,7 @@ lint:
- cd js - cd js
- yarn install - yarn install
#- yarn run lint || export EXITVALUE=1 #- yarn run lint || export EXITVALUE=1
- yarn run prettier -c .
- yarn run build - yarn run build
- cd ../ - cd ../
- exit $EXITVALUE - exit $EXITVALUE

View File

@ -50,10 +50,12 @@ module.exports = {
ignorePatterns: ["src/typings/*.d.ts", "vue.config.js"], ignorePatterns: ["src/typings/*.d.ts", "vue.config.js"],
overrides: [{ overrides: [
{
files: ["**/__tests__/*.{j,t}s?(x)", "**/tests/unit/**/*.spec.{j,t}s?(x)"], files: ["**/__tests__/*.{j,t}s?(x)", "**/tests/unit/**/*.spec.{j,t}s?(x)"],
env: { env: {
mocha: true, mocha: true,
}, },
}], },
],
}; };

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
@ -11,12 +10,13 @@
<body> <body>
<noscript> <noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work <strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to properly without JavaScript enabled. Please enable it to
continue.</strong> continue.</strong
>
</noscript> </noscript>
<div id="app"></div> <div id="app"></div>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->
</body> </body>
</html> </html>

View File

@ -1,6 +1,6 @@
a { a {
text-decoration: underline; text-decoration: underline;
text-decoration-color: #ED8D07; text-decoration-color: #ed8d07;
text-decoration-thickness: 2px; text-decoration-thickness: 2px;
&.navbar-item, &.navbar-item,
@ -17,6 +17,10 @@ a {
} }
} }
nav.breadcrumb ul li a {
text-decoration: none;
}
input.input { input.input {
border-color: $input-border-color !important; border-color: $input-border-color !important;
} }

View File

@ -1,24 +1,25 @@
<template> <template>
<li class="setting-menu-item" :class="{ active: isActive }"> <li class="setting-menu-item" :class="{ active: isActive }">
<router-link v-if="menuItem.to" :to="menuItem.to"> <router-link v-if="to" :to="to">
<span>{{ menuItem.title }}</span> <span>{{ title }}</span>
</router-link> </router-link>
<span v-else>{{ menuItem.title }}</span> <span v-else>{{ title }}</span>
</li> </li>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator"; import { Component, Prop, Vue } from "vue-property-decorator";
import { ISettingMenuSection } from "@/types/setting-menu.model"; import { Route } from "vue-router";
@Component @Component
export default class SettingMenuItem extends Vue { export default class SettingMenuItem extends Vue {
@Prop({ required: true, type: Object }) menuItem!: ISettingMenuSection; @Prop({ required: false, type: String }) title!: string;
@Prop({ required: true, type: Object }) to!: Route;
get isActive() { get isActive() {
if (!this.menuItem.to) return false; if (!this.to) return false;
if (this.menuItem.to.name === this.$route.name) { if (this.to.name === this.$route.name) {
if (this.menuItem.to.params) { if (this.to.params) {
return this.menuItem.to.params.identityName === this.$route.params.identityName; return this.to.params.identityName === this.$route.params.identityName;
} }
return true; return true;
} }

View File

@ -1,28 +1,36 @@
<template> <template>
<li :class="{ active: sectionActive }"> <li :class="{ active: sectionActive }">
<router-link v-if="menuSection.to" :to="menuSection.to">{{ menuSection.title }}</router-link> <router-link v-if="to" :to="to">{{ title }}</router-link>
<b v-else>{{ menuSection.title }}</b> <b v-else>{{ title }}</b>
<ul> <ul>
<setting-menu-item :menu-item="item" v-for="item in menuSection.items" :key="item.title" /> <slot></slot>
</ul> </ul>
</li> </li>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator"; import { Component, Prop, Vue } from "vue-property-decorator";
import { ISettingMenuSection } from "@/types/setting-menu.model";
import SettingMenuItem from "@/components/Settings/SettingMenuItem.vue"; import SettingMenuItem from "@/components/Settings/SettingMenuItem.vue";
import { Route } from "vue-router";
@Component({ @Component({
components: { SettingMenuItem }, components: { SettingMenuItem },
}) })
export default class SettingMenuSection extends Vue { export default class SettingMenuSection extends Vue {
@Prop({ required: true, type: Object }) menuSection!: ISettingMenuSection; @Prop({ required: false, type: String }) title!: string;
@Prop({ required: true, type: Object }) to!: Route;
get sectionActive(): boolean | undefined { get sectionActive() {
return ( if (this.$slots.default) {
this.menuSection.items && return this.$slots.default.some(
this.menuSection.items.some(({ to }) => to && to.name === this.$route.name) ({
componentOptions: {
// @ts-ignore
propsData: { to },
},
}) => to && to.name === this.$route.name
); );
} }
return false;
}
} }
</script> </script>

View File

@ -1,27 +1,88 @@
<template> <template>
<aside> <aside>
<ul> <ul>
<SettingMenuSection <SettingMenuSection :title="$t('Account')" :to="{ name: RouteName.ACCOUNT_SETTINGS }">
v-for="section in menuValue" <SettingMenuItem
:key="section.title" :title="this.$t('General')"
:menu-section="section" :to="{ name: RouteName.ACCOUNT_SETTINGS_GENERAL }"
/> />
<SettingMenuItem :title="$t('Preferences')" :to="{ name: RouteName.PREFERENCES }" />
<SettingMenuItem
:title="this.$t('Email notifications')"
:to="{ name: RouteName.NOTIFICATIONS }"
/>
</SettingMenuSection>
<SettingMenuSection :title="$t('Profiles')" :to="{ name: RouteName.IDENTITIES }">
<SettingMenuItem
v-for="profile in identities"
:key="profile.preferredUsername"
:title="profile.preferredUsername"
:to="{
name: RouteName.UPDATE_IDENTITY,
params: { identityName: profile.preferredUsername },
}"
/>
<SettingMenuItem :title="$t('New profile')" :to="{ name: RouteName.CREATE_IDENTITY }" />
</SettingMenuSection>
<SettingMenuSection
v-if="
[ICurrentUserRole.MODERATOR, ICurrentUserRole.ADMINISTRATOR].includes(
this.currentUser.role
)
"
:title="$t('Moderation')"
:to="{ name: RouteName.MODERATION }"
>
<SettingMenuItem :title="$t('Reports')" :to="{ name: RouteName.REPORTS }" />
<SettingMenuItem :title="$t('Moderation log')" :to="{ name: RouteName.REPORT_LOGS }" />
<SettingMenuItem :title="$t('Users')" :to="{ name: RouteName.USERS }" />
<SettingMenuItem :title="$t('Profiles')" :to="{ name: RouteName.PROFILES }" />
</SettingMenuSection>
<SettingMenuSection
v-if="this.currentUser.role == ICurrentUserRole.ADMINISTRATOR"
:title="$t('Admin')"
:to="{ name: RouteName.ADMIN }"
>
<SettingMenuItem :title="$t('Dashboard')" :to="{ name: RouteName.ADMIN_DASHBOARD }" />
<SettingMenuItem
:title="$t('Instance settings')"
:to="{ name: RouteName.ADMIN_SETTINGS }"
/>
<SettingMenuItem :title="$t('Federation')" :to="{ name: RouteName.RELAYS }" />
</SettingMenuSection>
</ul> </ul>
</aside> </aside>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator"; import { Component, Prop, Vue } from "vue-property-decorator";
import SettingMenuSection from "@/components/Settings/SettingMenuSection.vue"; import SettingMenuSection from "./SettingMenuSection.vue";
import { ISettingMenuSection } from "@/types/setting-menu.model"; import SettingMenuItem from "./SettingMenuItem.vue";
import { IDENTITIES } from "../../graphql/actor";
import { IPerson, Person } from "../../types/actor";
import { CURRENT_USER_CLIENT } from "../../graphql/user";
import { ICurrentUser, ICurrentUserRole } from "../../types/current-user.model";
import RouteName from "../../router/name";
@Component({ @Component({
components: { SettingMenuSection }, components: { SettingMenuSection, SettingMenuItem },
apollo: {
identities: {
query: IDENTITIES,
update: (data) => data.identities.map((identity: IPerson) => new Person(identity)),
},
currentUser: CURRENT_USER_CLIENT,
},
}) })
export default class SettingsMenu extends Vue { export default class SettingsMenu extends Vue {
@Prop({ required: true, type: Array }) menu!: ISettingMenuSection[]; profiles = [];
get menuValue() { currentUser!: ICurrentUser;
return this.menu;
} identities!: IPerson[];
ICurrentUserRole = ICurrentUserRole;
RouteName = RouteName;
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -106,6 +106,7 @@ export const USER_SETTINGS_FRAGMENT = gql`
export const USER_SETTINGS = gql` export const USER_SETTINGS = gql`
query UserSetting { query UserSetting {
loggedUser { loggedUser {
id
locale locale
settings { settings {
...UserSettingFragment ...UserSettingFragment

View File

@ -695,5 +695,6 @@
"contact uninformed": "contact uninformed", "contact uninformed": "contact uninformed",
"Can be an email or a link, or just plain text.": "Can be an email or a link, or just plain text.", "Can be an email or a link, or just plain text.": "Can be an email or a link, or just plain text.",
"No profiles found": "No profiles found", "No profiles found": "No profiles found",
"URL copied to clipboard": "URL copied to clipboard" "URL copied to clipboard": "URL copied to clipboard",
"Report #{reportNumber}": "Report #{reportNumber}"
} }

View File

@ -695,5 +695,6 @@
"A place for your code of conduct, rules or guidelines. You can use HTML tags.": "Une section appropriée pour votre code de conduite, règles ou lignes directrices. Vous pouvez utiliser des balises HTML.", "A place for your code of conduct, rules or guidelines. You can use HTML tags.": "Une section appropriée pour votre code de conduite, règles ou lignes directrices. Vous pouvez utiliser des balises HTML.",
"contact uninformed": "contact non renseigné", "contact uninformed": "contact non renseigné",
"Can be an email or a link, or just plain text.": "Peut être une adresse email ou bien un lien, ou alors du simple texte brut.", "Can be an email or a link, or just plain text.": "Peut être une adresse email ou bien un lien, ou alors du simple texte brut.",
"URL copied to clipboard": "URL copiée dans le presse-papiers" "URL copied to clipboard": "URL copiée dans le presse-papiers",
"Report #{reportNumber}": "Signalement #{reportNumber}"
} }

View File

@ -1,8 +0,0 @@
import { Route } from "vue-router";
export interface ISettingMenuSection {
title: string;
to: Route;
items?: ISettingMenuSection[];
parents?: ISettingMenuSection[];
}

View File

@ -7,19 +7,19 @@ $violet: #424056;
/** /**
* Text body, paragraphs * Text body, paragraphs
*/ */
$violet-1: #3A384C; $violet-1: #3a384c;
$violet-2: #474467; $violet-2: #474467;
/** /**
* Titles, dark borders, buttons * Titles, dark borders, buttons
*/ */
$violet-3: #3C376E; $violet-3: #3c376e;
/** /**
* Borders * Borders
*/ */
$borders: #D7D6DE; $borders: #d7d6de;
$backgrounds: #ECEBF2; $backgrounds: #ecebf2;
/** /**
* Text * Text
@ -29,15 +29,15 @@ $purple-1: #757199;
/** /**
* Background * Background
*/ */
$purple-2: #CDCAEA; $purple-2: #cdcaea;
$purple-3: #E6E4F4; $purple-3: #e6e4f4;
$orange-2: #ED8D07; $orange-2: #ed8d07;
$orange-3: #D35204; $orange-3: #d35204;
$yellow-1: #FFD599; $yellow-1: #ffd599;
$yellow-2: #FFF1DE; $yellow-2: #fff1de;
$yellow-3: #FBD5CB; $yellow-3: #fbd5cb;
$yellow-4: #f7ba30; $yellow-4: #f7ba30;
$primary: $bleuvert; $primary: $bleuvert;
@ -47,36 +47,45 @@ $secondary-invert: findColorInvert($secondary);
$background-color: $violet-2; $background-color: $violet-2;
$success: #0D8758; $success: #0d8758;
$success-invert: findColorInvert($success); $success-invert: findColorInvert($success);
$info: #36bcd4; $info: #36bcd4;
$info-invert: findColorInvert($info); $info-invert: findColorInvert($info);
$danger: #FF2E54; $danger: #ff2e54;
$danger-invert: findColorInvert($danger); $danger-invert: findColorInvert($danger);
$link: $primary; $link: $primary;
$link-invert: $primary-invert; $link-invert: $primary-invert;
$text: $violet-1; $text: $violet-1;
$colors: map-merge($colors, $colors: map-merge(
("primary": ($primary, $colors,
(
"primary": (
$primary,
$primary-invert, $primary-invert,
), ),
"secondary": ($secondary, "secondary": (
$secondary,
$secondary-invert, $secondary-invert,
), ),
"success": ($success, "success": (
$success,
$success-invert, $success-invert,
), ),
"info": ($info, "info": (
$info,
$info-invert, $info-invert,
), ),
"danger": ($danger, "danger": (
$danger,
$danger-invert, $danger-invert,
), ),
"link": ($link, "link": (
$link,
$link-invert, $link-invert,
), ),
)); )
);
// Navbar // Navbar
$navbar-background-color: $secondary; $navbar-background-color: $secondary;
@ -96,11 +105,7 @@ main>.container {
} }
$title-color: #3c376e; $title-color: #3c376e;
$title-family: "Liberation Sans", $title-family: "Liberation Sans", "Helvetica Neue", Roboto, Helvetica, Arial,
"Helvetica Neue",
Roboto,
Helvetica,
Arial,
serif; serif;
$title-weight: 700; $title-weight: 700;
$title-size: 40px; $title-size: 40px;
@ -108,11 +113,7 @@ $title-sub-size: 45px;
$title-sup-size: 30px; $title-sup-size: 30px;
$subtitle-color: #3a384c; $subtitle-color: #3a384c;
$subtitle-family: "Liberation Sans", $subtitle-family: "Liberation Sans", "Helvetica Neue", Roboto, Helvetica, Arial,
"Helvetica Neue",
Roboto,
Helvetica,
Arial,
serif; serif;
$subtitle-weight: 400; $subtitle-weight: 400;
$subtitle-size: 32px; $subtitle-size: 32px;

View File

@ -1,4 +1,26 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.IDENTITIES }">{{ $t("Profiles") }}</router-link>
</li>
<li class="is-active" v-if="isUpdate && identity">
<router-link
:to="{
name: RouteName.UPDATE_IDENTITY,
params: { identityName: identity.preferredUsername },
}"
>{{ identity.name }}</router-link
>
</li>
<li class="is-active" v-else>
<router-link :to="{ name: RouteName.CREATE_IDENTITY }">{{
$t("New profile")
}}</router-link>
</li>
</ul>
</nav>
<div class="root" v-if="identity"> <div class="root" v-if="identity">
<h1 class="title"> <h1 class="title">
<span v-if="isUpdate">{{ identity.displayName() }}</span> <span v-if="isUpdate">{{ identity.displayName() }}</span>
@ -55,7 +77,9 @@
<b-field class="submit"> <b-field class="submit">
<div class="control"> <div class="control">
<button type="button" class="button is-primary" @click="submit()">{{ $t("Save") }}</button> <button type="button" class="button is-primary" @click="submit()">
{{ $t("Save") }}
</button>
</div> </div>
</b-field> </b-field>
@ -63,6 +87,7 @@
<span @click="openDeleteIdentityConfirmation()">{{ $t("Delete this identity") }}</span> <span @click="openDeleteIdentityConfirmation()">{{ $t("Delete this identity") }}</span>
</div> </div>
</div> </div>
</div>
</template> </template>
<style scoped type="scss"> <style scoped type="scss">
@ -148,6 +173,8 @@ export default class EditIdentity extends mixins(identityEditionMixin) {
private currentActor: IPerson | null = null; private currentActor: IPerson | null = null;
RouteName = RouteName;
get message() { get message() {
if (this.isUpdate) return null; if (this.isUpdate) return null;
return this.$t("Only alphanumeric characters and underscores are supported."); return this.$t("Only alphanumeric characters and underscores are supported.");

View File

@ -1,4 +1,15 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.ADMIN }">{{ $t("Admin") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.ADMIN_DASHBOARD }">{{ $t("Dashboard") }}</router-link>
</li>
</ul>
</nav>
<section> <section>
<h1 class="title">{{ $t("Administration") }}</h1> <h1 class="title">{{ $t("Administration") }}</h1>
<div class="tile is-ancestor" v-if="dashboard"> <div class="tile is-ancestor" v-if="dashboard">
@ -48,6 +59,7 @@
</div> </div>
</div> </div>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";

View File

@ -1,4 +1,23 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.ADMIN }">{{ $t("Admin") }}</router-link>
</li>
<li>
<router-link :to="{ name: RouteName.RELAYS }">{{ $t("Federation") }}</router-link>
</li>
<li class="is-active" v-if="$route.name == RouteName.RELAY_FOLLOWINGS">
<router-link :to="{ name: RouteName.RELAY_FOLLOWINGS }">{{
$t("Followings")
}}</router-link>
</li>
<li class="is-active" v-if="$route.name == RouteName.RELAY_FOLLOWERS">
<router-link :to="{ name: RouteName.RELAY_FOLLOWERS }">{{ $t("Followers") }}</router-link>
</li>
</ul>
</nav>
<section> <section>
<h1 class="title">{{ $t("Instances") }}</h1> <h1 class="title">{{ $t("Instances") }}</h1>
<div class="tabs is-boxed"> <div class="tabs is-boxed">
@ -35,6 +54,7 @@
</div> </div>
<router-view></router-view> <router-view></router-view>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -1,4 +1,15 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.MODERATION }">{{ $t("Moderation") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.PROFILES }">{{ $t("Profiles") }}</router-link>
</li>
</ul>
</nav>
<div v-if="persons"> <div v-if="persons">
<b-switch v-model="local">{{ $t("Local") }}</b-switch> <b-switch v-model="local">{{ $t("Local") }}</b-switch>
<b-switch v-model="suspended">{{ $t("Suspended") }}</b-switch> <b-switch v-model="suspended">{{ $t("Suspended") }}</b-switch>
@ -65,6 +76,7 @@
</template> </template>
</b-table> </b-table>
</div> </div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Watch } from "vue-property-decorator"; import { Component, Vue, Watch } from "vue-property-decorator";

View File

@ -1,4 +1,17 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.ADMIN }">{{ $t("Admin") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.ADMIN_SETTINGS }">{{
$t("Instance settings")
}}</router-link>
</li>
</ul>
</nav>
<section v-if="adminSettings"> <section v-if="adminSettings">
<form @submit.prevent="updateSettings"> <form @submit.prevent="updateSettings">
<b-field :label="$t('Instance Name')"> <b-field :label="$t('Instance Name')">
@ -44,7 +57,9 @@
<div class="field"> <div class="field">
<label class="label has-help">{{ $t("Instance Rules") }}</label> <label class="label has-help">{{ $t("Instance Rules") }}</label>
<small> <small>
{{ $t("A place for your code of conduct, rules or guidelines. You can use HTML tags.") }} {{
$t("A place for your code of conduct, rules or guidelines. You can use HTML tags.")
}}
</small> </small>
<b-input type="textarea" v-model="adminSettings.instanceRules" /> <b-input type="textarea" v-model="adminSettings.instanceRules" />
</div> </div>
@ -196,7 +211,9 @@
v-if="adminSettings.instancePrivacyPolicyType === InstancePrivacyType.URL" v-if="adminSettings.instancePrivacyPolicyType === InstancePrivacyType.URL"
> >
<b>{{ $t("URL") }}</b> <b>{{ $t("URL") }}</b>
<p class="content">{{ $t("Set an URL to a page with your own privacy policy.") }}</p> <p class="content">
{{ $t("Set an URL to a page with your own privacy policy.") }}
</p>
</div> </div>
<div <div
class="notification" class="notification"
@ -236,6 +253,7 @@
<b-button native-type="submit" type="is-primary">{{ $t("Save") }}</b-button> <b-button native-type="submit" type="is-primary">{{ $t("Save") }}</b-button>
</form> </form>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";

View File

@ -1,4 +1,15 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.MODERATION }">{{ $t("Moderation") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.USERS }">{{ $t("Users") }}</router-link>
</li>
</ul>
</nav>
<div v-if="users"> <div v-if="users">
<b-table <b-table
:data="users.elements" :data="users.elements"
@ -73,6 +84,7 @@
</template> </template>
</b-table> </b-table>
</div> </div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";

View File

@ -756,9 +756,9 @@ export default class Event extends EventMixin {
}); });
}); });
this.$on('eventDeleted', () => { this.$on("eventDeleted", () => {
return this.$router.push({ name: RouteName.HOME }); return this.$router.push({ name: RouteName.HOME });
}) });
} }
/** /**

View File

@ -1,4 +1,20 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.GROUP }">{{ group.name }}</router-link>
</li>
<li>
<router-link :to="{ name: RouteName.GROUP_SETTINGS }">{{ $t("Settings") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.GROUP_MEMBERS_SETTINGS }">{{
$t("Members")
}}</router-link>
</li>
</ul>
</nav>
<section class="container section" v-if="group"> <section class="container section" v-if="group">
<form @submit.prevent="inviteMember"> <form @submit.prevent="inviteMember">
<b-field :label="$t('Invite a new member')" custom-class="add-relay" horizontal> <b-field :label="$t('Invite a new member')" custom-class="add-relay" horizontal>
@ -15,6 +31,7 @@
<h1>{{ $t("Group Members") }} ({{ group.members.total }})</h1> <h1>{{ $t("Group Members") }} ({{ group.members.total }})</h1>
<pre>{{ group.members }}</pre> <pre>{{ group.members }}</pre>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -2,19 +2,21 @@
<aside class="section container"> <aside class="section container">
<h1 class="title">{{ $t("Settings") }}</h1> <h1 class="title">{{ $t("Settings") }}</h1>
<div class="columns"> <div class="columns">
<SettingsMenu class="column is-one-quarter-desktop" :menu="menu" /> <aside class="column is-one-quarter-desktop">
<div class="column">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul> <ul>
<li <SettingMenuSection :title="$t('Settings')" :to="{ name: RouteName.GROUP_SETTINGS }">
v-for="route in routes.get($route.name)" <SettingMenuItem
:class="{ 'is-active': route.to.name === $route.name }" :title="this.$t('Public')"
:key="route.title" :to="{ name: RouteName.GROUP_PUBLIC_SETTINGS }"
> />
<router-link :to="{ name: route.to.name }">{{ route.title }}</router-link> <SettingMenuItem
</li> :title="this.$t('Members')"
:to="{ name: RouteName.GROUP_MEMBERS_SETTINGS }"
/>
</SettingMenuSection>
</ul> </ul>
</nav> </aside>
<div class="column">
<router-view /> <router-view />
</div> </div>
</div> </div>
@ -22,70 +24,20 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Watch } from "vue-property-decorator"; import { Component, Vue, Watch } from "vue-property-decorator";
import SettingsMenu from "@/components/Settings/SettingsMenu.vue";
import { ISettingMenuSection } from "@/types/setting-menu.model";
import { Route } from "vue-router"; import { Route } from "vue-router";
import { IGroup, IPerson } from "@/types/actor"; import { IGroup, IPerson } from "@/types/actor";
import { FETCH_GROUP } from "@/graphql/actor"; import { FETCH_GROUP } from "@/graphql/actor";
import RouteName from "../../router/name"; import RouteName from "../../router/name";
import SettingMenuSection from "../../components/Settings/SettingMenuSection.vue";
import SettingMenuItem from "../../components/Settings/SettingMenuItem.vue";
@Component({ @Component({
components: { SettingsMenu }, components: { SettingMenuSection, SettingMenuItem },
apollo: {
group: {
query: FETCH_GROUP,
},
},
}) })
export default class Settings extends Vue { export default class Settings extends Vue {
RouteName = RouteName; RouteName = RouteName;
menu: ISettingMenuSection[] = [];
group!: IGroup[]; group!: IGroup[];
mounted() {
this.menu = [
{
title: this.$t("Settings") as string,
to: { name: RouteName.GROUP_SETTINGS } as Route,
items: [
{
title: this.$t("Public") as string,
to: { name: RouteName.GROUP_PUBLIC_SETTINGS } as Route,
},
{
title: this.$t("Members") as string,
to: { name: RouteName.GROUP_MEMBERS_SETTINGS } as Route,
},
],
},
];
}
get routes(): Map<string, Route[]> {
return this.getPath(this.menu);
}
getPath(object: ISettingMenuSection[]) {
function iter(menu: ISettingMenuSection[] | ISettingMenuSection, acc: ISettingMenuSection[]) {
if (Array.isArray(menu)) {
return menu.forEach((item: ISettingMenuSection) => {
iter(item, acc.concat(item));
});
}
if (menu.items && menu.items.length > 0) {
return menu.items.forEach((item: ISettingMenuSection) => {
iter(item, acc.concat(item));
});
}
result.set(menu.to.name, acc);
}
const result = new Map();
iter(object, []);
return result;
}
} }
</script> </script>

View File

@ -1,4 +1,17 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.MODERATION }">{{ $t("Moderation") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.REPORT_LOGS }">{{
$t("Moderation log")
}}</router-link>
</li>
</ul>
</nav>
<section> <section>
<ul v-if="actionLogs.length > 0"> <ul v-if="actionLogs.length > 0">
<li v-for="log in actionLogs" :key="log.id"> <li v-for="log in actionLogs" :key="log.id">
@ -141,6 +154,7 @@
<b-message type="is-info">{{ $t("No moderation logs yet") }}</b-message> <b-message type="is-info">{{ $t("No moderation logs yet") }}</b-message>
</div> </div>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";

View File

@ -1,4 +1,20 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs" v-if="report">
<ul>
<li>
<router-link :to="{ name: RouteName.MODERATION }">{{ $t("Moderation") }}</router-link>
</li>
<li>
<router-link :to="{ name: RouteName.REPORTS }">{{ $t("Reports") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.REPORT, params: { id: report.id } }">{{
$t("Report #{reportNumber}", { reportNumber: report.id })
}}</router-link>
</li>
</ul>
</nav>
<section> <section>
<b-message title="Error" type="is-danger" v-for="error in errors" :key="error"> <b-message title="Error" type="is-danger" v-for="error in errors" :key="error">
{{ error }} {{ error }}
@ -197,6 +213,7 @@
</form> </form>
</div> </div>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator"; import { Component, Prop, Vue } from "vue-property-decorator";

View File

@ -1,4 +1,15 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.MODERATION }">{{ $t("Moderation") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.REPORTS }">{{ $t("Reports") }}</router-link>
</li>
</ul>
</nav>
<section> <section>
<b-field> <b-field>
<b-radio-button v-model="filterReports" :native-value="ReportStatusEnum.OPEN">{{ <b-radio-button v-model="filterReports" :native-value="ReportStatusEnum.OPEN">{{
@ -30,6 +41,7 @@
</b-message> </b-message>
</div> </div>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator"; import { Component, Prop, Vue, Watch } from "vue-property-decorator";

View File

@ -2,19 +2,8 @@
<div class="section container"> <div class="section container">
<h1 class="title">{{ $t("Settings") }}</h1> <h1 class="title">{{ $t("Settings") }}</h1>
<div class="columns"> <div class="columns">
<SettingsMenu class="column is-one-quarter-desktop" :menu="menu" /> <SettingsMenu class="column is-one-quarter-desktop" />
<div class="column"> <div class="column">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li
v-for="route in routes.get($route.name)"
:class="{ 'is-active': route.to.name === $route.name }"
:key="route.to.name"
>
<router-link :to="{ name: route.to.name }">{{ route.title }}</router-link>
</li>
</ul>
</nav>
<router-view /> <router-view />
</div> </div>
</div> </div>
@ -25,7 +14,6 @@ import { Component, Vue, Watch } from "vue-property-decorator";
import { Route } from "vue-router"; import { Route } from "vue-router";
import SettingsMenu from "../components/Settings/SettingsMenu.vue"; import SettingsMenu from "../components/Settings/SettingsMenu.vue";
import RouteName from "../router/name"; import RouteName from "../router/name";
import { ISettingMenuSection } from "../types/setting-menu.model";
import { IPerson, Person } from "../types/actor"; import { IPerson, Person } from "../types/actor";
import { IDENTITIES } from "../graphql/actor"; import { IDENTITIES } from "../graphql/actor";
import { CURRENT_USER_CLIENT } from "../graphql/user"; import { CURRENT_USER_CLIENT } from "../graphql/user";
@ -44,148 +32,9 @@ import { ICurrentUser, ICurrentUserRole } from "../types/current-user.model";
export default class Settings extends Vue { export default class Settings extends Vue {
RouteName = RouteName; RouteName = RouteName;
menu: ISettingMenuSection[] = [];
identities!: IPerson[]; identities!: IPerson[];
newIdentity!: ISettingMenuSection;
currentUser!: ICurrentUser; currentUser!: ICurrentUser;
mounted() {
this.newIdentity = {
title: this.$t("New profile") as string,
to: { name: RouteName.CREATE_IDENTITY } as Route,
};
this.menu = [
{
title: this.$t("Account") as string,
to: { name: RouteName.ACCOUNT_SETTINGS } as Route,
items: [
{
title: this.$t("General") as string,
to: { name: RouteName.ACCOUNT_SETTINGS_GENERAL } as Route,
},
{
title: this.$t("Preferences") as string,
to: { name: RouteName.PREFERENCES } as Route,
},
{
title: this.$t("Email notifications") as string,
to: { name: RouteName.NOTIFICATIONS } as Route,
},
],
},
{
title: this.$t("Profiles") as string,
to: { name: RouteName.IDENTITIES } as Route,
items: [this.newIdentity],
},
];
if (
[ICurrentUserRole.MODERATOR, ICurrentUserRole.ADMINISTRATOR].includes(this.currentUser.role)
) {
this.menu.push({
title: this.$t("Moderation") as string,
to: { name: RouteName.MODERATION } as Route,
items: [
{
title: this.$t("Reports") as string,
to: { name: RouteName.REPORTS } as Route,
items: [
{
title: this.$t("Report") as string,
to: { name: RouteName.REPORT } as Route,
},
],
},
{
title: this.$t("Moderation log") as string,
to: { name: RouteName.REPORT_LOGS } as Route,
},
{
title: this.$t("Users") as string,
to: { name: RouteName.USERS } as Route,
},
{
title: this.$t("Profiles") as string,
to: { name: RouteName.PROFILES } as Route,
},
],
});
}
if (this.currentUser.role === ICurrentUserRole.ADMINISTRATOR) {
this.menu.push({
title: this.$t("Admin") as string,
to: { name: RouteName.ADMIN } as Route,
items: [
{
title: this.$t("Dashboard") as string,
to: { name: RouteName.ADMIN_DASHBOARD } as Route,
},
{
title: this.$t("Instance settings") as string,
to: { name: RouteName.ADMIN_SETTINGS } as Route,
},
{
title: this.$t("Federation") as string,
to: { name: RouteName.RELAYS } as Route,
items: [
{
title: this.$t("Followings") as string,
to: { name: RouteName.RELAY_FOLLOWINGS } as Route,
},
{
title: this.$t("Followers") as string,
to: { name: RouteName.RELAY_FOLLOWERS } as Route,
},
],
},
],
});
}
}
@Watch("identities")
updateIdentities(identities: IPerson[]) {
if (!identities) return;
if (!this.menu[1].items) return;
this.menu[1].items = [];
this.menu[1].items.push(
...identities.map((identity: IPerson) => ({
to: ({
name: RouteName.UPDATE_IDENTITY,
params: { identityName: identity.preferredUsername },
} as unknown) as Route,
title: `@${identity.preferredUsername}`,
}))
);
this.menu[1].items.push(this.newIdentity);
}
get routes(): Map<string, Route[]> {
return this.getPath(this.menu);
}
getPath(object: ISettingMenuSection[]) {
function iter(menu: ISettingMenuSection[] | ISettingMenuSection, acc: ISettingMenuSection[]) {
if (Array.isArray(menu)) {
return menu.forEach((item: ISettingMenuSection) => {
iter(item, acc.concat(item));
});
}
if (menu.items && menu.items.length > 0) {
return menu.items.forEach((item: ISettingMenuSection) => {
iter(item, acc.concat(item));
});
}
result.set(menu.to.name, acc);
}
const result = new Map();
iter(object, []);
return result;
}
} }
</script> </script>

View File

@ -1,4 +1,17 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.ACCOUNT_SETTINGS }">{{ $t("Account") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.ACCOUNT_SETTINGS_GENERAL }">{{
$t("General")
}}</router-link>
</li>
</ul>
</nav>
<section> <section>
<div class="setting-title"> <div class="setting-title">
<h2>{{ $t("Email") }}</h2> <h2>{{ $t("Email") }}</h2>
@ -140,6 +153,7 @@
</section> </section>
</b-modal> </b-modal>
</section> </section>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -1,5 +1,17 @@
<template> <template>
<div v-if="loggedUser"> <div v-if="loggedUser">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.ACCOUNT_SETTINGS }">{{ $t("Account") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.NOTIFICATIONS }">{{
$t("Email notifications")
}}</router-link>
</li>
</ul>
</nav>
<section> <section>
<div class="setting-title"> <div class="setting-title">
<h2>{{ $t("Participation notifications") }}</h2> <h2>{{ $t("Participation notifications") }}</h2>

View File

@ -1,4 +1,15 @@
<template> <template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.ACCOUNT_SETTINGS }">{{ $t("Account") }}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.PREFERENCES }">{{ $t("Preferences") }}</router-link>
</li>
</ul>
</nav>
<div> <div>
<b-field :label="$t('Language')"> <b-field :label="$t('Language')">
<b-select <b-select
@ -34,6 +45,7 @@
}) })
}}</em> }}</em>
</div> </div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Watch } from "vue-property-decorator"; import { Component, Vue, Watch } from "vue-property-decorator";
@ -42,6 +54,7 @@ import { USER_SETTINGS, SET_USER_SETTINGS, UPDATE_USER_LOCALE } from "../../grap
import { IConfig } from "../../types/config.model"; import { IConfig } from "../../types/config.model";
import { ICurrentUser } from "../../types/current-user.model"; import { ICurrentUser } from "../../types/current-user.model";
import langs from "../../i18n/langs.json"; import langs from "../../i18n/langs.json";
import RouteName from "../../router/name";
@Component({ @Component({
apollo: { apollo: {
@ -58,6 +71,8 @@ export default class Preferences extends Vue {
locale: string | null = null; locale: string | null = null;
RouteName = RouteName;
@Watch("loggedUser") @Watch("loggedUser")
setSavedTimezone(loggedUser: ICurrentUser) { setSavedTimezone(loggedUser: ICurrentUser) {
if (loggedUser && loggedUser.settings.timezone) { if (loggedUser && loggedUser.settings.timezone) {

View File

@ -1144,9 +1144,9 @@
"@types/geojson" "*" "@types/geojson" "*"
"@types/lodash@^4.14.141": "@types/lodash@^4.14.141":
version "4.14.156" version "4.14.157"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.156.tgz#cbe30909c89a1feeb7c60803e785344ea0ec82d1" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.157.tgz#fdac1c52448861dfde1a2e1515dbc46e54926dc8"
integrity sha512-l2AgHXcKUwx2DsvP19wtRPqZ4NkONjmorOdq4sMcxIjqdIuuV/ULo2ftuv4NUpevwfW7Ju/UKLqo0ZXuEt/8lQ== integrity sha512-Ft5BNFmv2pHDgxV5JDsndOWTRJ+56zte0ZpYLowp03tW+K+t8u8YMOzAnpuqPgzX6WO1XpDIUm7u04M8vdDiVQ==
"@types/minimatch@*": "@types/minimatch@*":
version "3.0.3" version "3.0.3"
@ -1164,9 +1164,9 @@
integrity sha512-6nlq2eEh75JegDGUXis9wGTYIJpUvbori4qx++PRKQsV3YRkaqUNPNykzphniqPSZADXCouBuAnyptjUkMkhvw== integrity sha512-6nlq2eEh75JegDGUXis9wGTYIJpUvbori4qx++PRKQsV3YRkaqUNPNykzphniqPSZADXCouBuAnyptjUkMkhvw==
"@types/node@*", "@types/node@>=6": "@types/node@*", "@types/node@>=6":
version "14.0.13" version "14.0.14"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.13.tgz#ee1128e881b874c371374c1f72201893616417c9" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce"
integrity sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA== integrity sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==
"@types/normalize-package-data@^2.4.0": "@types/normalize-package-data@^2.4.0":
version "2.4.0" version "2.4.0"
@ -1629,14 +1629,14 @@
prettier "^1.18.2" prettier "^1.18.2"
"@vue/eslint-config-airbnb@^5.0.2": "@vue/eslint-config-airbnb@^5.0.2":
version "5.0.2" version "5.1.0"
resolved "https://registry.yarnpkg.com/@vue/eslint-config-airbnb/-/eslint-config-airbnb-5.0.2.tgz#4e3ba49e8d7a7c0bf6b244b4d7a2fe488bfb9371" resolved "https://registry.yarnpkg.com/@vue/eslint-config-airbnb/-/eslint-config-airbnb-5.1.0.tgz#6a72e166af18ac821120ff36aae8b76b940f28aa"
integrity sha512-9wD5OfdkQ0TDYLRynP46AxOHck866zkvZoT8MgjyJNBPegTtrsIQ3cu10ZF4Nl/aU5qKeSOaY58D4YXPqF0NZg== integrity sha512-kme7oQRb3AY8UWd3X7d/uTkmrsbkhwcxhS7rvbxdvfJykLDy4GtO4MdQhmKWa7b8R/gjIMfBXaCN6XUZU9PC6Q==
dependencies: dependencies:
eslint-config-airbnb-base "^14.0.0" eslint-config-airbnb-base "^14.0.0"
eslint-import-resolver-node "^0.3.3" eslint-import-resolver-node "^0.3.4"
eslint-import-resolver-webpack "^0.11.1" eslint-import-resolver-webpack "^0.12.2"
eslint-plugin-import "^2.18.2" eslint-plugin-import "^2.21.2"
"@vue/eslint-config-prettier@^6.0.0": "@vue/eslint-config-prettier@^6.0.0":
version "6.0.0" version "6.0.0"
@ -2523,13 +2523,13 @@ atob@^2.1.2:
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
autoprefixer@^9.8.0: autoprefixer@^9.8.0:
version "9.8.2" version "9.8.4"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.2.tgz#7347396ee576b18687041bfbacd76d78e27baa56" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.4.tgz#736f1012673a70fa3464671d78d41abd54512863"
integrity sha512-9UwMMU8Rg7Fj0c55mbOpXrr/2WrRqoOwOlLNTyyYt+nhiyQdIBWipp5XWzt+Lge8r3DK5y+EHMc1OBf8VpZA6Q== integrity sha512-84aYfXlpUe45lvmS+HoAWKCkirI/sw4JK0/bTeeqgHYco3dcsOn0NqdejISjptsYwNji/21dnkDri9PsYKk89A==
dependencies: dependencies:
browserslist "^4.12.0" browserslist "^4.12.0"
caniuse-lite "^1.0.30001084" caniuse-lite "^1.0.30001087"
kleur "^4.0.1" colorette "^1.2.0"
normalize-range "^0.1.2" normalize-range "^0.1.2"
num2fraction "^1.2.2" num2fraction "^1.2.2"
postcss "^7.0.32" postcss "^7.0.32"
@ -2919,14 +2919,14 @@ browserslist@4.7.0:
node-releases "^1.1.29" node-releases "^1.1.29"
browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.5: browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.5:
version "4.12.0" version "4.12.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.0.tgz#06c6d5715a1ede6c51fc39ff67fd647f740b656d" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.1.tgz#6d08bef149b70d153930780ba762644e0f329122"
integrity sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg== integrity sha512-WMjXwFtPskSW1pQUDJRxvRKRkeCr7usN0O/Za76N+F4oadaTdQHotSGcX9jT/Hs7mSKPkyMFNvqawB/1HzYDKQ==
dependencies: dependencies:
caniuse-lite "^1.0.30001043" caniuse-lite "^1.0.30001088"
electron-to-chromium "^1.3.413" electron-to-chromium "^1.3.481"
node-releases "^1.1.53" escalade "^3.0.1"
pkg-up "^2.0.0" node-releases "^1.1.58"
buble@0.19.8, buble@^0.19.7: buble@0.19.8, buble@^0.19.7:
version "0.19.8" version "0.19.8"
@ -3185,10 +3185,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2" lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001043, caniuse-lite@^1.0.30001084: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001087, caniuse-lite@^1.0.30001088:
version "1.0.30001087" version "1.0.30001088"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001087.tgz#4a0bdc5998a114fcf8b7954e7ba6c2c29831c54a" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001088.tgz#23a6b9e192106107458528858f2c0e0dba0d9073"
integrity sha512-KAQRGtt+eGCQBSp2iZTQibdCf9oe6cNTi5lmpsW38NnxP4WMYzfU6HCRmh4kJyh6LrTM9/uyElK4xcO93kafpg== integrity sha512-6eYUrlShRYveyqKG58HcyOfPgh3zb2xqs7NvT2VVtP3hEUeeWvc3lqhpeMTxYWBBeeaT9A4bKsrtjATm66BTHg==
capture-stack-trace@^1.0.0: capture-stack-trace@^1.0.0:
version "1.0.1" version "1.0.1"
@ -3692,6 +3692,11 @@ color@^3.0.0:
color-convert "^1.9.1" color-convert "^1.9.1"
color-string "^1.5.2" color-string "^1.5.2"
colorette@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.0.tgz#45306add826d196e8c87236ac05d797f25982e63"
integrity sha512-soRSroY+OF/8OdA3PTQXwaDJeMc7TfknKKrxeSCencL2a4+Tx5zhxmmv7hdpCjhKBjehzp8+bwe/T68K0hpIjw==
colors@^1.1.2: colors@^1.1.2:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
@ -4445,7 +4450,7 @@ de-indent@^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"
integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -4932,10 +4937,10 @@ ejs@^2.6.1:
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.413: electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.481:
version "1.3.481" version "1.3.483"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.481.tgz#0d59e72a0aaeb876b43fb1d6e84bf0dfc99617e8" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.483.tgz#9269e7cfc1c8e72709824da171cbe47ca5e3ca9e"
integrity sha512-q2PeCP2PQXSYadDo9uNY+uHXjdB9PcsUpCVoGlY8TZOPHGlXdevlqW9PkKeqCxn2QBkGB8b6AcMO++gh8X82bA== integrity sha512-+05RF8S9rk8S0G8eBCqBRBaRq7+UN3lDs2DAvnG8SBSgQO3hjy0+qt4CmRk5eiuGbTcaicgXfPmBi31a+BD3lg==
elegant-spinner@^1.0.1: elegant-spinner@^1.0.1:
version "1.0.1" version "1.0.1"
@ -4999,6 +5004,15 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies: dependencies:
once "^1.4.0" once "^1.4.0"
enhanced-resolve@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=
dependencies:
graceful-fs "^4.1.2"
memory-fs "^0.2.0"
tapable "^0.1.8"
enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1: enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.2.0.tgz#5d43bda4a0fd447cb0ebbe71bef8deff8805ad0d" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.2.0.tgz#5d43bda4a0fd447cb0ebbe71bef8deff8805ad0d"
@ -5008,15 +5022,6 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1:
memory-fs "^0.5.0" memory-fs "^0.5.0"
tapable "^1.0.0" tapable "^1.0.0"
enhanced-resolve@~0.9.0:
version "0.9.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=
dependencies:
graceful-fs "^4.1.2"
memory-fs "^0.2.0"
tapable "^0.1.8"
entities@^1.1.1: entities@^1.1.1:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
@ -5091,6 +5096,11 @@ es6-promisify@^5.0.0:
dependencies: dependencies:
es6-promise "^4.0.3" es6-promise "^4.0.3"
escalade@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.1.tgz#52568a77443f6927cd0ab9c73129137533c965ed"
integrity sha512-DR6NO3h9niOT+MZs7bjxlj2a1k+POu5RN8CLTPX2+i78bRi9eLe7+0zXgUHMnGXWybYcL61E9hGhPKqedy8tQA==
escape-html@~1.0.3: escape-html@~1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -5129,7 +5139,7 @@ eslint-config-prettier@^6.0.0, eslint-config-prettier@^6.11.0:
dependencies: dependencies:
get-stdin "^6.0.0" get-stdin "^6.0.0"
eslint-import-resolver-node@^0.3.3: eslint-import-resolver-node@^0.3.3, eslint-import-resolver-node@^0.3.4:
version "0.3.4" version "0.3.4"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
@ -5137,21 +5147,21 @@ eslint-import-resolver-node@^0.3.3:
debug "^2.6.9" debug "^2.6.9"
resolve "^1.13.1" resolve "^1.13.1"
eslint-import-resolver-webpack@^0.11.1: eslint-import-resolver-webpack@^0.12.2:
version "0.11.1" version "0.12.2"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.11.1.tgz#fcf1fd57a775f51e18f442915f85dd6ba45d2f26" resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.2.tgz#769e86cd0c752a1536c19855ebd90aa14ce384ee"
integrity sha512-eK3zR7xVQR/MaoBWwGuD+CULYVuqe5QFlDukman71aI6IboCGzggDUohHNfu1ZeBnbHcUHJc0ywWoXUBNB6qdg== integrity sha512-7Jnm4YAoNNkvqPaZkKdIHsKGmv8/uNnYC5QsXkiSodvX4XEEfH2AKOna98FK52fCDXm3q4HzuX+7pRMKkJ64EQ==
dependencies: dependencies:
array-find "^1.0.0" array-find "^1.0.0"
debug "^2.6.8" debug "^2.6.9"
enhanced-resolve "~0.9.0" enhanced-resolve "^0.9.1"
find-root "^1.1.0" find-root "^1.1.0"
has "^1.0.1" has "^1.0.3"
interpret "^1.0.0" interpret "^1.2.0"
lodash "^4.17.4" lodash "^4.17.15"
node-libs-browser "^1.0.0 || ^2.0.0" node-libs-browser "^1.0.0 || ^2.0.0"
resolve "^1.10.0" resolve "^1.13.1"
semver "^5.3.0" semver "^5.7.1"
eslint-loader@^2.2.1: eslint-loader@^2.2.1:
version "2.2.1" version "2.2.1"
@ -5179,7 +5189,7 @@ eslint-plugin-cypress@^2.10.3:
dependencies: dependencies:
globals "^11.12.0" globals "^11.12.0"
eslint-plugin-import@^2.18.2, eslint-plugin-import@^2.20.2: eslint-plugin-import@^2.20.2, eslint-plugin-import@^2.21.2:
version "2.21.2" version "2.21.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.21.2.tgz#8fef77475cc5510801bedc95f84b932f7f334a7c" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.21.2.tgz#8fef77475cc5510801bedc95f84b932f7f334a7c"
integrity sha512-FEmxeGI6yaz+SnEB6YgNHlQK1Bs2DKLM+YF+vuTk5H8J9CLbJLtlPvRFgZZ2+sXiKAlN5dpdlrWOjK8ZoZJpQA== integrity sha512-FEmxeGI6yaz+SnEB6YgNHlQK1Bs2DKLM+YF+vuTk5H8J9CLbJLtlPvRFgZZ2+sXiKAlN5dpdlrWOjK8ZoZJpQA==
@ -6736,7 +6746,7 @@ has-yarn@^2.1.0:
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
has@^1.0.0, has@^1.0.1, has@^1.0.3: has@^1.0.0, has@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
@ -7261,7 +7271,7 @@ internal-ip@^4.3.0:
default-gateway "^4.2.0" default-gateway "^4.2.0"
ipaddr.js "^1.9.0" ipaddr.js "^1.9.0"
interpret@^1.0.0, interpret@^1.2.0, interpret@^1.4.0: interpret@^1.2.0, interpret@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
@ -7846,9 +7856,9 @@ jest-worker@^25.4.0:
supports-color "^7.0.0" supports-color "^7.0.0"
js-base64@^2.1.8, js-base64@^2.1.9, js-base64@^2.3.2: js-base64@^2.1.8, js-base64@^2.1.9, js-base64@^2.3.2:
version "2.6.1" version "2.6.2"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.1.tgz#c328374225d2e65569791ded73c258e2c59334c7" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.2.tgz#cf9301bc5cc756892a9a6c8d7138322e5944fb0d"
integrity sha512-G5x2saUTupU9D/xBY9snJs3TxvwX8EkpLFiYlPpDt/VmMHOXprnSU1nxiTmFbijCX4BLF/cMRIfAcC5BiMYgFQ== integrity sha512-1hgLrLIrmCgZG+ID3VoLNLOSwjGnoZa8tyrUdEteMeIzsT6PH7PMLyUvbDwzNE56P3PNxyvuIOx4Uh2E5rzQIw==
js-beautify@^1.6.12: js-beautify@^1.6.12:
version "1.11.0" version "1.11.0"
@ -8212,11 +8222,6 @@ kleur@^3.0.3:
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
kleur@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.0.1.tgz#3d4948534b666e2578f93b6fafb62108e64f05ef"
integrity sha512-Qs6SqCLm63rd0kNVh+wO4XsWLU6kgfwwaPYsLiClWf0Tewkzsa6MvB21bespb8cz+ANS+2t3So1ge3gintzhlw==
latest-version@^3.0.0: latest-version@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
@ -9386,7 +9391,7 @@ node-ipc@^9.1.1:
util "^0.11.0" util "^0.11.0"
vm-browserify "^1.0.1" vm-browserify "^1.0.1"
node-releases@^1.1.29, node-releases@^1.1.3, node-releases@^1.1.53: node-releases@^1.1.29, node-releases@^1.1.3, node-releases@^1.1.58:
version "1.1.58" version "1.1.58"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.58.tgz#8ee20eef30fa60e52755fcc0942def5a734fe935" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.58.tgz#8ee20eef30fa60e52755fcc0942def5a734fe935"
integrity sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg== integrity sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg==
@ -10286,7 +10291,7 @@ pkg-dir@^4.1.0:
dependencies: dependencies:
find-up "^4.0.0" find-up "^4.0.0"
pkg-up@2.0.0, pkg-up@^2.0.0: pkg-up@2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= integrity sha1-yBmscoBZpGHKscOImivjxJoATX8=
@ -11019,9 +11024,9 @@ prosemirror-view@1.14.7:
prosemirror-transform "^1.1.0" prosemirror-transform "^1.1.0"
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3: prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3:
version "1.14.13" version "1.15.0"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.14.13.tgz#c86967b2679652ae21f610620f5089ba654cb413" resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.15.0.tgz#372102c91d05b3b0f371b3eb59aeacedb5011bba"
integrity sha512-UmAAi72eHApZ6KMklUTORc9FkmGXyeI+rWtqxqZ+6V4vs6K6spbOVozQChKmtVL2EjQlOILvJIJdWKWu0Hkvpw== integrity sha512-a7Q76sO/DCZr2UX2Rv1Rbw52cr9kVIz8iJOf/rq4mPN1NA3lugq2BKJgUMwlB3U4utyw3olLigqouRHM48NJyg==
dependencies: dependencies:
prosemirror-model "^1.1.0" prosemirror-model "^1.1.0"
prosemirror-state "^1.0.0" prosemirror-state "^1.0.0"
@ -12292,7 +12297,7 @@ semver-diff@^2.0.0:
dependencies: dependencies:
semver "^5.0.3" semver "^5.0.3"
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: "semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1:
version "5.7.1" version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@ -14314,9 +14319,9 @@ vue-inbrowser-compiler@^4.23.3:
walkes "^0.2.1" walkes "^0.2.1"
vue-loader@^15.9.2: vue-loader@^15.9.2:
version "15.9.2" version "15.9.3"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.2.tgz#ae01f5f4c9c6a04bff4483912e72ef91a402c1ae" resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.3.tgz#0de35d9e555d3ed53969516cac5ce25531299dda"
integrity sha512-oXBubaY//CYEISBlHX+c2YPJbmOH68xXPXjFv4MAgPqQvUsnjrBAjCJi8HXZ/r/yfn0tPL5VZj1Zcp8mJPI8VA== integrity sha512-Y67VnGGgVLH5Voostx8JBZgPQTlDQeOVBLOEsjc2cXbCYBKexSKEpOA56x0YZofoDOTszrLnIShyOX1p9uCEHA==
dependencies: dependencies:
"@vue/component-compiler-utils" "^3.1.0" "@vue/component-compiler-utils" "^3.1.0"
hash-sum "^1.0.2" hash-sum "^1.0.2"