mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) updates from grist-core
This commit is contained in:
commit
919cff0398
31
.github/workflows/docker.yml
vendored
31
.github/workflows/docker.yml
vendored
@ -8,17 +8,35 @@ on:
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
name: Push Docker image to Docker Hub
|
||||
name: Push Docker images to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
image:
|
||||
# We build two images, `grist-oss` and `grist`.
|
||||
# See https://github.com/gristlabs/grist-core?tab=readme-ov-file#available-docker-images
|
||||
- name: "grist-oss"
|
||||
repo: "grist-core"
|
||||
- name: "grist"
|
||||
repo: "grist-ee"
|
||||
# For now, we build it twice, with `grist-ee` being a
|
||||
# backwards-compatible synoym for `grist`.
|
||||
- name: "grist-ee"
|
||||
repo: "grist-ee"
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check out the ext/ directory
|
||||
if: matrix.image.name != 'grist-oss'
|
||||
run: buildtools/checkout-ext-directory.sh ${{ matrix.image.repo }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ github.repository_owner }}/grist
|
||||
${{ github.repository_owner }}/${{ matrix.image.name }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
@ -28,13 +46,16 @@ jobs:
|
||||
stable
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Push to Docker Hub
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
@ -44,3 +65,5 @@ jobs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-contexts: ${{ matrix.image.name != 'grist-oss' && 'ext=ext' || '' }}
|
||||
|
||||
|
60
.github/workflows/docker_latest.yml
vendored
60
.github/workflows/docker_latest.yml
vendored
@ -10,6 +10,12 @@ on:
|
||||
# Run at 5:41 UTC daily
|
||||
- cron: '41 5 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
latest_branch:
|
||||
description: "Branch from which to create the latest Docker image (default: latest_candidate)"
|
||||
type: string
|
||||
required: true
|
||||
default_value: latest_candidate
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
@ -19,54 +25,98 @@ jobs:
|
||||
matrix:
|
||||
python-version: [3.9]
|
||||
node-version: [18.x]
|
||||
image:
|
||||
# We build two images, `grist-oss` and `grist`.
|
||||
# See https://github.com/gristlabs/grist-core?tab=readme-ov-file#available-docker-images
|
||||
- name: "grist-oss"
|
||||
repo: "grist-core"
|
||||
- name: "grist"
|
||||
repo: "grist-ee"
|
||||
# For now, we build it twice, with `grist-ee` being a
|
||||
# backwards-compatible synonym for `grist`.
|
||||
- name: "grist-ee"
|
||||
repo: "grist-ee"
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: latest_candidate
|
||||
ref: ${{ inputs.latest_branch }}
|
||||
|
||||
- name: Check out the ext/ directory
|
||||
if: matrix.image.name != 'grist-oss'
|
||||
run: buildtools/checkout-ext-directory.sh ${{ matrix.image.repo }}
|
||||
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Prepare image but do not push it yet
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
load: true
|
||||
tags: ${{ github.repository_owner }}/grist:latest
|
||||
tags: ${{ github.repository_owner }}/${{ matrix.image.name }}:experimental
|
||||
cache-from: type=gha
|
||||
build-contexts: ${{ matrix.image.name != 'grist-oss' && 'ext=ext' || '' }}
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }} for testing
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }} for testing - maybe not needed
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
pip install virtualenv
|
||||
yarn run install:python
|
||||
|
||||
- name: Install Node.js packages
|
||||
run: yarn install
|
||||
|
||||
- name: Build Node.js code
|
||||
run: yarn run build:prod
|
||||
run: |
|
||||
pushd ext && \
|
||||
{ if [ -e package.json ] ; then yarn install --frozen-lockfile --modules-folder=../../node_modules; fi } && \
|
||||
popd
|
||||
yarn run build:prod
|
||||
|
||||
- name: Run tests
|
||||
run: TEST_IMAGE=${{ github.repository_owner }}/grist VERBOSE=1 DEBUG=1 MOCHA_WEBDRIVER_HEADLESS=1 yarn run test:docker
|
||||
run: TEST_IMAGE=${{ github.repository_owner }}/${{ matrix.image.name }}:experimental VERBOSE=1 DEBUG=1 MOCHA_WEBDRIVER_HEADLESS=1 yarn run test:docker
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Push to Docker Hub
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
push: true
|
||||
tags: ${{ github.repository_owner }}/grist:latest
|
||||
tags: ${{ github.repository_owner }}/${{ matrix.image.name }}:experimental
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-contexts: ${{ matrix.image.name != 'grist-oss' && 'ext=ext' || '' }}
|
||||
|
||||
update_latest_branch:
|
||||
name: Update latest branch
|
||||
runs-on: ubuntu-latest
|
||||
needs: push_to_registry
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ inputs.latest_branch }}
|
||||
|
||||
- name: Update latest branch
|
||||
uses: ad-m/github-push-action@8407731efefc0d8f72af254c74276b7a90be36e1
|
||||
with:
|
||||
|
13
Dockerfile
13
Dockerfile
@ -122,6 +122,15 @@ RUN \
|
||||
mv /grist/static-built/* /grist/static && \
|
||||
rmdir /grist/static-built
|
||||
|
||||
# To ensure non-root users can run grist, 'other' users need read access (and execute on directories)
|
||||
# This should be the case by default when copying files in.
|
||||
# Only uncomment this if running into permissions issues, as it takes a long time to execute on some systems.
|
||||
# RUN chmod -R o+rX /grist
|
||||
|
||||
# Add a user to allow de-escalating from root on startup
|
||||
RUN useradd -ms /bin/bash grist
|
||||
ENV GRIST_DOCKER_USER=grist \
|
||||
GRIST_DOCKER_GROUP=grist
|
||||
WORKDIR /grist
|
||||
|
||||
# Set some default environment variables to give a setup that works out of the box when
|
||||
@ -151,5 +160,5 @@ ENV \
|
||||
|
||||
EXPOSE 8484
|
||||
|
||||
ENTRYPOINT ["/usr/bin/tini", "-s", "--"]
|
||||
CMD ["./sandbox/run.sh"]
|
||||
ENTRYPOINT ["./sandbox/docker_entrypoint.sh"]
|
||||
CMD ["node", "./sandbox/supervisor.mjs"]
|
||||
|
39
README.md
39
README.md
@ -83,7 +83,8 @@ If you just want a quick demo of Grist:
|
||||
* Or you can see a fully in-browser build of Grist at [gristlabs.github.io/grist-static](https://gristlabs.github.io/grist-static/).
|
||||
* Or you can download Grist as a desktop app from [github.com/gristlabs/grist-desktop](https://github.com/gristlabs/grist-desktop).
|
||||
|
||||
To get `grist-core` running on your computer with [Docker](https://www.docker.com/get-started), do:
|
||||
To get the default version of `grist-core` running on your computer
|
||||
with [Docker](https://www.docker.com/get-started), do:
|
||||
|
||||
```sh
|
||||
docker pull gristlabs/grist
|
||||
@ -117,22 +118,40 @@ You can find a lot more about configuring Grist, setting up authentication,
|
||||
and running it on a public server in our
|
||||
[Self-Managed Grist](https://support.getgrist.com/self-managed/) handbook.
|
||||
|
||||
## Activating the boot page for diagnosing problems
|
||||
## Available Docker images
|
||||
|
||||
You can turn on a special "boot page" to inspect the status of your
|
||||
installation. Just visit `/boot` on your Grist server for instructions.
|
||||
Since it is useful for the boot page to be available even when authentication
|
||||
isn't set up, you can give it a special access key by setting `GRIST_BOOT_KEY`.
|
||||
The default Docker image is `gristlabs/grist`. This contains all of
|
||||
the standard Grist functionality, as well as extra source-available
|
||||
code for enterprise customers taken from the the
|
||||
[grist-ee](https://github.com/gristlabs/grist-ee) repository. This
|
||||
extra code is not under a free or open source license. By default,
|
||||
however, the code from the `grist-ee` repository is completely inert and
|
||||
inactive. This code becomes active only when an administrator enables
|
||||
it by setting either `GRIST_ACTIVATION` or `GRIST_ACTIVATION_FILE`.
|
||||
|
||||
If you would rather use an image that contains exclusively free and
|
||||
open source code, the `gristlabs/grist-oss` Docker image is available
|
||||
for this purpose. It is by default functionally equivalent to the
|
||||
`gristlabs/grist` image.
|
||||
|
||||
## The administrator panel
|
||||
|
||||
You can turn on a special admininistrator panel to inspect the status
|
||||
of your installation. Just visit `/admin` on your Grist server for
|
||||
instructions. Since it is useful for the admin panel to be
|
||||
available even when authentication isn't set up, you can give it a
|
||||
special access key by setting `GRIST_BOOT_KEY`.
|
||||
|
||||
```
|
||||
docker run -p 8484:8484 -e GRIST_BOOT_KEY=secret -it gristlabs/grist
|
||||
```
|
||||
|
||||
The boot page should then be available at `/boot/<GRIST_BOOT_KEY>`. We are
|
||||
starting to collect probes for common problems there. If you hit a problem that
|
||||
isn't covered, it would be great if you could add a probe for it in
|
||||
The boot page should then be available at
|
||||
`/admin?boot-key=<GRIST_BOOT_KEY>`. We are collecting probes for
|
||||
common problems there. If you hit a problem that isn't covered, it
|
||||
would be great if you could add a probe for it in
|
||||
[BootProbes](https://github.com/gristlabs/grist-core/blob/main/app/server/lib/BootProbes.ts).
|
||||
Or file an issue so someone else can add it, we're just getting start with this.
|
||||
You may instead file an issue so someone else can add it.
|
||||
|
||||
## Building from source
|
||||
|
||||
|
@ -145,6 +145,13 @@ Please log in as an administrator.`)),
|
||||
description: t('Current authentication method'),
|
||||
value: this._buildAuthenticationDisplay(owner),
|
||||
expandedContent: this._buildAuthenticationNotice(owner),
|
||||
}),
|
||||
dom.create(AdminSectionItem, {
|
||||
id: 'session',
|
||||
name: t('Session Secret'),
|
||||
description: t('Key to sign sessions with'),
|
||||
value: this._buildSessionSecretDisplay(owner),
|
||||
expandedContent: this._buildSessionSecretNotice(owner),
|
||||
})
|
||||
]),
|
||||
dom.create(AdminSection, t('Version'), [
|
||||
@ -241,6 +248,27 @@ We recommend enabling one of these if Grist is accessible over the network or be
|
||||
to multiple people.');
|
||||
}
|
||||
|
||||
private _buildSessionSecretDisplay(owner: IDisposableOwner) {
|
||||
return dom.domComputed(
|
||||
use => {
|
||||
const req = this._checks.requestCheckById(use, 'session-secret');
|
||||
const result = req ? use(req.result) : undefined;
|
||||
|
||||
if (result?.status === 'warning') {
|
||||
return cssValueLabel(cssDangerText('default'));
|
||||
}
|
||||
|
||||
return cssValueLabel(cssHappyText('configured'));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _buildSessionSecretNotice(owner: IDisposableOwner) {
|
||||
return t('Grist signs user session cookies with a secret key. Please set this key via the environment variable \
|
||||
GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice \
|
||||
in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.');
|
||||
}
|
||||
|
||||
private _buildUpdates(owner: MultiHolder) {
|
||||
// We can be in those states:
|
||||
enum State {
|
||||
@ -472,7 +500,11 @@ to multiple people.');
|
||||
return dom.domComputed(
|
||||
use => [
|
||||
...use(this._checks.probes).map(probe => {
|
||||
const isRedundant = probe.id === 'sandboxing';
|
||||
const isRedundant = [
|
||||
'sandboxing',
|
||||
'authentication',
|
||||
'session-secret'
|
||||
].includes(probe.id);
|
||||
const show = isRedundant ? options.showRedundant : options.showNovel;
|
||||
if (!show) { return null; }
|
||||
const req = this._checks.requestCheck(probe);
|
||||
|
@ -8,7 +8,8 @@ export type BootProbeIds =
|
||||
'sandboxing' |
|
||||
'system-user' |
|
||||
'authentication' |
|
||||
'websockets'
|
||||
'websockets' |
|
||||
'session-secret'
|
||||
;
|
||||
|
||||
export interface BootProbeResult {
|
||||
|
@ -29,6 +29,9 @@ export class User extends BaseEntity {
|
||||
@Column({name: 'first_login_at', type: Date, nullable: true})
|
||||
public firstLoginAt: Date | null;
|
||||
|
||||
@Column({name: 'last_connection_at', type: Date, nullable: true})
|
||||
public lastConnectionAt: Date | null;
|
||||
|
||||
@OneToOne(type => Organization, organization => organization.owner)
|
||||
public personalOrg: Organization;
|
||||
|
||||
|
@ -395,14 +395,6 @@ export class UsersManager {
|
||||
user.name = (profile && (profile.name || email.split('@')[0])) || '';
|
||||
needUpdate = true;
|
||||
}
|
||||
if (profile && !user.firstLoginAt) {
|
||||
// set first login time to now (remove milliseconds for compatibility with other
|
||||
// timestamps in db set by typeorm, and since second level precision is fine)
|
||||
const nowish = new Date();
|
||||
nowish.setMilliseconds(0);
|
||||
user.firstLoginAt = nowish;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (!user.picture && profile && profile.picture) {
|
||||
// Set the user's profile picture if our provider knows it.
|
||||
user.picture = profile.picture;
|
||||
@ -432,6 +424,25 @@ export class UsersManager {
|
||||
user.options = {...(user.options ?? {}), authSubject: userOptions.authSubject};
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
// get date of now (remove milliseconds for compatibility with other
|
||||
// timestamps in db set by typeorm, and since second level precision is fine)
|
||||
const nowish = new Date();
|
||||
nowish.setMilliseconds(0);
|
||||
if (profile && !user.firstLoginAt) {
|
||||
// set first login time to now
|
||||
user.firstLoginAt = nowish;
|
||||
needUpdate = true;
|
||||
}
|
||||
const getTimestampStartOfDay = (date: Date) => {
|
||||
const timestamp = Math.floor(date.getTime() / 1000); // unix timestamp seconds from epoc
|
||||
const startOfDay = timestamp - (timestamp % 86400 /*24h*/); // start of a day in seconds since epoc
|
||||
return startOfDay;
|
||||
};
|
||||
if (!user.lastConnectionAt || getTimestampStartOfDay(user.lastConnectionAt) !== getTimestampStartOfDay(nowish)) {
|
||||
user.lastConnectionAt = nowish;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate) {
|
||||
login.user = user;
|
||||
await manager.save([user, login]);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {User} from 'app/gen-server/entity/User';
|
||||
import {makeId} from 'app/server/lib/idUtils';
|
||||
import {chunk} from 'lodash';
|
||||
import {MigrationInterface, QueryRunner, TableColumn} from "typeorm";
|
||||
|
||||
export class UserUUID1663851423064 implements MigrationInterface {
|
||||
@ -16,11 +16,20 @@ export class UserUUID1663851423064 implements MigrationInterface {
|
||||
// Updating so many rows in a multiple queries is not ideal. We will send updates in chunks.
|
||||
// 300 seems to be a good number, for 24k rows we have 80 queries.
|
||||
const userList = await queryRunner.manager.createQueryBuilder()
|
||||
.select("users")
|
||||
.from(User, "users")
|
||||
.select(["users.id", "users.ref"])
|
||||
.from("users", "users")
|
||||
.getMany();
|
||||
userList.forEach(u => u.ref = makeId());
|
||||
await queryRunner.manager.save(userList, { chunk: 300 });
|
||||
|
||||
const userChunks = chunk(userList, 300);
|
||||
for (const users of userChunks) {
|
||||
await queryRunner.connection.transaction(async manager => {
|
||||
const queries = users.map((user: any, _index: number, _array: any[]) => {
|
||||
return queryRunner.manager.update("users", user.id, user);
|
||||
});
|
||||
await Promise.all(queries);
|
||||
});
|
||||
}
|
||||
|
||||
// We are not making this column unique yet, because it can fail
|
||||
// if there are some old workers still running, and any new user
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {User} from 'app/gen-server/entity/User';
|
||||
import {makeId} from 'app/server/lib/idUtils';
|
||||
import {chunk} from 'lodash';
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class UserRefUnique1664528376930 implements MigrationInterface {
|
||||
@ -9,12 +9,21 @@ export class UserRefUnique1664528376930 implements MigrationInterface {
|
||||
|
||||
// Update users that don't have unique ref set.
|
||||
const userList = await queryRunner.manager.createQueryBuilder()
|
||||
.select("users")
|
||||
.from(User, "users")
|
||||
.where("ref is null")
|
||||
.select(["users.id", "users.ref"])
|
||||
.from("users", "users")
|
||||
.where("users.ref is null")
|
||||
.getMany();
|
||||
userList.forEach(u => u.ref = makeId());
|
||||
await queryRunner.manager.save(userList, {chunk: 300});
|
||||
|
||||
const userChunks = chunk(userList, 300);
|
||||
for (const users of userChunks) {
|
||||
await queryRunner.connection.transaction(async manager => {
|
||||
const queries = users.map((user: any, _index: number, _array: any[]) => {
|
||||
return queryRunner.manager.update("users", user.id, user);
|
||||
});
|
||||
await Promise.all(queries);
|
||||
});
|
||||
}
|
||||
|
||||
// Mark column as unique and non-nullable.
|
||||
const users = (await queryRunner.getTable('users'))!;
|
||||
|
18
app/gen-server/migration/1713186031023-UserLastConnection.ts
Normal file
18
app/gen-server/migration/1713186031023-UserLastConnection.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {MigrationInterface, QueryRunner, TableColumn} from 'typeorm';
|
||||
|
||||
export class UserLastConnection1713186031023 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
const sqlite = queryRunner.connection.driver.options.type === 'sqlite';
|
||||
const datetime = sqlite ? "datetime" : "timestamp with time zone";
|
||||
await queryRunner.addColumn('users', new TableColumn({
|
||||
name: 'last_connection_at',
|
||||
type: datetime,
|
||||
isNullable: true
|
||||
}));
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.dropColumn('users', 'last_connection_at');
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import { GristServer } from 'app/server/lib/GristServer';
|
||||
import * as express from 'express';
|
||||
import WS from 'ws';
|
||||
import fetch from 'node-fetch';
|
||||
import { DEFAULT_SESSION_SECRET } from 'app/server/lib/coreCreator';
|
||||
|
||||
/**
|
||||
* Self-diagnostics useful when installing Grist.
|
||||
@ -61,6 +62,7 @@ export class BootProbes {
|
||||
this._probes.push(_sandboxingProbe);
|
||||
this._probes.push(_authenticationProbe);
|
||||
this._probes.push(_webSocketsProbe);
|
||||
this._probes.push(_sessionSecretProbe);
|
||||
this._probeById = new Map(this._probes.map(p => [p.id, p]));
|
||||
}
|
||||
}
|
||||
@ -284,3 +286,17 @@ const _authenticationProbe: Probe = {
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const _sessionSecretProbe: Probe = {
|
||||
id: 'session-secret',
|
||||
name: 'Session secret',
|
||||
apply: async(server, req) => {
|
||||
const usingDefaultSessionSecret = server.create.sessionSecret() === DEFAULT_SESSION_SECRET;
|
||||
return {
|
||||
status: usingDefaultSessionSecret ? 'warning' : 'success',
|
||||
details: {
|
||||
"GRIST_SESSION_SECRET": process.env.GRIST_SESSION_SECRET ? "set" : "not set",
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
@ -1883,6 +1883,22 @@ export class FlexServer implements GristServer {
|
||||
const probes = new BootProbes(this.app, this, '/api', adminMiddleware);
|
||||
probes.addEndpoints();
|
||||
|
||||
this.app.post('/api/admin/restart', requireInstallAdmin, expressWrap(async (req, resp) => {
|
||||
const newConfig = req.body.newConfig;
|
||||
resp.on('finish', () => {
|
||||
// If we have IPC with parent process (e.g. when running under
|
||||
// Docker) tell the parent that we have a new environment so it
|
||||
// can restart us.
|
||||
if (process.send) {
|
||||
process.send({ action: 'restart', newConfig });
|
||||
}
|
||||
});
|
||||
// On the topic of http response codes, thus spake MDN:
|
||||
// "409: This response is sent when a request conflicts with the current state of the server."
|
||||
const status = process.send ? 200 : 409;
|
||||
return resp.status(status).send();
|
||||
}));
|
||||
|
||||
// Restrict this endpoint to install admins
|
||||
this.app.get('/api/install/prefs', requireInstallAdmin, expressWrap(async (_req, resp) => {
|
||||
const activation = await this._activations.current();
|
||||
|
@ -3,11 +3,14 @@ import { checkMinIOBucket, checkMinIOExternalStorage,
|
||||
import { makeSimpleCreator } from 'app/server/lib/ICreate';
|
||||
import { Telemetry } from 'app/server/lib/Telemetry';
|
||||
|
||||
export const DEFAULT_SESSION_SECRET =
|
||||
'Phoo2ag1jaiz6Moo2Iese2xoaphahbai3oNg7diemohlah0ohtae9iengafieS2Hae7quungoCi9iaPh';
|
||||
|
||||
export const makeCoreCreator = () => makeSimpleCreator({
|
||||
deploymentType: 'core',
|
||||
// This can and should be overridden by GRIST_SESSION_SECRET
|
||||
// (or generated randomly per install, like grist-omnibus does).
|
||||
sessionSecret: 'Phoo2ag1jaiz6Moo2Iese2xoaphahbai3oNg7diemohlah0ohtae9iengafieS2Hae7quungoCi9iaPh',
|
||||
sessionSecret: DEFAULT_SESSION_SECRET,
|
||||
storage: [
|
||||
{
|
||||
name: 'minio',
|
||||
|
@ -6,10 +6,10 @@ import {GristServer} from 'app/server/lib/GristServer';
|
||||
import {fromCallback} from 'app/server/lib/serverUtils';
|
||||
import {Sessions} from 'app/server/lib/Sessions';
|
||||
import {promisifyAll} from 'bluebird';
|
||||
import * as crypto from 'crypto';
|
||||
import * as express from 'express';
|
||||
import assignIn = require('lodash/assignIn');
|
||||
import * as path from 'path';
|
||||
import * as shortUUID from "short-uuid";
|
||||
|
||||
|
||||
export const cookieName = process.env.GRIST_SESSION_COOKIE || 'grist_sid';
|
||||
@ -118,7 +118,10 @@ export function initGristSessions(instanceRoot: string, server: GristServer) {
|
||||
// cookie could be stolen (with some effort) by the custom domain's owner, we limit the damage
|
||||
// by only honoring custom-domain cookies for requests to that domain.
|
||||
const generateId = (req: RequestWithOrg) => {
|
||||
const uid = shortUUID.generate();
|
||||
// Generate 256 bits of cryptographically random data to use as the session ID.
|
||||
// This ensures security against brute-force session hijacking even without signing the session ID.
|
||||
const randomNumbers = crypto.getRandomValues(new Uint8Array(32));
|
||||
const uid = Buffer.from(randomNumbers).toString("hex");
|
||||
return req.isCustomHost ? `c-${uid}@${req.org}@${req.get('host')}` : `g-${uid}`;
|
||||
};
|
||||
const sessionSecret = server.create.sessionSecret();
|
||||
|
@ -21,8 +21,8 @@ export const TEST_HTTPS_OFFSET = process.env.GRIST_TEST_HTTPS_OFFSET ?
|
||||
|
||||
// Database fields that we permit in entities but don't want to cross the api.
|
||||
const INTERNAL_FIELDS = new Set([
|
||||
'apiKey', 'billingAccountId', 'firstLoginAt', 'filteredOut', 'ownerId', 'gracePeriodStart', 'stripeCustomerId',
|
||||
'stripeSubscriptionId', 'stripeProductId', 'userId', 'isFirstTimeUser', 'allowGoogleLogin',
|
||||
'apiKey', 'billingAccountId', 'firstLoginAt', 'lastConnectionAt', 'filteredOut', 'ownerId', 'gracePeriodStart',
|
||||
'stripeCustomerId', 'stripeSubscriptionId', 'stripeProductId', 'userId', 'isFirstTimeUser', 'allowGoogleLogin',
|
||||
'authSubject', 'usage', 'createdBy'
|
||||
]);
|
||||
|
||||
|
1
buildtools/.grist-ee-version
Normal file
1
buildtools/.grist-ee-version
Normal file
@ -0,0 +1 @@
|
||||
0.9.2
|
@ -5,7 +5,11 @@ set -e
|
||||
PROJECT=""
|
||||
if [[ -e ext/app ]]; then
|
||||
PROJECT="tsconfig-ext.json"
|
||||
echo "Using extra app directory"
|
||||
else
|
||||
echo "No extra app directory found"
|
||||
fi
|
||||
|
||||
WEBPACK_CONFIG=buildtools/webpack.config.js
|
||||
if [[ -e ext/buildtools/webpack.config.js ]]; then
|
||||
# Allow webpack config file to be replaced (useful
|
||||
|
18
buildtools/checkout-ext-directory.sh
Executable file
18
buildtools/checkout-ext-directory.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This checks out the ext/ directory from the extra repo (e.g.
|
||||
# grist-ee or grist-desktop) depending on the supplied repo name.
|
||||
|
||||
set -e
|
||||
|
||||
repo=$1
|
||||
dir=$(dirname $0)
|
||||
ref=$(cat $dir/.$repo-version)
|
||||
|
||||
git clone --branch $ref --depth 1 --filter=tree:0 "https://github.com/gristlabs/$repo"
|
||||
pushd $repo
|
||||
git sparse-checkout set ext
|
||||
git checkout
|
||||
popd
|
||||
mv $repo/ext .
|
||||
rm -rf $repo
|
297
documentation/database.md
Normal file
297
documentation/database.md
Normal file
@ -0,0 +1,297 @@
|
||||
# Database
|
||||
|
||||
> [!WARNING]
|
||||
> This documentation is meant to describe the state of the database. The reader should be aware that some undocumented changes may have been done after its last updates, and for this purpose should check the git history of this file.
|
||||
>
|
||||
> Also contributions are welcome! :heart:
|
||||
|
||||
Grist manages two databases:
|
||||
1. The Home Database;
|
||||
2. The Document Database (also known as "the grist document");
|
||||
|
||||
The Home database is responsible for things related to the instance, such as:
|
||||
- the users and the groups registered on the instance,
|
||||
- the billing,
|
||||
- the organisations (also called sites), the workspaces,
|
||||
- the documents' metadata (such as ID, name, or workspace under which it is located);
|
||||
- the access permissions (ACLs) to organisations, workspaces and documents (access to the content of the document is controlled by the document itself);
|
||||
|
||||
A Grist Document contains data such as:
|
||||
- The tables, pages, views data;
|
||||
- The ACL *inside* to access to all or part of tables (rows or columns);
|
||||
|
||||
## The Document Database
|
||||
|
||||
### Inspecting the Document
|
||||
|
||||
A Grist Document (with the `.grist` extension) is actually a SQLite database. You may download a document like [this one](https://api.getgrist.com/o/templates/api/docs/keLK5sVeyfPkxyaXqijz2x/download?template=false&nohistory=false) and inspect its content using a tool such as the `sqlite3` command:
|
||||
|
||||
````
|
||||
$ sqlite3 Flashcards.grist
|
||||
sqlite> .tables
|
||||
Flashcards_Data _grist_TabBar
|
||||
Flashcards_Data_summary_Card_Set _grist_TabItems
|
||||
GristDocTour _grist_TableViews
|
||||
_grist_ACLMemberships _grist_Tables
|
||||
_grist_ACLPrincipals _grist_Tables_column
|
||||
_grist_ACLResources _grist_Triggers
|
||||
_grist_ACLRules _grist_Validations
|
||||
_grist_Attachments _grist_Views
|
||||
_grist_Cells _grist_Views_section
|
||||
_grist_DocInfo _grist_Views_section_field
|
||||
_grist_External_database _gristsys_Action
|
||||
_grist_External_table _gristsys_ActionHistory
|
||||
_grist_Filters _gristsys_ActionHistoryBranch
|
||||
_grist_Imports _gristsys_Action_step
|
||||
_grist_Pages _gristsys_FileInfo
|
||||
_grist_REPL_Hist _gristsys_Files
|
||||
_grist_Shares _gristsys_PluginData
|
||||
````
|
||||
|
||||
:warning: If you want to ensure that you will not alter a document's contents, make a backup copy beforehand.
|
||||
|
||||
### The migrations
|
||||
|
||||
The migrations are handled in the Python sandbox in this code:
|
||||
https://github.com/gristlabs/grist-core/blob/main/sandbox/grist/migrations.py
|
||||
|
||||
For more information, please consult [the documentation for migrations](./migrations.md).
|
||||
|
||||
## The Home Database
|
||||
|
||||
The home database may either be a SQLite or a PostgreSQL database depending on how the Grist instance has been installed. For details, please refer to the `TYPEORM_*` env variables in the [README](https://github.com/gristlabs/grist-core/blob/main/README.md#database-variables).
|
||||
|
||||
Unless otherwise configured, the home database is a SQLite file. In the default Docker image, it is stored at this location: `/persist/home.sqlite3`.
|
||||
|
||||
The schema below is the same (except for minor differences in the column types), regardless of what the database type is.
|
||||
|
||||
### The Schema
|
||||
|
||||
The database schema is the following:
|
||||
|
||||
![Schema of the home database](./images/homedb-schema.svg)
|
||||
|
||||
> [!NOTE]
|
||||
> For simplicity's sake, we have removed tables related to the billing and to the migrations.
|
||||
|
||||
If you want to generate the above schema by yourself, you may run the following command using [SchemaCrawler](https://www.schemacrawler.com/) ([a docker image is available for a quick run](https://www.schemacrawler.com/docker-image.html)):
|
||||
````bash
|
||||
# You may adapt the --database argument to fit with the actual file name
|
||||
# You may also remove the `--grep-tables` option and all that follows to get the full schema.
|
||||
$ schemacrawler --server=sqlite --database=landing.db --info-level=standard \
|
||||
--portable-names --command=schema --output-format=svg \
|
||||
--output-file=/tmp/graph.svg \
|
||||
--grep-tables="products|billing_accounts|limits|billing_account_managers|activations|migrations" \
|
||||
--invert-match
|
||||
````
|
||||
|
||||
### `orgs` table
|
||||
|
||||
Stores organisations (also called "Team sites") information.
|
||||
|
||||
| Column name | Description |
|
||||
| ------------- | -------------- |
|
||||
| id | The primary key |
|
||||
| name | The name as displayed in the UI |
|
||||
| domain | The part that should be added in the URL |
|
||||
| owner | The id of the user who owns the org |
|
||||
| host | ??? |
|
||||
|
||||
### `workspaces` table
|
||||
|
||||
Stores workspaces information.
|
||||
|
||||
| Column name | Description |
|
||||
| ------------- | -------------- |
|
||||
| id | The primary key |
|
||||
| name | The name as displayed in the UI |
|
||||
| org_id | The organisation to which the workspace belongs |
|
||||
| removed_at | If not null, stores the date when the workspaces has been placed in the trash (it will be hard deleted after 30 days) |
|
||||
|
||||
|
||||
### `docs` table
|
||||
|
||||
Stores document information that is not portable, which means that it does not store the document data nor the ACL rules (see the "Document Database" section).
|
||||
|
||||
| Column name | Description |
|
||||
| ------------- | -------------- |
|
||||
| id | The primary key |
|
||||
| name | The name as displayed in the UI |
|
||||
| workspace_id | The workspace the document belongs to |
|
||||
| is_pinned | Whether the document has been pinned or not |
|
||||
| url_id | Short version of the `id`, as displayed in the URL |
|
||||
| removed_at | If not null, stores the date when the workspaces has been placed in the trash (it will be hard deleted after 30 days) |
|
||||
| options | Serialized options as described in the [DocumentOptions](https://github.com/gristlabs/grist-core/blob/4567fad94787c20f65db68e744c47d5f44b932e4/app/common/UserAPI.ts#L125-L135) interface |
|
||||
| grace_period_start | Specific to getgrist.com (TODO describe it) |
|
||||
| usage | stats about the document (see [DocumentUsage](https://github.com/gristlabs/grist-core/blob/4567fad94787c20f65db68e744c47d5f44b932e4/app/common/DocUsage.ts)) |
|
||||
| trunk_id | If set, the current document is a fork (only from a tutorial), and this column references the original document |
|
||||
| type | If set, the current document is a special one (as specified in [DocumentType](https://github.com/gristlabs/grist-core/blob/4567fad94787c20f65db68e744c47d5f44b932e4/app/common/UserAPI.ts#L123)) |
|
||||
|
||||
### `aliases` table
|
||||
|
||||
Aliases for documents.
|
||||
|
||||
FIXME: What's the difference between `docs.url_id` and `alias.url_id`?
|
||||
|
||||
| Column name | Description |
|
||||
| ------------- | -------------- |
|
||||
| url_id | The URL alias for the doc_id |
|
||||
| org_id | The organisation the document belongs to |
|
||||
| doc_id | The document id |
|
||||
|
||||
### `acl_rules` table
|
||||
|
||||
Permissions to access either a document, workspace or an organisation.
|
||||
|
||||
| Column name | Description |
|
||||
| ------------- | -------------- |
|
||||
| id | The primary key |
|
||||
| permissions | The permissions granted to the group. See below. |
|
||||
| type | Either equals to `ACLRuleOrg`, `ACLRuleWs` or `ACLRuleDoc` |
|
||||
| org_id | The org id associated to this ACL (if set, workspace_id and doc_id are null) |
|
||||
| workspace_id | The workspace id associated to this ACL (if set, doc_id and org_id are null) |
|
||||
| doc_id | The document id associated to this ACL (if set, workspace_id and org_id are null) |
|
||||
| group_id | The group of users for which the ACL applies |
|
||||
|
||||
<a name="acl-permissions"></a>
|
||||
The permissions are stored as an integer which is read in its binary form which allows to make bitwise operations:
|
||||
|
||||
| Name | Value (binary) | Description |
|
||||
| --------------- | --------------- | --------------- |
|
||||
| VIEW | +0b00000001 | can view |
|
||||
| UPDATE | +0b00000010 | can update |
|
||||
| ADD | +0b00000100 | can add |
|
||||
| REMOVE | +0b00001000 | can remove |
|
||||
| SCHEMA_EDIT | +0b00010000 | can change schema of tables |
|
||||
| ACL_EDIT | +0b00100000 | can edit the ACL (docs) or manage the teams (orgs and workspaces) of the resource |
|
||||
| (reserved) | +0b01000000 | (reserved bit for the future) |
|
||||
| PUBLIC | +0b10000000 | virtual bit meaning that the resource is shared publicly (not currently used) |
|
||||
|
||||
You notice that the permissions can be then composed:
|
||||
- EDITOR permissions = `VIEW | UPDATE | ADD | REMOVE` = `0b00000001+0b00000010+0b00000100+0b00001000` = `0b00001111` = `15`
|
||||
- ADMIN permissions = `EDITOR | SCHEMA_EDIT` = `0b00001111+0b00010000` = `0b00011111` = `31`
|
||||
- OWNER permissions = `ADMIN | ACL_EDIT` = `0b00011111+0b00100000` = `0b0011111` = `63`
|
||||
|
||||
For more details about that part, please refer [to the code](https://github.com/gristlabs/grist-core/blob/192e2f36ba77ec67069c58035d35205978b9215e/app/gen-server/lib/Permissions.ts).
|
||||
|
||||
### `secrets` table
|
||||
|
||||
Stores secret informations related to documents, so the document may not store them (otherwise someone who downloads a doc may access them). Used to store the unsubscribe key and the target url of Webhooks.
|
||||
|
||||
| Column name | Description |
|
||||
| ------------- | -------------- |
|
||||
| id | The primary key |
|
||||
| value | The value of the secret (despite the table name, its stored unencrypted) |
|
||||
| doc_id | The document id |
|
||||
|
||||
### `prefs` table
|
||||
|
||||
Stores special grants for documents for anyone having the key.
|
||||
|
||||
| Column name | Description |
|
||||
| ------------- | -------------- |
|
||||
| id | The primary key |
|
||||
| key | A long string secret to identify the share. Suitable for URLs. Unique across the database / installation. |
|
||||
| link_id | A string to identify the share. This identifier is common to the home database and the document specified by docId. It need only be unique within that document, and is not a secret. | doc_id | The document to which the share belongs |
|
||||
| options | Any overall qualifiers on the share |
|
||||
|
||||
For more information, please refer [to the comments in the code](https://github.com/gristlabs/grist-core/blob/192e2f36ba77ec67069c58035d35205978b9215e/app/gen-server/entity/Share.ts).
|
||||
|
||||
### `groups` table
|
||||
|
||||
The groups are entities that may contain either other groups and/or users.
|
||||
|
||||
| Column name | Description |
|
||||
|--------------- | --------------- |
|
||||
| id | The primary key |
|
||||
| name | The name (see the 5 types of groups below) |
|
||||
|
||||
Only 5 types of groups exist, which corresponds actually to Roles (for the permissions, please refer to the [ACL rules permissions details](#acl-permissions)):
|
||||
- `owners` (see the `OWNERS` permissions)
|
||||
- `editors` (see the `EDITORS` permissions)
|
||||
- `viewers` (see the `VIEWS` permissions)
|
||||
- `members`
|
||||
- `guests`
|
||||
|
||||
`viewers`, `members` and `guests` have basically the same rights (like viewers), the only difference between them is that:
|
||||
- `viewers` are explicitly allowed to view the resource and its descendants;
|
||||
- `members` are specific to the organisations and are meant to allow access to be granted to individual documents or workspaces, rather than the full team site.
|
||||
- `guests` are (FIXME: help please on this one :))
|
||||
|
||||
Each time a resource is created, the groups corresponding to the roles above are created (except the `members` which are specific to organisations).
|
||||
|
||||
### `group_groups` table
|
||||
|
||||
The table which allows groups to contain other groups. It is also used for the inheritance mechanism (see below).
|
||||
|
||||
| Column name | Description |
|
||||
|--------------- | --------------- |
|
||||
| group_id | The id of the group containing the subgroup |
|
||||
| subgroup_id | The id of the subgroup |
|
||||
|
||||
### `group_users` table
|
||||
|
||||
The table which assigns users to groups.
|
||||
|
||||
| Column name | Description |
|
||||
|--------------- | --------------- |
|
||||
| group_id | The id of the group containing the user |
|
||||
| user_id | The id of the user |
|
||||
|
||||
### `groups`, `group_groups`, `group_users` and inheritances
|
||||
|
||||
We mentioned earlier that the groups currently holds the roles with the associated permissions.
|
||||
|
||||
The database stores the inheritances of rights as described below.
|
||||
|
||||
Let's imagine that a user is granted the role of *Owner* for the "Org1" organisation, s/he therefore belongs to the group "Org1 Owners" (whose ID is `id_org1_owner_grp`) which also belongs to the "WS1 Owners" (whose ID is `id_ws1_owner_grp`) by default. In other words, this user is by default owner of both the Org1 organization and of the WS1 workspace.
|
||||
|
||||
The below schema illustrates both the inheritance of between the groups and the state of the database:
|
||||
|
||||
![BDD state by default](./images/BDD-doc-inheritance-default.svg) <!-- Use diagrams.net and import ./images/BDD.drawio to edit this image -->
|
||||
|
||||
This inheritance can be changed through the Users management popup in the Contextual Menu for the Workspaces:
|
||||
|
||||
![The drop-down list after "Inherit access:" in the workspaces Users Management popup](./images/ws-users-management-popup.png)
|
||||
|
||||
If you change the inherit access to "View Only", here is what happens:
|
||||
|
||||
![BDD state after inherit access has changed, the `group_groups.group_id` value has changed](./images/BDD-doc-inheritance-after-change.svg) <!-- Use diagrams.net and import ./images/BDD.drawio to edit this image -->
|
||||
|
||||
The Org1 owners now belongs to the "WS1 Viewers" group, and the user despite being *Owner* of "Org1" can only view the workspace WS1 and its documents because s/he only gets the Viewer role for this workspace. Regarding the database, `group_groups` which holds the group inheritance has been updated, so the parent group for `id_org1_owner_grp` is now `id_ws1_viewers_grp`.
|
||||
|
||||
### `users` table
|
||||
|
||||
Stores `users` information.
|
||||
|
||||
| Column name | Description |
|
||||
|--------------- | --------------- |
|
||||
| id | The primary key |
|
||||
| name | The user's name |
|
||||
| api_key | If generated, the [HTTP API Key](https://support.getgrist.com/rest-api/) used to authenticate the user |
|
||||
| picture | The URL to the user's picture (must be provided by the SSO Identity Provider) |
|
||||
| first_login_at | The date of the first login |
|
||||
| is_first_time_user | Whether the user discovers Grist (used to trigger the Welcome Tour) |
|
||||
| options | Serialized options as described in [UserOptions](https://github.com/gristlabs/grist-core/blob/513e13e6ab57c918c0e396b1d56686e45644ee1a/app/common/UserAPI.ts#L169-L179) interface |
|
||||
| connect_id | Used by [GristConnect](https://github.com/gristlabs/grist-ee/blob/5ae19a7dfb436c8a3d67470b993076e51cf83f21/ext/app/server/lib/GristConnect.ts) in Enterprise Edition to identify user in external provider |
|
||||
| ref | Used to identify a user in the automated tests |
|
||||
|
||||
### `logins` table
|
||||
|
||||
Stores information related to the identification.
|
||||
|
||||
> [!NOTE]
|
||||
> A user may have many `logins` records associated to him/her, like several emails used for identification.
|
||||
|
||||
|
||||
| Column name | Description |
|
||||
|--------------- | --------------- |
|
||||
| id | The primary key |
|
||||
| user_id | The user's id |
|
||||
| email | The normalized email address used for equality and indexing (specifically converted to lower case) |
|
||||
| display_email | The user's email address as displayed in the UI |
|
||||
|
||||
### The migrations
|
||||
|
||||
The database migrations are handled by TypeORM ([documentation](https://typeorm.io/migrations)). The migration files are located at `app/gen-server/migration` and are run at startup (so you don't have to worry about running them yourself).
|
||||
|
@ -130,6 +130,7 @@ Check out this repository: https://github.com/gristlabs/grist-widget#readme
|
||||
|
||||
Some documentation to help you starting developing:
|
||||
- [Overview of Grist Components](./overview.md)
|
||||
- [The database](./database.md)
|
||||
- [GrainJS & Grist Front-End Libraries](./grainjs.md)
|
||||
- [GrainJS Documentation](https://github.com/gristlabs/grainjs/) (The library used to build the DOM)
|
||||
- [The user support documentation](https://support.getgrist.com/)
|
||||
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 238 KiB |
4
documentation/images/BDD-doc-inheritance-default.svg
Normal file
4
documentation/images/BDD-doc-inheritance-default.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 191 KiB |
234
documentation/images/BDD.drawio
Normal file
234
documentation/images/BDD.drawio
Normal file
@ -0,0 +1,234 @@
|
||||
<mxfile host="app.diagrams.net" modified="2024-05-03T07:57:06.222Z" agent="Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0" etag="d5mpqxfjE_YjavJEgyO5" version="24.3.1" type="device" pages="2">
|
||||
<diagram name="doc - Inheritance : default" id="HMcLKXGEOIWPtuluTPJ-">
|
||||
<mxGraphModel dx="1654" dy="872" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-0" />
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-1" parent="uSf0n1dOcknmwi0iKCrK-0" />
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="uSf0n1dOcknmwi0iKCrK-1" source="uSf0n1dOcknmwi0iKCrK-3" target="uSf0n1dOcknmwi0iKCrK-4" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-3" value="Org1" style="rounded=0;whiteSpace=wrap;html=1;" parent="uSf0n1dOcknmwi0iKCrK-1" vertex="1">
|
||||
<mxGeometry x="109" y="493.5" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-4" value="Workspace1" style="rounded=0;whiteSpace=wrap;html=1;" parent="uSf0n1dOcknmwi0iKCrK-1" vertex="1">
|
||||
<mxGeometry x="109" y="317" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="uSf0n1dOcknmwi0iKCrK-1" source="uSf0n1dOcknmwi0iKCrK-6" target="uSf0n1dOcknmwi0iKCrK-10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" parent="uSf0n1dOcknmwi0iKCrK-1" source="uSf0n1dOcknmwi0iKCrK-22" target="uSf0n1dOcknmwi0iKCrK-6" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="459" y="595" />
|
||||
<mxPoint x="548" y="595" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-21" value="" style="group;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-1" vertex="1" connectable="0">
|
||||
<mxGeometry x="437.5" y="611" width="43" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-22" value="Some user" style="html=1;verticalLabelPosition=bottom;align=center;labelBackgroundColor=#ffffff;verticalAlign=top;strokeWidth=2;strokeColor=#0080F0;shadow=0;dashed=0;shape=mxgraph.ios7.icons.user;" parent="uSf0n1dOcknmwi0iKCrK-21" vertex="1">
|
||||
<mxGeometry x="6.5" y="35" width="30" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-24" value="group_users" style="shape=table;startSize=30;container=1;collapsible=0;childLayout=tableLayout;strokeColor=default;fontSize=16;fontStyle=1" parent="uSf0n1dOcknmwi0iKCrK-1" vertex="1">
|
||||
<mxGeometry x="713" y="593" width="359" height="118" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-25" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-24" vertex="1">
|
||||
<mxGeometry y="30" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-26" value="<b>group_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-25" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-27" value="<b>user_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-25" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-28" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-24" vertex="1">
|
||||
<mxGeometry y="74" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-29" value="id_org1_owner_grp" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-28" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-30" value="id_some_user" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-28" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-31" value="group_groups" style="shape=table;startSize=30;container=1;collapsible=0;childLayout=tableLayout;strokeColor=default;fontSize=16;fontStyle=1" parent="uSf0n1dOcknmwi0iKCrK-1" vertex="1">
|
||||
<mxGeometry x="711" y="288" width="359" height="118" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-32" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-31" vertex="1">
|
||||
<mxGeometry y="30" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-33" value="<b>group_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-32" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-34" value="<b>subgroup_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-32" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-35" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-31" vertex="1">
|
||||
<mxGeometry y="74" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-36" value="<div>id_ws1_owner_grp</div>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-35" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-37" value="id_org1_owner_grp" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="uSf0n1dOcknmwi0iKCrK-35" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-5" value="" style="group;labelBackgroundColor=default;labelBorderColor=none;" parent="uSf0n1dOcknmwi0iKCrK-1" vertex="1" connectable="0">
|
||||
<mxGeometry x="523" y="464" width="50" height="78" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-6" value="<font style="font-size: 16px;">Org1 Owners</font>" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;fillColor=#505050;shape=mxgraph.mscae.intune.user_group;labelBackgroundColor=default;spacingTop=9;" parent="uSf0n1dOcknmwi0iKCrK-5" vertex="1">
|
||||
<mxGeometry y="41" width="50" height="37" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-7" value="" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://cdn0.iconfinder.com/data/icons/phosphor-fill-vol-2/256/crown-simple-fill-128.png" parent="uSf0n1dOcknmwi0iKCrK-5" vertex="1">
|
||||
<mxGeometry x="3.5" width="43" height="43" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-9" value="" style="group" parent="uSf0n1dOcknmwi0iKCrK-1" vertex="1" connectable="0">
|
||||
<mxGeometry x="523" y="281" width="50" height="83" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-10" value="<div style="font-size: 16px; padding-left: 0px; margin-top: 10px;"><font style="font-size: 16px;"><span style="background-color: rgb(255, 255, 255);">Ws1 Owners</span></font></div>" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;fillColor=#505050;shape=mxgraph.mscae.intune.user_group" parent="uSf0n1dOcknmwi0iKCrK-9" vertex="1">
|
||||
<mxGeometry y="46" width="50" height="37" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="uSf0n1dOcknmwi0iKCrK-11" value="" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://cdn0.iconfinder.com/data/icons/phosphor-fill-vol-2/256/crown-simple-fill-128.png" parent="uSf0n1dOcknmwi0iKCrK-9" vertex="1">
|
||||
<mxGeometry x="3.5" width="43" height="43" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram name="doc - inheritance : after change" id="ejp4Dg6iXyrIoHg3_VKk">
|
||||
<mxGraphModel dx="1654" dy="872" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-0" />
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-1" parent="cy84TbzhjBedF44X58Xk-0" />
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="cy84TbzhjBedF44X58Xk-1" source="cy84TbzhjBedF44X58Xk-3" target="cy84TbzhjBedF44X58Xk-4" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-3" value="Org1" style="rounded=0;whiteSpace=wrap;html=1;" parent="cy84TbzhjBedF44X58Xk-1" vertex="1">
|
||||
<mxGeometry x="109" y="493.5" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-4" value="Workspace1" style="rounded=0;whiteSpace=wrap;html=1;" parent="cy84TbzhjBedF44X58Xk-1" vertex="1">
|
||||
<mxGeometry x="109" y="317" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;" parent="cy84TbzhjBedF44X58Xk-1" source="cy84TbzhjBedF44X58Xk-24" target="cy84TbzhjBedF44X58Xk-27" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" parent="cy84TbzhjBedF44X58Xk-1" source="cy84TbzhjBedF44X58Xk-8" target="cy84TbzhjBedF44X58Xk-24" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="459" y="595" />
|
||||
<mxPoint x="548" y="595" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-7" value="" style="group" parent="cy84TbzhjBedF44X58Xk-1" vertex="1" connectable="0">
|
||||
<mxGeometry x="437.5" y="611" width="43" height="65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-8" value="Some user" style="html=1;verticalLabelPosition=bottom;align=center;labelBackgroundColor=#ffffff;verticalAlign=top;strokeWidth=2;strokeColor=#0080F0;shadow=0;dashed=0;shape=mxgraph.ios7.icons.user;" parent="cy84TbzhjBedF44X58Xk-7" vertex="1">
|
||||
<mxGeometry x="6.5" y="35" width="30" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-9" value="group_users" style="shape=table;startSize=30;container=1;collapsible=0;childLayout=tableLayout;strokeColor=default;fontSize=16;fontStyle=1" parent="cy84TbzhjBedF44X58Xk-1" vertex="1">
|
||||
<mxGeometry x="758" y="589" width="359" height="118" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-10" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="cy84TbzhjBedF44X58Xk-9" vertex="1">
|
||||
<mxGeometry y="30" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-11" value="<b>group_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="cy84TbzhjBedF44X58Xk-10" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-12" value="<b>user_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="cy84TbzhjBedF44X58Xk-10" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-13" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="cy84TbzhjBedF44X58Xk-9" vertex="1">
|
||||
<mxGeometry y="74" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-14" value="id_org1_owner_grp" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="cy84TbzhjBedF44X58Xk-13" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-15" value="id_some_user" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="cy84TbzhjBedF44X58Xk-13" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-23" value="" style="group;labelBackgroundColor=default;labelBorderColor=none;" parent="cy84TbzhjBedF44X58Xk-1" vertex="1" connectable="0">
|
||||
<mxGeometry x="523" y="464" width="50" height="78" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-24" value="<font style="font-size: 16px;">Org1 Owners</font>" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;fillColor=#505050;shape=mxgraph.mscae.intune.user_group;labelBackgroundColor=default;spacingTop=9;" parent="cy84TbzhjBedF44X58Xk-23" vertex="1">
|
||||
<mxGeometry y="41" width="50" height="37" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-25" value="" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://cdn0.iconfinder.com/data/icons/phosphor-fill-vol-2/256/crown-simple-fill-128.png" parent="cy84TbzhjBedF44X58Xk-23" vertex="1">
|
||||
<mxGeometry x="3.5" width="43" height="43" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-26" value="" style="group" parent="cy84TbzhjBedF44X58Xk-1" vertex="1" connectable="0">
|
||||
<mxGeometry x="401" y="281" width="50" height="83" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-27" value="<div style="font-size: 16px; padding-left: 0px; margin-top: 10px;"><font style="font-size: 16px;"><span style="background-color: rgb(255, 255, 255);">Ws1 Owners</span></font></div>" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;fillColor=#505050;shape=mxgraph.mscae.intune.user_group" parent="cy84TbzhjBedF44X58Xk-26" vertex="1">
|
||||
<mxGeometry y="46" width="50" height="37" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cy84TbzhjBedF44X58Xk-28" value="" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://cdn0.iconfinder.com/data/icons/phosphor-fill-vol-2/256/crown-simple-fill-128.png" parent="cy84TbzhjBedF44X58Xk-26" vertex="1">
|
||||
<mxGeometry x="3.5" width="43" height="43" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Cej_1C5x5ezJ23L6Zn-K-0" value="" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://cdn4.iconfinder.com/data/icons/essentials-72/24/039_-_Cross-128.png" parent="cy84TbzhjBedF44X58Xk-1" vertex="1">
|
||||
<mxGeometry x="406" y="434.5" width="41" height="41" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Cej_1C5x5ezJ23L6Zn-K-2" value="NEW" style="dashed=0;html=1;rounded=1;strokeColor=#6554C0;fontSize=12;align=center;fontStyle=1;strokeWidth=2;fontColor=#6554C0" parent="cy84TbzhjBedF44X58Xk-1" vertex="1">
|
||||
<mxGeometry x="668" y="445" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Cej_1C5x5ezJ23L6Zn-K-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="cy84TbzhjBedF44X58Xk-1" source="cy84TbzhjBedF44X58Xk-24" target="Cej_1C5x5ezJ23L6Zn-K-5" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Cej_1C5x5ezJ23L6Zn-K-5" value="<div style="font-size: 16px; padding-left: 0px; margin-top: 10px;"><font style="font-size: 16px;"><span style="background-color: rgb(255, 255, 255);">Ws1 Viewers</span></font></div><div style="font-size: 16px; padding-left: 0px; margin-top: 10px;"><font style="font-size: 16px;"><span style="background-color: rgb(255, 255, 255);"><br></span></font></div>" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;fillColor=#505050;shape=mxgraph.mscae.intune.user_group" parent="cy84TbzhjBedF44X58Xk-1" vertex="1">
|
||||
<mxGeometry x="634" y="327" width="50" height="37" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="rRc6SIQjJta77vA1fWc8-0" value="group_groups" style="shape=table;startSize=30;container=1;collapsible=0;childLayout=tableLayout;strokeColor=default;fontSize=16;fontStyle=1" parent="cy84TbzhjBedF44X58Xk-1" vertex="1">
|
||||
<mxGeometry x="758" y="288" width="359" height="118" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="rRc6SIQjJta77vA1fWc8-1" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="rRc6SIQjJta77vA1fWc8-0" vertex="1">
|
||||
<mxGeometry y="30" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="rRc6SIQjJta77vA1fWc8-2" value="<b>group_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="rRc6SIQjJta77vA1fWc8-1" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="rRc6SIQjJta77vA1fWc8-3" value="<b>subgroup_id</b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="rRc6SIQjJta77vA1fWc8-1" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="rRc6SIQjJta77vA1fWc8-4" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;strokeColor=inherit;top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=16;" parent="rRc6SIQjJta77vA1fWc8-0" vertex="1">
|
||||
<mxGeometry y="74" width="359" height="44" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="rRc6SIQjJta77vA1fWc8-5" value="<div><strike><b><font color="#ff3333">id_ws1_owner_grp</font></b></strike></div><b><font color="#00cc00">id_ws1_viewers_grp</font></b>" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="rRc6SIQjJta77vA1fWc8-4" vertex="1">
|
||||
<mxGeometry width="179" height="44" as="geometry">
|
||||
<mxRectangle width="179" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="rRc6SIQjJta77vA1fWc8-6" value="id_org1_owner_grp" style="shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;strokeColor=inherit;overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;fontSize=16;" parent="rRc6SIQjJta77vA1fWc8-4" vertex="1">
|
||||
<mxGeometry x="179" width="180" height="44" as="geometry">
|
||||
<mxRectangle width="180" height="44" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
609
documentation/images/homedb-schema.svg
Normal file
609
documentation/images/homedb-schema.svg
Normal file
@ -0,0 +1,609 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 9.0.0 (20230911.1827)
|
||||
-->
|
||||
<!-- Title: SchemaCrawler_Diagram Pages: 1 -->
|
||||
<svg width="1587pt" height="914pt"
|
||||
viewBox="0.00 0.00 1587.00 914.26" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 910.26)">
|
||||
<title>SchemaCrawler_Diagram</title>
|
||||
<polygon fill="white" stroke="none" points="-4,4 -4,-910.26 1583,-910.26 1583,4 -4,4"/>
|
||||
<text text-anchor="start" x="1304" y="-31.7" font-family="Helvetica,sans-Serif" font-size="14.00">generated by</text>
|
||||
<text text-anchor="start" x="1400.88" y="-31.7" font-family="Helvetica,sans-Serif" font-size="14.00">SchemaCrawler 16.21.2</text>
|
||||
<text text-anchor="start" x="1304" y="-10.7" font-family="Helvetica,sans-Serif" font-size="14.00">generated on</text>
|
||||
<text text-anchor="start" x="1401" y="-10.7" font-family="Helvetica,sans-Serif" font-size="14.00">2024-04-15 14:21:22</text>
|
||||
<polygon fill="none" stroke="#888888" points="1301,-4 1301,-48 1571,-48 1571,-4 1301,-4"/>
|
||||
<!-- acl_rules_53bd8961 -->
|
||||
<g id="node1" class="node">
|
||||
<title>acl_rules_53bd8961</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1319,-731.08 1319,-752.08 1424,-752.08 1424,-731.08 1319,-731.08"/>
|
||||
<text text-anchor="start" x="1321" y="-737.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">acl_rules</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1424,-731.08 1424,-752.08 1570,-752.08 1570,-731.08 1424,-731.08"/>
|
||||
<text text-anchor="start" x="1523" y="-736.78" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="1321" y="-716.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="1417.75" y="-715.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1426" y="-715.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="1417.75" y="-694.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1426" y="-694.78" font-family="Helvetica,sans-Serif" font-size="14.00">auto-incremented</text>
|
||||
<text text-anchor="start" x="1321" y="-673.78" font-family="Helvetica,sans-Serif" font-size="14.00">permissions</text>
|
||||
<text text-anchor="start" x="1417.75" y="-673.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1426" y="-673.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="1321" y="-652.78" font-family="Helvetica,sans-Serif" font-size="14.00">type</text>
|
||||
<text text-anchor="start" x="1417.75" y="-652.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1425.75" y="-652.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="1320.62" y="-631.78" font-family="Helvetica,sans-Serif" font-size="14.00">workspace_id</text>
|
||||
<text text-anchor="start" x="1417.75" y="-631.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1426" y="-631.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="1321" y="-610.78" font-family="Helvetica,sans-Serif" font-size="14.00">org_id</text>
|
||||
<text text-anchor="start" x="1417.75" y="-610.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1426" y="-610.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="1321" y="-589.78" font-family="Helvetica,sans-Serif" font-size="14.00">doc_id</text>
|
||||
<text text-anchor="start" x="1417.75" y="-589.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1426" y="-589.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="1321" y="-568.78" font-family="Helvetica,sans-Serif" font-size="14.00">group_id</text>
|
||||
<text text-anchor="start" x="1417.75" y="-568.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1426" y="-568.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<polygon fill="none" stroke="#888888" points="1318,-562.08 1318,-753.08 1571,-753.08 1571,-562.08 1318,-562.08"/>
|
||||
</g>
|
||||
<!-- docs_2f969a -->
|
||||
<g id="node3" class="node">
|
||||
<title>docs_2f969a</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="976,-535.08 976,-556.08 1117,-556.08 1117,-535.08 976,-535.08"/>
|
||||
<text text-anchor="start" x="978" y="-541.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">docs</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1117,-535.08 1117,-556.08 1265,-556.08 1265,-535.08 1117,-535.08"/>
|
||||
<text text-anchor="start" x="1218" y="-540.78" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="978" y="-520.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="1110.75" y="-519.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-519.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="978" y="-498.78" font-family="Helvetica,sans-Serif" font-size="14.00">name</text>
|
||||
<text text-anchor="start" x="1110.75" y="-498.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-498.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="978" y="-477.78" font-family="Helvetica,sans-Serif" font-size="14.00">created_at</text>
|
||||
<text text-anchor="start" x="1110.75" y="-477.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1118.62" y="-477.78" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME NOT NULL</text>
|
||||
<text text-anchor="start" x="978" y="-456.78" font-family="Helvetica,sans-Serif" font-size="14.00">updated_at</text>
|
||||
<text text-anchor="start" x="1110.75" y="-456.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1118.62" y="-456.78" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME NOT NULL</text>
|
||||
<text text-anchor="start" x="978" y="-435.78" font-family="Helvetica,sans-Serif" font-size="14.00">workspace_id</text>
|
||||
<text text-anchor="start" x="1110.75" y="-435.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-435.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="978" y="-414.78" font-family="Helvetica,sans-Serif" font-size="14.00">is_pinned</text>
|
||||
<text text-anchor="start" x="1110.75" y="-414.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-414.78" font-family="Helvetica,sans-Serif" font-size="14.00">BOOLEAN NOT NULL</text>
|
||||
<text text-anchor="start" x="978" y="-393.78" font-family="Helvetica,sans-Serif" font-size="14.00">url_id</text>
|
||||
<text text-anchor="start" x="1110.75" y="-393.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-393.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="978" y="-372.78" font-family="Helvetica,sans-Serif" font-size="14.00">removed_at</text>
|
||||
<text text-anchor="start" x="1110.75" y="-372.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-372.78" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME</text>
|
||||
<text text-anchor="start" x="978" y="-351.78" font-family="Helvetica,sans-Serif" font-size="14.00">options</text>
|
||||
<text text-anchor="start" x="1110.75" y="-351.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-351.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="978" y="-330.78" font-family="Helvetica,sans-Serif" font-size="14.00">grace_period_start</text>
|
||||
<text text-anchor="start" x="1110.75" y="-330.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-330.78" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME</text>
|
||||
<text text-anchor="start" x="978" y="-309.78" font-family="Helvetica,sans-Serif" font-size="14.00">usage</text>
|
||||
<text text-anchor="start" x="1110.75" y="-309.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-309.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="978" y="-288.78" font-family="Helvetica,sans-Serif" font-size="14.00">created_by</text>
|
||||
<text text-anchor="start" x="1110.75" y="-288.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-288.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="978" y="-267.78" font-family="Helvetica,sans-Serif" font-size="14.00">trunk_id</text>
|
||||
<text text-anchor="start" x="1110.75" y="-267.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-267.78" font-family="Helvetica,sans-Serif" font-size="14.00">TEXT</text>
|
||||
<text text-anchor="start" x="978" y="-246.78" font-family="Helvetica,sans-Serif" font-size="14.00">type</text>
|
||||
<text text-anchor="start" x="1110.75" y="-246.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1119" y="-246.78" font-family="Helvetica,sans-Serif" font-size="14.00">TEXT</text>
|
||||
<polygon fill="none" stroke="#888888" points="975,-240.08 975,-557.08 1266,-557.08 1266,-240.08 975,-240.08"/>
|
||||
</g>
|
||||
<!-- acl_rules_53bd8961->docs_2f969a -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>acl_rules_53bd8961:w->docs_2f969a:e</title>
|
||||
<path fill="none" stroke="black" d="M1300.15,-586C1288.9,-569.65 1294.6,-534.89 1276.05,-526.46"/>
|
||||
<polygon fill="black" stroke="black" points="1308.24,-590 1315.21,-598.47 1313.02,-592.37 1316.9,-594.29 1316.9,-594.29 1316.9,-594.29 1313.02,-592.37 1319.2,-590.4 1308.24,-590"/>
|
||||
<ellipse fill="none" stroke="black" cx="1303.11" cy="-587.47" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1266.52,-529.68 1268.44,-519.87 1270.41,-520.25 1268.48,-530.07 1266.52,-529.68"/>
|
||||
<polyline fill="none" stroke="black" points="1266.5,-524.58 1271.41,-525.55"/>
|
||||
<polygon fill="black" stroke="black" points="1271.43,-530.64 1273.35,-520.83 1275.31,-521.22 1273.39,-531.03 1271.43,-530.64"/>
|
||||
<polyline fill="none" stroke="black" points="1271.41,-525.55 1276.31,-526.51"/>
|
||||
</g>
|
||||
<!-- groups_b63e4e33 -->
|
||||
<g id="node8" class="node">
|
||||
<title>groups_b63e4e33</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1018.5,-191.58 1018.5,-212.58 1076.5,-212.58 1076.5,-191.58 1018.5,-191.58"/>
|
||||
<text text-anchor="start" x="1020.5" y="-198.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">groups</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1076.5,-191.58 1076.5,-212.58 1222.5,-212.58 1222.5,-191.58 1076.5,-191.58"/>
|
||||
<text text-anchor="start" x="1175.5" y="-197.28" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="1020.5" y="-177.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="1066.5" y="-176.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1078.5" y="-176.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="1066.5" y="-155.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1078.5" y="-155.28" font-family="Helvetica,sans-Serif" font-size="14.00">auto-incremented</text>
|
||||
<text text-anchor="start" x="1020.5" y="-134.28" font-family="Helvetica,sans-Serif" font-size="14.00">name</text>
|
||||
<text text-anchor="start" x="1066.5" y="-134.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1078.25" y="-134.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="1017.5,-127.58 1017.5,-213.58 1223.5,-213.58 1223.5,-127.58 1017.5,-127.58"/>
|
||||
</g>
|
||||
<!-- acl_rules_53bd8961->groups_b63e4e33 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>acl_rules_53bd8961:w->groups_b63e4e33:e</title>
|
||||
<path fill="none" stroke="black" d="M1299.63,-566.93C1251.73,-524.31 1306.41,-289.28 1274,-226.58 1261.87,-203.11 1255.27,-186.14 1233.44,-182.37"/>
|
||||
<polygon fill="black" stroke="black" points="1307.81,-569.98 1315.62,-577.68 1312.81,-571.84 1316.87,-573.35 1316.87,-573.35 1316.87,-573.35 1312.81,-571.84 1318.76,-569.25 1307.81,-569.98"/>
|
||||
<ellipse fill="none" stroke="black" cx="1302.46" cy="-567.98" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1224.1,-186.65 1224.89,-176.68 1226.89,-176.84 1226.1,-186.81 1224.1,-186.65"/>
|
||||
<polyline fill="none" stroke="black" points="1223.5,-181.58 1228.48,-181.98"/>
|
||||
<polygon fill="black" stroke="black" points="1229.09,-187.04 1229.88,-177.07 1231.87,-177.23 1231.08,-187.2 1229.09,-187.04"/>
|
||||
<polyline fill="none" stroke="black" points="1228.48,-181.98 1233.47,-182.37"/>
|
||||
</g>
|
||||
<!-- orgs_34a26e -->
|
||||
<g id="node10" class="node">
|
||||
<title>orgs_34a26e</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="341,-681.58 341,-702.58 476,-702.58 476,-681.58 341,-681.58"/>
|
||||
<text text-anchor="start" x="343" y="-688.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">orgs</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="476,-681.58 476,-702.58 624,-702.58 624,-681.58 476,-681.58"/>
|
||||
<text text-anchor="start" x="577" y="-687.28" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="343" y="-667.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="469.75" y="-666.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="478" y="-666.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="469.75" y="-645.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="478" y="-645.28" font-family="Helvetica,sans-Serif" font-size="14.00">auto-incremented</text>
|
||||
<text text-anchor="start" x="343" y="-624.28" font-family="Helvetica,sans-Serif" font-size="14.00">name</text>
|
||||
<text text-anchor="start" x="469.75" y="-624.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="478" y="-624.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="343" y="-603.28" font-family="Helvetica,sans-Serif" font-size="14.00">domain</text>
|
||||
<text text-anchor="start" x="469.75" y="-603.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="478" y="-603.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="343" y="-582.28" font-family="Helvetica,sans-Serif" font-size="14.00">created_at</text>
|
||||
<text text-anchor="start" x="469.75" y="-582.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="477.62" y="-582.28" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME NOT NULL</text>
|
||||
<text text-anchor="start" x="343" y="-561.28" font-family="Helvetica,sans-Serif" font-size="14.00">updated_at</text>
|
||||
<text text-anchor="start" x="469.75" y="-561.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="477.62" y="-561.28" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME NOT NULL</text>
|
||||
<text text-anchor="start" x="343" y="-540.28" font-family="Helvetica,sans-Serif" font-size="14.00">owner_id</text>
|
||||
<text text-anchor="start" x="469.75" y="-540.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="478" y="-540.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="343" y="-519.28" font-family="Helvetica,sans-Serif" font-size="14.00">billing_account_id</text>
|
||||
<text text-anchor="start" x="469.75" y="-519.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="478" y="-519.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="343" y="-498.28" font-family="Helvetica,sans-Serif" font-size="14.00">host</text>
|
||||
<text text-anchor="start" x="469.75" y="-498.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="478" y="-498.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<polygon fill="none" stroke="#888888" points="340,-491.58 340,-703.58 625,-703.58 625,-491.58 340,-491.58"/>
|
||||
</g>
|
||||
<!-- acl_rules_53bd8961->orgs_34a26e -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>acl_rules_53bd8961:w->orgs_34a26e:e</title>
|
||||
<path fill="none" stroke="black" d="M1298.17,-615.35C1142.54,-611.87 795.65,-571.59 669,-626.58 647.07,-636.11 651.25,-662.5 635.2,-669.73"/>
|
||||
<polygon fill="black" stroke="black" points="1307.17,-615.46 1317.11,-620.08 1312.5,-615.52 1316.83,-615.58 1316.83,-615.58 1316.83,-615.58 1312.5,-615.52 1317.22,-611.08 1307.17,-615.46"/>
|
||||
<ellipse fill="none" stroke="black" cx="1301.45" cy="-615.39" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="627.42,-676.31 625.54,-666.49 627.51,-666.11 629.39,-675.93 627.42,-676.31"/>
|
||||
<polyline fill="none" stroke="black" points="625.5,-671.58 630.41,-670.65"/>
|
||||
<polygon fill="black" stroke="black" points="632.33,-675.37 630.45,-665.55 632.42,-665.17 634.3,-674.99 632.33,-675.37"/>
|
||||
<polyline fill="none" stroke="black" points="630.41,-670.65 635.32,-669.71"/>
|
||||
</g>
|
||||
<!-- workspaces_e61add -->
|
||||
<g id="node13" class="node">
|
||||
<title>workspaces_e61add</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="678,-787.58 678,-808.58 774,-808.58 774,-787.58 678,-787.58"/>
|
||||
<text text-anchor="start" x="679.88" y="-794.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">workspaces</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="774,-787.58 774,-808.58 922,-808.58 922,-787.58 774,-787.58"/>
|
||||
<text text-anchor="start" x="875" y="-793.28" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="680" y="-773.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="766" y="-772.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="776" y="-772.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="766" y="-751.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="776" y="-751.28" font-family="Helvetica,sans-Serif" font-size="14.00">auto-incremented</text>
|
||||
<text text-anchor="start" x="680" y="-730.28" font-family="Helvetica,sans-Serif" font-size="14.00">name</text>
|
||||
<text text-anchor="start" x="766" y="-730.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="776" y="-730.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="680" y="-709.28" font-family="Helvetica,sans-Serif" font-size="14.00">created_at</text>
|
||||
<text text-anchor="start" x="766" y="-709.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="775.62" y="-709.28" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME NOT NULL</text>
|
||||
<text text-anchor="start" x="680" y="-688.28" font-family="Helvetica,sans-Serif" font-size="14.00">updated_at</text>
|
||||
<text text-anchor="start" x="766" y="-688.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="775.62" y="-688.28" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME NOT NULL</text>
|
||||
<text text-anchor="start" x="680" y="-667.28" font-family="Helvetica,sans-Serif" font-size="14.00">org_id</text>
|
||||
<text text-anchor="start" x="766" y="-667.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="776" y="-667.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="680" y="-646.28" font-family="Helvetica,sans-Serif" font-size="14.00">removed_at</text>
|
||||
<text text-anchor="start" x="766" y="-646.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="776" y="-646.28" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME</text>
|
||||
<polygon fill="none" stroke="#888888" points="677,-639.58 677,-809.58 923,-809.58 923,-639.58 677,-639.58"/>
|
||||
</g>
|
||||
<!-- acl_rules_53bd8961->workspaces_e61add -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>acl_rules_53bd8961:w->workspaces_e61add:e</title>
|
||||
<path fill="none" stroke="black" d="M1298.2,-637.11C1132.65,-646.28 1103.61,-772.76 932.84,-777.45"/>
|
||||
<polygon fill="black" stroke="black" points="1307.17,-636.86 1317.29,-641.09 1312.5,-636.72 1316.83,-636.6 1316.83,-636.6 1316.83,-636.6 1312.5,-636.72 1317.04,-632.09 1307.17,-636.86"/>
|
||||
<ellipse fill="none" stroke="black" cx="1301.45" cy="-637.02" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="924.07,-782.57 923.93,-772.57 925.93,-772.54 926.07,-782.54 924.07,-782.57"/>
|
||||
<polyline fill="none" stroke="black" points="923,-777.58 928,-777.52"/>
|
||||
<polygon fill="black" stroke="black" points="929.07,-782.5 928.93,-772.5 930.93,-772.48 931.07,-782.47 929.07,-782.5"/>
|
||||
<polyline fill="none" stroke="black" points="928,-777.52 933,-777.45"/>
|
||||
</g>
|
||||
<!-- aliases_c97dc35d -->
|
||||
<g id="node2" class="node">
|
||||
<title>aliases_c97dc35d</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1328.5,-869.08 1328.5,-890.08 1412.5,-890.08 1412.5,-869.08 1328.5,-869.08"/>
|
||||
<text text-anchor="start" x="1330.5" y="-875.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">aliases</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1412.5,-869.08 1412.5,-890.08 1560.5,-890.08 1560.5,-869.08 1412.5,-869.08"/>
|
||||
<text text-anchor="start" x="1513.5" y="-874.78" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="1330.5" y="-854.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">url_id</text>
|
||||
<text text-anchor="start" x="1406.25" y="-853.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1414.5" y="-853.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="1330.5" y="-833.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">org_id</text>
|
||||
<text text-anchor="start" x="1406.25" y="-832.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1414.5" y="-832.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="1330.5" y="-811.78" font-family="Helvetica,sans-Serif" font-size="14.00">doc_id</text>
|
||||
<text text-anchor="start" x="1406.25" y="-811.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1414.5" y="-811.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="1330.5" y="-790.78" font-family="Helvetica,sans-Serif" font-size="14.00">created_at</text>
|
||||
<text text-anchor="start" x="1406.25" y="-790.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1414.12" y="-790.78" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="1327.5,-784.08 1327.5,-891.08 1561.5,-891.08 1561.5,-784.08 1327.5,-784.08"/>
|
||||
</g>
|
||||
<!-- aliases_c97dc35d->docs_2f969a -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>aliases_c97dc35d:w->docs_2f969a:e</title>
|
||||
<path fill="none" stroke="black" d="M1310.57,-807.2C1277.15,-760.25 1319.85,-552.09 1276.08,-527.05"/>
|
||||
<polygon fill="black" stroke="black" points="1318.46,-811.57 1325.03,-820.36 1323.13,-814.16 1326.91,-816.26 1326.91,-816.26 1326.91,-816.26 1323.13,-814.16 1329.39,-812.49 1318.46,-811.57"/>
|
||||
<ellipse fill="none" stroke="black" cx="1313.46" cy="-808.8" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1266.22,-529.68 1268.71,-519.99 1270.65,-520.49 1268.16,-530.17 1266.22,-529.68"/>
|
||||
<polyline fill="none" stroke="black" points="1266.5,-524.58 1271.34,-525.83"/>
|
||||
<polygon fill="black" stroke="black" points="1271.06,-530.92 1273.56,-521.24 1275.49,-521.74 1273,-531.42 1271.06,-530.92"/>
|
||||
<polyline fill="none" stroke="black" points="1271.34,-525.83 1276.18,-527.08"/>
|
||||
</g>
|
||||
<!-- aliases_c97dc35d->orgs_34a26e -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>aliases_c97dc35d:w->orgs_34a26e:e</title>
|
||||
<path fill="none" stroke="black" d="M1308.43,-837.82C1028.83,-844.61 895.79,-997.34 669,-822.58 616.6,-782.2 687.11,-682.83 635.33,-672.46"/>
|
||||
<polygon fill="black" stroke="black" points="1317.17,-837.71 1327.22,-842.09 1322.5,-837.64 1326.83,-837.59 1326.83,-837.59 1326.83,-837.59 1322.5,-837.64 1327.11,-833.09 1317.17,-837.71"/>
|
||||
<ellipse fill="none" stroke="black" cx="1311.45" cy="-837.78" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="626.05,-676.65 626.94,-666.69 628.93,-666.87 628.04,-676.83 626.05,-676.65"/>
|
||||
<polyline fill="none" stroke="black" points="625.5,-671.58 630.48,-672.03"/>
|
||||
<polygon fill="black" stroke="black" points="631.03,-677.1 631.92,-667.14 633.91,-667.32 633.02,-677.28 631.03,-677.1"/>
|
||||
<polyline fill="none" stroke="black" points="630.48,-672.03 635.46,-672.47"/>
|
||||
</g>
|
||||
<!-- docs_2f969a->docs_2f969a -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>docs_2f969a:w->docs_2f969a:e</title>
|
||||
<path fill="none" stroke="black" d="M961.45,-285.94C896.25,-362.58 909.45,-579.08 1120.5,-579.08 1337.27,-579.08 1345.31,-567.96 1274.08,-529.19"/>
|
||||
<polygon fill="black" stroke="black" points="968.01,-279.7 978.36,-276.08 971.88,-276.03 975.02,-273.04 975.02,-273.04 975.02,-273.04 971.88,-276.03 972.16,-269.55 968.01,-279.7"/>
|
||||
<ellipse fill="none" stroke="black" cx="963.87" cy="-283.65" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1264.02,-529.46 1268.75,-520.65 1270.51,-521.6 1265.78,-530.41 1264.02,-529.46"/>
|
||||
<polyline fill="none" stroke="black" points="1265.5,-524.58 1269.91,-526.95"/>
|
||||
<polygon fill="black" stroke="black" points="1268.42,-531.83 1273.15,-523.02 1274.91,-523.96 1270.18,-532.77 1268.42,-531.83"/>
|
||||
<polyline fill="none" stroke="black" points="1269.91,-526.95 1274.31,-529.31"/>
|
||||
</g>
|
||||
<!-- docs_2f969a->workspaces_e61add -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>docs_2f969a:w->workspaces_e61add:e</title>
|
||||
<path fill="none" stroke="black" d="M957.27,-449.25C918.44,-499.22 983.9,-749.14 932.68,-775.36"/>
|
||||
<polygon fill="black" stroke="black" points="965.27,-445.23 976.22,-444.75 970.03,-442.83 973.9,-440.88 973.9,-440.88 973.9,-440.88 970.03,-442.83 972.18,-436.71 965.27,-445.23"/>
|
||||
<ellipse fill="none" stroke="black" cx="960.16" cy="-447.8" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="925.1,-782.23 922.85,-772.49 924.8,-772.04 927.04,-781.78 925.1,-782.23"/>
|
||||
<polyline fill="none" stroke="black" points="923,-777.58 927.87,-776.46"/>
|
||||
<polygon fill="black" stroke="black" points="929.97,-781.11 927.73,-771.37 929.68,-770.92 931.92,-780.66 929.97,-781.11"/>
|
||||
<polyline fill="none" stroke="black" points="927.87,-776.46 932.75,-775.34"/>
|
||||
</g>
|
||||
<!-- users_6a70267 -->
|
||||
<g id="node14" class="node">
|
||||
<title>users_6a70267</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="9,-293.08 9,-314.08 141,-314.08 141,-293.08 9,-293.08"/>
|
||||
<text text-anchor="start" x="11" y="-299.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">users</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="141,-293.08 141,-314.08 287,-314.08 287,-293.08 141,-293.08"/>
|
||||
<text text-anchor="start" x="240" y="-298.78" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="11" y="-278.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="134.75" y="-277.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-277.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="134.75" y="-256.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-256.78" font-family="Helvetica,sans-Serif" font-size="14.00">auto-incremented</text>
|
||||
<text text-anchor="start" x="11" y="-235.78" font-family="Helvetica,sans-Serif" font-size="14.00">name</text>
|
||||
<text text-anchor="start" x="134.75" y="-235.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="142.75" y="-235.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="11" y="-214.78" font-family="Helvetica,sans-Serif" font-size="14.00">api_key</text>
|
||||
<text text-anchor="start" x="134.75" y="-214.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-214.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="11" y="-193.78" font-family="Helvetica,sans-Serif" font-size="14.00">picture</text>
|
||||
<text text-anchor="start" x="134.75" y="-193.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-193.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="11" y="-172.78" font-family="Helvetica,sans-Serif" font-size="14.00">first_login_at</text>
|
||||
<text text-anchor="start" x="134.75" y="-172.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-172.78" font-family="Helvetica,sans-Serif" font-size="14.00">DATETIME</text>
|
||||
<text text-anchor="start" x="10.62" y="-151.78" font-family="Helvetica,sans-Serif" font-size="14.00">is_first_time_user</text>
|
||||
<text text-anchor="start" x="134.75" y="-151.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-151.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="11" y="-130.78" font-family="Helvetica,sans-Serif" font-size="14.00">options</text>
|
||||
<text text-anchor="start" x="134.75" y="-130.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-130.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="11" y="-109.78" font-family="Helvetica,sans-Serif" font-size="14.00">connect_id</text>
|
||||
<text text-anchor="start" x="134.75" y="-109.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="143" y="-109.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR</text>
|
||||
<text text-anchor="start" x="11" y="-88.78" font-family="Helvetica,sans-Serif" font-size="14.00">"ref"</text>
|
||||
<text text-anchor="start" x="134.75" y="-88.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="142.75" y="-88.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="8,-82.08 8,-315.08 288,-315.08 288,-82.08 8,-82.08"/>
|
||||
</g>
|
||||
<!-- docs_2f969a->users_6a70267 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>docs_2f969a:w->users_6a70267:e</title>
|
||||
<path fill="none" stroke="black" d="M955.27,-293.33C817.2,-289.57 779.98,-245.61 633,-232.58 499.74,-220.78 453.9,-177.48 332,-232.58 308.61,-243.16 314.96,-272.99 297.75,-280.73"/>
|
||||
<polygon fill="black" stroke="black" points="964.17,-293.45 974.11,-298.08 969.5,-293.52 973.83,-293.58 973.83,-293.58 973.83,-293.58 969.5,-293.52 974.23,-289.08 964.17,-293.45"/>
|
||||
<ellipse fill="none" stroke="black" cx="958.45" cy="-293.37" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="289.92,-287.31 288.05,-277.49 290.01,-277.11 291.88,-286.94 289.92,-287.31"/>
|
||||
<polyline fill="none" stroke="black" points="288,-282.58 292.91,-281.65"/>
|
||||
<polygon fill="black" stroke="black" points="294.83,-286.38 292.96,-276.55 294.93,-276.18 296.79,-286 294.83,-286.38"/>
|
||||
<polyline fill="none" stroke="black" points="292.91,-281.65 297.82,-280.72"/>
|
||||
</g>
|
||||
<!-- secrets_756efc22 -->
|
||||
<g id="node4" class="node">
|
||||
<title>secrets_756efc22</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1340,-513.58 1340,-534.58 1403,-534.58 1403,-513.58 1340,-513.58"/>
|
||||
<text text-anchor="start" x="1342" y="-520.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">secrets</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1403,-513.58 1403,-534.58 1549,-534.58 1549,-513.58 1403,-513.58"/>
|
||||
<text text-anchor="start" x="1502" y="-519.28" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="1342" y="-499.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="1396.75" y="-498.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1404.75" y="-498.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="1342" y="-477.28" font-family="Helvetica,sans-Serif" font-size="14.00">"value"</text>
|
||||
<text text-anchor="start" x="1396.75" y="-477.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1404.75" y="-477.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="1342" y="-456.28" font-family="Helvetica,sans-Serif" font-size="14.00">doc_id</text>
|
||||
<text text-anchor="start" x="1396.75" y="-456.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1404.75" y="-456.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="1339,-449.58 1339,-535.58 1550,-535.58 1550,-449.58 1339,-449.58"/>
|
||||
</g>
|
||||
<!-- secrets_756efc22->docs_2f969a -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>secrets_756efc22:w->docs_2f969a:e</title>
|
||||
<path fill="none" stroke="black" d="M1319.93,-466.26C1301.02,-480.27 1301.16,-515.89 1276.38,-523.24"/>
|
||||
<polygon fill="black" stroke="black" points="1328.62,-463.61 1339.5,-464.99 1333.72,-462.05 1337.86,-460.78 1337.86,-460.78 1337.86,-460.78 1333.72,-462.05 1336.86,-456.38 1328.62,-463.61"/>
|
||||
<ellipse fill="none" stroke="black" cx="1323.15" cy="-465.28" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1268.16,-529.4 1266.82,-519.49 1268.8,-519.23 1270.15,-529.13 1268.16,-529.4"/>
|
||||
<polyline fill="none" stroke="black" points="1266.5,-524.58 1271.45,-523.91"/>
|
||||
<polygon fill="black" stroke="black" points="1273.12,-528.73 1271.77,-518.82 1273.75,-518.55 1275.1,-528.46 1273.12,-528.73"/>
|
||||
<polyline fill="none" stroke="black" points="1271.45,-523.91 1276.41,-523.24"/>
|
||||
</g>
|
||||
<!-- shares_ca2520d3 -->
|
||||
<g id="node5" class="node">
|
||||
<title>shares_ca2520d3</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1340,-401.08 1340,-422.08 1403,-422.08 1403,-401.08 1340,-401.08"/>
|
||||
<text text-anchor="start" x="1342" y="-407.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">shares</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1403,-401.08 1403,-422.08 1549,-422.08 1549,-401.08 1403,-401.08"/>
|
||||
<text text-anchor="start" x="1502" y="-406.78" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="1342" y="-386.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="1396.75" y="-385.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1405" y="-385.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="1396.75" y="-364.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1405" y="-364.78" font-family="Helvetica,sans-Serif" font-size="14.00">auto-incremented</text>
|
||||
<text text-anchor="start" x="1342" y="-343.78" font-family="Helvetica,sans-Serif" font-size="14.00">key</text>
|
||||
<text text-anchor="start" x="1396.75" y="-343.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1404.75" y="-343.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="1342" y="-322.78" font-family="Helvetica,sans-Serif" font-size="14.00">doc_id</text>
|
||||
<text text-anchor="start" x="1396.75" y="-322.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1404.75" y="-322.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="1342" y="-301.78" font-family="Helvetica,sans-Serif" font-size="14.00">link_id</text>
|
||||
<text text-anchor="start" x="1396.75" y="-301.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1404.75" y="-301.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="1342" y="-280.78" font-family="Helvetica,sans-Serif" font-size="14.00">options</text>
|
||||
<text text-anchor="start" x="1396.75" y="-280.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1404.75" y="-280.78" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="1339,-274.08 1339,-423.08 1550,-423.08 1550,-274.08 1339,-274.08"/>
|
||||
</g>
|
||||
<!-- shares_ca2520d3->docs_2f969a -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>shares_ca2520d3:w->docs_2f969a:e</title>
|
||||
<path fill="none" stroke="black" d="M1319.52,-331.34C1264.99,-357.46 1344.98,-511.2 1276.17,-523.77"/>
|
||||
<polygon fill="black" stroke="black" points="1328.36,-329.59 1339.05,-332.06 1333.6,-328.56 1337.84,-327.71 1337.84,-327.71 1337.84,-327.71 1333.6,-328.56 1337.3,-323.23 1328.36,-329.59"/>
|
||||
<ellipse fill="none" stroke="black" cx="1322.75" cy="-330.7" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1267.92,-529.48 1267.08,-519.52 1269.07,-519.35 1269.91,-529.31 1267.92,-529.48"/>
|
||||
<polyline fill="none" stroke="black" points="1266.5,-524.58 1271.48,-524.16"/>
|
||||
<polygon fill="black" stroke="black" points="1272.9,-529.06 1272.06,-519.1 1274.05,-518.93 1274.89,-528.89 1272.9,-529.06"/>
|
||||
<polyline fill="none" stroke="black" points="1271.48,-524.16 1276.46,-523.74"/>
|
||||
</g>
|
||||
<!-- group_groups_dfa1d7f3 -->
|
||||
<g id="node6" class="node">
|
||||
<title>group_groups_dfa1d7f3</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1319.5,-215.08 1319.5,-236.08 1429.5,-236.08 1429.5,-215.08 1319.5,-215.08"/>
|
||||
<text text-anchor="start" x="1321.25" y="-221.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">group_groups</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1429.5,-215.08 1429.5,-236.08 1569.5,-236.08 1569.5,-215.08 1429.5,-215.08"/>
|
||||
<text text-anchor="start" x="1522.5" y="-220.78" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="1321.5" y="-200.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">group_id</text>
|
||||
<text text-anchor="start" x="1421.5" y="-199.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1431.25" y="-199.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="1321.5" y="-179.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">subgroup_id</text>
|
||||
<text text-anchor="start" x="1421.5" y="-178.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1431.25" y="-178.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="1318.5,-172.08 1318.5,-237.08 1570.5,-237.08 1570.5,-172.08 1318.5,-172.08"/>
|
||||
</g>
|
||||
<!-- group_groups_dfa1d7f3->groups_b63e4e33 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>group_groups_dfa1d7f3:w->groups_b63e4e33:e</title>
|
||||
<path fill="none" stroke="black" d="M1299.26,-202.86C1274.06,-198.03 1262.08,-184.59 1233.43,-182.01"/>
|
||||
<polygon fill="black" stroke="black" points="1308.21,-203.66 1317.76,-209.04 1313.52,-204.14 1317.83,-204.52 1317.83,-204.52 1317.83,-204.52 1313.52,-204.14 1318.57,-200.07 1308.21,-203.66"/>
|
||||
<ellipse fill="none" stroke="black" cx="1302.51" cy="-203.15" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1224.28,-186.62 1224.72,-176.63 1226.71,-176.72 1226.28,-186.71 1224.28,-186.62"/>
|
||||
<polyline fill="none" stroke="black" points="1223.5,-181.58 1228.5,-181.8"/>
|
||||
<polygon fill="black" stroke="black" points="1229.28,-186.84 1229.71,-176.85 1231.71,-176.94 1231.28,-186.93 1229.28,-186.84"/>
|
||||
<polyline fill="none" stroke="black" points="1228.5,-181.8 1233.49,-182.02"/>
|
||||
</g>
|
||||
<!-- group_groups_dfa1d7f3->groups_b63e4e33 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>group_groups_dfa1d7f3:w->groups_b63e4e33:e</title>
|
||||
<path fill="none" stroke="black" d="M1299.21,-183.43C1274.4,-183 1261.19,-181.84 1233.16,-181.62"/>
|
||||
<polygon fill="black" stroke="black" points="1308.17,-183.5 1318.13,-188.08 1313.5,-183.54 1317.83,-183.58 1317.83,-183.58 1317.83,-183.58 1313.5,-183.54 1318.2,-179.08 1308.17,-183.5"/>
|
||||
<ellipse fill="none" stroke="black" cx="1302.45" cy="-183.45" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1224.48,-186.59 1224.52,-176.59 1226.52,-176.6 1226.48,-186.6 1224.48,-186.59"/>
|
||||
<polyline fill="none" stroke="black" points="1223.5,-181.58 1228.5,-181.6"/>
|
||||
<polygon fill="black" stroke="black" points="1229.48,-186.61 1229.52,-176.61 1231.52,-176.61 1231.48,-186.61 1229.48,-186.61"/>
|
||||
<polyline fill="none" stroke="black" points="1228.5,-181.6 1233.5,-181.62"/>
|
||||
</g>
|
||||
<!-- group_users_41cb40a7 -->
|
||||
<g id="node7" class="node">
|
||||
<title>group_users_41cb40a7</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1325,-124.08 1325,-145.08 1424,-145.08 1424,-124.08 1325,-124.08"/>
|
||||
<text text-anchor="start" x="1326.88" y="-130.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">group_users</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="1424,-124.08 1424,-145.08 1564,-145.08 1564,-124.08 1424,-124.08"/>
|
||||
<text text-anchor="start" x="1517" y="-129.78" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="1327" y="-109.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">group_id</text>
|
||||
<text text-anchor="start" x="1407" y="-108.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1425.75" y="-108.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="1327" y="-88.78" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">user_id</text>
|
||||
<text text-anchor="start" x="1407" y="-87.78" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="1425.75" y="-87.78" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="1324,-81.08 1324,-146.08 1565,-146.08 1565,-81.08 1324,-81.08"/>
|
||||
</g>
|
||||
<!-- group_users_41cb40a7->groups_b63e4e33 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>group_users_41cb40a7:w->groups_b63e4e33:e</title>
|
||||
<path fill="none" stroke="black" d="M1304.58,-117.05C1273.18,-129.88 1270.19,-174.26 1233.11,-180.78"/>
|
||||
<polygon fill="black" stroke="black" points="1313.33,-115.45 1323.98,-118.07 1318.58,-114.48 1322.84,-113.7 1322.84,-113.7 1322.84,-113.7 1318.58,-114.48 1322.36,-109.22 1313.33,-115.45"/>
|
||||
<ellipse fill="none" stroke="black" cx="1307.71" cy="-116.48" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="1224.91,-186.48 1224.08,-176.52 1226.07,-176.35 1226.91,-186.32 1224.91,-186.48"/>
|
||||
<polyline fill="none" stroke="black" points="1223.5,-181.58 1228.48,-181.17"/>
|
||||
<polygon fill="black" stroke="black" points="1229.89,-186.07 1229.06,-176.1 1231.06,-175.94 1231.89,-185.9 1229.89,-186.07"/>
|
||||
<polyline fill="none" stroke="black" points="1228.48,-181.17 1233.47,-180.75"/>
|
||||
</g>
|
||||
<!-- group_users_41cb40a7->users_6a70267 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>group_users_41cb40a7:w->users_6a70267:e</title>
|
||||
<path fill="none" stroke="black" d="M1304.18,-92.49C874.76,-88.48 691.37,46.75 332,-201.58 301.46,-222.69 323.78,-272.07 297.75,-281.14"/>
|
||||
<polygon fill="black" stroke="black" points="1313.17,-92.54 1323.14,-97.08 1318.5,-92.56 1322.83,-92.58 1322.83,-92.58 1322.83,-92.58 1318.5,-92.56 1323.19,-88.08 1313.17,-92.54"/>
|
||||
<ellipse fill="none" stroke="black" cx="1307.45" cy="-92.51" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="289.72,-287.38 288.26,-277.49 290.23,-277.2 291.7,-287.09 289.72,-287.38"/>
|
||||
<polyline fill="none" stroke="black" points="288,-282.58 292.95,-281.85"/>
|
||||
<polygon fill="black" stroke="black" points="294.67,-286.65 293.2,-276.76 295.18,-276.46 296.65,-286.36 294.67,-286.65"/>
|
||||
<polyline fill="none" stroke="black" points="292.95,-281.85 297.89,-281.12"/>
|
||||
</g>
|
||||
<!-- logins_be987289 -->
|
||||
<g id="node9" class="node">
|
||||
<title>logins_be987289</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="357,-443.58 357,-464.58 462,-464.58 462,-443.58 357,-443.58"/>
|
||||
<text text-anchor="start" x="359" y="-450.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">logins</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="462,-443.58 462,-464.58 608,-464.58 608,-443.58 462,-443.58"/>
|
||||
<text text-anchor="start" x="561" y="-449.28" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="359" y="-429.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">id</text>
|
||||
<text text-anchor="start" x="455.75" y="-428.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="464" y="-428.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="455.75" y="-407.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="464" y="-407.28" font-family="Helvetica,sans-Serif" font-size="14.00">auto-incremented</text>
|
||||
<text text-anchor="start" x="359" y="-386.28" font-family="Helvetica,sans-Serif" font-size="14.00">user_id</text>
|
||||
<text text-anchor="start" x="455.75" y="-386.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="464" y="-386.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER NOT NULL</text>
|
||||
<text text-anchor="start" x="359" y="-365.28" font-family="Helvetica,sans-Serif" font-size="14.00">email</text>
|
||||
<text text-anchor="start" x="455.75" y="-365.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="463.75" y="-365.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<text text-anchor="start" x="358.62" y="-344.28" font-family="Helvetica,sans-Serif" font-size="14.00">display_email</text>
|
||||
<text text-anchor="start" x="455.75" y="-344.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="463.75" y="-344.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="356,-337.58 356,-465.58 609,-465.58 609,-337.58 356,-337.58"/>
|
||||
</g>
|
||||
<!-- logins_be987289->users_6a70267 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>logins_be987289:w->users_6a70267:e</title>
|
||||
<path fill="none" stroke="black" d="M337.12,-384.78C311.76,-364.01 332.95,-294.11 297.64,-283.85"/>
|
||||
<polygon fill="black" stroke="black" points="345.65,-387.47 353.83,-394.77 350.73,-389.08 354.86,-390.38 354.86,-390.38 354.86,-390.38 350.73,-389.08 356.54,-386.19 345.65,-387.47"/>
|
||||
<ellipse fill="none" stroke="black" cx="340.19" cy="-385.75" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="288.34,-287.67 289.64,-277.76 291.62,-278.02 290.33,-287.93 288.34,-287.67"/>
|
||||
<polyline fill="none" stroke="black" points="288,-282.58 292.96,-283.23"/>
|
||||
<polygon fill="black" stroke="black" points="293.3,-288.32 294.6,-278.41 296.58,-278.67 295.28,-288.58 293.3,-288.32"/>
|
||||
<polyline fill="none" stroke="black" points="292.96,-283.23 297.92,-283.88"/>
|
||||
</g>
|
||||
<!-- id_dc7c64b2 -->
|
||||
<g id="node11" class="node">
|
||||
<title>id_dc7c64b2</title>
|
||||
<text text-anchor="start" x="83.88" y="-518.91" font-family="Helvetica,sans-Serif" font-size="14.00">billing_accounts.id</text>
|
||||
</g>
|
||||
<!-- orgs_34a26e->id_dc7c64b2 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>orgs_34a26e:w->id_dc7c64b2:e</title>
|
||||
<path fill="none" stroke="black" d="M320.17,-523.58C285.36,-523.58 269.06,-523.58 230.68,-523.58"/>
|
||||
<polygon fill="black" stroke="black" points="329.17,-523.58 339.17,-528.08 334.5,-523.58 338.83,-523.58 338.83,-523.58 338.83,-523.58 334.5,-523.58 339.17,-519.08 329.17,-523.58"/>
|
||||
<ellipse fill="none" stroke="black" cx="323.45" cy="-523.58" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="222,-528.58 222,-518.58 224,-518.58 224,-528.58 222,-528.58"/>
|
||||
<polyline fill="none" stroke="black" points="221,-523.58 226,-523.58"/>
|
||||
<polygon fill="black" stroke="black" points="227,-528.58 227,-518.58 229,-518.58 229,-528.58 227,-528.58"/>
|
||||
<polyline fill="none" stroke="black" points="226,-523.58 231,-523.58"/>
|
||||
</g>
|
||||
<!-- orgs_34a26e->users_6a70267 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>orgs_34a26e:w->users_6a70267:e</title>
|
||||
<path fill="none" stroke="black" d="M325.84,-543.17C239.04,-523.2 391.49,-297.37 297.85,-283.27"/>
|
||||
<polygon fill="black" stroke="black" points="339.02,-539.51 337.99,-549.45 336,-549.25 337.03,-539.3 339.02,-539.51"/>
|
||||
<polyline fill="none" stroke="black" points="339.5,-544.58 334.53,-544.07"/>
|
||||
<ellipse fill="none" stroke="black" cx="330.05" cy="-543.61" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="288.65,-287.64 289.35,-277.67 291.34,-277.81 290.64,-287.78 288.65,-287.64"/>
|
||||
<polyline fill="none" stroke="black" points="288,-282.58 292.99,-282.93"/>
|
||||
<polygon fill="black" stroke="black" points="293.64,-287.99 294.33,-278.02 296.33,-278.15 295.63,-288.13 293.64,-287.99"/>
|
||||
<polyline fill="none" stroke="black" points="292.99,-282.93 297.98,-283.28"/>
|
||||
</g>
|
||||
<!-- prefs_660170f -->
|
||||
<g id="node12" class="node">
|
||||
<title>prefs_660170f</title>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="696,-445.58 696,-466.58 758,-466.58 758,-445.58 696,-445.58"/>
|
||||
<text text-anchor="start" x="698" y="-452.28" font-family="Helvetica,sans-Serif" font-weight="bold" font-style="italic" font-size="14.00">prefs</text>
|
||||
<polygon fill="#f2e6c2" stroke="none" points="758,-445.58 758,-466.58 904,-466.58 904,-445.58 758,-445.58"/>
|
||||
<text text-anchor="start" x="857" y="-451.28" font-family="Helvetica,sans-Serif" font-size="14.00">[table]</text>
|
||||
<text text-anchor="start" x="698" y="-430.28" font-family="Helvetica,sans-Serif" font-size="14.00">org_id</text>
|
||||
<text text-anchor="start" x="751.75" y="-430.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="760" y="-430.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="697.88" y="-409.28" font-family="Helvetica,sans-Serif" font-size="14.00">user_id</text>
|
||||
<text text-anchor="start" x="751.75" y="-409.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="760" y="-409.28" font-family="Helvetica,sans-Serif" font-size="14.00">INTEGER</text>
|
||||
<text text-anchor="start" x="698" y="-388.28" font-family="Helvetica,sans-Serif" font-size="14.00">prefs</text>
|
||||
<text text-anchor="start" x="751.75" y="-388.28" font-family="Helvetica,sans-Serif" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="759.75" y="-388.28" font-family="Helvetica,sans-Serif" font-size="14.00">VARCHAR NOT NULL</text>
|
||||
<polygon fill="none" stroke="#888888" points="695,-381.58 695,-467.58 905,-467.58 905,-381.58 695,-381.58"/>
|
||||
</g>
|
||||
<!-- prefs_660170f->orgs_34a26e -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>prefs_660170f:w->orgs_34a26e:e</title>
|
||||
<path fill="none" stroke="black" d="M676.04,-438.74C607.35,-465.76 718.99,-657.4 635.43,-670.84"/>
|
||||
<polygon fill="black" stroke="black" points="684.81,-437.28 695.41,-440.08 690.07,-436.41 694.34,-435.69 694.34,-435.69 694.34,-435.69 690.07,-436.41 693.93,-431.2 684.81,-437.28"/>
|
||||
<ellipse fill="none" stroke="black" cx="679.17" cy="-438.22" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="626.87,-676.5 626.12,-666.52 628.12,-666.37 628.86,-676.35 626.87,-676.5"/>
|
||||
<polyline fill="none" stroke="black" points="625.5,-671.58 630.49,-671.21"/>
|
||||
<polygon fill="black" stroke="black" points="631.86,-676.12 631.11,-666.15 633.1,-666 633.85,-675.97 631.86,-676.12"/>
|
||||
<polyline fill="none" stroke="black" points="630.49,-671.21 635.47,-670.84"/>
|
||||
</g>
|
||||
<!-- prefs_660170f->users_6a70267 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>prefs_660170f:w->users_6a70267:e</title>
|
||||
<path fill="none" stroke="black" d="M676.43,-408.64C654.09,-393.14 667.37,-345.27 633,-324.58 625.47,-320.05 353.85,-288.98 297.83,-283.43"/>
|
||||
<polygon fill="black" stroke="black" points="685.01,-410.93 693.52,-417.85 690.17,-412.3 694.35,-413.41 694.35,-413.41 694.35,-413.41 690.17,-412.3 695.83,-409.15 685.01,-410.93"/>
|
||||
<ellipse fill="none" stroke="black" cx="679.49" cy="-409.46" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="288.57,-287.65 289.43,-277.69 291.42,-277.86 290.56,-287.82 288.57,-287.65"/>
|
||||
<polyline fill="none" stroke="black" points="288,-282.58 292.98,-283.01"/>
|
||||
<polygon fill="black" stroke="black" points="293.55,-288.08 294.41,-278.12 296.4,-278.29 295.54,-288.25 293.55,-288.08"/>
|
||||
<polyline fill="none" stroke="black" points="292.98,-283.01 297.96,-283.44"/>
|
||||
</g>
|
||||
<!-- workspaces_e61add->orgs_34a26e -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>workspaces_e61add:w->orgs_34a26e:e</title>
|
||||
<path fill="none" stroke="black" d="M657.73,-671.58C650.41,-671.58 644.29,-671.58 635.42,-671.58"/>
|
||||
<polygon fill="black" stroke="black" points="666.67,-671.58 676.67,-676.08 672,-671.58 676.33,-671.58 676.33,-671.58 676.33,-671.58 672,-671.58 676.67,-667.08 666.67,-671.58"/>
|
||||
<ellipse fill="none" stroke="black" cx="660.95" cy="-671.58" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="626.5,-676.58 626.5,-666.58 628.5,-666.58 628.5,-676.58 626.5,-676.58"/>
|
||||
<polyline fill="none" stroke="black" points="625.5,-671.58 630.5,-671.58"/>
|
||||
<polygon fill="black" stroke="black" points="631.5,-676.58 631.5,-666.58 633.5,-666.58 633.5,-676.58 631.5,-676.58"/>
|
||||
<polyline fill="none" stroke="black" points="630.5,-671.58 635.5,-671.58"/>
|
||||
</g>
|
||||
<!-- user_id_2d5fdf94 -->
|
||||
<g id="node15" class="node">
|
||||
<title>user_id_2d5fdf94</title>
|
||||
<text text-anchor="start" x="365.12" y="-254.91" font-family="Helvetica,sans-Serif" font-size="14.00">billing_account_managers.user_id</text>
|
||||
</g>
|
||||
<!-- user_id_2d5fdf94->users_6a70267 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>user_id_2d5fdf94:w->users_6a70267:e</title>
|
||||
<path fill="none" stroke="black" d="M337.53,-262.88C323.26,-268.29 315.11,-278.78 297.91,-281.77"/>
|
||||
<polygon fill="black" stroke="black" points="346.32,-261.35 356.94,-264.07 351.57,-260.44 355.84,-259.7 355.84,-259.7 355.84,-259.7 351.57,-260.44 355.4,-255.21 346.32,-261.35"/>
|
||||
<ellipse fill="none" stroke="black" cx="340.68" cy="-262.33" rx="4" ry="4"/>
|
||||
<polygon fill="black" stroke="black" points="289.41,-287.49 288.59,-277.52 290.58,-277.35 291.4,-287.32 289.41,-287.49"/>
|
||||
<polyline fill="none" stroke="black" points="288,-282.58 292.98,-282.17"/>
|
||||
<polygon fill="black" stroke="black" points="294.39,-287.07 293.57,-277.11 295.56,-276.94 296.38,-286.91 294.39,-287.07"/>
|
||||
<polyline fill="none" stroke="black" points="292.98,-282.17 297.97,-281.76"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 56 KiB |
BIN
documentation/images/ws-users-management-popup.png
Normal file
BIN
documentation/images/ws-users-management-popup.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
175
publiccode.yml
Normal file
175
publiccode.yml
Normal file
@ -0,0 +1,175 @@
|
||||
# This repository adheres to the publiccode.yml standard by including this
|
||||
# metadata file that makes public software easily discoverable.
|
||||
# More info at https://github.com/italia/publiccode.yml
|
||||
|
||||
publiccodeYmlVersion: '0.2'
|
||||
categories:
|
||||
- data-collection
|
||||
- crm
|
||||
- compliance-management
|
||||
- office
|
||||
dependsOn:
|
||||
open:
|
||||
- name: NodeJS
|
||||
optional: false
|
||||
version: ''
|
||||
versionMax: ''
|
||||
versionMin: '18'
|
||||
- name: Python
|
||||
optional: false
|
||||
version: ''
|
||||
versionMax: ''
|
||||
versionMin: '3.9'
|
||||
- name: Yarn
|
||||
optional: true
|
||||
version: ''
|
||||
versionMax: ''
|
||||
versionMin: ''
|
||||
- name: Postgresql
|
||||
optional: true
|
||||
version: ''
|
||||
versionMax: ''
|
||||
versionMin: ''
|
||||
- name: Redis
|
||||
optional: true
|
||||
version: ''
|
||||
versionMax: ''
|
||||
versionMin: ''
|
||||
description:
|
||||
en:
|
||||
apiDocumentation: 'https://support.getgrist.com/api/'
|
||||
documentation: 'https://support.getgrist.com/'
|
||||
features:
|
||||
- database
|
||||
- spreadsheet
|
||||
- low-code
|
||||
- no-code
|
||||
- form generation
|
||||
- webhook
|
||||
- calendar
|
||||
- map
|
||||
- python formulas
|
||||
genericName: collaborative spreadsheet
|
||||
longDescription: |
|
||||
Grist is a hybrid database/spreadsheet, meaning that:
|
||||
|
||||
- Columns work like they do in databases: they are named, and they hold one kind of data.
|
||||
- Columns can be filled by formula, spreadsheet-style, with automatic updates when referenced cells change.
|
||||
|
||||
|
||||
This difference can confuse people coming directly from Excel or Google
|
||||
Sheets. Give it a chance! There's also a [Grist for Spreadsheet
|
||||
Users](https://www.getgrist.com/blog/grist-for-spreadsheet-users/) article
|
||||
to help get you oriented. If you're coming from Airtable, you'll find the
|
||||
model familiar (and there's also our [Grist vs
|
||||
Airtable](https://www.getgrist.com/blog/grist-v-airtable/) article for a
|
||||
direct comparison).
|
||||
|
||||
Here are some specific feature highlights of Grist:
|
||||
|
||||
- Python formulas.
|
||||
- Full [Python syntax is supported](https://support.getgrist.com/formulas/#python), including the standard library.
|
||||
- Many [Excel functions](https://support.getgrist.com/functions/) also available.
|
||||
- An [AI Assistant](https://www.getgrist.com/ai-formula-assistant/) specifically tuned for formula generation (using OpenAI gpt-3.5-turbo or [Llama](https://ai.meta.com/llama/) via [llama-cpp-python](https://github.com/abetlen/llama-cpp-python)).
|
||||
- A portable, self-contained format.
|
||||
- Based on SQLite, the most widely deployed database engine.
|
||||
- Any tool that can read SQLite can read numeric and text data from a Grist file.
|
||||
- Enables [backups](https://support.getgrist.com/exports/#backing-up-an-entire-document) that you can confidently restore in full.
|
||||
- Great for moving between different hosts.
|
||||
- Can be displayed on a static website with [`grist-static`](https://github.com/gristlabs/grist-static) – no special server needed.
|
||||
- A self-contained desktop app for viewing and editing locally: [`grist-electron`](https://github.com/gristlabs/grist-electron).
|
||||
- Convenient editing and formatting features.
|
||||
- Choices and [choice lists](https://support.getgrist.com/col-types/#choice-list-columns), for adding colorful tags to records.
|
||||
- [References](https://support.getgrist.com/col-refs/#creating-a-new-reference-list-column) and reference lists, for cross-referencing records in other tables.
|
||||
- [Attachments](https://support.getgrist.com/col-types/#attachment-columns), to include media or document files in records.
|
||||
- Dates and times, toggles, and special numerics such as currency all have specialized editors and formatting options.
|
||||
- [Conditional Formatting](https://support.getgrist.com/conditional-formatting/), letting you control the style of cells with formulas to draw attention to important information.
|
||||
- Drag-and-drop dashboards.
|
||||
- [Charts](https://support.getgrist.com/widget-chart/), [card views](https://support.getgrist.com/widget-card/) and a [calendar widget](https://support.getgrist.com/widget-calendar/) for visualization.
|
||||
- [Summary tables](https://support.getgrist.com/summary-tables/) for summing and counting across groups.
|
||||
- [Widget linking](https://support.getgrist.com/linking-widgets/) streamlines filtering and editing data. Grist has a unique approach to visualization, where you can lay out and link distinct widgets to show together, without cramming mixed material into a table.
|
||||
- [Filter bar](https://support.getgrist.com/search-sort-filter/#filter-buttons) for quick slicing and dicing.
|
||||
- [Incremental imports](https://support.getgrist.com/imports/#updating-existing-records).
|
||||
- Import a CSV of the last three months activity from your bank...
|
||||
- ...and import new activity a month later without fuss or duplication.
|
||||
- Integrations.
|
||||
- A [REST API](https://support.getgrist.com/api/), [Zapier actions/triggers](https://support.getgrist.com/integrators/#integrations-via-zapier), and support from similar [integrators](https://support.getgrist.com/integrators/).
|
||||
- Import/export to Google drive, Excel format, CSV.
|
||||
- Link data with [custom widgets](https://support.getgrist.com/widget-custom/#_top), hosted externally.
|
||||
- Configurable outgoing webhooks.
|
||||
- [Many templates](https://templates.getgrist.com/) to get you started, from investment research to organizing treasure hunts.
|
||||
- Access control options.
|
||||
- (You'll need SSO logins set up to make use of these options; [`grist-omnibus`](https://github.com/gristlabs/grist-omnibus) has a prepackaged solution if configuring this feels daunting)
|
||||
- Share [individual documents](https://support.getgrist.com/sharing/), workspaces, or [team sites](https://support.getgrist.com/team-sharing/).
|
||||
- Control access to [individual rows, columns, and tables](https://support.getgrist.com/access-rules/).
|
||||
- Control access based on cell values and user attributes.
|
||||
- Self-maintainable.
|
||||
- Useful for intranet operation and specific compliance requirements.
|
||||
- Sandboxing options for untrusted documents.
|
||||
- On Linux or with Docker, you can enable [gVisor](https://github.com/google/gvisor) sandboxing at the individual document level.
|
||||
- On macOS, you can use native sandboxing.
|
||||
- On any OS, including Windows, you can use a wasm-based sandbox.
|
||||
- Translated to many languages.
|
||||
- `F1` key brings up some quick help. This used to go without saying, but in general Grist has good keyboard support.
|
||||
shortDescription: |-
|
||||
Grist is a modern relational spreadsheet. It combines the flexibility of a
|
||||
|
||||
spreadsheet with the robustness of a database.
|
||||
videos:
|
||||
- 'https://www.youtube.com/watch?v=XYZ_ZGSxU00'
|
||||
developmentStatus: stable
|
||||
inputTypes:
|
||||
- application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
- text/csv
|
||||
it:
|
||||
conforme:
|
||||
gdpr: false
|
||||
lineeGuidaDesign: false
|
||||
misureMinimeSicurezza: false
|
||||
modelloInteroperabilita: false
|
||||
countryExtensionVersion: '0.2'
|
||||
piattaforme:
|
||||
anpr: false
|
||||
cie: false
|
||||
pagopa: false
|
||||
spid: false
|
||||
landingURL: 'https://getgrist.com'
|
||||
legal:
|
||||
license: Apache-2.0
|
||||
localisation:
|
||||
availableLanguages:
|
||||
- en
|
||||
- fr
|
||||
- ru
|
||||
- de
|
||||
- es
|
||||
- pt
|
||||
- zh
|
||||
- it
|
||||
- ja
|
||||
- 'no'
|
||||
- ro
|
||||
- sl
|
||||
- uk
|
||||
localisationReady: true
|
||||
logo: |-
|
||||
https://raw.githubusercontent.com/gristlabs/grist-core/master/static/img/logo-grist.png
|
||||
maintenance:
|
||||
contacts:
|
||||
- affiliation: Grist Labs
|
||||
email: paul@getgrist.com
|
||||
name: Paul Fitzpatrick
|
||||
type: internal
|
||||
name: Grist
|
||||
outputTypes:
|
||||
- application/x-sqlite3
|
||||
platforms:
|
||||
- web
|
||||
releaseDate: '2024-06-12'
|
||||
roadmap: 'https://github.com/gristlabs/grist-core/projects/1'
|
||||
softwareType: standalone/other
|
||||
softwareVersion: 1.1.15
|
||||
url: 'https://github.com/gristlabs/grist-core'
|
||||
usedBy:
|
||||
- 'ANCT (https://anct.gouv.fr)'
|
||||
- 'DINUM (https://www.numerique.gouv.fr/dinum/)'
|
40
sandbox/docker_entrypoint.sh
Executable file
40
sandbox/docker_entrypoint.sh
Executable file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Runs the command provided as arguments, but attempts to configure permissions first.
|
||||
|
||||
important_read_dirs=("/grist" "/persist")
|
||||
write_dir="/persist"
|
||||
current_user_id=$(id -u)
|
||||
|
||||
# We want to avoid running Grist as root if possible.
|
||||
# Try to setup permissions and de-elevate to a normal user.
|
||||
if [[ $current_user_id == 0 ]]; then
|
||||
target_user=${GRIST_DOCKER_USER:-grist}
|
||||
target_group=${GRIST_DOCKER_GROUP:-grist}
|
||||
|
||||
# Make sure the target user owns everything that Grist needs write access to.
|
||||
find $write_dir ! -user "$target_user" -exec chown "$target_user" "{}" +
|
||||
|
||||
# Restart as the target user, replacing the current process (replacement is needed for security).
|
||||
# Alternative tools to setpriv are: chroot, gosu.
|
||||
# Need to use `exec` to close the parent shell, to avoid vulnerabilities: https://github.com/tianon/gosu/issues/37
|
||||
exec setpriv --reuid "$target_user" --regid "$target_group" --init-groups /usr/bin/env bash "$0" "$@"
|
||||
fi
|
||||
|
||||
# Validate that this user has access to the top level of each important directory.
|
||||
# There might be a benefit to testing individual files, but this is simpler as the dir may start empty.
|
||||
for dir in "${important_read_dirs[@]}"; do
|
||||
if ! { test -r "$dir" ;} ; then
|
||||
echo "Invalid permissions, cannot read '$dir'. Aborting." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
for dir in "${important_write_dirs[@]}"; do
|
||||
if ! { test -r "$dir" && test -w "$dir" ;} ; then
|
||||
echo "Invalid permissions, cannot write '$dir'. Aborting." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exec /usr/bin/tini -s -- "$@"
|
35
sandbox/supervisor.mjs
Normal file
35
sandbox/supervisor.mjs
Normal file
@ -0,0 +1,35 @@
|
||||
import {spawn} from 'child_process';
|
||||
|
||||
let grist;
|
||||
|
||||
function startGrist(newConfig={}) {
|
||||
saveNewConfig(newConfig);
|
||||
// H/T https://stackoverflow.com/a/36995148/11352427
|
||||
grist = spawn('./sandbox/run.sh', {
|
||||
stdio: ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
});
|
||||
grist.on('message', function(data) {
|
||||
if (data.action === 'restart') {
|
||||
console.log('Restarting Grist with new environment');
|
||||
|
||||
// Note that we only set this event handler here, after we have
|
||||
// a new environment to reload with. Small chance of a race here
|
||||
// in case something else sends a SIGINT before we do it
|
||||
// ourselves further below.
|
||||
grist.on('exit', () => {
|
||||
grist = startGrist(data.newConfig);
|
||||
});
|
||||
|
||||
grist.kill('SIGINT');
|
||||
}
|
||||
});
|
||||
return grist;
|
||||
}
|
||||
|
||||
// Stub function
|
||||
function saveNewConfig(newConfig) {
|
||||
// TODO: something here to actually persist the new config before
|
||||
// restarting Grist.
|
||||
}
|
||||
|
||||
startGrist();
|
@ -347,7 +347,9 @@
|
||||
"Formula timer": "Formel Timer",
|
||||
"Cancel": "Abbrechen",
|
||||
"Timing is on": "Das Timing läuft",
|
||||
"You can make changes to the document, then stop timing to see the results.": "Sie können Änderungen an dem Dokument vornehmen und dann die Zeitmessung stoppen, um die Ergebnisse zu sehen."
|
||||
"You can make changes to the document, then stop timing to see the results.": "Sie können Änderungen an dem Dokument vornehmen und dann die Zeitmessung stoppen, um die Ergebnisse zu sehen.",
|
||||
"Only available to document editors": "Nur für Redakteure von Dokumenten verfügbar",
|
||||
"Only available to document owners": "Nur für Eigentümer von Dokumenten verfügbar"
|
||||
},
|
||||
"DocumentUsage": {
|
||||
"Attachments Size": "Größe der Anhänge",
|
||||
@ -1611,7 +1613,11 @@
|
||||
"No fault detected.": "Kein Fehler erkannt.",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "In Grist können verschiedene Arten der Authentifizierung konfiguriert werden, darunter SAML und OIDC. Wir empfehlen, eine davon zu aktivieren, wenn Grist über das Netzwerk zugänglich ist oder mehreren Personen zur Verfügung gestellt wird.",
|
||||
"Or, as a fallback, you can set: {{bootKey}} in the environment and visit: {{url}}": "Als Ausweichmöglichkeit können Sie auch {{bootKey}} in der Umgebung einstellen und {{url}} besuchen",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "In Grist können verschiedene Arten der Authentifizierung konfiguriert werden, darunter SAML und OIDC. Wir empfehlen, eine davon zu aktivieren, wenn Grist über das Netzwerk zugänglich ist oder mehreren Personen zur Verfügung gestellt wird."
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "In Grist können verschiedene Arten der Authentifizierung konfiguriert werden, darunter SAML und OIDC. Wir empfehlen, eine davon zu aktivieren, wenn Grist über das Netzwerk zugänglich ist oder mehreren Personen zur Verfügung gestellt wird.",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist signiert die Sitzungscookies der Benutzer mit einem geheimen Schlüssel. Bitte setzen Sie diesen Schlüssel über die Umgebungsvariable GRIST_SESSION_SECRET. Grist greift auf eine hart kodierte Voreinstellung zurück, wenn sie nicht gesetzt ist. Wir werden diesen Hinweis möglicherweise in Zukunft entfernen, da Sitzungs-IDs, die seit v1.1.16 erzeugt werden, von Natur aus kryptographisch sicher sind.",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist signiert die Sitzungscookies der Benutzer mit einem geheimen Schlüssel. Bitte setzen Sie diesen Schlüssel über die Umgebungsvariable GRIST_SESSION_SECRET. Grist greift auf eine hart kodierte Voreinstellung zurück, wenn sie nicht gesetzt ist. Wir werden diesen Hinweis möglicherweise in Zukunft entfernen, da Sitzungs-IDs, die seit v1.1.16 erzeugt werden, von Natur aus kryptographisch sicher sind.",
|
||||
"Key to sign sessions with": "Schlüssel zum Anmelden von Sitzungen mit",
|
||||
"Session Secret": "Sitzungsgeheimnis"
|
||||
},
|
||||
"Section": {
|
||||
"Insert section above": "Abschnitt oben einfügen",
|
||||
|
@ -1541,6 +1541,7 @@
|
||||
"Error": "Error",
|
||||
"Error checking for updates": "Error checking for updates",
|
||||
"Grist allows for very powerful formulas, using Python. We recommend setting the environment variable GRIST_SANDBOX_FLAVOR to gvisor if your hardware supports it (most will), to run formulas in each document within a sandbox isolated from other documents and isolated from the network.": "Grist allows for very powerful formulas, using Python. We recommend setting the environment variable GRIST_SANDBOX_FLAVOR to gvisor if your hardware supports it (most will), to run formulas in each document within a sandbox isolated from other documents and isolated from the network.",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.",
|
||||
"Grist is up to date": "Grist is up to date",
|
||||
"Grist releases are at ": "Grist releases are at ",
|
||||
"Last checked {{time}}": "Last checked {{time}}",
|
||||
@ -1567,7 +1568,10 @@
|
||||
"Results": "Results",
|
||||
"Self Checks": "Self Checks",
|
||||
"You do not have access to the administrator panel.\nPlease log in as an administrator.": "You do not have access to the administrator panel.\nPlease log in as an administrator.",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people."
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.",
|
||||
"Key to sign sessions with": "Key to sign sessions with",
|
||||
"Session Secret": "Session Secret"
|
||||
},
|
||||
"Columns": {
|
||||
"Remove Column": "Remove Column"
|
||||
|
@ -289,7 +289,9 @@
|
||||
"Reload data engine": "Recargar el motor de datos",
|
||||
"Reload data engine?": "¿Recargar motor de datos?",
|
||||
"You can make changes to the document, then stop timing to see the results.": "Puede realizar cambios en el documento y luego detener el cronometraje para ver los resultados.",
|
||||
"Stop timing...": "Dejando de cronometrar..."
|
||||
"Stop timing...": "Dejando de cronometrar...",
|
||||
"Only available to document editors": "Sólo disponible para editores de documentos",
|
||||
"Only available to document owners": "Solo disponible para los propietarios de documentos"
|
||||
},
|
||||
"DuplicateTable": {
|
||||
"Copy all data in addition to the table structure.": "Copiar todos los datos además de la estructura de la tabla.",
|
||||
@ -1605,7 +1607,11 @@
|
||||
"Or, as a fallback, you can set: {{bootKey}} in the environment and visit: {{url}}": "O, como alternativa, puedes configurar: {{bootKey}} en el entorno y visita: {{url}}",
|
||||
"You do not have access to the administrator panel.\nPlease log in as an administrator.": "No tienes acceso al panel de administrador.\nInicia sesión como administrador.",
|
||||
"Self Checks": "Controles automáticos",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Grist permite configurar diferentes tipos de autenticación, incluidos SAML y OIDC. Recomendamos habilitar uno de estos si se puede acceder a Grist a través de la red o si está disponible para varias personas."
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Grist permite configurar diferentes tipos de autenticación, incluidos SAML y OIDC. Recomendamos habilitar uno de estos si se puede acceder a Grist a través de la red o si está disponible para varias personas.",
|
||||
"Session Secret": "Secreto de sesión",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist firma las cookies de sesión de usuario con una clave secreta. Establezca esta clave mediante la variable de entorno GRIST_SESSION_SECRET. Si no se establece, Grist vuelve a un valor predeterminado. Es posible que quitemos este aviso en el futuro, ya que los identificadores de sesión generados desde la versión 1.1.16 son intrínsecamente seguros desde el punto de vista criptográfico.",
|
||||
"Key to sign sessions with": "Clave para firmar sesiones con",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist firma las cookies de sesión de usuario con una clave secreta. Establezca esta clave mediante la variable de entorno GRIST_SESSION_SECRET. Si no se establece, Grist vuelve a un valor predeterminado. Es posible que quitemos este aviso en el futuro, ya que los identificadores de sesión generados desde la versión 1.1.16 son intrínsecamente seguros desde el punto de vista criptográfico."
|
||||
},
|
||||
"CreateTeamModal": {
|
||||
"Cancel": "Cancelar",
|
||||
|
@ -41,7 +41,8 @@
|
||||
"Trash": "Cestino",
|
||||
"Workspace will be moved to Trash.": "Lo spazio di lavoro sarà spostato nel cestino.",
|
||||
"Workspaces": "Spazi di lavoro",
|
||||
"Tutorial": "Tutorial"
|
||||
"Tutorial": "Tutorial",
|
||||
"Terms of service": "Condizioni di servizio"
|
||||
},
|
||||
"MakeCopyMenu": {
|
||||
"However, it appears to be already identical.": "Tuttavia, sembra essere già identico.",
|
||||
@ -549,7 +550,9 @@
|
||||
"Legacy": "Vecchia versione",
|
||||
"Personal Site": "Sito personale",
|
||||
"Team Site": "Sito del team",
|
||||
"Grist Templates": "Template di Grist"
|
||||
"Grist Templates": "Template di Grist",
|
||||
"Billing Account": "Dati di fatturazione",
|
||||
"Manage Team": "Gestisci il team"
|
||||
},
|
||||
"ChartView": {
|
||||
"Create separate series for each value of the selected column.": "Creare serie separate per ciascun valore delle colonne selezionate.",
|
||||
@ -726,7 +729,19 @@
|
||||
"Currency": "Valuta",
|
||||
"Document ID to use whenever the REST API calls for {{docId}}. See {{apiURL}}": "ID Documento da usare quando le Api REST chiedono {{docId}}. Vedi {{apiURL}}",
|
||||
"Python version used": "Versione di Python in uso",
|
||||
"Try API calls from the browser": "Prova le chiamate Api nel browser"
|
||||
"Try API calls from the browser": "Prova le chiamate Api nel browser",
|
||||
"Stop timing...": "Ferma cronometro...",
|
||||
"Timing is on": "Cronometro attivo",
|
||||
"You can make changes to the document, then stop timing to see the results.": "Puoi fare modifiche al documento, quindi fermare il cronometro e vedere il risultato.",
|
||||
"Cancel": "Annulla",
|
||||
"Reload data engine?": "Ricarica il motore dati?",
|
||||
"Force reload the document while timing formulas, and show the result.": "Ricarica il documenti cronometrando le formule, e mostra il risultato.",
|
||||
"Formula timer": "Cronometro per le formule",
|
||||
"Reload data engine": "Ricarica il motore dati",
|
||||
"Start timing": "Avvia cronometro",
|
||||
"Time reload": "Ricarica tempo",
|
||||
"Only available to document editors": "Disponibile solo per gli editor del documento",
|
||||
"Only available to document owners": "Disponibile solo per i proprietari del documento"
|
||||
},
|
||||
"DocumentUsage": {
|
||||
"Data Size": "Dimensione dei dati",
|
||||
@ -1106,7 +1121,9 @@
|
||||
"Add conditional style": "Aggiungi stile condizionale",
|
||||
"Error in style rule": "Errore nella regola di stile",
|
||||
"Row Style": "Stile riga",
|
||||
"Rule must return True or False": "La regola deve restituire Vero o Falso"
|
||||
"Rule must return True or False": "La regola deve restituire Vero o Falso",
|
||||
"Conditional Style": "Stile condizionale",
|
||||
"IF...": "SE..."
|
||||
},
|
||||
"CurrencyPicker": {
|
||||
"Invalid currency": "Valuta non valida"
|
||||
@ -1466,7 +1483,22 @@
|
||||
"Check now": "Controlla adesso",
|
||||
"Checking for updates...": "Controllo gli aggiornamenti...",
|
||||
"Grist releases are at ": "Le release di Grist sono a ",
|
||||
"Sandbox settings for data engine": "Impostazione della sandbox per il motore dati"
|
||||
"Sandbox settings for data engine": "Impostazione della sandbox per il motore dati",
|
||||
"Current authentication method": "Metodo di autenticazione attuale",
|
||||
"No fault detected.": "Nessun problema rilevato.",
|
||||
"Or, as a fallback, you can set: {{bootKey}} in the environment and visit: {{url}}": "O, come fallback, puoi impostare: {{bootKey}} nell'ambiente, e visitare: {{url}}",
|
||||
"Results": "Risultati",
|
||||
"Self Checks": "Auto-diagnostica",
|
||||
"You do not have access to the administrator panel.\nPlease log in as an administrator.": "Non hai accesso al pannello di amministrazione.\nAccedi come amministratore.",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Grist consente di configurare diversi tipi di autenticazione, compresi SAML e OIDC. Raccomandiamo di attivarne uno, se Grist è dispobile in rete, o raggiungibile da più persone.",
|
||||
"Details": "Dettagli",
|
||||
"Notes": "Note",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "Grist firma i cookie della sessione con una chiave segreta. Impostare questa chiave con la variabile d'ambiente GRIST_SESSION_SECRET. Se questa non è definita, Grist usa un default non modificabile. Potremmo rimuovere questo avviso in futuro, perché gli ID di sessione generati a partire dalla versione 1.1.16 sono intrinsecamente sicuri dal punto di vista crittografico.",
|
||||
"Administrator Panel Unavailable": "Pannello di amministrazione non disponibile",
|
||||
"Authentication": "Autenticazione",
|
||||
"Check failed.": "Controllo fallito.",
|
||||
"Check succeeded.": "Controllo riuscito.",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "Grist consente di configurare diversi tipi di autenticazione, compresi SAML e OIDC. Raccomandiamo di attivarne uno, se Grist è dispobile in rete, o raggiungibile da più persone."
|
||||
},
|
||||
"WelcomeCoachingCall": {
|
||||
"Maybe Later": "Forse più tardi",
|
||||
@ -1587,5 +1619,15 @@
|
||||
"Chart": "Grafico",
|
||||
"Custom": "Personalizzato",
|
||||
"Form": "Modulo"
|
||||
},
|
||||
"TimingPage": {
|
||||
"Average Time (s)": "Media tempi (sec)",
|
||||
"Total Time (s)": "Tempo totale (sec)",
|
||||
"Loading timing data. Don't close this tab.": "Caricamento dei dati cronometrici. Non chiudere questa scheda.",
|
||||
"Max Time (s)": "Tempo massimo (sec)",
|
||||
"Number of Calls": "Numero di chiamate",
|
||||
"Table ID": "ID Tabella",
|
||||
"Column ID": "ID colonna",
|
||||
"Formula timer": "Cronometro formule"
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +347,9 @@
|
||||
"Reload data engine": "Recarregar o motor de dados",
|
||||
"Reload data engine?": "Recarregar o motor de dados?",
|
||||
"Start timing": "Iniciar cronometragem",
|
||||
"Stop timing...": "Pare de cronometrar..."
|
||||
"Stop timing...": "Pare de cronometrar...",
|
||||
"Only available to document editors": "Disponível apenas para editores de documentos",
|
||||
"Only available to document owners": "Disponível apenas para proprietários de documentos"
|
||||
},
|
||||
"DocumentUsage": {
|
||||
"Attachments Size": "Tamanho dos Anexos",
|
||||
@ -1615,7 +1617,11 @@
|
||||
"Check failed.": "A verificação falhou.",
|
||||
"Current authentication method": "Método de autenticação atual",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "O Grist permite a configuração de diferentes tipos de autenticação, incluindo SAML e OIDC. Recomendamos ativar um desses tipos se o Grist for acessível pela rede ou estiver sendo disponibilizado para várias pessoas.",
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "O Grist permite a configuração de diferentes tipos de autenticação, incluindo SAML e OIDC. Recomendamos ativar um desses tipos se o Grist for acessível pela rede ou estiver sendo disponibilizado para várias pessoas."
|
||||
"Grist allows different types of authentication to be configured, including SAML and OIDC. We recommend enabling one of these if Grist is accessible over the network or being made available to multiple people.": "O Grist permite a configuração de diferentes tipos de autenticação, incluindo SAML e OIDC. Recomendamos ativar um desses tipos se o Grist for acessível pela rede ou estiver sendo disponibilizado para várias pessoas.",
|
||||
"Key to sign sessions with": "Chave para assinar sessões com",
|
||||
"Session Secret": "Segredo da sessão",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future since session IDs have been updated to be inherently cryptographically secure.": "O Grist assina os cookies de sessão do usuário com uma chave secreta. Defina essa chave por meio da variável de ambiente GRIST_SESSION_SECRET. O Grist retorna a um padrão codificado quando ele não está definido. Poderemos remover esse aviso no futuro, pois os IDs de sessão gerados desde a versão 1.1.16 são inerentemente seguros em termos de criptografia.",
|
||||
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "O Grist assina os cookies de sessão do usuário com uma chave secreta. Defina essa chave por meio da variável de ambiente GRIST_SESSION_SECRET. O Grist retorna a um padrão codificado quando ele não está definido. Poderemos remover esse aviso no futuro, pois os IDs de sessão gerados desde a versão 1.1.16 são inerentemente seguros em termos de criptografia."
|
||||
},
|
||||
"Field": {
|
||||
"No choices configured": "Nenhuma opção configurada",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -538,7 +538,9 @@
|
||||
"Cancel": "Prekliči",
|
||||
"Force reload the document while timing formulas, and show the result.": "Prisilno znova naloži dokument med časovnimi formulami in prikaži rezultat.",
|
||||
"Timing is on": "Merjenje časa je vklopljeno",
|
||||
"You can make changes to the document, then stop timing to see the results.": "Dokument lahko spremeniš in nato ustaviš merjenje časa, da vidiš rezultat."
|
||||
"You can make changes to the document, then stop timing to see the results.": "Dokument lahko spremeniš in nato ustaviš merjenje časa, da vidiš rezultat.",
|
||||
"Only available to document editors": "Na voljo samo urednikom dokumentov",
|
||||
"Only available to document owners": "Na voljo samo lastnikom dokumentov"
|
||||
},
|
||||
"GridOptions": {
|
||||
"Horizontal Gridlines": "Vodoravne linije",
|
||||
|
@ -42,6 +42,8 @@ import {ActivationPrefs1682636695021 as ActivationPrefs} from 'app/gen-server/mi
|
||||
import {AssistantLimit1685343047786 as AssistantLimit} from 'app/gen-server/migration/1685343047786-AssistantLimit';
|
||||
import {Shares1701557445716 as Shares} from 'app/gen-server/migration/1701557445716-Shares';
|
||||
import {Billing1711557445716 as BillingFeatures} from 'app/gen-server/migration/1711557445716-Billing';
|
||||
import {UserLastConnection1713186031023
|
||||
as UserLastConnection} from 'app/gen-server/migration/1713186031023-UserLastConnection';
|
||||
|
||||
const home: HomeDBManager = new HomeDBManager();
|
||||
|
||||
@ -50,7 +52,8 @@ const migrations = [Initial, Login, PinDocs, UserPicture, DisplayEmail, DisplayE
|
||||
CustomerIndex, ExtraIndexes, OrgHost, DocRemovedAt, Prefs,
|
||||
ExternalBilling, DocOptions, Secret, UserOptions, GracePeriodStart,
|
||||
DocumentUsage, Activations, UserConnectId, UserUUID, UserUniqueRefUUID,
|
||||
Forks, ForkIndexes, ActivationPrefs, AssistantLimit, Shares, BillingFeatures];
|
||||
Forks, ForkIndexes, ActivationPrefs, AssistantLimit, Shares, BillingFeatures,
|
||||
UserLastConnection];
|
||||
|
||||
// Assert that the "members" acl rule and group exist (or not).
|
||||
function assertMembersGroup(org: Organization, exists: boolean) {
|
||||
@ -113,6 +116,33 @@ describe('migrations', function() {
|
||||
// be doing something.
|
||||
});
|
||||
|
||||
it('can migrate UserUUID and UserUniqueRefUUID with user in table', async function() {
|
||||
this.timeout(60000);
|
||||
const runner = home.connection.createQueryRunner();
|
||||
|
||||
// Create 400 users to test the chunk (each chunk is 300 users)
|
||||
const nbUsersToCreate = 400;
|
||||
for (const migration of migrations) {
|
||||
if (migration === UserUUID) {
|
||||
for (let i = 0; i < nbUsersToCreate; i++) {
|
||||
await runner.query(`INSERT INTO users (id, name, is_first_time_user) VALUES (${i}, 'name${i}', true)`);
|
||||
}
|
||||
}
|
||||
|
||||
await (new migration()).up(runner);
|
||||
}
|
||||
|
||||
// Check that all refs are unique
|
||||
const userList = await runner.manager.createQueryBuilder()
|
||||
.select(["users.id", "users.ref"])
|
||||
.from("users", "users")
|
||||
.getMany();
|
||||
const setOfUserRefs = new Set(userList.map(u => u.ref));
|
||||
assert.equal(nbUsersToCreate, userList.length);
|
||||
assert.equal(setOfUserRefs.size, userList.length);
|
||||
await addSeedData(home.connection);
|
||||
});
|
||||
|
||||
it('can correctly switch display_email column to non-null with data', async function() {
|
||||
this.timeout(60000);
|
||||
const sqlite = home.connection.driver.options.type === 'sqlite';
|
||||
|
@ -3,6 +3,9 @@
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{ "path": "./app" },
|
||||
{ "path": "./stubs/app" },
|
||||
{ "path": "./test" },
|
||||
{ "path": "./ext/app" }
|
||||
],
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user