diff --git a/.build-files/docker-compose-local.template.yml b/.build-files/docker-compose-local.template.yml
index bd699b5f..80ec9004 100644
--- a/.build-files/docker-compose-local.template.yml
+++ b/.build-files/docker-compose-local.template.yml
@@ -22,12 +22,107 @@ services:
- path: ${DOCKER_ENV_FILE} # relative to docker compose (has to be in same directory)
required: true
+ # Depends on database. Database must be healthy before starting server
+ server:
+ build:
+ context: ../ # relative to docker compose
+ dockerfile: ./.build-files/Dockerfile.server # relatvie to build context
+ args:
+ DOCKER_ENV_FILE: ${DOCKER_ENV_FILE}
+ ports:
+ - "8000:8000"
+ environment:
+ DJANGO_ENV_FILE: "/app/.env"
+ volumes:
+ # - ../apps/server/api/migrations:/app/api/migrations
+ - ${MIGRATIONS_SOURCE}:/app/api/migrations
+ - ${LOCAL_DATA_VOLUME_LOCATION}:/app/data
+ depends_on:
+ db:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ data:
+ condition: service_started
+
+ celery:
+ build:
+ context: ../ # relative to docker compose
+ dockerfile: ./.build-files/Dockerfile.celery # relatvie to build context
+ args:
+ DOCKER_ENV_FILE: ${DOCKER_ENV_FILE}
+ command:
+ [
+ "celery",
+ "--app",
+ "celery_app",
+ "worker",
+ "--loglevel",
+ "info",
+ "--without-heartbeat",
+ "-c",
+ "4",
+ ]
+ # Docker Compose does not set the TTY width, which causes Celery errors
+ tty: false
+ environment:
+ DJANGO_ENV_FILE: "/app/.env"
+ volumes:
+ - ${LOCAL_DATA_VOLUME_LOCATION}:/app/data
+ depends_on:
+ db:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ data:
+ condition: service_started
+
+ # MySQL service. Has healthcheck which uses mysqladmin to ping before reporting healthy.
+ db:
+ image: mysql:latest
+ environment:
+ MYSQL_DATABASE: ${DATABASE_NAME}
+ MYSQL_USER: ${DATABASE_USER}
+ MYSQL_PASSWORD: ${DATABASE_PASSWORD}
+ MYSQL_ROOT_PASSWORD: ${DATABASE_ROOT_PASSWORD}
+ volumes:
+ - mysql-data:/var/lib/mysql
+ ports:
+ - "3306:3306"
+ healthcheck:
+ test:
+ [
+ "CMD",
+ "mysqladmin",
+ "ping",
+ "-h",
+ "localhost",
+ "-u",
+ "root",
+ "-p${DATABASE_ROOT_PASSWORD}",
+ ]
+ timeout: 20s
+ retries: 10
+ env_file:
+ - path: ${DOCKER_ENV_FILE} # relative to docker compose (has to be in same directory)
+ required: true
+
+ redis:
+ image: redis:latest
+ ports:
+ - "6379:6379"
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
data:
build:
context: ./
dockerfile: Dockerfile.data
ports:
- - "9000:9000"
+ - "9001:9000"
volumes:
- ${LOCAL_DATA_VOLUME_LOCATION}:/app/data # relative to docker compose
duckdb:
@@ -40,5 +135,6 @@ services:
- duckdb-data:/app/duckdb-data
volumes:
+ mysql-data:
duckdb-data:
migrations_volume:
diff --git a/.gitignore b/.gitignore
index ee8290f3..39aa557f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ certs
#Random
apps/server/api/*.jpg
apps/server/api/secrets.json
+apps/server/passwords.json
.env
.env.production
.env.*
diff --git a/README.md b/README.md
index 8cd187cc..06404e42 100644
--- a/README.md
+++ b/README.md
@@ -54,29 +54,34 @@ In the root of the repository, run the following following command:
python3 build.py --prepare-dev
```
-### Prepare Development Environment and Run Separately with Experiment Visibility Control
+### User Authentication & Experiment Gating
-Experiment visibility control allows users to control which experiments are visible to them. You specify which experiments are visible to users in the `aa_index.json` file.
+Loon supports user-based access control. You can manage users and define which experiments are visible to specific users.
-```bash
-python3 build.py --prepare-dev --experiment-visibility-control
-```
+#### Managing Users
+Admin users can manage accounts and passwords via the **Admin Control Panel** accessible at `/admin` within the application.
-Experiment visibility control example:
+#### Gating Experiments
+Access is defined in the `aa_index.json` file using the `users` array. Experiments can be either public (string) or gated (object with `users` array).
+Example `aa_index.json`:
```json
{
"experiments": [
{
- "filename": "Data Discovery - Automated Cell Lineage Tracking.json",
- "visible-by-default": true
+ "filename": "restricted_experiment.json",
+ "users": ["lab", "jess"]
},
- "Quality Control - Cancer Triggering Microenvironments.json",
- "Communication - Tumorigenic Cell States.json"
+ "public_experiment.json"
]
}
```
+Experiments are filtered as follows:
+- **Plain string**: Visible to everyone.
+- **Admin**: Sees all experiments regardless of gating.
+- **Gated (users list)**: Only visible to listed users and administrators.
+
This will generate the necessary environment file in the client directory while still running the rest of the container. Then, the development server can be started separately by the following:
@@ -133,7 +138,6 @@ The build script will do its best to validate the config before starting the doc
| -o, --overwrite | When set, any settings in your configuration file which are present as environment variables in the current session will be overwritten. | -o |
| -s, --disable-spinner | When set, disables inline spinner | -s |
| --prepare-dev | When set, will create the `.env` file based on the current configuration that is required to run a separate client development server. | --prepare-dev |
-| --experiment-visibility-control | When set, will create the `.env` file based on the current configuration that is required to run a separate client development server. | --experiment-visibility-control|
In the repository, you will see two docker directories: `docker` and `docker-local`. The main deployment will use the `docker` directory. The `docker-local` directory is a separate local version of Loon which we will discuss shortly. Below are some examples.
diff --git a/apps/client/src/App.vue b/apps/client/src/App.vue
index 703eb7d8..faf2ba18 100644
--- a/apps/client/src/App.vue
+++ b/apps/client/src/App.vue
@@ -7,9 +7,12 @@ import { useProvenanceStore } from '@/stores/misc/provenanceStore';
import { onKeyStroke } from '@vueuse/core';
import { router } from '@/router';
import LBtn from './components/custom/LBtn.vue';
+import LoginModal from './components/auth/LoginModal.vue';
+import { useAuthStore } from '@/stores/misc/authStore';
const $q = useQuasar();
const provenanceStore = useProvenanceStore();
+const authStore = useAuthStore();
onKeyStroke(['z', 'Z'], (e: KeyboardEvent) => {
if (globalSettings.usingMac && !e.metaKey) return;
@@ -26,6 +29,8 @@ onKeyStroke(['z', 'Z'], (e: KeyboardEvent) => {
});
const globalSettings = useGlobalSettings();
+const showLoginModal = ref(false);
+
watch(
() => globalSettings.darkMode,
(newDarkMode: boolean) => {
@@ -71,8 +76,25 @@ onBeforeMount(() => {
type="basic"
label="Upload"
/>
+
+
+
diff --git a/apps/client/src/components/auth/LoginModal.vue b/apps/client/src/components/auth/LoginModal.vue
new file mode 100644
index 00000000..6377de5e
--- /dev/null
+++ b/apps/client/src/components/auth/LoginModal.vue
@@ -0,0 +1,197 @@
+
+
+
+
+
+