mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[es6] use let/const wherever es6 is in use
This commit is contained in:
parent
7fb0d0fb00
commit
adac24f770
7 changed files with 97 additions and 97 deletions
|
@ -1,6 +1,6 @@
|
|||
var _ = require('lodash');
|
||||
var reEsc = require('lodash').escapeRegExp;
|
||||
var { parse, format } = require('url');
|
||||
const _ = require('lodash');
|
||||
const reEsc = require('lodash').escapeRegExp;
|
||||
const { parse, format } = require('url');
|
||||
|
||||
const urlJoin = (a, b) => {
|
||||
if (!b) return a;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
let Tab = require('../Tab');
|
||||
let expect = require('expect.js');
|
||||
let TabFakeStore = require('./_TabFakeStore');
|
||||
const Tab = require('../Tab');
|
||||
const expect = require('expect.js');
|
||||
const TabFakeStore = require('./_TabFakeStore');
|
||||
|
||||
describe.only('Chrome Tab', function () {
|
||||
describe('construction', function () {
|
||||
it('accepts id, title, resetWhenActive, trackLastUrl, activeIndicatorColor, baseUrl', function () {
|
||||
let tab = new Tab({
|
||||
const tab = new Tab({
|
||||
id: 'foo',
|
||||
title: 'Foo App',
|
||||
resetWhenActive: false,
|
||||
|
@ -19,7 +19,7 @@ describe.only('Chrome Tab', function () {
|
|||
expect(tab.activeIndicatorColor).to.equal(true);
|
||||
expect(tab.rootUrl).to.equal('proto:host.domain:999/foo');
|
||||
|
||||
tab = new Tab({
|
||||
const tab2 = new Tab({
|
||||
id: 'bar',
|
||||
title: 'Bar App',
|
||||
resetWhenActive: true,
|
||||
|
@ -27,27 +27,27 @@ describe.only('Chrome Tab', function () {
|
|||
baseUrl: 'proto:host.domain:999/sub/#/'
|
||||
});
|
||||
|
||||
expect(tab.id).to.equal('bar');
|
||||
expect(tab.title).to.equal('Bar App');
|
||||
expect(tab.resetWhenActive).to.equal(true);
|
||||
expect(tab.activeIndicatorColor).to.equal(null);
|
||||
expect(tab.rootUrl).to.equal('proto:host.domain:999/sub/#/bar');
|
||||
expect(tab2.id).to.equal('bar');
|
||||
expect(tab2.title).to.equal('Bar App');
|
||||
expect(tab2.resetWhenActive).to.equal(true);
|
||||
expect(tab2.activeIndicatorColor).to.equal(null);
|
||||
expect(tab2.rootUrl).to.equal('proto:host.domain:999/sub/#/bar');
|
||||
});
|
||||
|
||||
it('starts inactive', function () {
|
||||
let tab = new Tab();
|
||||
const tab = new Tab();
|
||||
expect(tab.active).to.equal(false);
|
||||
});
|
||||
|
||||
it('uses the id to set the rootUrl', function () {
|
||||
let id = 'foo';
|
||||
let tab = new Tab({ id });
|
||||
const id = 'foo';
|
||||
const tab = new Tab({ id });
|
||||
expect(tab.id).to.equal(id);
|
||||
expect(tab.rootUrl).to.equal(`/${id}`);
|
||||
});
|
||||
|
||||
it('creates a regexp for matching the rootUrl', function () {
|
||||
let tab = new Tab({ id: 'foo' });
|
||||
const tab = new Tab({ id: 'foo' });
|
||||
|
||||
expect('/foo').to.match(tab.rootRegExp);
|
||||
expect('/foo/bar').to.match(tab.rootRegExp);
|
||||
|
@ -62,7 +62,7 @@ describe.only('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
it('includes the baseUrl in the rootRegExp if specified', function () {
|
||||
let tab = new Tab({
|
||||
const tab = new Tab({
|
||||
id: 'foo',
|
||||
baseUrl: 'http://spiderman.com/kibana'
|
||||
});
|
||||
|
@ -75,7 +75,7 @@ describe.only('Chrome Tab', function () {
|
|||
|
||||
it('accepts a function for activeIndicatorColor', function () {
|
||||
let i = 0;
|
||||
let tab = new Tab({
|
||||
const tab = new Tab({
|
||||
activeIndicatorColor: function () {
|
||||
return i++;
|
||||
}
|
||||
|
@ -87,23 +87,23 @@ describe.only('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
it('discovers the lastUrl', function () {
|
||||
let lastUrlStore = new TabFakeStore();
|
||||
let tab = new Tab({ id: 'foo', lastUrlStore });
|
||||
const lastUrlStore = new TabFakeStore();
|
||||
const tab = new Tab({ id: 'foo', lastUrlStore });
|
||||
expect(tab.lastUrl).to.not.equal('bar');
|
||||
|
||||
tab.setLastUrl('bar');
|
||||
expect(tab.lastUrl).to.equal('bar');
|
||||
|
||||
tab = new Tab({ id: 'foo', lastUrlStore });
|
||||
expect(tab.lastUrl).to.equal('bar');
|
||||
const tab2 = new Tab({ id: 'foo', lastUrlStore });
|
||||
expect(tab2.lastUrl).to.equal('bar');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#setLastUrl()', function () {
|
||||
it('updates the lastUrl and storage value if passed a lastUrlStore', function () {
|
||||
let lastUrlStore = new TabFakeStore();
|
||||
let tab = new Tab({ id: 'foo', lastUrlStore });
|
||||
const lastUrlStore = new TabFakeStore();
|
||||
const tab = new Tab({ id: 'foo', lastUrlStore });
|
||||
|
||||
expect(tab.lastUrl).to.not.equal('foo');
|
||||
tab.setLastUrl('foo');
|
||||
|
@ -112,35 +112,35 @@ describe.only('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
it('only updates lastUrl if no lastUrlStore', function () {
|
||||
let tab = new Tab({ id: 'foo' });
|
||||
const tab = new Tab({ id: 'foo' });
|
||||
|
||||
expect(tab.lastUrl).to.equal(null);
|
||||
tab.setLastUrl('foo');
|
||||
expect(tab.lastUrl).to.equal('foo');
|
||||
|
||||
tab = new Tab({ id: 'foo' });
|
||||
expect(tab.lastUrl).to.not.equal('foo');
|
||||
const tab2 = new Tab({ id: 'foo' });
|
||||
expect(tab2.lastUrl).to.not.equal('foo');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#href()', function () {
|
||||
it('returns the rootUrl/id be default', function () {
|
||||
let tab = new Tab({ id: 'foo' });
|
||||
const tab = new Tab({ id: 'foo' });
|
||||
expect(tab.href()).to.equal(tab.rootUrl);
|
||||
});
|
||||
|
||||
it('returns the lastUrl if tracking is on', function () {
|
||||
let tab = new Tab({ id: 'foo' });
|
||||
const tab = new Tab({ id: 'foo' });
|
||||
tab.setLastUrl('okay');
|
||||
expect(tab.href()).to.equal('okay');
|
||||
});
|
||||
|
||||
describe('when the tab is active', function () {
|
||||
it('returns the rootUrl when resetWhenActive: true', function () {
|
||||
let id = 'foo';
|
||||
let resetWhenActive = true;
|
||||
let tab = new Tab({ id, resetWhenActive });
|
||||
const id = 'foo';
|
||||
const resetWhenActive = true;
|
||||
const tab = new Tab({ id, resetWhenActive });
|
||||
|
||||
tab.active = true;
|
||||
|
||||
|
@ -149,7 +149,7 @@ describe.only('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
it('or returns null when not', function () {
|
||||
let tab = new Tab({ id: 'foo', resetWhenActive: false });
|
||||
const tab = new Tab({ id: 'foo', resetWhenActive: false });
|
||||
tab.active = true;
|
||||
|
||||
expect(tab.href()).to.not.equal('butt');
|
||||
|
@ -160,8 +160,8 @@ describe.only('Chrome Tab', function () {
|
|||
|
||||
describe('#getLastPath()', function () {
|
||||
it('parses a path out of the lastUrl by removing the baseUrl', function () {
|
||||
let baseUrl = 'http://local:5601/app/visualize#';
|
||||
let tab = new Tab({ baseUrl });
|
||||
const baseUrl = 'http://local:5601/app/visualize#';
|
||||
const tab = new Tab({ baseUrl });
|
||||
|
||||
tab.setLastUrl('http://local:5601/app/visualize#/index');
|
||||
expect(tab.getLastPath()).to.equal('/index');
|
||||
|
@ -169,8 +169,8 @@ describe.only('Chrome Tab', function () {
|
|||
|
||||
it('throws an error if the lastUrl does not extend the root url', function () {
|
||||
expect(function () {
|
||||
let baseUrl = 'http://local:5601/app/visualize#';
|
||||
let tab = new Tab({ baseUrl });
|
||||
const baseUrl = 'http://local:5601/app/visualize#';
|
||||
const tab = new Tab({ baseUrl });
|
||||
|
||||
tab.setLastUrl('http://local:5601/');
|
||||
tab.getLastPath();
|
||||
|
@ -179,7 +179,7 @@ describe.only('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
describe('updateLastUrlGlobalState', function () {
|
||||
let bases = [
|
||||
const bases = [
|
||||
'http://local:5601',
|
||||
'',
|
||||
'weird.domain/with/subpath?path#',
|
||||
|
@ -187,7 +187,7 @@ describe.only('Chrome Tab', function () {
|
|||
];
|
||||
|
||||
context('with new state sets _g properly', function () {
|
||||
let paths = [
|
||||
const paths = [
|
||||
[ '/', '/?_g=newState' ],
|
||||
[ '/?first', '/?first=&_g=newState' ],
|
||||
[ '/path?first=1&_g=afterHash', '/path?first=1&_g=newState' ],
|
||||
|
@ -200,10 +200,10 @@ describe.only('Chrome Tab', function () {
|
|||
|
||||
bases.forEach(baseUrl => {
|
||||
paths.forEach(([pathFrom, pathTo]) => {
|
||||
let fromUrl = `${baseUrl}${pathFrom}`;
|
||||
let toUrl = `${baseUrl}${pathTo}`;
|
||||
const fromUrl = `${baseUrl}${pathFrom}`;
|
||||
const toUrl = `${baseUrl}${pathTo}`;
|
||||
it(`${fromUrl} => ${toUrl}`, function () {
|
||||
let tab = new Tab({ baseUrl });
|
||||
const tab = new Tab({ baseUrl });
|
||||
tab.setLastUrl(fromUrl);
|
||||
tab.updateLastUrlGlobalState('newState');
|
||||
expect(tab.getLastUrl()).to.equal(toUrl);
|
||||
|
@ -213,7 +213,7 @@ describe.only('Chrome Tab', function () {
|
|||
});
|
||||
|
||||
context('with new empty state removes _g', function () {
|
||||
let paths = [
|
||||
const paths = [
|
||||
[ '/', '/' ],
|
||||
[ '/?first', '/?first=' ],
|
||||
[ '/path?first=1&_g=afterHash', '/path?first=1' ],
|
||||
|
@ -226,10 +226,10 @@ describe.only('Chrome Tab', function () {
|
|||
|
||||
bases.forEach(baseUrl => {
|
||||
paths.forEach(([pathFrom, pathTo]) => {
|
||||
let fromUrl = `${baseUrl}${pathFrom}`;
|
||||
let toUrl = `${baseUrl}${pathTo}`;
|
||||
const fromUrl = `${baseUrl}${pathFrom}`;
|
||||
const toUrl = `${baseUrl}${pathTo}`;
|
||||
it(`${fromUrl}`, function () {
|
||||
let tab = new Tab({ baseUrl });
|
||||
const tab = new Tab({ baseUrl });
|
||||
tab.setLastUrl(fromUrl);
|
||||
tab.updateLastUrlGlobalState();
|
||||
expect(tab.getLastUrl()).to.equal(toUrl);
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
let expect = require('expect.js');
|
||||
let { indexBy, random } = require('lodash');
|
||||
const expect = require('expect.js');
|
||||
const { indexBy, random } = require('lodash');
|
||||
|
||||
let TabFakeStore = require('./_TabFakeStore');
|
||||
let TabCollection = require('../TabCollection');
|
||||
let Tab = require('../Tab');
|
||||
const TabFakeStore = require('./_TabFakeStore');
|
||||
const TabCollection = require('../TabCollection');
|
||||
const Tab = require('../Tab');
|
||||
|
||||
describe('Chrome TabCollection', function () {
|
||||
describe('empty state', function () {
|
||||
it('has no tabs', function () {
|
||||
let tabs = new TabCollection();
|
||||
const tabs = new TabCollection();
|
||||
expect(tabs.get()).to.eql([]);
|
||||
});
|
||||
|
||||
it('has no active tab', function () {
|
||||
let tabs = new TabCollection();
|
||||
const tabs = new TabCollection();
|
||||
expect(!tabs.getActive()).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#set()', function () {
|
||||
it('consumes an ordered list of Tab specs', function () {
|
||||
let tabs = new TabCollection();
|
||||
const tabs = new TabCollection();
|
||||
tabs.set([
|
||||
{ id: 'foo' },
|
||||
{ id: 'bar' }
|
||||
]);
|
||||
|
||||
let ts = tabs.get();
|
||||
const ts = tabs.get();
|
||||
expect(ts.length).to.equal(2);
|
||||
expect(ts[0].id).to.equal('foo');
|
||||
expect(ts[1].id).to.equal('bar');
|
||||
|
@ -35,7 +35,7 @@ describe('Chrome TabCollection', function () {
|
|||
|
||||
describe('#setDefaults()', function () {
|
||||
it('applies the defaults used to create tabs', function () {
|
||||
let tabs = new TabCollection();
|
||||
const tabs = new TabCollection();
|
||||
tabs.setDefaults({ id: 'thing' });
|
||||
tabs.set([ {} ]);
|
||||
|
||||
|
@ -43,7 +43,7 @@ describe('Chrome TabCollection', function () {
|
|||
});
|
||||
|
||||
it('recreates existing tabs with new defaults', function () {
|
||||
let tabs = new TabCollection();
|
||||
const tabs = new TabCollection();
|
||||
tabs.set([ {} ]);
|
||||
expect(!tabs.get()[0].id).to.equal(true);
|
||||
|
||||
|
@ -54,16 +54,16 @@ describe('Chrome TabCollection', function () {
|
|||
|
||||
describe('#consumeRouteUpdate()', function () {
|
||||
it('updates the active tab', function () {
|
||||
let store = new TabFakeStore();
|
||||
let baseUrl = `http://localhost:${random(1000, 9999)}`;
|
||||
let tabs = new TabCollection({ store, defaults: { baseUrl } });
|
||||
const store = new TabFakeStore();
|
||||
const baseUrl = `http://localhost:${random(1000, 9999)}`;
|
||||
const tabs = new TabCollection({ store, defaults: { baseUrl } });
|
||||
tabs.set([
|
||||
{ id: 'a' },
|
||||
{ id: 'b' }
|
||||
]);
|
||||
|
||||
tabs.consumeRouteUpdate(`${baseUrl}/a`);
|
||||
let {a, b} = indexBy(tabs.get(), 'id');
|
||||
const {a, b} = indexBy(tabs.get(), 'id');
|
||||
expect(a.active).to.equal(true);
|
||||
expect(b.active).to.equal(false);
|
||||
expect(tabs.getActive()).to.equal(a);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let store = Symbol('store');
|
||||
const store = Symbol('store');
|
||||
|
||||
export default class TabFakeStore {
|
||||
constructor() { this[store] = new Map(); }
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
let expect = require('expect.js');
|
||||
const expect = require('expect.js');
|
||||
|
||||
let setup = require('../apps');
|
||||
let TabFakeStore = require('../../__tests__/_TabFakeStore');
|
||||
const setup = require('../apps');
|
||||
const TabFakeStore = require('../../__tests__/_TabFakeStore');
|
||||
|
||||
describe('Chrome API :: apps', function () {
|
||||
describe('#get/setShowAppsLink()', function () {
|
||||
describe('defaults to false if there are less than two apps', function () {
|
||||
it('appCount = 0', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, { appCount: 0 });
|
||||
expect(chrome.getShowAppsLink()).to.equal(false);
|
||||
});
|
||||
|
||||
it('appCount = 1', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, { appCount: 1 });
|
||||
expect(chrome.getShowAppsLink()).to.equal(false);
|
||||
});
|
||||
|
@ -21,26 +21,26 @@ describe('Chrome API :: apps', function () {
|
|||
|
||||
describe('defaults to true if there are two or more apps', function () {
|
||||
it('appCount = 2', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, { appCount: 2 });
|
||||
expect(chrome.getShowAppsLink()).to.equal(true);
|
||||
});
|
||||
|
||||
it('appCount = 3', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, { appCount: 3 });
|
||||
expect(chrome.getShowAppsLink()).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('is chainable', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, { appCount: 1 });
|
||||
expect(chrome.setShowAppsLink(true)).to.equal(chrome);
|
||||
});
|
||||
|
||||
it('can be changed', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, { appCount: 1 });
|
||||
|
||||
expect(chrome.setShowAppsLink(true).getShowAppsLink()).to.equal(true);
|
||||
|
@ -53,8 +53,8 @@ describe('Chrome API :: apps', function () {
|
|||
|
||||
describe('#getApp()', function () {
|
||||
it('returns a clone of the current app', function () {
|
||||
let chrome = {};
|
||||
let app = { 1: 2 };
|
||||
const chrome = {};
|
||||
const app = { 1: 2 };
|
||||
setup(chrome, { app });
|
||||
|
||||
expect(chrome.getApp()).to.eql(app);
|
||||
|
@ -62,7 +62,7 @@ describe('Chrome API :: apps', function () {
|
|||
});
|
||||
|
||||
it('returns undefined if no active app', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, {});
|
||||
expect(chrome.getApp()).to.equal(undefined);
|
||||
});
|
||||
|
@ -70,14 +70,14 @@ describe('Chrome API :: apps', function () {
|
|||
|
||||
describe('#getAppTitle()', function () {
|
||||
it('returns the title property of the current app', function () {
|
||||
let chrome = {};
|
||||
let app = { title: 'foo' };
|
||||
const chrome = {};
|
||||
const app = { title: 'foo' };
|
||||
setup(chrome, { app });
|
||||
expect(chrome.getAppTitle()).to.eql('foo');
|
||||
});
|
||||
|
||||
it('returns undefined if no active app', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, {});
|
||||
expect(chrome.getAppTitle()).to.equal(undefined);
|
||||
});
|
||||
|
@ -85,14 +85,14 @@ describe('Chrome API :: apps', function () {
|
|||
|
||||
describe('#getAppUrl()', function () {
|
||||
it('returns the url property of the current app', function () {
|
||||
let chrome = {};
|
||||
let app = { url: 'foo' };
|
||||
const chrome = {};
|
||||
const app = { url: 'foo' };
|
||||
setup(chrome, { app });
|
||||
expect(chrome.getAppUrl()).to.eql('foo');
|
||||
});
|
||||
|
||||
it('returns undefined if no active app', function () {
|
||||
let chrome = {};
|
||||
const chrome = {};
|
||||
setup(chrome, {});
|
||||
expect(chrome.getAppUrl()).to.equal(undefined);
|
||||
});
|
||||
|
@ -101,8 +101,8 @@ describe('Chrome API :: apps', function () {
|
|||
describe('#getInjected()', function () {
|
||||
describe('called without args', function () {
|
||||
it('returns a clone of all injectedVars', function () {
|
||||
let chrome = {};
|
||||
let vars = { name: 'foo' };
|
||||
const chrome = {};
|
||||
const vars = { name: 'foo' };
|
||||
setup(chrome, { vars });
|
||||
expect(chrome.getInjected()).to.eql(vars);
|
||||
expect(chrome.getInjected()).to.not.equal(vars);
|
||||
|
@ -111,8 +111,8 @@ describe('Chrome API :: apps', function () {
|
|||
|
||||
describe('called with a var name', function () {
|
||||
it('returns the var at that name', function () {
|
||||
let chrome = {};
|
||||
let vars = { name: 'foo' };
|
||||
const chrome = {};
|
||||
const vars = { name: 'foo' };
|
||||
setup(chrome, { vars });
|
||||
expect(chrome.getInjected('name')).to.equal('foo');
|
||||
});
|
||||
|
@ -120,22 +120,22 @@ describe('Chrome API :: apps', function () {
|
|||
|
||||
describe('called with a var name and default', function () {
|
||||
it('returns the default when the var is undefined', function () {
|
||||
let chrome = {};
|
||||
let vars = { name: undefined };
|
||||
const chrome = {};
|
||||
const vars = { name: undefined };
|
||||
setup(chrome, { vars });
|
||||
expect(chrome.getInjected('name', 'bar')).to.equal('bar');
|
||||
});
|
||||
|
||||
it('returns null when the var is null', function () {
|
||||
let chrome = {};
|
||||
let vars = { name: null };
|
||||
const chrome = {};
|
||||
const vars = { name: null };
|
||||
setup(chrome, { vars });
|
||||
expect(chrome.getInjected('name', 'bar')).to.equal(null);
|
||||
});
|
||||
|
||||
it('returns var if not undefined', function () {
|
||||
let chrome = {};
|
||||
let vars = { name: 'kim' };
|
||||
const chrome = {};
|
||||
const vars = { name: 'kim' };
|
||||
setup(chrome, { vars });
|
||||
expect(chrome.getInjected('name', 'bar')).to.equal('kim');
|
||||
});
|
||||
|
@ -143,8 +143,8 @@ describe('Chrome API :: apps', function () {
|
|||
|
||||
describe('#get/setLastUrlFor()', function () {
|
||||
it('reads/writes last url from storage', function () {
|
||||
let chrome = {};
|
||||
let store = new TabFakeStore();
|
||||
const chrome = {};
|
||||
const store = new TabFakeStore();
|
||||
setup(chrome, { appUrlStore: store });
|
||||
expect(chrome.getLastUrlFor('app')).to.equal(undefined);
|
||||
chrome.setLastUrlFor('app', 'url');
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
let { clone, get } = require('lodash');
|
||||
let { resolve } = require('url');
|
||||
const { clone, get } = require('lodash');
|
||||
const { resolve } = require('url');
|
||||
|
||||
module.exports = function (chrome, internals) {
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module.exports = function (chrome, internals) {
|
||||
let { startsWith } = require('lodash');
|
||||
const { startsWith } = require('lodash');
|
||||
|
||||
chrome.getNavLinks = function () {
|
||||
return internals.nav;
|
||||
|
@ -10,7 +10,7 @@ module.exports = function (chrome, internals) {
|
|||
};
|
||||
|
||||
internals.trackPossibleSubUrl = function (url) {
|
||||
for (let link of internals.nav) {
|
||||
for (const link of internals.nav) {
|
||||
if (startsWith(url, link.url)) {
|
||||
link.lastSubUrl = url;
|
||||
internals.appUrlStore.setItem(`lastSubUrl:${link.url}`, url);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue