mirror of
https://github.com/plankanban/planka.git
synced 2025-07-25 08:09:44 +02:00
Move from prettier-eslint to eslint-plugin-prettier, update dependencies
This commit is contained in:
parent
f0e7fb8fd1
commit
9c7c96a780
254 changed files with 5539 additions and 5170 deletions
|
@ -1,26 +1,28 @@
|
|||
module.exports.up = (knex) => knex.raw(`
|
||||
CREATE SEQUENCE next_id_seq;
|
||||
module.exports.up = knex =>
|
||||
knex.raw(`
|
||||
CREATE SEQUENCE next_id_seq;
|
||||
|
||||
CREATE FUNCTION next_id(OUT id BIGINT) AS $$
|
||||
DECLARE
|
||||
shard INT := 1;
|
||||
epoch BIGINT := 1567191600000;
|
||||
CREATE FUNCTION next_id(OUT id BIGINT) AS $$
|
||||
DECLARE
|
||||
shard INT := 1;
|
||||
epoch BIGINT := 1567191600000;
|
||||
|
||||
sequence BIGINT;
|
||||
milliseconds BIGINT;
|
||||
BEGIN
|
||||
SELECT nextval('next_id_seq') % 1024 INTO sequence;
|
||||
SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000) INTO milliseconds;
|
||||
sequence BIGINT;
|
||||
milliseconds BIGINT;
|
||||
BEGIN
|
||||
SELECT nextval('next_id_seq') % 1024 INTO sequence;
|
||||
SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000) INTO milliseconds;
|
||||
|
||||
id := (milliseconds - epoch) << 23;
|
||||
id := id | (shard << 10);
|
||||
id := id | (sequence);
|
||||
END;
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
`);
|
||||
id := (milliseconds - epoch) << 23;
|
||||
id := id | (shard << 10);
|
||||
id := id | (sequence);
|
||||
END;
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
`);
|
||||
|
||||
module.exports.down = (knex) => knex.raw(`
|
||||
DROP SEQUENCE next_id_seq;
|
||||
module.exports.down = knex =>
|
||||
knex.raw(`
|
||||
DROP SEQUENCE next_id_seq;
|
||||
|
||||
DROP FUNCTION next_id(OUT id BIGINT);
|
||||
`);
|
||||
DROP FUNCTION next_id(OUT id BIGINT);
|
||||
`);
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('archive', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('archive', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.text('from_model').notNullable();
|
||||
table.bigInteger('original_record_id').notNullable();
|
||||
table.json('original_record').notNullable();
|
||||
table.text('from_model').notNullable();
|
||||
table.bigInteger('original_record_id').notNullable();
|
||||
table.json('original_record').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.unique(['from_model', 'original_record_id']);
|
||||
});
|
||||
table.unique(['from_model', 'original_record_id']);
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('archive');
|
||||
module.exports.down = knex => knex.schema.dropTable('archive');
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
module.exports.up = (knex) => knex.schema
|
||||
.createTable('user', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema
|
||||
.createTable('user', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.text('email').notNullable();
|
||||
table.text('password').notNullable();
|
||||
table.boolean('is_admin').notNullable();
|
||||
table.text('name').notNullable();
|
||||
table.text('avatar');
|
||||
table.text('email').notNullable();
|
||||
table.text('password').notNullable();
|
||||
table.boolean('is_admin').notNullable();
|
||||
table.text('name').notNullable();
|
||||
table.text('avatar');
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('deleted_at', true);
|
||||
})
|
||||
.raw(
|
||||
'ALTER TABLE "user" ADD CONSTRAINT "user_email_unique" EXCLUDE ("email" WITH =) WHERE ("deleted_at" IS NULL)',
|
||||
);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('deleted_at', true);
|
||||
})
|
||||
.raw(
|
||||
'ALTER TABLE "user" ADD CONSTRAINT "user_email_unique" EXCLUDE ("email" WITH =) WHERE ("deleted_at" IS NULL)',
|
||||
);
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('user');
|
||||
module.exports.down = knex => knex.schema.dropTable('user');
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('project', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('project', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.text('name').notNullable();
|
||||
table.text('name').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
});
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('project');
|
||||
module.exports.down = knex => knex.schema.dropTable('project');
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('project_membership', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('project_membership', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('project_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
table.bigInteger('project_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.unique(['project_id', 'user_id']);
|
||||
table.index('user_id');
|
||||
});
|
||||
table.unique(['project_id', 'user_id']);
|
||||
table.index('user_id');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('project_membership');
|
||||
module.exports.down = knex => knex.schema.dropTable('project_membership');
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('board', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('board', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('project_id').notNullable();
|
||||
table.bigInteger('project_id').notNullable();
|
||||
|
||||
table.specificType('position', 'double precision').notNullable();
|
||||
table.text('name').notNullable();
|
||||
table.specificType('position', 'double precision').notNullable();
|
||||
table.text('name').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.index('project_id');
|
||||
table.index('position');
|
||||
});
|
||||
table.index('project_id');
|
||||
table.index('position');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('board');
|
||||
module.exports.down = knex => knex.schema.dropTable('board');
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('list', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('list', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('board_id').notNullable();
|
||||
table.bigInteger('board_id').notNullable();
|
||||
|
||||
table.specificType('position', 'double precision').notNullable();
|
||||
table.text('name').notNullable();
|
||||
table.specificType('position', 'double precision').notNullable();
|
||||
table.text('name').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.index('board_id');
|
||||
table.index('position');
|
||||
});
|
||||
table.index('board_id');
|
||||
table.index('position');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('list');
|
||||
module.exports.down = knex => knex.schema.dropTable('list');
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('label', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('label', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('board_id').notNullable();
|
||||
table.bigInteger('board_id').notNullable();
|
||||
|
||||
table.text('name');
|
||||
table.text('color').notNullable();
|
||||
table.text('name');
|
||||
table.text('color').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.index('board_id');
|
||||
});
|
||||
table.index('board_id');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('label');
|
||||
module.exports.down = knex => knex.schema.dropTable('label');
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('card', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('card', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('list_id').notNullable();
|
||||
table.bigInteger('board_id').notNullable();
|
||||
table.bigInteger('list_id').notNullable();
|
||||
table.bigInteger('board_id').notNullable();
|
||||
|
||||
table.specificType('position', 'double precision').notNullable();
|
||||
table.text('name').notNullable();
|
||||
table.text('description');
|
||||
table.timestamp('dueDate', true);
|
||||
table.jsonb('timer');
|
||||
table.specificType('position', 'double precision').notNullable();
|
||||
table.text('name').notNullable();
|
||||
table.text('description');
|
||||
table.timestamp('dueDate', true);
|
||||
table.jsonb('timer');
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.index('list_id');
|
||||
table.index('position');
|
||||
});
|
||||
table.index('list_id');
|
||||
table.index('position');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('card');
|
||||
module.exports.down = knex => knex.schema.dropTable('card');
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('card_subscription', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('card_subscription', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
|
||||
table.boolean('is_permanent').notNullable();
|
||||
table.boolean('is_permanent').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.unique(['card_id', 'user_id']);
|
||||
table.index('user_id');
|
||||
});
|
||||
table.unique(['card_id', 'user_id']);
|
||||
table.index('user_id');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('card_subscription');
|
||||
module.exports.down = knex => knex.schema.dropTable('card_subscription');
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('card_membership', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('card_membership', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.unique(['card_id', 'user_id']);
|
||||
table.index('user_id');
|
||||
});
|
||||
table.unique(['card_id', 'user_id']);
|
||||
table.index('user_id');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('card_membership');
|
||||
module.exports.down = knex => knex.schema.dropTable('card_membership');
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('card_label', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('card_label', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('label_id').notNullable();
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('label_id').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.unique(['card_id', 'label_id']);
|
||||
table.index('label_id');
|
||||
});
|
||||
table.unique(['card_id', 'label_id']);
|
||||
table.index('label_id');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('card_label');
|
||||
module.exports.down = knex => knex.schema.dropTable('card_label');
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('task', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('task', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('card_id').notNullable();
|
||||
|
||||
table.text('name').notNullable();
|
||||
table.boolean('is_completed').notNullable();
|
||||
table.text('name').notNullable();
|
||||
table.boolean('is_completed').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.index('card_id');
|
||||
});
|
||||
table.index('card_id');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('task');
|
||||
module.exports.down = knex => knex.schema.dropTable('task');
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('action', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('action', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
|
||||
table.text('type').notNullable();
|
||||
table.jsonb('data').notNullable();
|
||||
table.text('type').notNullable();
|
||||
table.jsonb('data').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.index('card_id');
|
||||
});
|
||||
table.index('card_id');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('action');
|
||||
module.exports.down = knex => knex.schema.dropTable('action');
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
module.exports.up = (knex) => knex.schema.createTable('notification', (table) => {
|
||||
/* Columns */
|
||||
module.exports.up = knex =>
|
||||
knex.schema.createTable('notification', table => {
|
||||
/* Columns */
|
||||
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
table
|
||||
.bigInteger('id')
|
||||
.primary()
|
||||
.defaultTo(knex.raw('next_id()'));
|
||||
|
||||
table.bigInteger('user_id').notNullable();
|
||||
table.bigInteger('action_id').notNullable();
|
||||
table.bigInteger('card_id').notNullable();
|
||||
table.bigInteger('user_id').notNullable();
|
||||
table.bigInteger('action_id').notNullable();
|
||||
table.bigInteger('card_id').notNullable();
|
||||
|
||||
table.boolean('is_read').notNullable();
|
||||
table.boolean('is_read').notNullable();
|
||||
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
table.timestamp('created_at', true);
|
||||
table.timestamp('updated_at', true);
|
||||
|
||||
/* Indexes */
|
||||
/* Indexes */
|
||||
|
||||
table.index('user_id');
|
||||
table.index('action_id');
|
||||
table.index('card_id');
|
||||
table.index('is_read');
|
||||
});
|
||||
table.index('user_id');
|
||||
table.index('action_id');
|
||||
table.index('card_id');
|
||||
table.index('is_read');
|
||||
});
|
||||
|
||||
module.exports.down = (knex) => knex.schema.dropTable('notification');
|
||||
module.exports.down = knex => knex.schema.dropTable('notification');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const bcrypt = require('bcrypt');
|
||||
import bcrypt from 'bcrypt';
|
||||
|
||||
exports.seed = (knex) => {
|
||||
exports.seed = knex => {
|
||||
const date = new Date().toUTCString();
|
||||
|
||||
return knex('user').insert({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue