mirror of
https://github.com/anyproto/anytype-ts.git
synced 2025-06-07 21:47:02 +09:00
json files formatting + refactoring
This commit is contained in:
parent
4a43c5c0b7
commit
6ab1e2c20e
15 changed files with 156 additions and 184 deletions
23
src/json/color.ts
Normal file
23
src/json/color.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
export default {
|
||||
icons: {
|
||||
steps: { from: 0.2292, to: 1 },
|
||||
colors: [
|
||||
{ from: '#f6eb7d', to: '#cbd2fa' },
|
||||
{ from: '#112156', to: '#cbd2fa' },
|
||||
{ from: '#ffa15e', to: '#cbd2fa' },
|
||||
{ from: '#bc3a54', to: '#cbd2fa' },
|
||||
{ from: '#4d7aff', to: '#cbd2fa' },
|
||||
{ from: '#f6eb7d', to: '#bc3a54' },
|
||||
{ from: '#112156', to: '#bc3a54' },
|
||||
{ from: '#cbd2fa', to: '#bc3a54' },
|
||||
{ from: '#ffa25e', to: '#bc3a54' },
|
||||
{ from: '#4d7aff', to: '#bc3a54' },
|
||||
{ from: '#cbd2fa', to: '#ffa25e' },
|
||||
{ from: '#4d7aff', to: '#ffa25e' },
|
||||
{ from: '#bc3a54', to: '#ffa25e' },
|
||||
{ from: '#f6eb7d', to: '#ffa25e' },
|
||||
{ from: '#bc3a54', to: '#f6eb7d' },
|
||||
{ from: '#4d7aff', to: '#f6eb7d' }
|
||||
]
|
||||
}
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
export default {
|
||||
"gradientIcons": {
|
||||
"common": {
|
||||
"steps": { "from": 0.2292, "to": 1 }
|
||||
},
|
||||
"options": [
|
||||
{ "colors": { "from": "#f6eb7d", "to": "#cbd2fa" } },
|
||||
{ "colors": { "from": "#112156", "to": "#cbd2fa" } },
|
||||
{ "colors": { "from": "#ffa15e", "to": "#cbd2fa" } },
|
||||
{ "colors": { "from": "#bc3a54", "to": "#cbd2fa" } },
|
||||
{ "colors": { "from": "#4d7aff", "to": "#cbd2fa" } },
|
||||
{ "colors": { "from": "#f6eb7d", "to": "#bc3a54" } },
|
||||
{ "colors": { "from": "#112156", "to": "#bc3a54" } },
|
||||
{ "colors": { "from": "#cbd2fa", "to": "#bc3a54" } },
|
||||
{ "colors": { "from": "#ffa25e", "to": "#bc3a54" } },
|
||||
{ "colors": { "from": "#4d7aff", "to": "#bc3a54" } },
|
||||
{ "colors": { "from": "#cbd2fa", "to": "#ffa25e" } },
|
||||
{ "colors": { "from": "#4d7aff", "to": "#ffa25e" } },
|
||||
{ "colors": { "from": "#bc3a54", "to": "#ffa25e" } },
|
||||
{ "colors": { "from": "#f6eb7d", "to": "#ffa25e" } },
|
||||
{ "colors": { "from": "#bc3a54", "to": "#f6eb7d" } },
|
||||
{ "colors": { "from": "#4d7aff", "to": "#f6eb7d" } }
|
||||
]
|
||||
}
|
||||
};
|
|
@ -1,16 +1,16 @@
|
|||
export default {
|
||||
"Code": {
|
||||
"ANYTYPE_NEEDS_UPGRADE": 10,
|
||||
"NO_ACCOUNTS_FOUND": 101,
|
||||
"FAILED_TO_FIND_ACCOUNT_INFO": 104,
|
||||
"ANOTHER_ANYTYPE_PROCESS_IS_RUNNING": 108,
|
||||
"ACCOUNT_IS_DELETED": 109,
|
||||
"PROTOCOL_NEEDS_UPGRADE": 110,
|
||||
"NOT_FOUND": 3,
|
||||
"OBJECT_DELETED": 4,
|
||||
"NO_OBJECTS_TO_IMPORT": 5
|
||||
Code: {
|
||||
ANYTYPE_NEEDS_UPGRADE: 10,
|
||||
NO_ACCOUNTS_FOUND: 101,
|
||||
FAILED_TO_FIND_ACCOUNT_INFO: 104,
|
||||
ANOTHER_ANYTYPE_PROCESS_IS_RUNNING: 108,
|
||||
ACCOUNT_IS_DELETED: 109,
|
||||
PROTOCOL_NEEDS_UPGRADE: 110,
|
||||
NOT_FOUND: 3,
|
||||
OBJECT_DELETED: 4,
|
||||
NO_OBJECTS_TO_IMPORT: 5
|
||||
},
|
||||
|
||||
"Error: net::ERR_TIMED_OUT": "Network time-out",
|
||||
"Error: net::ERR_CONNECTION_CLOSED": "Connection closed"
|
||||
'Error: net::ERR_TIMED_OUT': 'Network time-out',
|
||||
'Error: net::ERR_CONNECTION_CLOSED': 'Connection closed',
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
export default {
|
||||
"clipper": {
|
||||
"ids": [ "jbnammhjiplhpjfncnlejjjejghimdkf", "jkmhmgghdjjbafmkgjmplhemjjnkligf" ],
|
||||
"name": "Anytype Webclipper",
|
||||
"prefix": "anytypeWebclipper",
|
||||
"emojiUrl": "https://anytype-static.fra1.cdn.digitaloceanspaces.com/emojies/"
|
||||
clipper: {
|
||||
ids: [ 'jbnammhjiplhpjfncnlejjjejghimdkf', 'jkmhmgghdjjbafmkgjmplhemjjnkligf' ],
|
||||
name: 'Anytype Webclipper',
|
||||
prefix: 'anytypeWebclipper',
|
||||
emojiUrl: 'https://anytype-static.fra1.cdn.digitaloceanspaces.com/emojies/'
|
||||
}
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
import Color from './colors';
|
||||
import Color from './color';
|
||||
import Constant from './constant';
|
||||
import Emoji from './emoji';
|
||||
import Error from './error';
|
||||
|
@ -6,7 +6,6 @@ import Extension from './extension';
|
|||
import Key from './key';
|
||||
import Latex from './latex';
|
||||
import Route from './route';
|
||||
import Survey from './survey';
|
||||
import Theme from './theme';
|
||||
import Url from './url';
|
||||
|
||||
|
@ -19,7 +18,6 @@ export {
|
|||
Key,
|
||||
Latex,
|
||||
Route,
|
||||
Survey,
|
||||
Theme,
|
||||
Url,
|
||||
};
|
110
src/json/key.ts
110
src/json/key.ts
|
@ -1,57 +1,57 @@
|
|||
export default {
|
||||
"backspace": 8,
|
||||
"tab": 9,
|
||||
"enter": 13,
|
||||
"shift": 16,
|
||||
"ctrl": 17,
|
||||
"alt": 18,
|
||||
"escape": 27,
|
||||
"space": 32,
|
||||
"left": 37,
|
||||
"up": 38,
|
||||
"right": 39,
|
||||
"down": 40,
|
||||
"0": 48,
|
||||
"1": 49,
|
||||
"2": 50,
|
||||
"3": 51,
|
||||
"4": 52,
|
||||
"5": 53,
|
||||
"6": 54,
|
||||
"7": 55,
|
||||
"8": 56,
|
||||
"9": 57,
|
||||
"a": 65,
|
||||
"b": 66,
|
||||
"c": 67,
|
||||
"d": 68,
|
||||
"e": 69,
|
||||
"f": 70,
|
||||
"g": 71,
|
||||
"h": 72,
|
||||
"i": 73,
|
||||
"j": 74,
|
||||
"k": 75,
|
||||
"l": 76,
|
||||
"m": 77,
|
||||
"n": 78,
|
||||
"o": 79,
|
||||
"p": 80,
|
||||
"q": 81,
|
||||
"r": 82,
|
||||
"s": 83,
|
||||
"t": 84,
|
||||
"u": 85,
|
||||
"v": 86,
|
||||
"w": 87,
|
||||
"x": 88,
|
||||
"y": 89,
|
||||
"z": 90,
|
||||
"cmd": 91,
|
||||
"comma": 188,
|
||||
"minus": 189,
|
||||
"dot": 190,
|
||||
"slash": 191,
|
||||
"/": 191,
|
||||
"dead": 192
|
||||
backspace: 8,
|
||||
tab: 9,
|
||||
enter: 13,
|
||||
shift: 16,
|
||||
ctrl: 17,
|
||||
alt: 18,
|
||||
escape: 27,
|
||||
space: 32,
|
||||
left: 37,
|
||||
up: 38,
|
||||
right: 39,
|
||||
down: 40,
|
||||
0: 48,
|
||||
1: 49,
|
||||
2: 50,
|
||||
3: 51,
|
||||
4: 52,
|
||||
5: 53,
|
||||
6: 54,
|
||||
7: 55,
|
||||
8: 56,
|
||||
9: 57,
|
||||
a: 65,
|
||||
b: 66,
|
||||
c: 67,
|
||||
d: 68,
|
||||
e: 69,
|
||||
f: 70,
|
||||
g: 71,
|
||||
h: 72,
|
||||
i: 73,
|
||||
j: 74,
|
||||
k: 75,
|
||||
l: 76,
|
||||
m: 77,
|
||||
n: 78,
|
||||
o: 79,
|
||||
p: 80,
|
||||
q: 81,
|
||||
r: 82,
|
||||
s: 83,
|
||||
t: 84,
|
||||
u: 85,
|
||||
v: 86,
|
||||
w: 87,
|
||||
x: 88,
|
||||
y: 89,
|
||||
z: 90,
|
||||
cmd: 91,
|
||||
comma: 188,
|
||||
minus: 189,
|
||||
dot: 190,
|
||||
slash: 191,
|
||||
'/': 191,
|
||||
dead: 192
|
||||
};
|
|
@ -1,11 +1,9 @@
|
|||
export default [
|
||||
{ "path": "/" },
|
||||
|
||||
{ "path": "/:page/:action/" },
|
||||
{ "path": "/:page/:action/:id?" },
|
||||
{ "path": "/:page/:action/:id?/spaceId/:spaceId?" },
|
||||
{ "path": "/:page/:action/:id?/spaceId/:spaceId?/viewId/:viewId?" },
|
||||
|
||||
{ "path": "/object" },
|
||||
{ "path": "/invite" }
|
||||
'/',
|
||||
'/:page/:action/',
|
||||
'/:page/:action/:id?',
|
||||
'/:page/:action/:id?/spaceId/:spaceId?',
|
||||
'/:page/:action/:id?/spaceId/:spaceId?/viewId/:viewId?',
|
||||
'/object',
|
||||
'/invite',
|
||||
];
|
|
@ -1,25 +0,0 @@
|
|||
export default {
|
||||
"register": {
|
||||
"url": "https://community.anytype.io/survey0"
|
||||
},
|
||||
|
||||
"delete": {
|
||||
"url": "https://community.anytype.io/survey1"
|
||||
},
|
||||
|
||||
"pmf": {
|
||||
"url": "https://community.anytype.io/survey2#anytypeid=%s"
|
||||
},
|
||||
|
||||
"object": {
|
||||
"url": "https://community.anytype.io/survey3"
|
||||
},
|
||||
|
||||
"shared": {
|
||||
"url": "https://community.anytype.io/survey4"
|
||||
},
|
||||
|
||||
"multiplayer": {
|
||||
"url": "https://community.anytype.io/survey5"
|
||||
}
|
||||
};
|
|
@ -1,25 +1,33 @@
|
|||
export default {
|
||||
"community": "https://community.anytype.io/t/how-to-file-a-bug-report/957",
|
||||
"tutorial": "https://doc.anytype.io/",
|
||||
"telegram": "https://t.me/anytype",
|
||||
"twitter": "https://twitter.com/AnytypeLabs",
|
||||
"mail": "https://anytype.io/?popup=mailinglist",
|
||||
"unsplash": {
|
||||
"site": "https://unsplash.com/",
|
||||
"utm": "?utm_source=Anytype&utm_medium=referral"
|
||||
community: 'https://community.anytype.io/t/how-to-file-a-bug-report/957',
|
||||
tutorial: 'https://doc.anytype.io/',
|
||||
telegram: 'https://t.me/anytype',
|
||||
twitter: 'https://twitter.com/AnytypeLabs',
|
||||
mail: 'https://anytype.io/?popup=mailinglist',
|
||||
unsplash: {
|
||||
site: 'https://unsplash.com/',
|
||||
utm: '?utm_source=Anytype&utm_medium=referral'
|
||||
},
|
||||
"protocol": "anytype://",
|
||||
"download": "https://download.anytype.io/?utm_campaign=add_device&utm_source=app&utm_medium=qr",
|
||||
"terms": "https://anytype.io/terms_of_use/",
|
||||
"privacy": "https://anytype.io/app_privacy/",
|
||||
"vision": "https://anytype.io/why",
|
||||
"pricing": "https://anytype.io/pricing",
|
||||
"contact": "mailto:support@anytype.io?subject=Support%20request%2C%20account%20%25accountId%25&body=%0A%0ATechnical%20information%0A----------------------------------------------%0AOS%20version%3A%20%25os%25%0AApp%20version%3A%20%25version%25%0ABuild%20number%3A%20%25build%25%0ALibrary%20version%3A%20%25middleware%25%0AAccount%20ID%3A%20%25accountId%25%0AAnalytics%20ID%3A%20%25analyticsId%25%0ADevice%20ID%3A%20%25deviceId%25",
|
||||
"extendStorage": "mailto:storage@anytype.io?subject=Get%20more%20storage%2C%20account%20%25accountId%25&body=Hi%2C%20Anytype%20team.%20I%20am%20reaching%20out%20to%20request%20an%20increase%20in%20my%20file%20storage%20capacity%20as%20I%20have%20run%20out%20of%20storage.%20My%20current%20limit%20is%20%25storageLimit%25.%20My%20account%20id%20is%20%25accountId%25.%20Cheers%2C%20%25spaceName%25",
|
||||
"membershipUpgrade": "mailto:membership-upgrade@anytype.io?subject=Upgrade%20%25name%25&body=Hello%20Anytype%20team%21%20I%20would%20like%20to%20extend%20my%20current%20membership%20for%20more%20%28please%20choose%20an%20option%29%3A%20%0A%0AExtra%20remote%20storage%0A%0AMore%20space%20editors%0A%0AAdditional%20shared%20spaces%0A%0ASpecifically%2C%20Please%20provide%20specific%20details%20of%20your%20needs%20here.",
|
||||
"gallery": "https://gallery.any.coop",
|
||||
"cdn": "https://anytype-static.fra1.cdn.digitaloceanspaces.com",
|
||||
"webclipper": "https://chromewebstore.google.com/detail/anytype-web-clipper/jbnammhjiplhpjfncnlejjjejghimdkf?hl=en",
|
||||
"membershipSpecial": "mailto:support@anytype.io?subject=Special%20Pricing%20Request%20AnytypeId%20%25accountId%25&body=Please%20specify%20your%20request%3A%0A-%20highlight%20if%20you%20represent%20an%20educational%2C%20governmental%2C%20or%20non-profit%20organization%0A-%20tell%20us%20more%20about%20your%20organization%3A%20number%20of%20employees%20and%20future%20Anytype%20users%2C%20markets%20you%27re%20working%20on%2C%20etc.%2C%0A-%20provide%20additional%20details%20about%20how%20your%20organization%20uses%20Anytype",
|
||||
"invite": "https://invite.any.coop/%s#%s"
|
||||
download: 'https://download.anytype.io/?utm_campaign=add_device&utm_source=app&utm_medium=qr',
|
||||
terms: 'https://anytype.io/terms_of_use/',
|
||||
privacy: 'https://anytype.io/app_privacy/',
|
||||
vision: 'https://anytype.io/why',
|
||||
pricing: 'https://anytype.io/pricing',
|
||||
contact: 'mailto:support@anytype.io?subject=Support%20request%2C%20account%20%25accountId%25&body=%0A%0ATechnical%20information%0A----------------------------------------------%0AOS%20version%3A%20%25os%25%0AApp%20version%3A%20%25version%25%0ABuild%20number%3A%20%25build%25%0ALibrary%20version%3A%20%25middleware%25%0AAccount%20ID%3A%20%25accountId%25%0AAnalytics%20ID%3A%20%25analyticsId%25%0ADevice%20ID%3A%20%25deviceId%25',
|
||||
extendStorage: 'mailto:storage@anytype.io?subject=Get%20more%20storage%2C%20account%20%25accountId%25&body=Hi%2C%20Anytype%20team.%20I%20am%20reaching%20out%20to%20request%20an%20increase%20in%20my%20file%20storage%20capacity%20as%20I%20have%20run%20out%20of%20storage.%20My%20current%20limit%20is%20%25storageLimit%25.%20My%20account%20id%20is%20%25accountId%25.%20Cheers%2C%20%25spaceName%25',
|
||||
membershipUpgrade: 'mailto:membership-upgrade@anytype.io?subject=Upgrade%20%25name%25&body=Hello%20Anytype%20team%21%20I%20would%20like%20to%20extend%20my%20current%20membership%20for%20more%20%28please%20choose%20an%20option%29%3A%20%0A%0AExtra%20remote%20storage%0A%0AMore%20space%20editors%0A%0AAdditional%20shared%20spaces%0A%0ASpecifically%2C%20Please%20provide%20specific%20details%20of%20your%20needs%20here.',
|
||||
gallery: 'https://gallery.any.coop',
|
||||
cdn: 'https://anytype-static.fra1.cdn.digitaloceanspaces.com',
|
||||
webclipper: 'https://chromewebstore.google.com/detail/anytype-web-clipper/jbnammhjiplhpjfncnlejjjejghimdkf?hl=en',
|
||||
membershipSpecial: 'mailto:support@anytype.io?subject=Special%20Pricing%20Request%20AnytypeId%20%25accountId%25&body=Please%20specify%20your%20request%3A%0A-%20highlight%20if%20you%20represent%20an%20educational%2C%20governmental%2C%20or%20non-profit%20organization%0A-%20tell%20us%20more%20about%20your%20organization%3A%20number%20of%20employees%20and%20future%20Anytype%20users%2C%20markets%20you%27re%20working%20on%2C%20etc.%2C%0A-%20provide%20additional%20details%20about%20how%20your%20organization%20uses%20Anytype',
|
||||
invite: 'https://invite.any.coop/%s#%s',
|
||||
|
||||
survey: {
|
||||
register: 'https://community.anytype.io/survey0',
|
||||
delete: 'https://community.anytype.io/survey1',
|
||||
pmf: 'https://community.anytype.io/survey2#anytypeid=%s',
|
||||
object: 'https://community.anytype.io/survey3',
|
||||
shared: 'https://community.anytype.io/survey4',
|
||||
multiplayer: 'https://community.anytype.io/survey5'
|
||||
}
|
||||
};
|
|
@ -41,8 +41,6 @@ const history = memoryHistory();
|
|||
const electron = U.Common.getElectron();
|
||||
const isPackaged = electron.isPackaged;
|
||||
|
||||
interface RouteElement { path: string; };
|
||||
|
||||
interface State {
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
@ -204,8 +202,8 @@ class App extends React.Component<object, State> {
|
|||
<ListNotification key="listNotification" />
|
||||
|
||||
<Switch>
|
||||
{J.Route.map((item: RouteElement, i: number) => (
|
||||
<Route path={item.path} exact={true} key={i} component={RoutePage} />
|
||||
{J.Route.map((path: string, i: number) => (
|
||||
<Route path={path} exact={true} key={i} component={RoutePage} />
|
||||
))}
|
||||
</Switch>
|
||||
</div>
|
||||
|
|
|
@ -416,7 +416,7 @@ class MenuObject extends React.Component<I.Menu> {
|
|||
};
|
||||
|
||||
case 'pageLink': {
|
||||
U.Common.clipboardCopy({ text: J.Url.protocol + U.Object.universalRoute(object) });
|
||||
U.Common.clipboardCopy({ text: `${J.Constant.protocol}://${U.Object.universalRoute(object)}` });
|
||||
analytics.event('CopyLink', { route });
|
||||
break;
|
||||
};
|
||||
|
|
|
@ -515,14 +515,14 @@ const IconObject = observer(class IconObject extends React.Component<Props> {
|
|||
gradientSvg (radius: number): string {
|
||||
const object = this.getObject();
|
||||
const iconSize = this.iconSize();
|
||||
const option = J.Color.gradientIcons.options[object.iconOption - 1] as any;
|
||||
const steps = option.steps || J.Color.gradientIcons.common.steps;
|
||||
const item = J.Color.icons.colors[object.iconOption - 1] as any;
|
||||
const { from, to } = J.Color.icons.steps;
|
||||
|
||||
const gradient = `
|
||||
<defs>
|
||||
<radialGradient id="gradient">
|
||||
<stop offset="${steps.from}" stop-color="${option.colors.from}" />
|
||||
<stop offset="${steps.to}" stop-color="${option.colors.to}" />
|
||||
<stop offset="${from}" stop-color="${item.from}" />
|
||||
<stop offset="${to}" stop-color="${item.to}" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
`;
|
||||
|
|
|
@ -45,7 +45,7 @@ class Survey {
|
|||
};
|
||||
|
||||
Storage.setSurvey(type, param);
|
||||
Renderer.send('urlOpen', U.Common.sprintf(J.Survey[t].url, account.id));
|
||||
Renderer.send('urlOpen', U.Common.sprintf(J.Url.survey[t], account.id));
|
||||
analytics.event('SurveyOpen', { type });
|
||||
};
|
||||
|
||||
|
|
|
@ -74,28 +74,27 @@ class UtilGraph {
|
|||
};
|
||||
|
||||
gradientIcon (iconOption: number, small?: boolean) {
|
||||
const option: any = J.Color.gradientIcons.options[iconOption - 1];
|
||||
const option: any = J.Color.icons.colors[iconOption - 1];
|
||||
if (!option) {
|
||||
return;
|
||||
};
|
||||
|
||||
const theme = S.Common.getThemeClass();
|
||||
const { from, to } = option.colors;
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const w = 160;
|
||||
const r = w / 2;
|
||||
const fillW = small ? w * 0.7 : w;
|
||||
const fillR = fillW / 2;
|
||||
const steps = option.steps || J.Color.gradientIcons.common.steps;
|
||||
const step0 = U.Common.getPercentage(fillR, steps.from * 100);
|
||||
const step1 = U.Common.getPercentage(fillR, steps.to * 100);
|
||||
const { from, to } = J.Color.icons.steps;
|
||||
const step0 = U.Common.getPercentage(fillR, from * 100);
|
||||
const step1 = U.Common.getPercentage(fillR, to * 100);
|
||||
const grd = ctx.createRadialGradient(r, r, step0, r, r, step1);
|
||||
|
||||
canvas.width = w;
|
||||
canvas.height = w;
|
||||
grd.addColorStop(0, from);
|
||||
grd.addColorStop(1, to);
|
||||
grd.addColorStop(0, option.from);
|
||||
grd.addColorStop(1, option.to);
|
||||
|
||||
if (small) {
|
||||
ctx.fillStyle = J.Theme[theme].graph.iconBg;
|
||||
|
|
|
@ -76,6 +76,13 @@ class UtilRouter {
|
|||
return;
|
||||
};
|
||||
|
||||
const change = () => {
|
||||
this.history.push(route);
|
||||
if (onRouteChange) {
|
||||
onRouteChange();
|
||||
};
|
||||
};
|
||||
|
||||
const onTimeout = () => {
|
||||
Preview.hideAll();
|
||||
|
||||
|
@ -85,11 +92,7 @@ class UtilRouter {
|
|||
};
|
||||
|
||||
if (!animate) {
|
||||
this.history.push(route);
|
||||
|
||||
if (onRouteChange) {
|
||||
onRouteChange();
|
||||
};
|
||||
change();
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -103,12 +106,7 @@ class UtilRouter {
|
|||
onFadeOut();
|
||||
};
|
||||
|
||||
this.history.push(route);
|
||||
|
||||
if (onRouteChange) {
|
||||
onRouteChange();
|
||||
};
|
||||
|
||||
change();
|
||||
fade.removeClass('show');
|
||||
}, J.Constant.delay.route);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue