mirror of
https://github.com/Sudo-JHare/FHIRFLARE-IG-Toolkit.git
synced 2025-06-14 12:10:03 +00:00
Updates
UI, Core logic, FHIR UI GOFSH integration THEME FIXES
This commit is contained in:
parent
7a5c21dd36
commit
833bc12d4d
26
DockerCommands.MD
Normal file
26
DockerCommands.MD
Normal file
@ -0,0 +1,26 @@
|
||||
Docker Commands.MD
|
||||
|
||||
|
||||
<HAPI-server.>
|
||||
to pull and clone:
|
||||
git clone https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git hapi-fhir-jpaserver
|
||||
|
||||
to build:
|
||||
mvn clean package -DskipTests=true -Pboot
|
||||
|
||||
to run:
|
||||
java -jar target/ROOT.war
|
||||
|
||||
|
||||
<rest-of-the-app:>
|
||||
|
||||
docker-compose build --no-cache
|
||||
docker-compose up -d
|
||||
|
||||
|
||||
|
||||
<useful-stuff:>
|
||||
|
||||
cp <CONTAINERID>:/app/PATH/Filename.ext . - . copies to the root folder you ran it from
|
||||
|
||||
docker exec -it <CONTAINERID> bash - to get a bash - session in the container -
|
@ -1,15 +1,15 @@
|
||||
# Base image with Python and Java
|
||||
FROM tomcat:10.1-jdk17
|
||||
|
||||
# Install build dependencies and Node.js 18
|
||||
# Install build dependencies, Node.js 18, and coreutils (for stdbuf)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3 python3-pip python3-venv curl \
|
||||
python3 python3-pip python3-venv curl coreutils \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install GoFSH globally
|
||||
RUN npm install -g gofsh
|
||||
# Install specific versions of GoFSH and SUSHI
|
||||
RUN npm install -g gofsh fsh-sushi
|
||||
|
||||
# Set up Python environment
|
||||
WORKDIR /app
|
||||
|
743
README.md
743
README.md
@ -1,308 +1,573 @@
|
||||
# FHIRFLARE IG Toolkit
|
||||
FHIRFLARE IG Toolkit
|
||||
Overview
|
||||
The FHIRFLARE IG Toolkit is a Flask-based web application designed to streamline the management, processing, validation, and deployment of FHIR Implementation Guides (IGs). It offers a user-friendly interface for importing IG packages, extracting metadata, validating FHIR resources or bundles, pushing IGs to FHIR servers, and converting FHIR resources to FHIR Shorthand (FSH) using GoFSH with advanced features. The toolkit includes a live console for real-time feedback and a waiting spinner for FSH conversion, making it an essential tool for FHIR developers and implementers.
|
||||
The application runs in a Dockerized environment with a Flask frontend, SQLite database, and an embedded HAPI FHIR server, ensuring consistent deployment and easy setup across platforms.
|
||||
Features
|
||||
|
||||
## Overview
|
||||
Import IGs: Download FHIR IG packages and dependencies from a package registry, supporting flexible version formats (e.g., 1.2.3, 1.1.0-preview, 1.1.2-ballot, current).
|
||||
Manage IGs: View, process, unload, or delete downloaded IGs, with duplicate detection and resolution.
|
||||
Process IGs: Extract resource types, profiles, must-support elements, examples, and profile relationships (structuredefinition-compliesWithProfile and structuredefinition-imposeProfile).
|
||||
Validate FHIR Resources/Bundles: Validate single FHIR resources or bundles against selected IGs, with detailed error and warning reports (alpha feature, work in progress).
|
||||
Push IGs: Upload IG resources to a FHIR server (e.g., HAPI FHIR) with real-time console output and optional validation against imposed profiles.
|
||||
Profile Relationships: Display and validate compliesWithProfile and imposeProfile extensions in the UI.
|
||||
FSH Converter: Convert FHIR JSON/XML resources to FHIR Shorthand (FSH) using GoFSH, with advanced options:
|
||||
Package selection for context (e.g., hl7.fhir.au.core#1.1.0-preview).
|
||||
Input modes: File upload or text input.
|
||||
Output styles: file-per-definition, group-by-fsh-type, group-by-profile, single-file.
|
||||
Log levels: error, warn, info, debug.
|
||||
FHIR versions: R4, R4B, R5, or auto-detect.
|
||||
Fishing Trip: Round-trip validation with SUSHI, generating a comparison report (fshing-trip-comparison.html) accessible via a "Click here for SUSHI Validation" badge button.
|
||||
Dependencies: Load additional FHIR packages (e.g., hl7.fhir.us.core@6.1.0).
|
||||
Indented Rules: Output FSH with context path indentation for readability.
|
||||
Meta Profile Handling: Control meta.profile usage (only-one, first, none).
|
||||
Alias File: Load existing FSH aliases (e.g., $MyAlias = http://example.org).
|
||||
No Alias: Disable automatic alias generation.
|
||||
Waiting Spinner: Displays a themed animation (light/dark) during FSH execution to indicate processing.
|
||||
|
||||
The FHIRFLARE IG Toolkit is a Flask-based web application designed to simplify the management, processing, validation, and deployment of FHIR Implementation Guides (IGs). It allows users to import IG packages, process them to extract resource types and profiles, validate FHIR resources or bundles against IGs, and push IGs to a FHIR server. The application features a user-friendly interface with a live console for real-time feedback during operations like pushing IGs or validating resources.
|
||||
|
||||
## Features
|
||||
API Support: RESTful API endpoints for importing, pushing, and retrieving IG metadata, including profile relationships.
|
||||
Live Console: Real-time logs for push, validation, and FSH conversion operations.
|
||||
Configurable Behavior: Enable/disable imposed profile validation and UI display of profile relationships.
|
||||
|
||||
- **Import IGs**: Download FHIR IG packages and their dependencies from a package registry, supporting flexible version formats (e.g., `1.2.3`, `1.1.0-preview`, `1.1.2-ballot`, `current`).
|
||||
- **Manage IGs**: View, process, unload, or delete downloaded IGs, with duplicate detection and resolution.
|
||||
- **Process IGs**: Extract resource types, profiles, must-support elements, examples, and profile relationships (`compliesWithProfile` and `imposeProfile`) from IGs.
|
||||
- **Validate FHIR Resources/Bundles**: Validate single FHIR resources or bundles against selected IGs, with detailed error and warning reports (alpha feature, work in progress).
|
||||
- **Push IGs**: Upload IG resources to a FHIR server with real-time console output, including validation against imposed profiles.
|
||||
- **Profile Relationships**: Support for `structuredefinition-compliesWithProfile` and `structuredefinition-imposeProfile` extensions, with validation and UI display.
|
||||
- **API Support**: RESTful API endpoints for importing, pushing, and validating IGs, including profile relationship metadata.
|
||||
- **Live Console**: Displays real-time logs during push and validation operations.
|
||||
- **Configurable Behavior**: Options to enable/disable imposed profile validation and UI display of profile relationships.
|
||||
Technology Stack
|
||||
|
||||
## Technology Stack
|
||||
Python 3.12+: Core backend language.
|
||||
Flask 2.3.3: Web framework for the application.
|
||||
Flask-SQLAlchemy 3.0.5: ORM for SQLite database management.
|
||||
Flask-WTF 1.2.1: Form creation, validation, and CSRF protection.
|
||||
Jinja2: Templating engine for HTML rendering.
|
||||
Bootstrap 5.3.3: Responsive frontend framework.
|
||||
JavaScript (ES6): Client-side scripting for interactive features (e.g., live console, form toggles, waiting spinner).
|
||||
Lottie-Web 5.12.2: Renders JSON-based animations for the FSH converter waiting spinner.
|
||||
SQLite: Lightweight database for processed IG metadata.
|
||||
Docker: Containerization with Flask and HAPI FHIR server.
|
||||
Node.js 18+: For GoFSH and SUSHI, used in the FSH Converter feature.
|
||||
GoFSH: Tool for converting FHIR resources to FHIR Shorthand (FSH).
|
||||
SUSHI: FSH compiler for round-trip validation in Fishing Trip.
|
||||
Requests 2.31.0: HTTP requests to FHIR servers.
|
||||
Tarfile: Handling .tgz package files.
|
||||
Logging: Python’s built-in logging for debugging.
|
||||
|
||||
The FHIRFLARE IG Toolkit is built using the following technologies:
|
||||
Prerequisites
|
||||
|
||||
- **Python 3.9+**: Core programming language for the backend.
|
||||
- **Flask 2.0+**: Lightweight web framework for building the application.
|
||||
- **Flask-SQLAlchemy**: ORM for managing the SQLite database.
|
||||
- **Flask-WTF**: Handles form creation, validation, and CSRF protection.
|
||||
- **Jinja2**: Templating engine for rendering HTML pages.
|
||||
- **Bootstrap 5**: Frontend framework for responsive UI design.
|
||||
- **JavaScript (ES6)**: Client-side scripting for interactive features like the live console and JSON validation preview.
|
||||
- **SQLite**: Lightweight database for storing processed IG metadata.
|
||||
- **Docker**: Containerization for consistent deployment.
|
||||
- **Requests**: Python library for making HTTP requests to FHIR servers.
|
||||
- **Tarfile**: Python library for handling `.tgz` package files.
|
||||
- **Logging**: Python's built-in logging for debugging and monitoring.
|
||||
Docker: Required for containerized deployment.
|
||||
Git: For cloning repositories.
|
||||
Maven: For building the HAPI FHIR server.
|
||||
Windows (if using batch files): For running Build and Run for first time.bat and Run.bat.
|
||||
Linux/MacOS (if using manual steps): For running equivalent commands.
|
||||
|
||||
## Prerequisites
|
||||
Setup Instructions
|
||||
The toolkit can be set up using batch files (Windows) or manual steps (cross-platform).
|
||||
Using Batch Files (Windows)
|
||||
First-Time Setup and Build:
|
||||
|
||||
- **Python 3.9+**: Ensure Python is installed on your system.
|
||||
- **Docker**: Required for containerized deployment.
|
||||
- **pip**: Python package manager for installing dependencies.
|
||||
Run Build and Run for first time.bat:
|
||||
cd "<project folder>"
|
||||
git clone https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git hapi-fhir-jpaserver
|
||||
copy .\hapi-fhir-Setup\target\classes\application.yaml .\hapi-fhir-jpaserver\target\classes\application.yaml
|
||||
mvn clean package -DskipTests=true -Pboot
|
||||
docker-compose build --no-cache
|
||||
docker-compose up -d
|
||||
|
||||
## Setup Instructions
|
||||
This clones the HAPI FHIR server, copies configuration, builds the project, and starts the containers.
|
||||
|
||||
1. **Clone the Repository**:
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd fhirflare-ig-toolkit
|
||||
```
|
||||
|
||||
2. **Install Dependencies**:
|
||||
Create a virtual environment and install the required packages:
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
Subsequent Runs:
|
||||
|
||||
3. **Set Environment Variables**:
|
||||
Set the `FLASK_SECRET_KEY` and `API_KEY` for security and CSRF protection:
|
||||
```bash
|
||||
export FLASK_SECRET_KEY='your-secure-secret-key'
|
||||
export API_KEY='your-api-key'
|
||||
```
|
||||
Run Run.bat:
|
||||
cd "<project folder>"
|
||||
docker-compose up -d
|
||||
|
||||
4. **Initialize the Database**:
|
||||
Ensure the `instance` directory is writable for SQLite:
|
||||
```bash
|
||||
mkdir -p instance
|
||||
chmod -R 777 instance
|
||||
```
|
||||
This starts the Flask app (port 5000) and HAPI FHIR server (port 8080).
|
||||
|
||||
5. **Run the Application Locally**:
|
||||
Start the Flask development server:
|
||||
```bash
|
||||
export FLASK_APP=app.py
|
||||
flask run
|
||||
```
|
||||
The application will be available at `http://localhost:5000`.
|
||||
|
||||
6. **Run with Docker**:
|
||||
Build and run the application using Docker, mounting the `instance` directory for persistence:
|
||||
```bash
|
||||
docker build -t flare-fhir-ig-toolkit .
|
||||
docker run -p 5000:5000 -e FLASK_SECRET_KEY='your-secure-secret-key' -e API_KEY='your-api-key' -v $(pwd)/instance:/app/instance flare-fhir-ig-toolkit
|
||||
```
|
||||
Access the application at `http://localhost:5000`.
|
||||
Access the Application:
|
||||
|
||||
## Usage
|
||||
Flask UI: http://localhost:5000
|
||||
HAPI FHIR server: http://localhost:8080
|
||||
|
||||
1. **Import an IG**:
|
||||
- Navigate to the "Import IG" tab.
|
||||
- Enter a package name (e.g., `hl7.fhir.au.core`) and version (e.g., `1.1.0-preview`, `1.1.2-ballot`, or `current`).
|
||||
- Choose a dependency mode (e.g., Recursive, Tree Shaking).
|
||||
- Click "Import" to download the package and its dependencies.
|
||||
Manual Setup (Linux/MacOS/Windows)
|
||||
Preparation:
|
||||
cd <project folder>
|
||||
git clone https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git hapi-fhir-jpaserver
|
||||
cp ./hapi-fhir-Setup/target/classes/application.yaml ./hapi-fhir-jpaserver/target/classes/application.yaml
|
||||
|
||||
2. **Manage IGs**:
|
||||
- Go to the "Manage FHIR Packages" tab to view downloaded and processed IGs.
|
||||
- Process IGs to extract metadata, unload processed IGs from the database, or delete packages from the filesystem.
|
||||
- Duplicates are highlighted for resolution (e.g., multiple versions of the same package).
|
||||
Build:
|
||||
mvn clean package -DskipTests=true -Pboot
|
||||
docker-compose build --no-cache
|
||||
|
||||
3. **View Processed IGs**:
|
||||
- After processing an IG, view its details, including resource types, profiles, must-support elements, examples, and profile relationships (`compliesWithProfile` and `imposeProfile`).
|
||||
- Profile relationships are displayed if enabled via `DISPLAY_PROFILE_RELATIONSHIPS`.
|
||||
Run:
|
||||
docker-compose up -d
|
||||
|
||||
4. **Validate FHIR Resources/Bundles**:
|
||||
- Navigate to the "Validate FHIR Sample" tab.
|
||||
- Select or enter a package (e.g., `hl7.fhir.au.core#1.1.0-preview`).
|
||||
- Choose validation mode (Single Resource or Bundle).
|
||||
- Paste FHIR JSON (e.g., a Patient or AllergyIntolerance resource).
|
||||
- Submit to validate, viewing errors and warnings in the report.
|
||||
- Note: Validation is in alpha; report issues to GitHub (remove PHI).
|
||||
Access the Application:
|
||||
|
||||
5. **Push IGs to a FHIR Server**:
|
||||
- Navigate to the "Push IGs" tab.
|
||||
- Select a package, enter a FHIR server URL (e.g., `http://hapi.fhir.org/baseR4`), and choose whether to include dependencies.
|
||||
- Click "Push to FHIR Server" to upload resources, with validation against imposed profiles (if enabled via `VALIDATE_IMPOSED_PROFILES`) and progress shown in the live console.
|
||||
Flask UI: http://localhost:5000
|
||||
HAPI FHIR server: http://localhost:8080
|
||||
|
||||
6. **API Usage**:
|
||||
- **Import IG**: `POST /api/import-ig`
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/import-ig \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"package_name": "hl7.fhir.au.core", "version": "1.1.0-preview", "api_key": "your-api-key"}'
|
||||
```
|
||||
Response includes `complies_with_profiles`, `imposed_profiles`, and duplicates.
|
||||
- **Push IG**: `POST /api/push-ig`
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/push-ig \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/x-ndjson" \
|
||||
-d '{"package_name": "hl7.fhir.au.core", "version": "1.1.0-preview", "fhir_server_url": "http://hapi.fhir.org/baseR4", "include_dependencies": true, "api_key": "your-api-key"}'
|
||||
```
|
||||
Resources are validated against imposed profiles before pushing.
|
||||
- **Validate Resource/Bundle**: Not yet exposed via API; use the UI at `/validate-sample`.
|
||||
Local Development (Without Docker)
|
||||
Clone the Repository:
|
||||
git clone https://github.com/Sudo-JHare/FHIRFLARE-IG-Toolkit.git
|
||||
cd FHIRFLARE-IG-Toolkit
|
||||
|
||||
## Configuration Options
|
||||
Install Dependencies:
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
- **`VALIDATE_IMPOSED_PROFILES`**: Set to `True` (default) to validate resources against imposed profiles during push operations. Set to `False` to skip:
|
||||
```python
|
||||
app.config['VALIDATE_IMPOSED_PROFILES'] = False
|
||||
```
|
||||
- **`DISPLAY_PROFILE_RELATIONSHIPS`**: Set to `True` (default) to show `compliesWithProfile` and `imposeProfile` in the UI. Set to `False` to hide:
|
||||
```python
|
||||
app.config['DISPLAY_PROFILE_RELATIONSHIPS'] = False
|
||||
```
|
||||
- **`FHIR_PACKAGES_DIR`**: Directory for storing `.tgz` packages and metadata (default: `/app/instance/fhir_packages`).
|
||||
- **`SECRET_KEY`**: Required for CSRF protection and session security:
|
||||
```python
|
||||
app.config['SECRET_KEY'] = 'your-secure-secret-key'
|
||||
```
|
||||
Install Node.js, GoFSH, and SUSHI (for FSH Converter):
|
||||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo bash -
|
||||
sudo apt-get install -y nodejs
|
||||
npm install -g gofsh fsh-sushi
|
||||
|
||||
## Testing
|
||||
Set Environment Variables:
|
||||
export FLASK_SECRET_KEY='your-secure-secret-key'
|
||||
export API_KEY='your-api-key'
|
||||
|
||||
The project includes a test suite to ensure reliability, covering UI, API, database, file operations, and security features.
|
||||
Initialize Directories:
|
||||
mkdir -p instance static/uploads logs
|
||||
chmod -R 777 instance static/uploads logs
|
||||
|
||||
### Test Prerequisites
|
||||
Run the Application:
|
||||
export FLASK_APP=app.py
|
||||
flask run
|
||||
|
||||
- **pytest**: For running tests.
|
||||
- **unittest-mock**: For mocking dependencies.
|
||||
Access at http://localhost:5000.
|
||||
Usage
|
||||
Import an IG
|
||||
|
||||
Install test dependencies:
|
||||
```bash
|
||||
Navigate to Import IG (/import-ig).
|
||||
Enter a package name (e.g., hl7.fhir.au.core) and version (e.g., 1.1.0-preview).
|
||||
Choose a dependency mode:
|
||||
Recursive: Import all dependencies.
|
||||
Patch Canonical: Import only canonical FHIR packages.
|
||||
Tree Shaking: Import only used dependencies.
|
||||
|
||||
|
||||
Click Import to download the package and dependencies.
|
||||
|
||||
Manage IGs
|
||||
|
||||
Go to Manage FHIR Packages (/view-igs) to view downloaded and processed IGs.
|
||||
Actions:
|
||||
Process: Extract metadata (resource types, profiles, must-support elements, examples).
|
||||
Unload: Remove processed IG data from the database.
|
||||
Delete: Remove package files from the filesystem.
|
||||
|
||||
|
||||
Duplicates are highlighted for resolution.
|
||||
|
||||
View Processed IGs
|
||||
|
||||
After processing, view IG details (/view-ig/<id>), including:
|
||||
Resource types and profiles.
|
||||
Must-support elements and examples.
|
||||
Profile relationships (compliesWithProfile, imposeProfile) if enabled (DISPLAY_PROFILE_RELATIONSHIPS).
|
||||
|
||||
|
||||
|
||||
Validate FHIR Resources/Bundles
|
||||
|
||||
Navigate to Validate FHIR Sample (/validate-sample).
|
||||
Select a package (e.g., hl7.fhir.au.core#1.1.0-preview).
|
||||
Choose Single Resource or Bundle mode.
|
||||
Paste or upload FHIR JSON/XML (e.g., a Patient resource).
|
||||
Submit to view validation errors/warnings.
|
||||
Note: Alpha feature; report issues to GitHub (remove PHI).
|
||||
|
||||
Push IGs to a FHIR Server
|
||||
|
||||
Go to Push IGs (/push-igs).
|
||||
Select a package, enter a FHIR server URL (e.g., http://localhost:8080/fhir), and choose whether to include dependencies.
|
||||
Click Push to FHIR Server to upload resources, with validation against imposed profiles (if enabled via VALIDATE_IMPOSED_PROFILES).
|
||||
Monitor progress in the live console.
|
||||
|
||||
Convert FHIR to FSH
|
||||
|
||||
Navigate to FSH Converter (/fsh-converter).
|
||||
Optionally select a package for context (e.g., hl7.fhir.au.core#1.1.0-preview).
|
||||
Choose input mode:
|
||||
Upload File: Upload a FHIR JSON/XML file.
|
||||
Paste Text: Paste FHIR JSON/XML content.
|
||||
|
||||
|
||||
Configure options:
|
||||
Output Style: file-per-definition, group-by-fsh-type, group-by-profile, single-file.
|
||||
Log Level: error, warn, info, debug.
|
||||
FHIR Version: R4, R4B, R5, or auto-detect.
|
||||
Fishing Trip: Enable round-trip validation with SUSHI, generating a comparison report.
|
||||
Dependencies: Specify additional packages (e.g., hl7.fhir.us.core@6.1.0, one per line).
|
||||
Indent Rules: Enable context path indentation for readable FSH.
|
||||
Meta Profile: Choose only-one, first, or none for meta.profile handling.
|
||||
Alias File: Upload an FSH file with aliases (e.g., $MyAlias = http://example.org).
|
||||
No Alias: Disable automatic alias generation.
|
||||
|
||||
|
||||
Click Convert to FSH to generate and display FSH output, with a waiting spinner (light/dark theme) during processing.
|
||||
If Fishing Trip is enabled, view the comparison report via the "Click here for SUSHI Validation" badge button.
|
||||
Download the result as a .fsh file.
|
||||
|
||||
Example Input:
|
||||
{
|
||||
"resourceType": "Patient",
|
||||
"id": "banks-mia-leanne",
|
||||
"meta": {
|
||||
"profile": ["http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient"]
|
||||
},
|
||||
"name": [
|
||||
{
|
||||
"family": "Banks",
|
||||
"given": ["Mia", "Leanne"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Example Output:
|
||||
Profile: AUCorePatient
|
||||
Parent: Patient
|
||||
* name 1..*
|
||||
* name.family 1..1
|
||||
* name.given 1..*
|
||||
|
||||
Explore FHIR Operations
|
||||
|
||||
Navigate to FHIR UI Operations (/fhir-ui-operations).
|
||||
Toggle between local HAPI (/fhir) or a custom FHIR server.
|
||||
Click Fetch Metadata to load the server’s CapabilityStatement.
|
||||
Select a resource type (e.g., Patient, Observation) or System to view operations:
|
||||
System operations: GET /metadata, POST /, GET /_history, GET/POST /$diff, POST /$reindex, POST /$expunge, etc.
|
||||
Resource operations: GET Patient/:id, POST Observation/_search, etc.
|
||||
|
||||
|
||||
Use Try it out to input parameters or request bodies, then Execute to view results in JSON, XML, or narrative formats.
|
||||
|
||||
API Usage
|
||||
Import IG
|
||||
curl -X POST http://localhost:5000/api/import-ig \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"package_name": "hl7.fhir.au.core", "version": "1.1.0-preview", "api_key": "your-api-key"}'
|
||||
|
||||
Returns complies_with_profiles, imposed_profiles, and duplicate info.
|
||||
Push IG
|
||||
curl -X POST http://localhost:5000/api/push-ig \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/x-ndjson" \
|
||||
-d '{"package_name": "hl7.fhir.au.core", "version": "1.1.0-preview", "fhir_server_url": "http://localhost:8080/fhir", "include_dependencies": true, "api_key": "your-api-key"}'
|
||||
|
||||
Validates resources against imposed profiles (if enabled).
|
||||
Validate Resource/Bundle
|
||||
Not yet exposed via API; use the UI at /validate-sample.
|
||||
Configuration Options
|
||||
|
||||
VALIDATE_IMPOSED_PROFILES:
|
||||
|
||||
Default: True
|
||||
|
||||
Validates resources against imposed profiles during push.
|
||||
|
||||
Set to False to skip:
|
||||
app.config['VALIDATE_IMPOSED_PROFILES'] = False
|
||||
|
||||
|
||||
|
||||
|
||||
DISPLAY_PROFILE_RELATIONSHIPS:
|
||||
|
||||
Default: True
|
||||
|
||||
Shows compliesWithProfile and imposeProfile in the UI.
|
||||
|
||||
Set to False to hide:
|
||||
app.config['DISPLAY_PROFILE_RELATIONSHIPS'] = False
|
||||
|
||||
|
||||
|
||||
|
||||
FHIR_PACKAGES_DIR:
|
||||
|
||||
Default: /app/instance/fhir_packages
|
||||
Stores .tgz packages and metadata.
|
||||
|
||||
|
||||
UPLOAD_FOLDER:
|
||||
|
||||
Default: /app/static/uploads
|
||||
Stores GoFSH output files and FSH comparison reports.
|
||||
|
||||
|
||||
SECRET_KEY:
|
||||
|
||||
Required for CSRF protection and sessions:
|
||||
app.config['SECRET_KEY'] = 'your-secure-secret-key'
|
||||
|
||||
|
||||
|
||||
|
||||
API_KEY:
|
||||
|
||||
Required for API authentication:
|
||||
app.config['API_KEY'] = 'your-api-key'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Testing
|
||||
The project includes a test suite covering UI, API, database, file operations, and security.
|
||||
Test Prerequisites
|
||||
|
||||
pytest: For running tests.
|
||||
pytest-mock: For mocking dependencies.
|
||||
|
||||
Install:
|
||||
pip install pytest pytest-mock
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
Running Tests
|
||||
cd <project folder>
|
||||
pytest tests/test_app.py -v
|
||||
|
||||
1. **Navigate to Project Root**:
|
||||
```bash
|
||||
cd /path/to/fhirflare-ig-toolkit
|
||||
```
|
||||
Test Coverage
|
||||
|
||||
2. **Run Tests**:
|
||||
```bash
|
||||
pytest tests/test_app.py -v
|
||||
```
|
||||
- `-v` provides verbose output.
|
||||
- Tests are in `tests/test_app.py`, covering 27 cases.
|
||||
UI Pages: Homepage, Import IG, Manage IGs, Push IGs, Validate Sample, View Processed IG, FSH Converter.
|
||||
API Endpoints: POST /api/import-ig, POST /api/push-ig, GET /get-structure, GET /get-example.
|
||||
Database: IG processing, unloading, viewing.
|
||||
File Operations: Package processing, deletion, FSH output.
|
||||
Security: CSRF protection, flash messages, secret key.
|
||||
FSH Converter: Form submission, file/text input, GoFSH execution, Fishing Trip comparison.
|
||||
|
||||
### Test Coverage
|
||||
|
||||
Tests include:
|
||||
- **UI Pages**:
|
||||
- Homepage, Import IG, Manage IGs, Push IGs, Validate Sample, View Processed IG.
|
||||
- Form rendering, submissions, and error handling (e.g., invalid JSON, CSRF).
|
||||
- **API Endpoints**:
|
||||
- `POST /api/import-ig`: Success, invalid key, duplicates, profile relationships.
|
||||
- `POST /api/push-ig`: Success, validation, errors.
|
||||
- `GET /get-structure`, `GET /get-example`: Success and failure cases.
|
||||
- **Database**:
|
||||
- Processing, unloading, and viewing IGs.
|
||||
- **File Operations**:
|
||||
- Package processing, deletion.
|
||||
- **Security**:
|
||||
- CSRF protection, flash messages, secret key.
|
||||
|
||||
### Example Test Output
|
||||
|
||||
```
|
||||
Example Test Output
|
||||
================================================================ test session starts =================================================================
|
||||
platform linux -- Python 3.9.22, pytest-8.3.5, pluggy-1.5.0
|
||||
platform linux -- Python 3.12, pytest-8.3.5, pluggy-1.5.0
|
||||
rootdir: /app/tests
|
||||
collected 27 items
|
||||
|
||||
test_app.py::TestFHIRFlareIGToolkit::test_homepage PASSED [ 3%]
|
||||
test_app.py::TestFHIRFlareIGToolkit::test_import_ig_page PASSED [ 7%]
|
||||
test_app.py::TestFHIRFlareIGToolkit::test_fsh_converter_page PASSED [ 11%]
|
||||
...
|
||||
test_app.py::TestFHIRFlareIGToolkit::test_validate_sample_page PASSED [ 85%]
|
||||
test_app.py::TestFHIRFlareIGToolkit::test_validate_sample_success PASSED [ 88%]
|
||||
...
|
||||
============================================================= 27 passed in 1.23s ==============================================================
|
||||
```
|
||||
|
||||
### Troubleshooting Tests
|
||||
Troubleshooting Tests
|
||||
|
||||
- **ModuleNotFoundError**: Ensure `app.py`, `services.py`, and `forms.py` are in `/app/`. Run tests from the project root.
|
||||
- **TemplateNotFound**: Verify templates (`validate_sample.html`, etc.) are in `/app/templates/`.
|
||||
- **Database Errors**: Ensure `instance/fhir_ig.db` is writable (`chmod 777 instance`).
|
||||
- **Mock Failures**: Check `tests/test_app.py` for correct mocking of `services.py` functions.
|
||||
ModuleNotFoundError: Ensure app.py, services.py, forms.py are in /app/.
|
||||
TemplateNotFound: Verify templates are in /app/templates/.
|
||||
Database Errors: Ensure instance/fhir_ig.db is writable (chmod 777 instance).
|
||||
Mock Failures: Check tests/test_app.py for correct mocking.
|
||||
|
||||
## Development Notes
|
||||
Development Notes
|
||||
Background
|
||||
The toolkit addresses the need for a comprehensive FHIR IG management tool, with recent enhancements for resource validation, FSH conversion with advanced GoFSH features, and flexible versioning, making it a versatile platform for FHIR developers.
|
||||
Technical Decisions
|
||||
|
||||
### Background
|
||||
Flask: Lightweight and flexible for web development.
|
||||
SQLite: Simple for development; consider PostgreSQL for production.
|
||||
Bootstrap 5.3.3: Responsive UI with custom styling for duplicates, FSH output, and waiting spinner.
|
||||
Lottie-Web: Renders themed animations for FSH conversion waiting spinner.
|
||||
GoFSH/SUSHI: Integrated via Node.js for advanced FSH conversion and round-trip validation.
|
||||
Docker: Ensures consistent deployment with Flask and HAPI FHIR.
|
||||
Flexible Versioning: Supports non-standard IG versions (e.g., -preview, -ballot).
|
||||
Live Console: Real-time feedback for complex operations.
|
||||
Validation: Alpha feature with ongoing FHIRPath improvements.
|
||||
|
||||
The toolkit addresses the need for a user-friendly FHIR IG management tool, with recent enhancements for resource validation and flexible version handling (e.g., `1.1.0-preview`).
|
||||
Recent Updates
|
||||
|
||||
### Technical Decisions
|
||||
Waiting Spinner for FSH Converter (April 2025):
|
||||
Added a themed (light/dark) Lottie animation spinner during FSH execution to indicate processing.
|
||||
Path: templates/fsh_converter.html, static/animations/loading-dark.json, static/animations/loading-light.json, static/js/lottie-web.min.js.
|
||||
|
||||
- **Flask**: Lightweight and flexible for web development.
|
||||
- **SQLite**: Simple for development; consider PostgreSQL for production.
|
||||
- **Bootstrap 5**: Responsive UI with custom CSS for duplicate highlighting.
|
||||
- **Flask-WTF**: Robust form validation and CSRF protection.
|
||||
- **Docker**: Ensures consistent deployment.
|
||||
- **Flexible Versioning**: Supports non-standard version formats for FHIR IGs (e.g., `-preview`, `-ballot`).
|
||||
- **Validation**: Alpha feature for validating FHIR resources/bundles, with ongoing improvements to FHIRPath handling.
|
||||
|
||||
### Recent Updates
|
||||
Advanced FSH Converter (April 2025):
|
||||
Added support for GoFSH advanced options: --fshing-trip (round-trip validation with SUSHI), --dependency (additional packages), --indent (indented rules), --meta-profile (only-one, first, none), --alias-file (custom aliases), --no-alias (disable alias generation).
|
||||
Displays Fishing Trip comparison reports via a badge button.
|
||||
Path: templates/fsh_converter.html, app.py, services.py, forms.py.
|
||||
|
||||
- **Version Format Support**: Added support for flexible IG version formats (e.g., `1.1.0-preview`, `1.1.2-ballot`, `current`) in `forms.py`.
|
||||
- **CSRF Protection**: Fixed missing CSRF tokens in `cp_downloaded_igs.html` and `cp_push_igs.html`, ensuring secure form submissions.
|
||||
- **Form Handling**: Updated `validate_sample.html` and `app.py` to use `version` instead of `package_version`, aligning with `ValidationForm`.
|
||||
- **Validation Feature**: Added alpha support for validating FHIR resources/bundles against IGs, with error/warning reports (UI only).
|
||||
|
||||
### Known Issues and Workarounds
|
||||
FSH Converter (April 2025):
|
||||
Added /fsh-converter page for FHIR to FSH conversion using GoFSH.
|
||||
Path: templates/fsh_converter.html, app.py, services.py, forms.py.
|
||||
|
||||
- **CSRF Errors**: Ensure `SECRET_KEY` is set and forms include `{{ form.csrf_token }}`. Check logs for `flask_wtf.csrf` errors.
|
||||
- **Version Validation**: Previously restricted to `x.y.z`; now supports suffixes like `-preview`. Report any import issues.
|
||||
- **Validation Accuracy**: Resource validation is alpha; FHIRPath logic may miss complex constraints. Report anomalies to GitHub (remove PHI).
|
||||
- **Package Parsing**: Non-standard `.tgz` filenames may parse incorrectly. Fallback treats them as name-only packages.
|
||||
- **Permissions**: Ensure `instance` directory is writable (`chmod -R 777 instance`) to avoid database or file errors.
|
||||
|
||||
### Future Improvements
|
||||
Favicon Fix (April 2025):
|
||||
Resolved 404 for /favicon.ico on /fsh-converter by ensuring static/favicon.ico is served.
|
||||
Added fallback /favicon.ico route in app.py.
|
||||
|
||||
- [ ] **Sorting Versions**: Sort package versions in `/view-igs` (e.g., ascending).
|
||||
- [ ] **Duplicate Resolution**: Add options to keep latest version or merge resources.
|
||||
- [ ] **Production Database**: Support PostgreSQL for scalability.
|
||||
- [ ] **Validation Enhancements**: Improve FHIRPath handling for complex constraints; add API endpoint for validation.
|
||||
- [ ] **Error Reporting**: Enhance UI feedback for validation errors with specific element paths.
|
||||
|
||||
**Completed Items**:
|
||||
- ~~Testing: Comprehensive test suite for UI, API, and database.~~
|
||||
- ~~Inbound API: `POST /api/import-ig` with dependency and profile support.~~
|
||||
- ~~Outbound API: `POST /api/push-ig` with validation and feedback.~~
|
||||
- ~~Flexible Versioning: Support for `-preview`, `-ballot`, etc.~~
|
||||
- ~~CSRF Fixes: Secured forms in `cp_downloaded_igs.html`, `cp_push_igs.html`.~~
|
||||
- ~~Resource Validation: UI for validating resources/bundles (alpha).~~
|
||||
Menu Item (April 2025):
|
||||
Added “FSH Converter” to the navbar in base.html.
|
||||
|
||||
### Far-Distant Improvements
|
||||
|
||||
- **Cache Service**: Use Redis to cache IG metadata for faster queries.
|
||||
- **Database Optimization**: Add composite index on `ProcessedIg.package_name` and `ProcessedIg.version` for efficient lookups.
|
||||
UPLOAD_FOLDER Fix (April 2025):
|
||||
Fixed 500 error on /fsh-converter by setting app.config['UPLOAD_FOLDER'] = '/app/static/uploads'.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
- `app.py`: Main Flask application.
|
||||
- `services.py`: Logic for IG import, processing, validation, and pushing.
|
||||
- `forms.py`: Form definitions for import and validation.
|
||||
- `templates/`: HTML templates (`validate_sample.html`, `cp_downloaded_igs.html`, etc.).
|
||||
- `instance/`: SQLite database (`fhir_ig.db`) and packages (`fhir_packages/`).
|
||||
- `tests/test_app.py`: Test suite with 27 cases.
|
||||
- `requirements.txt`: Python dependencies.
|
||||
- `Dockerfile`: Docker configuration.
|
||||
Validation (April 2025):
|
||||
Alpha support for validating resources/bundles in /validate-sample.
|
||||
Path: templates/validate_sample.html, app.py, services.py.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! To contribute:
|
||||
1. Fork the repository.
|
||||
2. Create a feature branch (`git checkout -b feature/your-feature`).
|
||||
3. Commit changes (`git commit -m "Add your feature"`).
|
||||
4. Push to your branch (`git push origin feature/your-feature`).
|
||||
5. Open a Pull Request.
|
||||
CSRF Protection: Fixed missing CSRF tokens in cp_downloaded_igs.html, cp_push_igs.html.
|
||||
Version Support: Added flexible version formats (e.g., 1.1.0-preview) in forms.py.
|
||||
|
||||
Ensure code follows style guidelines and includes tests.
|
||||
Known Issues and Workarounds
|
||||
|
||||
## Troubleshooting
|
||||
Favicon 404: Clear browser cache or verify /app/static/favicon.ico:
|
||||
docker exec -it <container_name> curl http://localhost:5000/static/favicon.ico
|
||||
|
||||
- **CSRF Errors**: Verify `SECRET_KEY` is set and forms include `{{ form.csrf_token }}`. Check browser DevTools for POST data.
|
||||
- **Import Fails**: Confirm package name/version (e.g., `hl7.fhir.au.core#1.1.0-preview`) and internet connectivity.
|
||||
- **Validation Errors**: Alpha feature; report issues to GitHub with JSON samples (remove PHI).
|
||||
- **Database Issues**: Ensure `instance/fhir_ig.db` is writable (`chmod 777 instance`).
|
||||
- **Docker Volume**: Mount `instance` directory to persist data:
|
||||
```bash
|
||||
docker run -v $(pwd)/instance:/app/instance ...
|
||||
```
|
||||
|
||||
## License
|
||||
CSRF Errors: Set FLASK_SECRET_KEY and ensure {{ form.hidden_tag() }} in forms.
|
||||
|
||||
Licensed under the Apache 2.0 License. See `LICENSE` for details.
|
||||
Import Fails: Check package name/version and connectivity.
|
||||
|
||||
Validation Accuracy: Alpha feature; FHIRPath may miss complex constraints. Report issues to GitHub (remove PHI).
|
||||
|
||||
Package Parsing: Non-standard .tgz filenames may parse incorrectly. Fallback uses name-only parsing.
|
||||
|
||||
Permissions: Ensure instance/ and static/uploads/ are writable:
|
||||
chmod -R 777 instance static/uploads logs
|
||||
|
||||
|
||||
GoFSH/SUSHI Errors: Check ./logs/flask_err.log for ERROR:services:GoFSH failed. Ensure valid FHIR inputs and SUSHI installation:
|
||||
docker exec -it <container_name> sushi --version
|
||||
|
||||
|
||||
|
||||
Future Improvements
|
||||
|
||||
Validation: Enhance FHIRPath for complex constraints; add API endpoint.
|
||||
Sorting: Sort IG versions in /view-igs (e.g., ascending).
|
||||
Duplicate Resolution: Options to keep latest version or merge resources.
|
||||
Production Database: Support PostgreSQL.
|
||||
Error Reporting: Detailed validation error paths in the UI.
|
||||
FSH Enhancements: Add API endpoint for FSH conversion; support inline instance construction.
|
||||
FHIR Operations: Add complex parameter support (e.g., /$diff with left/right).
|
||||
Spinner Enhancements: Customize spinner animation speed or size.
|
||||
|
||||
Completed Items
|
||||
|
||||
Testing suite with 27 cases.
|
||||
API endpoints for POST /api/import-ig and POST /api/push-ig.
|
||||
Flexible versioning (-preview, -ballot).
|
||||
CSRF fixes for forms.
|
||||
Resource validation UI (alpha).
|
||||
FSH Converter with advanced GoFSH features and waiting spinner.
|
||||
|
||||
Far-Distant Improvements
|
||||
|
||||
Cache Service: Use Redis for IG metadata caching.
|
||||
Database Optimization: Composite index on ProcessedIg.package_name and ProcessedIg.version.
|
||||
|
||||
Directory Structure
|
||||
FHIRFLARE-IG-Toolkit/
|
||||
├── app.py # Main Flask application
|
||||
├── Build and Run for first time.bat # Windows script for first-time Docker setup
|
||||
├── docker-compose.yml # Docker Compose configuration
|
||||
├── Dockerfile # Docker configuration
|
||||
├── forms.py # Form definitions
|
||||
├── LICENSE.md # Apache 2.0 License
|
||||
├── README.md # Project documentation
|
||||
├── requirements.txt # Python dependencies
|
||||
├── Run.bat # Windows script for running Docker
|
||||
├── services.py # Logic for IG import, processing, validation, pushing, and FSH conversion
|
||||
├── supervisord.conf # Supervisor configuration
|
||||
├── hapi-fhir-Setup/
|
||||
│ ├── README.md # HAPI FHIR setup instructions
|
||||
│ └── target/
|
||||
│ └── classes/
|
||||
│ └── application.yaml # HAPI FHIR configuration
|
||||
├── instance/
|
||||
│ ├── fhir_ig.db # SQLite database
|
||||
│ ├── fhir_ig.db.old # Database backup
|
||||
│ └── fhir_packages/ # Stored IG packages and metadata
|
||||
│ ├── hl7.fhir.au.base-5.1.0-preview.metadata.json
|
||||
│ ├── hl7.fhir.au.base-5.1.0-preview.tgz
|
||||
│ ├── hl7.fhir.au.core-1.1.0-preview.metadata.json
|
||||
│ ├── hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
│ ├── hl7.fhir.r4.core-4.0.1.metadata.json
|
||||
│ ├── hl7.fhir.r4.core-4.0.1.tgz
|
||||
│ ├── hl7.fhir.uv.extensions.r4-5.2.0.metadata.json
|
||||
│ ├── hl7.fhir.uv.extensions.r4-5.2.0.tgz
|
||||
│ ├── hl7.fhir.uv.ipa-1.0.0.metadata.json
|
||||
│ ├── hl7.fhir.uv.ipa-1.0.0.tgz
|
||||
│ ├── hl7.fhir.uv.smart-app-launch-2.0.0.metadata.json
|
||||
│ ├── hl7.fhir.uv.smart-app-launch-2.0.0.tgz
|
||||
│ ├── hl7.fhir.uv.smart-app-launch-2.1.0.metadata.json
|
||||
│ ├── hl7.fhir.uv.smart-app-launch-2.1.0.tgz
|
||||
│ ├── hl7.terminology.r4-5.0.0.metadata.json
|
||||
│ ├── hl7.terminology.r4-5.0.0.tgz
|
||||
│ ├── hl7.terminology.r4-6.2.0.metadata.json
|
||||
│ └── hl7.terminology.r4-6.2.0.tgz
|
||||
├── logs/
|
||||
│ ├── flask.log # Flask application logs
|
||||
│ ├── flask_err.log # Flask error logs
|
||||
│ ├── supervisord.log # Supervisor logs
|
||||
│ ├── supervisord.pid # Supervisor PID file
|
||||
│ ├── tomcat.log # Tomcat logs for HAPI FHIR
|
||||
│ └── tomcat_err.log # Tomcat error logs
|
||||
├── static/
|
||||
│ ├── animations/
|
||||
│ │ ├── loading-dark.json # Dark theme spinner animation
|
||||
│ │ └── loading-light.json # Light theme spinner animation
|
||||
│ ├── favicon.ico # Application favicon
|
||||
│ ├── FHIRFLARE.png # Application logo
|
||||
│ ├── js/
|
||||
│ │ └── lottie-web.min.js # Lottie library for spinner
|
||||
│ └── uploads/
|
||||
│ ├── output.fsh # Generated FSH output
|
||||
│ └── fsh_output/
|
||||
│ ├── sushi-config.yaml # SUSHI configuration
|
||||
│ └── input/
|
||||
│ └── fsh/
|
||||
│ ├── aliases.fsh # FSH aliases
|
||||
│ ├── index.txt # FSH index
|
||||
│ └── instances/
|
||||
│ └── banks-mia-leanne.fsh # Example FSH instance
|
||||
├── templates/
|
||||
│ ├── base.html # Base template
|
||||
│ ├── cp_downloaded_igs.html # UI for managing IGs
|
||||
│ ├── cp_push_igs.html # UI for pushing IGs
|
||||
│ ├── cp_view_processed_ig.html # UI for viewing processed IGs
|
||||
│ ├── fhir_ui.html # UI for FHIR API explorer
|
||||
│ ├── fhir_ui_operations.html # UI for FHIR server operations
|
||||
│ ├── fsh_converter.html # UI for FSH conversion
|
||||
│ ├── import_ig.html # UI for importing IGs
|
||||
│ ├── index.html # Homepage
|
||||
│ ├── validate_sample.html # UI for validating resources/bundles
|
||||
│ └── _form_helpers.html # Form helper macros
|
||||
├── tests/
|
||||
│ └── test_app.py # Test suite with 27 cases
|
||||
└── hapi-fhir-jpaserver/ # HAPI FHIR server resources
|
||||
|
||||
Contributing
|
||||
|
||||
Fork the repository.
|
||||
Create a feature branch (git checkout -b feature/your-feature).
|
||||
Commit changes (git commit -m "Add your feature").
|
||||
Push to your branch (git push origin feature/your-feature).
|
||||
Open a Pull Request.
|
||||
|
||||
Ensure code follows PEP 8 and includes tests in tests/test_app.py.
|
||||
Troubleshooting
|
||||
|
||||
Favicon 404: Clear browser cache or verify /app/static/favicon.ico:
|
||||
docker exec -it <container_name> curl http://localhost:5000/static/favicon.ico
|
||||
|
||||
|
||||
CSRF Errors: Set FLASK_SECRET_KEY and ensure {{ form.hidden_tag() }} in forms.
|
||||
|
||||
Import Fails: Check package name/version and connectivity.
|
||||
|
||||
Validation Accuracy: Alpha feature; report issues to GitHub (remove PHI).
|
||||
|
||||
Package Parsing: Non-standard .tgz filenamesgrass may parse incorrectly. Fallback uses name-only parsing.
|
||||
|
||||
Permissions: Ensure instance/ and static/uploads/ are writable:
|
||||
chmod -R 777 instance static/uploads logs
|
||||
|
||||
|
||||
GoFSH/SUSHI Errors: Check ./logs/flask_err.log for ERROR:services:GoFSH failed. Ensure valid FHIR inputs and SUSHI installation:
|
||||
docker exec -it <container_name> sushi --version
|
||||
|
||||
|
||||
|
||||
License
|
||||
Licensed under the Apache 2.0 License. See LICENSE.md for details.
|
||||
|
214
app.py
214
app.py
@ -2,7 +2,8 @@ import sys
|
||||
import os
|
||||
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
|
||||
import datetime
|
||||
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, Response, current_app, session, send_file
|
||||
import shutil
|
||||
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, Response, current_app, session, send_file, make_response
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
@ -943,70 +944,168 @@ def proxy_hapi(subpath):
|
||||
logger.error(f"Proxy error: {str(e)}")
|
||||
return jsonify({'error': str(e)}), response.status_code if 'response' in locals() else 500
|
||||
|
||||
# Assuming 'app' and 'logger' are defined, and other necessary imports are present above
|
||||
|
||||
@app.route('/fsh-converter', methods=['GET', 'POST'])
|
||||
def fsh_converter():
|
||||
form = FSHConverterForm()
|
||||
error = None
|
||||
fsh_output = None
|
||||
|
||||
# Populate package choices
|
||||
error = None
|
||||
comparison_report = None
|
||||
|
||||
# --- Populate package choices ---
|
||||
packages = []
|
||||
packages_dir = app.config['FHIR_PACKAGES_DIR']
|
||||
packages_dir = app.config.get('FHIR_PACKAGES_DIR', '/app/instance/fhir_packages') # Use .get with default
|
||||
logger.debug(f"Scanning packages directory: {packages_dir}")
|
||||
if os.path.exists(packages_dir):
|
||||
for filename in os.listdir(packages_dir):
|
||||
if filename.endswith('.tgz'):
|
||||
try:
|
||||
with tarfile.open(os.path.join(packages_dir, filename), 'r:gz') as tar:
|
||||
package_json = tar.extractfile('package/package.json')
|
||||
if package_json:
|
||||
pkg_info = json.load(package_json)
|
||||
name = pkg_info.get('name')
|
||||
version = pkg_info.get('version')
|
||||
if name and version:
|
||||
packages.append((f"{name}#{version}", f"{name}#{version}"))
|
||||
except Exception as e:
|
||||
logger.warning(f"Error reading package {filename}: {e}")
|
||||
continue
|
||||
form.package.choices = [('', 'None')] + sorted(packages, key=lambda x: x[0])
|
||||
|
||||
if form.validate_on_submit():
|
||||
tgz_files = [f for f in os.listdir(packages_dir) if f.endswith('.tgz')]
|
||||
logger.debug(f"Found {len(tgz_files)} .tgz files: {tgz_files}")
|
||||
for filename in tgz_files:
|
||||
package_file_path = os.path.join(packages_dir, filename)
|
||||
try:
|
||||
# Check if it's a valid tar.gz file before opening
|
||||
if not tarfile.is_tarfile(package_file_path):
|
||||
logger.warning(f"Skipping non-tarfile or corrupted file: {filename}")
|
||||
continue
|
||||
|
||||
with tarfile.open(package_file_path, 'r:gz') as tar:
|
||||
# Find package.json case-insensitively and handle potential path variations
|
||||
package_json_path = next((m for m in tar.getmembers() if m.name.lower().endswith('package.json') and m.isfile() and ('/' not in m.name.replace('package/','', 1).lower())), None) # Handle package/ prefix better
|
||||
|
||||
if package_json_path:
|
||||
package_json_stream = tar.extractfile(package_json_path)
|
||||
if package_json_stream:
|
||||
try:
|
||||
pkg_info = json.load(package_json_stream)
|
||||
name = pkg_info.get('name')
|
||||
version = pkg_info.get('version')
|
||||
if name and version:
|
||||
package_id = f"{name}#{version}"
|
||||
packages.append((package_id, package_id))
|
||||
logger.debug(f"Added package: {package_id}")
|
||||
else:
|
||||
logger.warning(f"Missing name or version in {filename}/package.json: name={name}, version={version}")
|
||||
except json.JSONDecodeError as json_e:
|
||||
logger.warning(f"Error decoding package.json from {filename}: {json_e}")
|
||||
except Exception as read_e:
|
||||
logger.warning(f"Error reading stream from package.json in {filename}: {read_e}")
|
||||
finally:
|
||||
package_json_stream.close() # Ensure stream is closed
|
||||
else:
|
||||
logger.warning(f"Could not extract package.json stream from {filename} (path: {package_json_path.name})")
|
||||
else:
|
||||
logger.warning(f"No suitable package.json found in {filename}")
|
||||
except tarfile.ReadError as tar_e:
|
||||
logger.warning(f"Tarfile read error for {filename}: {tar_e}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error processing package {filename}: {str(e)}")
|
||||
continue # Continue to next file
|
||||
else:
|
||||
logger.warning(f"Packages directory does not exist: {packages_dir}")
|
||||
|
||||
unique_packages = sorted(list(set(packages)), key=lambda x: x[0])
|
||||
form.package.choices = [('', 'None')] + unique_packages
|
||||
logger.debug(f"Set package choices: {form.package.choices}")
|
||||
# --- End package choices ---
|
||||
|
||||
if form.validate_on_submit(): # This block handles POST requests
|
||||
input_mode = form.input_mode.data
|
||||
fhir_file = form.fhir_file.data
|
||||
# Use request.files.get to safely access file data
|
||||
fhir_file_storage = request.files.get(form.fhir_file.name)
|
||||
fhir_file = fhir_file_storage if fhir_file_storage and fhir_file_storage.filename != '' else None
|
||||
|
||||
fhir_text = form.fhir_text.data
|
||||
|
||||
alias_file_storage = request.files.get(form.alias_file.name)
|
||||
alias_file = alias_file_storage if alias_file_storage and alias_file_storage.filename != '' else None
|
||||
|
||||
output_style = form.output_style.data
|
||||
log_level = form.log_level.data
|
||||
fhir_version = form.fhir_version.data or None
|
||||
|
||||
# Process input
|
||||
input_path, temp_dir, error = services.process_fhir_input(input_mode, fhir_file, fhir_text)
|
||||
if error:
|
||||
fhir_version = form.fhir_version.data if form.fhir_version.data != 'auto' else None
|
||||
fishing_trip = form.fishing_trip.data
|
||||
dependencies = [dep.strip() for dep in form.dependencies.data.splitlines() if dep.strip()] if form.dependencies.data else None # Use splitlines()
|
||||
indent_rules = form.indent_rules.data
|
||||
meta_profile = form.meta_profile.data
|
||||
no_alias = form.no_alias.data
|
||||
|
||||
logger.debug(f"Processing input: mode={input_mode}, has_file={bool(fhir_file)}, has_text={bool(fhir_text)}, has_alias={bool(alias_file)}")
|
||||
# Pass the FileStorage object directly if needed by process_fhir_input
|
||||
input_file, temp_dir, alias_path, input_error = services.process_fhir_input(input_mode, fhir_file, fhir_text, alias_file)
|
||||
|
||||
if input_error:
|
||||
error = input_error
|
||||
flash(error, 'error')
|
||||
return render_template('fsh_converter.html', form=form, error=error, site_name='FHIRFLARE IG Toolkit', now=datetime.datetime.now())
|
||||
|
||||
# Run GoFSH
|
||||
output_dir = os.path.join(app.config['UPLOAD_FOLDER'], 'fsh_output')
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
fsh_output, error = services.run_gofsh(input_path, output_dir, output_style, log_level, fhir_version)
|
||||
|
||||
# Clean up temporary files
|
||||
if temp_dir and os.path.exists(temp_dir):
|
||||
import shutil
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
if error:
|
||||
flash(error, 'error')
|
||||
return render_template('fsh_converter.html', form=form, error=error, site_name='FHIRFLARE IG Toolkit', now=datetime.datetime.now())
|
||||
|
||||
# Store output for download
|
||||
session['fsh_output'] = fsh_output
|
||||
flash('Conversion successful!', 'success')
|
||||
return render_template('fsh_converter.html', form=form, fsh_output=fsh_output, site_name='FHIRFLARE IG Toolkit', now=datetime.datetime.now())
|
||||
|
||||
return render_template('fsh_converter.html', form=form, error=error, site_name='FHIRFLARE IG Toolkit', now=datetime.datetime.now())
|
||||
logger.error(f"Input processing error: {error}")
|
||||
if temp_dir and os.path.exists(temp_dir):
|
||||
try: shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
except Exception as cleanup_e: logger.warning(f"Error removing temp dir after input error {temp_dir}: {cleanup_e}")
|
||||
else:
|
||||
# Proceed only if input processing was successful
|
||||
output_dir = os.path.join(app.config.get('UPLOAD_FOLDER', '/app/static/uploads'), 'fsh_output') # Use .get
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
logger.debug(f"Running GoFSH with input: {input_file}, output_dir: {output_dir}")
|
||||
# Pass form data directly to run_gofsh
|
||||
fsh_output, comparison_report, gofsh_error = services.run_gofsh(
|
||||
input_file, output_dir, output_style, log_level, fhir_version,
|
||||
fishing_trip, dependencies, indent_rules, meta_profile, alias_path, no_alias
|
||||
)
|
||||
# Clean up temp dir after GoFSH run
|
||||
if temp_dir and os.path.exists(temp_dir):
|
||||
try:
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
logger.debug(f"Successfully removed temp directory: {temp_dir}")
|
||||
except Exception as cleanup_e:
|
||||
logger.warning(f"Error removing temp directory {temp_dir}: {cleanup_e}")
|
||||
|
||||
if gofsh_error:
|
||||
error = gofsh_error
|
||||
flash(error, 'error')
|
||||
logger.error(f"GoFSH error: {error}")
|
||||
else:
|
||||
# Store potentially large output carefully - session might have limits
|
||||
session['fsh_output'] = fsh_output
|
||||
flash('Conversion successful!', 'success')
|
||||
logger.info("FSH conversion successful")
|
||||
|
||||
# Return response for POST (AJAX or full page)
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
logger.debug("Returning partial HTML for AJAX POST request.")
|
||||
return render_template('_fsh_output.html', form=form, error=error, fsh_output=fsh_output, comparison_report=comparison_report)
|
||||
else:
|
||||
# For standard POST, re-render the full page with results/errors
|
||||
logger.debug("Handling standard POST request, rendering full page.")
|
||||
return render_template('fsh_converter.html', form=form, error=error, fsh_output=fsh_output, comparison_report=comparison_report, site_name='FHIRFLARE IG Toolkit', now=datetime.datetime.now())
|
||||
|
||||
# --- Handle GET request (Initial Page Load or Failed POST Validation) ---
|
||||
else:
|
||||
if request.method == 'POST': # POST but validation failed
|
||||
logger.warning("POST request failed form validation.")
|
||||
# Render the full page, WTForms errors will be displayed by render_field
|
||||
return render_template('fsh_converter.html', form=form, error="Form validation failed. Please check fields.", fsh_output=None, comparison_report=None, site_name='FHIRFLARE IG Toolkit', now=datetime.datetime.now())
|
||||
else:
|
||||
# This is the initial GET request
|
||||
logger.debug("Handling GET request for FSH converter page.")
|
||||
# **** FIX APPLIED HERE ****
|
||||
# Make the response object to add headers
|
||||
response = make_response(render_template(
|
||||
'fsh_converter.html',
|
||||
form=form, # Pass the empty form
|
||||
error=None,
|
||||
fsh_output=None,
|
||||
comparison_report=None,
|
||||
site_name='FHIRFLARE IG Toolkit',
|
||||
now=datetime.datetime.now()
|
||||
))
|
||||
# Add headers to prevent caching
|
||||
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
||||
response.headers['Pragma'] = 'no-cache'
|
||||
response.headers['Expires'] = '0'
|
||||
return response
|
||||
# **** END OF FIX ****
|
||||
|
||||
@app.route('/download-fsh')
|
||||
def download_fsh():
|
||||
fsh_output = session.get('fsh_output', '')
|
||||
fsh_output = session.get('fsh_output')
|
||||
if not fsh_output:
|
||||
flash('No FSH output available for download.', 'error')
|
||||
return redirect(url_for('fsh_converter'))
|
||||
@ -1017,6 +1116,19 @@ def download_fsh():
|
||||
|
||||
return send_file(temp_file, as_attachment=True, download_name='output.fsh')
|
||||
|
||||
@app.route('/favicon.ico')
|
||||
def favicon():
|
||||
return send_file(os.path.join(app.static_folder, 'favicon.ico'), mimetype='image/x-icon')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
with app.app_context():
|
||||
logger.debug(f"Instance path configuration: {app.instance_path}")
|
||||
logger.debug(f"Database URI: {app.config['SQLALCHEMY_DATABASE_URI']}")
|
||||
logger.debug(f"Packages path: {app.config['FHIR_PACKAGES_DIR']}")
|
||||
logger.debug(f"Flask instance folder path: {app.instance_path}")
|
||||
logger.debug(f"Directories created/verified: Instance: {app.instance_path}, Packages: {app.config['FHIR_PACKAGES_DIR']}")
|
||||
logger.debug(f"Attempting to create database tables for URI: {app.config['SQLALCHEMY_DATABASE_URI']}")
|
||||
db.create_all()
|
||||
logger.info("Database tables created successfully (if they didn't exist).")
|
||||
app.run(host='0.0.0.0', port=5000, debug=False)
|
26
forms.py
26
forms.py
@ -3,6 +3,8 @@ from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SelectField, TextAreaField, BooleanField, SubmitField, FileField
|
||||
from wtforms.validators import DataRequired, Regexp, ValidationError, Optional
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
import re
|
||||
|
||||
# Existing forms (IgImportForm, ValidationForm) remain unchanged
|
||||
class IgImportForm(FlaskForm):
|
||||
@ -68,12 +70,22 @@ class FSHConverterForm(FlaskForm):
|
||||
('info', 'Info'),
|
||||
('debug', 'Debug')
|
||||
], validators=[DataRequired()])
|
||||
fhir_version = SelectField('FHIR Version', choices=[
|
||||
fhir_version = SelectField('FXML Version', choices=[
|
||||
('', 'Auto-detect'),
|
||||
('4.0.1', 'R4'),
|
||||
('4.3.0', 'R4B'),
|
||||
('5.0.0', 'R5')
|
||||
], validators=[Optional()])
|
||||
fishing_trip = BooleanField('Run Fishing Trip (Round-Trip Validation with SUSHI)', default=False)
|
||||
dependencies = TextAreaField('Dependencies (e.g., hl7.fhir.us.core@6.1.0)', validators=[Optional()])
|
||||
indent_rules = BooleanField('Indent Rules with Context Paths', default=False)
|
||||
meta_profile = SelectField('Meta Profile Handling', choices=[
|
||||
('only-one', 'Only One Profile (Default)'),
|
||||
('first', 'First Profile'),
|
||||
('none', 'Ignore Profiles')
|
||||
], validators=[DataRequired()])
|
||||
alias_file = FileField('Alias FSH File', validators=[Optional()])
|
||||
no_alias = BooleanField('Disable Alias Generation', default=False)
|
||||
submit = SubmitField('Convert to FSH')
|
||||
|
||||
def validate(self, extra_validators=None):
|
||||
@ -91,7 +103,6 @@ class FSHConverterForm(FlaskForm):
|
||||
if content.startswith('{'):
|
||||
json.loads(content)
|
||||
elif content.startswith('<'):
|
||||
import xml.etree.ElementTree as ET
|
||||
ET.fromstring(content)
|
||||
else:
|
||||
self.fhir_text.errors.append('Text input must be valid JSON or XML.')
|
||||
@ -99,4 +110,15 @@ class FSHConverterForm(FlaskForm):
|
||||
except (json.JSONDecodeError, ET.ParseError):
|
||||
self.fhir_text.errors.append('Invalid JSON or XML format.')
|
||||
return False
|
||||
if self.dependencies.data:
|
||||
for dep in self.dependencies.data.split('\n'):
|
||||
dep = dep.strip()
|
||||
if dep and not re.match(r'^[a-zA-Z0-9\-\.]+@[a-zA-Z0-9\.\-]+$', dep):
|
||||
self.dependencies.errors.append(f'Invalid dependency format: {dep}. Use package@version (e.g., hl7.fhir.us.core@6.1.0).')
|
||||
return False
|
||||
if self.alias_file.data:
|
||||
content = self.alias_file.data.read().decode('utf-8')
|
||||
if not content.strip().endswith('.fsh'):
|
||||
self.alias_file.errors.append('Alias file must be a valid FSH file (.fsh).')
|
||||
return False
|
||||
return True
|
@ -2,3 +2,11 @@
|
||||
* Debug mode: off
|
||||
* Serving Flask app 'app'
|
||||
* Debug mode: off
|
||||
* Serving Flask app 'app'
|
||||
* Debug mode: off
|
||||
* Serving Flask app 'app'
|
||||
* Debug mode: off
|
||||
* Serving Flask app 'app'
|
||||
* Debug mode: off
|
||||
* Serving Flask app 'app'
|
||||
* Debug mode: off
|
||||
|
@ -5,129 +5,34 @@ DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
INFO:werkzeug:[31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:5000
|
||||
* Running on http://172.19.0.2:5000
|
||||
* Running on http://172.18.0.2:5000
|
||||
INFO:werkzeug:[33mPress CTRL+C to quit[0m
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:30] "GET /fhir-ui-operations HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:30] "GET /static/FHIRFLARE.png HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:31] "GET /static/favicon.ico HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:36] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:36] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:38:13] "GET / HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:38:14] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:services:Parsed 'hl7.fhir.au.base-5.1.0-preview.tgz' -> name='hl7.fhir.au.base-5.1.0', version='preview'
|
||||
DEBUG:services:Parsed 'hl7.fhir.au.core-1.1.0-preview.tgz' -> name='hl7.fhir.au.core-1.1.0', version='preview'
|
||||
DEBUG:services:Parsed 'hl7.fhir.r4.core-4.0.1.tgz' -> name='hl7.fhir.r4.core', version='4.0.1'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.extensions.r4-5.2.0.tgz' -> name='hl7.fhir.uv.extensions.r4', version='5.2.0'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.ipa-1.0.0.tgz' -> name='hl7.fhir.uv.ipa', version='1.0.0'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz' -> name='hl7.fhir.uv.smart-app-launch', version='2.0.0'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz' -> name='hl7.fhir.uv.smart-app-launch', version='2.1.0'
|
||||
DEBUG:services:Parsed 'hl7.terminology.r4-5.0.0.tgz' -> name='hl7.terminology.r4', version='5.0.0'
|
||||
DEBUG:services:Parsed 'hl7.terminology.r4-6.2.0.tgz' -> name='hl7.terminology.r4', version='6.2.0'
|
||||
DEBUG:__main__:Found packages: [{'name': 'hl7.fhir.au.base', 'version': '5.1.0-preview', 'filename': 'hl7.fhir.au.base-5.1.0-preview.tgz'}, {'name': 'hl7.fhir.au.core', 'version': '1.1.0-preview', 'filename': 'hl7.fhir.au.core-1.1.0-preview.tgz'}, {'name': 'hl7.fhir.r4.core', 'version': '4.0.1', 'filename': 'hl7.fhir.r4.core-4.0.1.tgz'}, {'name': 'hl7.fhir.uv.extensions.r4', 'version': '5.2.0', 'filename': 'hl7.fhir.uv.extensions.r4-5.2.0.tgz'}, {'name': 'hl7.fhir.uv.ipa', 'version': '1.0.0', 'filename': 'hl7.fhir.uv.ipa-1.0.0.tgz'}, {'name': 'hl7.fhir.uv.smart-app-launch', 'version': '2.0.0', 'filename': 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz'}, {'name': 'hl7.fhir.uv.smart-app-launch', 'version': '2.1.0', 'filename': 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz'}, {'name': 'hl7.terminology.r4', 'version': '5.0.0', 'filename': 'hl7.terminology.r4-5.0.0.tgz'}, {'name': 'hl7.terminology.r4', 'version': '6.2.0', 'filename': 'hl7.terminology.r4-6.2.0.tgz'}]
|
||||
DEBUG:__main__:Errors during package listing: []
|
||||
DEBUG:__main__:Duplicate groups: {'hl7.fhir.uv.smart-app-launch': ['2.0.0', '2.1.0'], 'hl7.terminology.r4': ['5.0.0', '6.2.0']}
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:56] "GET /view-igs HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:56] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Viewing IG hl7.fhir.au.core-1.1.0#preview: 25 profiles, 17 base resources, 1 optional elements
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:59] "GET /view-ig/1 HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:25:59] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Attempting to find SD for 'Practitioner' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Searching for SD matching 'Practitioner' with profile 'None' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Found SD: id=au-core-allergyintolerance, name=AUCoreAllergyIntolerance, type=AllergyIntolerance, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-allergyintolerance, path=package/StructureDefinition-au-core-allergyintolerance.json
|
||||
DEBUG:services:Found SD: id=au-core-bloodpressure, name=AUCoreBloodPressure, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bloodpressure, path=package/StructureDefinition-au-core-bloodpressure.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyheight, name=AUCoreBodyHeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyheight, path=package/StructureDefinition-au-core-bodyheight.json
|
||||
DEBUG:services:Found SD: id=au-core-bodytemp, name=AUCoreBodyTemperature, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodytemp, path=package/StructureDefinition-au-core-bodytemp.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyweight, name=AUCoreBodyWeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyweight, path=package/StructureDefinition-au-core-bodyweight.json
|
||||
DEBUG:services:Found SD: id=au-core-condition, name=AUCoreCondition, type=Condition, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-condition, path=package/StructureDefinition-au-core-condition.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult-path, name=AUCorePathologyResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult-path, path=package/StructureDefinition-au-core-diagnosticresult-path.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult, name=AUCoreDiagnosticResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult, path=package/StructureDefinition-au-core-diagnosticresult.json
|
||||
DEBUG:services:Found SD: id=au-core-encounter, name=AUCoreEncounter, type=Encounter, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-encounter, path=package/StructureDefinition-au-core-encounter.json
|
||||
DEBUG:services:Found SD: id=au-core-heartrate, name=AUCoreHeartRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-heartrate, path=package/StructureDefinition-au-core-heartrate.json
|
||||
DEBUG:services:Found SD: id=au-core-immunization, name=AUCoreImmunization, type=Immunization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-immunization, path=package/StructureDefinition-au-core-immunization.json
|
||||
DEBUG:services:Found SD: id=au-core-location, name=AUCoreLocation, type=Location, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-location, path=package/StructureDefinition-au-core-location.json
|
||||
DEBUG:services:Found SD: id=au-core-medication, name=AUCoreMedication, type=Medication, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medication, path=package/StructureDefinition-au-core-medication.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationrequest, name=AUCoreMedicationRequest, type=MedicationRequest, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationrequest, path=package/StructureDefinition-au-core-medicationrequest.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationstatement, name=AUCoreMedicationStatement, type=MedicationStatement, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationstatement, path=package/StructureDefinition-au-core-medicationstatement.json
|
||||
DEBUG:services:Found SD: id=au-core-organization, name=AUCoreOrganization, type=Organization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-organization, path=package/StructureDefinition-au-core-organization.json
|
||||
DEBUG:services:Found SD: id=au-core-patient, name=AUCorePatient, type=Patient, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient, path=package/StructureDefinition-au-core-patient.json
|
||||
DEBUG:services:Found SD: id=au-core-practitioner, name=AUCorePractitioner, type=Practitioner, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitioner, path=package/StructureDefinition-au-core-practitioner.json
|
||||
INFO:services:Found matching SD for 'Practitioner' at path: package/StructureDefinition-au-core-practitioner.json
|
||||
DEBUG:services:Found SD: id=au-core-practitionerrole, name=AUCorePractitionerRole, type=PractitionerRole, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitionerrole, path=package/StructureDefinition-au-core-practitionerrole.json
|
||||
INFO:services:Found matching SD for 'Practitioner' at path: package/StructureDefinition-au-core-practitionerrole.json
|
||||
DEBUG:services:Found SD: id=au-core-procedure, name=AUCoreProcedure, type=Procedure, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-procedure, path=package/StructureDefinition-au-core-procedure.json
|
||||
DEBUG:services:Found SD: id=au-core-relatedperson, name=AUCoreRelatedPerson, type=RelatedPerson, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-relatedperson, path=package/StructureDefinition-au-core-relatedperson.json
|
||||
DEBUG:services:Found SD: id=au-core-resprate, name=AUCoreRespirationRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-resprate, path=package/StructureDefinition-au-core-resprate.json
|
||||
DEBUG:services:Found SD: id=au-core-rsg-sexassignedab, name=AUCoreSexAssignedAtBirth, type=Extension, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-rsg-sexassignedab, path=package/StructureDefinition-au-core-rsg-sexassignedab.json
|
||||
DEBUG:services:Found SD: id=au-core-smokingstatus, name=AUCoreSmokingStatus, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-smokingstatus, path=package/StructureDefinition-au-core-smokingstatus.json
|
||||
DEBUG:services:Found SD: id=au-core-waistcircum, name=AUCoreWaistCircumference, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-waistcircum, path=package/StructureDefinition-au-core-waistcircum.json
|
||||
DEBUG:__main__:Retrieved 0 Must Support paths for 'Practitioner' from processed IG hl7.fhir.au.core-1.1.0#preview
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:26:04] "GET /get-structure?package_name=hl7.fhir.au.core-1.1.0&package_version=preview&resource_type=Practitioner HTTP/1.1" 200 -
|
||||
DEBUG:__main__:Attempting to find SD for 'au-core-practitioner' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Searching for SD matching 'au-core-practitioner' with profile 'None' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Found SD: id=au-core-allergyintolerance, name=AUCoreAllergyIntolerance, type=AllergyIntolerance, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-allergyintolerance, path=package/StructureDefinition-au-core-allergyintolerance.json
|
||||
DEBUG:services:Found SD: id=au-core-bloodpressure, name=AUCoreBloodPressure, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bloodpressure, path=package/StructureDefinition-au-core-bloodpressure.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyheight, name=AUCoreBodyHeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyheight, path=package/StructureDefinition-au-core-bodyheight.json
|
||||
DEBUG:services:Found SD: id=au-core-bodytemp, name=AUCoreBodyTemperature, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodytemp, path=package/StructureDefinition-au-core-bodytemp.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyweight, name=AUCoreBodyWeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyweight, path=package/StructureDefinition-au-core-bodyweight.json
|
||||
DEBUG:services:Found SD: id=au-core-condition, name=AUCoreCondition, type=Condition, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-condition, path=package/StructureDefinition-au-core-condition.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult-path, name=AUCorePathologyResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult-path, path=package/StructureDefinition-au-core-diagnosticresult-path.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult, name=AUCoreDiagnosticResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult, path=package/StructureDefinition-au-core-diagnosticresult.json
|
||||
DEBUG:services:Found SD: id=au-core-encounter, name=AUCoreEncounter, type=Encounter, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-encounter, path=package/StructureDefinition-au-core-encounter.json
|
||||
DEBUG:services:Found SD: id=au-core-heartrate, name=AUCoreHeartRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-heartrate, path=package/StructureDefinition-au-core-heartrate.json
|
||||
DEBUG:services:Found SD: id=au-core-immunization, name=AUCoreImmunization, type=Immunization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-immunization, path=package/StructureDefinition-au-core-immunization.json
|
||||
DEBUG:services:Found SD: id=au-core-location, name=AUCoreLocation, type=Location, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-location, path=package/StructureDefinition-au-core-location.json
|
||||
DEBUG:services:Found SD: id=au-core-medication, name=AUCoreMedication, type=Medication, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medication, path=package/StructureDefinition-au-core-medication.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationrequest, name=AUCoreMedicationRequest, type=MedicationRequest, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationrequest, path=package/StructureDefinition-au-core-medicationrequest.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationstatement, name=AUCoreMedicationStatement, type=MedicationStatement, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationstatement, path=package/StructureDefinition-au-core-medicationstatement.json
|
||||
DEBUG:services:Found SD: id=au-core-organization, name=AUCoreOrganization, type=Organization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-organization, path=package/StructureDefinition-au-core-organization.json
|
||||
DEBUG:services:Found SD: id=au-core-patient, name=AUCorePatient, type=Patient, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient, path=package/StructureDefinition-au-core-patient.json
|
||||
DEBUG:services:Found SD: id=au-core-practitioner, name=AUCorePractitioner, type=Practitioner, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitioner, path=package/StructureDefinition-au-core-practitioner.json
|
||||
INFO:services:Found matching SD for 'au-core-practitioner' at path: package/StructureDefinition-au-core-practitioner.json
|
||||
DEBUG:services:Found SD: id=au-core-practitionerrole, name=AUCorePractitionerRole, type=PractitionerRole, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitionerrole, path=package/StructureDefinition-au-core-practitionerrole.json
|
||||
INFO:services:Found matching SD for 'au-core-practitioner' at path: package/StructureDefinition-au-core-practitionerrole.json
|
||||
DEBUG:services:Found SD: id=au-core-procedure, name=AUCoreProcedure, type=Procedure, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-procedure, path=package/StructureDefinition-au-core-procedure.json
|
||||
DEBUG:services:Found SD: id=au-core-relatedperson, name=AUCoreRelatedPerson, type=RelatedPerson, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-relatedperson, path=package/StructureDefinition-au-core-relatedperson.json
|
||||
DEBUG:services:Found SD: id=au-core-resprate, name=AUCoreRespirationRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-resprate, path=package/StructureDefinition-au-core-resprate.json
|
||||
DEBUG:services:Found SD: id=au-core-rsg-sexassignedab, name=AUCoreSexAssignedAtBirth, type=Extension, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-rsg-sexassignedab, path=package/StructureDefinition-au-core-rsg-sexassignedab.json
|
||||
DEBUG:services:Found SD: id=au-core-smokingstatus, name=AUCoreSmokingStatus, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-smokingstatus, path=package/StructureDefinition-au-core-smokingstatus.json
|
||||
DEBUG:services:Found SD: id=au-core-waistcircum, name=AUCoreWaistCircumference, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-waistcircum, path=package/StructureDefinition-au-core-waistcircum.json
|
||||
DEBUG:__main__:Retrieved 5 Must Support paths for 'au-core-practitioner' from processed IG hl7.fhir.au.core-1.1.0#preview
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:26:15] "GET /get-structure?package_name=hl7.fhir.au.core-1.1.0&package_version=preview&resource_type=au-core-practitioner HTTP/1.1" 200 -
|
||||
DEBUG:__main__:Attempting to find SD for 'au-core-patient' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Searching for SD matching 'au-core-patient' with profile 'None' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Found SD: id=au-core-allergyintolerance, name=AUCoreAllergyIntolerance, type=AllergyIntolerance, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-allergyintolerance, path=package/StructureDefinition-au-core-allergyintolerance.json
|
||||
DEBUG:services:Found SD: id=au-core-bloodpressure, name=AUCoreBloodPressure, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bloodpressure, path=package/StructureDefinition-au-core-bloodpressure.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyheight, name=AUCoreBodyHeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyheight, path=package/StructureDefinition-au-core-bodyheight.json
|
||||
DEBUG:services:Found SD: id=au-core-bodytemp, name=AUCoreBodyTemperature, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodytemp, path=package/StructureDefinition-au-core-bodytemp.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyweight, name=AUCoreBodyWeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyweight, path=package/StructureDefinition-au-core-bodyweight.json
|
||||
DEBUG:services:Found SD: id=au-core-condition, name=AUCoreCondition, type=Condition, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-condition, path=package/StructureDefinition-au-core-condition.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult-path, name=AUCorePathologyResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult-path, path=package/StructureDefinition-au-core-diagnosticresult-path.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult, name=AUCoreDiagnosticResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult, path=package/StructureDefinition-au-core-diagnosticresult.json
|
||||
DEBUG:services:Found SD: id=au-core-encounter, name=AUCoreEncounter, type=Encounter, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-encounter, path=package/StructureDefinition-au-core-encounter.json
|
||||
DEBUG:services:Found SD: id=au-core-heartrate, name=AUCoreHeartRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-heartrate, path=package/StructureDefinition-au-core-heartrate.json
|
||||
DEBUG:services:Found SD: id=au-core-immunization, name=AUCoreImmunization, type=Immunization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-immunization, path=package/StructureDefinition-au-core-immunization.json
|
||||
DEBUG:services:Found SD: id=au-core-location, name=AUCoreLocation, type=Location, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-location, path=package/StructureDefinition-au-core-location.json
|
||||
DEBUG:services:Found SD: id=au-core-medication, name=AUCoreMedication, type=Medication, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medication, path=package/StructureDefinition-au-core-medication.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationrequest, name=AUCoreMedicationRequest, type=MedicationRequest, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationrequest, path=package/StructureDefinition-au-core-medicationrequest.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationstatement, name=AUCoreMedicationStatement, type=MedicationStatement, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationstatement, path=package/StructureDefinition-au-core-medicationstatement.json
|
||||
DEBUG:services:Found SD: id=au-core-organization, name=AUCoreOrganization, type=Organization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-organization, path=package/StructureDefinition-au-core-organization.json
|
||||
DEBUG:services:Found SD: id=au-core-patient, name=AUCorePatient, type=Patient, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient, path=package/StructureDefinition-au-core-patient.json
|
||||
INFO:services:Found matching SD for 'au-core-patient' at path: package/StructureDefinition-au-core-patient.json
|
||||
DEBUG:services:Found SD: id=au-core-practitioner, name=AUCorePractitioner, type=Practitioner, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitioner, path=package/StructureDefinition-au-core-practitioner.json
|
||||
DEBUG:services:Found SD: id=au-core-practitionerrole, name=AUCorePractitionerRole, type=PractitionerRole, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitionerrole, path=package/StructureDefinition-au-core-practitionerrole.json
|
||||
DEBUG:services:Found SD: id=au-core-procedure, name=AUCoreProcedure, type=Procedure, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-procedure, path=package/StructureDefinition-au-core-procedure.json
|
||||
DEBUG:services:Found SD: id=au-core-relatedperson, name=AUCoreRelatedPerson, type=RelatedPerson, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-relatedperson, path=package/StructureDefinition-au-core-relatedperson.json
|
||||
DEBUG:services:Found SD: id=au-core-resprate, name=AUCoreRespirationRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-resprate, path=package/StructureDefinition-au-core-resprate.json
|
||||
DEBUG:services:Found SD: id=au-core-rsg-sexassignedab, name=AUCoreSexAssignedAtBirth, type=Extension, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-rsg-sexassignedab, path=package/StructureDefinition-au-core-rsg-sexassignedab.json
|
||||
DEBUG:services:Found SD: id=au-core-smokingstatus, name=AUCoreSmokingStatus, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-smokingstatus, path=package/StructureDefinition-au-core-smokingstatus.json
|
||||
DEBUG:services:Found SD: id=au-core-waistcircum, name=AUCoreWaistCircumference, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-waistcircum, path=package/StructureDefinition-au-core-waistcircum.json
|
||||
DEBUG:__main__:Retrieved 19 Must Support paths for 'au-core-patient' from processed IG hl7.fhir.au.core-1.1.0#preview
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:26:16] "GET /get-structure?package_name=hl7.fhir.au.core-1.1.0&package_version=preview&resource_type=au-core-patient HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:26:19] "GET /get-example?package_name=hl7.fhir.au.core-1.1.0&package_version=preview&filename=package/example/Patient-banks-mia-leanne.json HTTP/1.1" 200 -
|
||||
DEBUG:services:Processed input: /tmp/tmph9efztgj/input.json
|
||||
ERROR:app:Exception on /fsh-converter [POST]
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Handling GET request for FSH converter page.
|
||||
ERROR:app:Exception on /fsh-converter [GET]
|
||||
Traceback (most recent call last):
|
||||
File "/app/venv/lib/python3.12/site-packages/flask/app.py", line 2190, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
@ -141,34 +46,18 @@ Traceback (most recent call last):
|
||||
File "/app/venv/lib/python3.12/site-packages/flask/app.py", line 1469, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/app/app.py", line 985, in fsh_converter
|
||||
output_dir = os.path.join(app.config['UPLOAD_FOLDER'], 'fsh_output')
|
||||
~~~~~~~~~~^^^^^^^^^^^^^^^^^
|
||||
KeyError: 'UPLOAD_FOLDER'
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:28:22] "[35m[1mPOST /fsh-converter HTTP/1.1[0m" 500 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:28:22] "[33mGET /favicon.ico HTTP/1.1[0m" 404 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:46] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:46] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:46] "[36mGET /static/favicon.ico HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:48] "GET / HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:48] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:services:Parsed 'hl7.fhir.au.base-5.1.0-preview.tgz' -> name='hl7.fhir.au.base-5.1.0', version='preview'
|
||||
DEBUG:services:Parsed 'hl7.fhir.au.core-1.1.0-preview.tgz' -> name='hl7.fhir.au.core-1.1.0', version='preview'
|
||||
DEBUG:services:Parsed 'hl7.fhir.r4.core-4.0.1.tgz' -> name='hl7.fhir.r4.core', version='4.0.1'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.extensions.r4-5.2.0.tgz' -> name='hl7.fhir.uv.extensions.r4', version='5.2.0'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.ipa-1.0.0.tgz' -> name='hl7.fhir.uv.ipa', version='1.0.0'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz' -> name='hl7.fhir.uv.smart-app-launch', version='2.0.0'
|
||||
DEBUG:services:Parsed 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz' -> name='hl7.fhir.uv.smart-app-launch', version='2.1.0'
|
||||
DEBUG:services:Parsed 'hl7.terminology.r4-5.0.0.tgz' -> name='hl7.terminology.r4', version='5.0.0'
|
||||
DEBUG:services:Parsed 'hl7.terminology.r4-6.2.0.tgz' -> name='hl7.terminology.r4', version='6.2.0'
|
||||
DEBUG:__main__:Found packages: [{'name': 'hl7.fhir.au.base', 'version': '5.1.0-preview', 'filename': 'hl7.fhir.au.base-5.1.0-preview.tgz'}, {'name': 'hl7.fhir.au.core', 'version': '1.1.0-preview', 'filename': 'hl7.fhir.au.core-1.1.0-preview.tgz'}, {'name': 'hl7.fhir.r4.core', 'version': '4.0.1', 'filename': 'hl7.fhir.r4.core-4.0.1.tgz'}, {'name': 'hl7.fhir.uv.extensions.r4', 'version': '5.2.0', 'filename': 'hl7.fhir.uv.extensions.r4-5.2.0.tgz'}, {'name': 'hl7.fhir.uv.ipa', 'version': '1.0.0', 'filename': 'hl7.fhir.uv.ipa-1.0.0.tgz'}, {'name': 'hl7.fhir.uv.smart-app-launch', 'version': '2.0.0', 'filename': 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz'}, {'name': 'hl7.fhir.uv.smart-app-launch', 'version': '2.1.0', 'filename': 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz'}, {'name': 'hl7.terminology.r4', 'version': '5.0.0', 'filename': 'hl7.terminology.r4-5.0.0.tgz'}, {'name': 'hl7.terminology.r4', 'version': '6.2.0', 'filename': 'hl7.terminology.r4-6.2.0.tgz'}]
|
||||
DEBUG:__main__:Errors during package listing: []
|
||||
DEBUG:__main__:Duplicate groups: {'hl7.fhir.uv.smart-app-launch': ['2.0.0', '2.1.0'], 'hl7.terminology.r4': ['5.0.0', '6.2.0']}
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:52] "GET /view-igs HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:52] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:57] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 06:45:57] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
File "/app/app.py", line 1061, in fsh_converter
|
||||
response = make_response(render_template( # <<< CORRECTED: Using make_response
|
||||
^^^^^^^^^^^^^
|
||||
NameError: name 'make_response' is not defined
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:38:21] "[35m[1mGET /fsh-converter HTTP/1.1[0m" 500 -
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
@ -179,80 +68,458 @@ INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
INFO:werkzeug:[31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:5000
|
||||
* Running on http://172.19.0.2:5000
|
||||
* Running on http://172.18.0.2:5000
|
||||
INFO:werkzeug:[33mPress CTRL+C to quit[0m
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:09] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:09] "GET /static/FHIRFLARE.png HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:09] "GET /static/favicon.ico HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:13] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:13] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Attempting to find SD for 'au-core-allergyintolerance' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Searching for SD matching 'au-core-allergyintolerance' with profile 'None' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Found SD: id=au-core-allergyintolerance, name=AUCoreAllergyIntolerance, type=AllergyIntolerance, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-allergyintolerance, path=package/StructureDefinition-au-core-allergyintolerance.json
|
||||
INFO:services:Found matching SD for 'au-core-allergyintolerance' at path: package/StructureDefinition-au-core-allergyintolerance.json
|
||||
DEBUG:services:Found SD: id=au-core-bloodpressure, name=AUCoreBloodPressure, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bloodpressure, path=package/StructureDefinition-au-core-bloodpressure.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyheight, name=AUCoreBodyHeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyheight, path=package/StructureDefinition-au-core-bodyheight.json
|
||||
DEBUG:services:Found SD: id=au-core-bodytemp, name=AUCoreBodyTemperature, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodytemp, path=package/StructureDefinition-au-core-bodytemp.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyweight, name=AUCoreBodyWeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyweight, path=package/StructureDefinition-au-core-bodyweight.json
|
||||
DEBUG:services:Found SD: id=au-core-condition, name=AUCoreCondition, type=Condition, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-condition, path=package/StructureDefinition-au-core-condition.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult-path, name=AUCorePathologyResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult-path, path=package/StructureDefinition-au-core-diagnosticresult-path.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult, name=AUCoreDiagnosticResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult, path=package/StructureDefinition-au-core-diagnosticresult.json
|
||||
DEBUG:services:Found SD: id=au-core-encounter, name=AUCoreEncounter, type=Encounter, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-encounter, path=package/StructureDefinition-au-core-encounter.json
|
||||
DEBUG:services:Found SD: id=au-core-heartrate, name=AUCoreHeartRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-heartrate, path=package/StructureDefinition-au-core-heartrate.json
|
||||
DEBUG:services:Found SD: id=au-core-immunization, name=AUCoreImmunization, type=Immunization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-immunization, path=package/StructureDefinition-au-core-immunization.json
|
||||
DEBUG:services:Found SD: id=au-core-location, name=AUCoreLocation, type=Location, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-location, path=package/StructureDefinition-au-core-location.json
|
||||
DEBUG:services:Found SD: id=au-core-medication, name=AUCoreMedication, type=Medication, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medication, path=package/StructureDefinition-au-core-medication.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationrequest, name=AUCoreMedicationRequest, type=MedicationRequest, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationrequest, path=package/StructureDefinition-au-core-medicationrequest.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationstatement, name=AUCoreMedicationStatement, type=MedicationStatement, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationstatement, path=package/StructureDefinition-au-core-medicationstatement.json
|
||||
DEBUG:services:Found SD: id=au-core-organization, name=AUCoreOrganization, type=Organization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-organization, path=package/StructureDefinition-au-core-organization.json
|
||||
DEBUG:services:Found SD: id=au-core-patient, name=AUCorePatient, type=Patient, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient, path=package/StructureDefinition-au-core-patient.json
|
||||
DEBUG:services:Found SD: id=au-core-practitioner, name=AUCorePractitioner, type=Practitioner, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitioner, path=package/StructureDefinition-au-core-practitioner.json
|
||||
DEBUG:services:Found SD: id=au-core-practitionerrole, name=AUCorePractitionerRole, type=PractitionerRole, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitionerrole, path=package/StructureDefinition-au-core-practitionerrole.json
|
||||
DEBUG:services:Found SD: id=au-core-procedure, name=AUCoreProcedure, type=Procedure, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-procedure, path=package/StructureDefinition-au-core-procedure.json
|
||||
DEBUG:services:Found SD: id=au-core-relatedperson, name=AUCoreRelatedPerson, type=RelatedPerson, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-relatedperson, path=package/StructureDefinition-au-core-relatedperson.json
|
||||
DEBUG:services:Found SD: id=au-core-resprate, name=AUCoreRespirationRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-resprate, path=package/StructureDefinition-au-core-resprate.json
|
||||
DEBUG:services:Found SD: id=au-core-rsg-sexassignedab, name=AUCoreSexAssignedAtBirth, type=Extension, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-rsg-sexassignedab, path=package/StructureDefinition-au-core-rsg-sexassignedab.json
|
||||
DEBUG:services:Found SD: id=au-core-smokingstatus, name=AUCoreSmokingStatus, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-smokingstatus, path=package/StructureDefinition-au-core-smokingstatus.json
|
||||
DEBUG:services:Found SD: id=au-core-waistcircum, name=AUCoreWaistCircumference, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-waistcircum, path=package/StructureDefinition-au-core-waistcircum.json
|
||||
DEBUG:__main__:Retrieved 8 Must Support paths for 'au-core-allergyintolerance' from processed IG hl7.fhir.au.core-1.1.0#preview
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:27] "GET /get-structure?package_name=hl7.fhir.au.core-1.1.0&package_version=preview&resource_type=au-core-allergyintolerance HTTP/1.1" 200 -
|
||||
DEBUG:__main__:Attempting to find SD for 'au-core-patient' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Searching for SD matching 'au-core-patient' with profile 'None' in hl7.fhir.au.core-1.1.0-preview.tgz
|
||||
DEBUG:services:Found SD: id=au-core-allergyintolerance, name=AUCoreAllergyIntolerance, type=AllergyIntolerance, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-allergyintolerance, path=package/StructureDefinition-au-core-allergyintolerance.json
|
||||
DEBUG:services:Found SD: id=au-core-bloodpressure, name=AUCoreBloodPressure, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bloodpressure, path=package/StructureDefinition-au-core-bloodpressure.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyheight, name=AUCoreBodyHeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyheight, path=package/StructureDefinition-au-core-bodyheight.json
|
||||
DEBUG:services:Found SD: id=au-core-bodytemp, name=AUCoreBodyTemperature, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodytemp, path=package/StructureDefinition-au-core-bodytemp.json
|
||||
DEBUG:services:Found SD: id=au-core-bodyweight, name=AUCoreBodyWeight, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-bodyweight, path=package/StructureDefinition-au-core-bodyweight.json
|
||||
DEBUG:services:Found SD: id=au-core-condition, name=AUCoreCondition, type=Condition, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-condition, path=package/StructureDefinition-au-core-condition.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult-path, name=AUCorePathologyResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult-path, path=package/StructureDefinition-au-core-diagnosticresult-path.json
|
||||
DEBUG:services:Found SD: id=au-core-diagnosticresult, name=AUCoreDiagnosticResult, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-diagnosticresult, path=package/StructureDefinition-au-core-diagnosticresult.json
|
||||
DEBUG:services:Found SD: id=au-core-encounter, name=AUCoreEncounter, type=Encounter, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-encounter, path=package/StructureDefinition-au-core-encounter.json
|
||||
DEBUG:services:Found SD: id=au-core-heartrate, name=AUCoreHeartRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-heartrate, path=package/StructureDefinition-au-core-heartrate.json
|
||||
DEBUG:services:Found SD: id=au-core-immunization, name=AUCoreImmunization, type=Immunization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-immunization, path=package/StructureDefinition-au-core-immunization.json
|
||||
DEBUG:services:Found SD: id=au-core-location, name=AUCoreLocation, type=Location, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-location, path=package/StructureDefinition-au-core-location.json
|
||||
DEBUG:services:Found SD: id=au-core-medication, name=AUCoreMedication, type=Medication, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medication, path=package/StructureDefinition-au-core-medication.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationrequest, name=AUCoreMedicationRequest, type=MedicationRequest, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationrequest, path=package/StructureDefinition-au-core-medicationrequest.json
|
||||
DEBUG:services:Found SD: id=au-core-medicationstatement, name=AUCoreMedicationStatement, type=MedicationStatement, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-medicationstatement, path=package/StructureDefinition-au-core-medicationstatement.json
|
||||
DEBUG:services:Found SD: id=au-core-organization, name=AUCoreOrganization, type=Organization, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-organization, path=package/StructureDefinition-au-core-organization.json
|
||||
DEBUG:services:Found SD: id=au-core-patient, name=AUCorePatient, type=Patient, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient, path=package/StructureDefinition-au-core-patient.json
|
||||
INFO:services:Found matching SD for 'au-core-patient' at path: package/StructureDefinition-au-core-patient.json
|
||||
DEBUG:services:Found SD: id=au-core-practitioner, name=AUCorePractitioner, type=Practitioner, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitioner, path=package/StructureDefinition-au-core-practitioner.json
|
||||
DEBUG:services:Found SD: id=au-core-practitionerrole, name=AUCorePractitionerRole, type=PractitionerRole, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitionerrole, path=package/StructureDefinition-au-core-practitionerrole.json
|
||||
DEBUG:services:Found SD: id=au-core-procedure, name=AUCoreProcedure, type=Procedure, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-procedure, path=package/StructureDefinition-au-core-procedure.json
|
||||
DEBUG:services:Found SD: id=au-core-relatedperson, name=AUCoreRelatedPerson, type=RelatedPerson, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-relatedperson, path=package/StructureDefinition-au-core-relatedperson.json
|
||||
DEBUG:services:Found SD: id=au-core-resprate, name=AUCoreRespirationRate, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-resprate, path=package/StructureDefinition-au-core-resprate.json
|
||||
DEBUG:services:Found SD: id=au-core-rsg-sexassignedab, name=AUCoreSexAssignedAtBirth, type=Extension, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-rsg-sexassignedab, path=package/StructureDefinition-au-core-rsg-sexassignedab.json
|
||||
DEBUG:services:Found SD: id=au-core-smokingstatus, name=AUCoreSmokingStatus, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-smokingstatus, path=package/StructureDefinition-au-core-smokingstatus.json
|
||||
DEBUG:services:Found SD: id=au-core-waistcircum, name=AUCoreWaistCircumference, type=Observation, url=http://hl7.org.au/fhir/core/StructureDefinition/au-core-waistcircum, path=package/StructureDefinition-au-core-waistcircum.json
|
||||
DEBUG:__main__:Retrieved 19 Must Support paths for 'au-core-patient' from processed IG hl7.fhir.au.core-1.1.0#preview
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:28] "GET /get-structure?package_name=hl7.fhir.au.core-1.1.0&package_version=preview&resource_type=au-core-patient HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:09:32] "GET /get-example?package_name=hl7.fhir.au.core-1.1.0&package_version=preview&filename=package/example/Patient-banks-mia-leanne.json HTTP/1.1" 200 -
|
||||
DEBUG:services:Processed input: /tmp/tmpgwv6g5vl/input.json
|
||||
INFO:services:GoFSH executed successfully for /tmp/tmpgwv6g5vl/input.json
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:10:23] "POST /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:10:23] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:11:09] "GET /download-fsh HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:16:19] "GET /fhir HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:16:19] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:16:56] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.19.0.1 - - [17/Apr/2025 07:16:56] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:45:38] "GET / HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:45:38] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Handling GET request for FSH converter page.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:45:46] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:45:46] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:45:46] "[36mGET /static/js/lottie.min.js HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
INFO:werkzeug:[31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:5000
|
||||
* Running on http://172.18.0.2:5000
|
||||
INFO:werkzeug:[33mPress CTRL+C to quit[0m
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:50:05] "GET / HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:50:06] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Handling GET request for FSH converter page.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:50:13] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:50:13] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:50:13] "[36mGET /static/js/lottie.min.js HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:50:13] "[36mGET /static/animations/loading-dark.json HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
INFO:werkzeug:[31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:5000
|
||||
* Running on http://172.18.0.2:5000
|
||||
INFO:werkzeug:[33mPress CTRL+C to quit[0m
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:53:18] "GET / HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:53:18] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:53:18] "[36mGET /static/favicon.ico HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Handling GET request for FSH converter page.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:53:24] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:53:24] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:53:24] "[36mGET /static/js/lottie.min.js HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
INFO:werkzeug:[31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:5000
|
||||
* Running on http://172.18.0.2:5000
|
||||
INFO:werkzeug:[33mPress CTRL+C to quit[0m
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:57:25] "GET / HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:57:25] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Handling GET request for FSH converter page.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:57:30] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:57:30] "[36mGET /static/FHIRFLARE.png HTTP/1.1[0m" 304 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 14:57:30] "[36mGET /static/js/lottie.min.js HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
DEBUG:__main__:Instance path configuration: /app/instance
|
||||
DEBUG:__main__:Database URI: sqlite:////app/instance/fhir_ig.db
|
||||
DEBUG:__main__:Packages path: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Flask instance folder path: /app/instance
|
||||
DEBUG:__main__:Directories created/verified: Instance: /app/instance, Packages: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Attempting to create database tables for URI: sqlite:////app/instance/fhir_ig.db
|
||||
INFO:__main__:Database tables created successfully (if they didn't exist).
|
||||
INFO:werkzeug:[31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:5000
|
||||
* Running on http://172.18.0.2:5000
|
||||
INFO:werkzeug:[33mPress CTRL+C to quit[0m
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Handling GET request for FSH converter page.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:00:57] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:00:57] "GET /static/FHIRFLARE.png HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:00:58] "GET /static/js/lottie.min.js HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:00:58] "GET /static/animations/loading-dark.json HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:00:58] "GET /static/favicon.ico HTTP/1.1" 200 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Processing input: mode=text, has_file=False, has_text=True, has_alias=False
|
||||
DEBUG:services:Processed input: ('/tmp/tmp_21icnfn/input.json', None)
|
||||
DEBUG:__main__:Running GoFSH with input: /tmp/tmp_21icnfn/input.json, output_dir: /app/static/uploads/fsh_output
|
||||
DEBUG:services:Wrapper script contents:
|
||||
#!/bin/bash
|
||||
exec 3>/dev/null
|
||||
"gofsh" "/tmp/tmp_21icnfn/input.json" "-o" "/tmp/tmpn9r4c9rl" "-s" "file-per-definition" "-l" "error" </dev/null >/tmp/gofsh_output.log 2>&1
|
||||
|
||||
DEBUG:services:Temp output directory contents before GoFSH: []
|
||||
DEBUG:services:GoFSH output:
|
||||
|
||||
╔═════════════════════════ GoFSH RESULTS ═════════════════════════╗
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Profiles │ Extensions │ Logicals │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Resources │ ValueSets │ CodeSystems │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Instances │ Invariants │ Mappings │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 1 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Aliases │ │ │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 3 │ │ │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ║
|
||||
╠═════════════════════════════════════════════════════════════════╣
|
||||
║ Not bad, but it cod be batter! 0 Errors 2 Warnings ║
|
||||
╚═════════════════════════════════════════════════════════════════╝
|
||||
|
||||
DEBUG:services:GoFSH fishing-trip wrapper script contents:
|
||||
#!/bin/bash
|
||||
exec 3>/dev/null
|
||||
exec >/dev/null 2>&1
|
||||
"gofsh" "/tmp/tmp_21icnfn/input.json" "-o" "/tmp/tmpllyiv7dp" "-s" "file-per-definition" "-l" "error" "--fshing-trip" </dev/null >/tmp/gofsh_output.log 2>&1
|
||||
|
||||
DEBUG:services:GoFSH fishing-trip output:
|
||||
|
||||
╔═════════════════════════ GoFSH RESULTS ═════════════════════════╗
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Profiles │ Extensions │ Logicals │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Resources │ ValueSets │ CodeSystems │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Instances │ Invariants │ Mappings │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 1 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Aliases │ │ │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 3 │ │ │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ║
|
||||
╠═════════════════════════════════════════════════════════════════╣
|
||||
║ Something smells fishy... 0 Errors 2 Warnings ║
|
||||
╚═════════════════════════════════════════════════════════════════╝
|
||||
╔═════════════════════════════════════════════════════════════════╗
|
||||
║ Generating round trip results via SUSHI ║
|
||||
╚═════════════════════════════════════════════════════════════════╝
|
||||
info Running SUSHI v3.15.0 (implements FHIR Shorthand specification v3.0.0)
|
||||
info Arguments:
|
||||
info /tmp/tmpllyiv7dp
|
||||
info No output path specified. Output to /tmp/tmpllyiv7dp
|
||||
info Using configuration file: /tmp/tmpllyiv7dp/sushi-config.yaml
|
||||
warn The FSHOnly property is set to true, so no output specific to IG creation will be generated. The following properties are unused and only relevant for IG creation: id, name. Consider removing these properties from sushi-config.yaml.
|
||||
File: /tmp/tmpllyiv7dp/sushi-config.yaml
|
||||
info Importing FSH text...
|
||||
info Preprocessed 2 documents with 3 aliases.
|
||||
info Imported 0 definitions and 1 instances.
|
||||
info Loaded virtual package sushi-r5forR4#1.0.0 with 7 resources
|
||||
info Resolved hl7.fhir.uv.tools.r4#latest to concrete version 0.5.0
|
||||
info Loaded hl7.fhir.uv.tools.r4#0.5.0 with 88 resources
|
||||
info Resolved hl7.terminology.r4#latest to concrete version 6.2.0
|
||||
info Loaded hl7.terminology.r4#6.2.0 with 4323 resources
|
||||
info Resolved hl7.fhir.uv.extensions.r4#latest to concrete version 5.2.0
|
||||
info Loaded hl7.fhir.uv.extensions.r4#5.2.0 with 759 resources
|
||||
info Loaded hl7.fhir.r4.core#4.0.1 with 4581 resources
|
||||
info Loaded virtual package sushi-local#LOCAL with 0 resources
|
||||
info Converting FSH to FHIR resources...
|
||||
info Converted 1 FHIR instances.
|
||||
info Exporting FHIR resources as JSON...
|
||||
info Exported 1 FHIR resources as JSON.
|
||||
info Exporting FSH definitions only. No IG related content will be exported.
|
||||
|
||||
========================= SUSHI RESULTS ===========================
|
||||
| ------------------------------------------------------------- |
|
||||
| | Profiles | Extensions | Logicals | Resources | |
|
||||
| |-------------------------------------------------------------| |
|
||||
| | 0 | 0 | 0 | 0 | |
|
||||
| ------------------------------------------------------------- |
|
||||
| ------------------------------------------------------------- |
|
||||
| | ValueSets | CodeSystems | Instances | |
|
||||
| |-------------------------------------------------------------| |
|
||||
| | 0 | 0 | 1 | |
|
||||
| ------------------------------------------------------------- |
|
||||
| |
|
||||
===================================================================
|
||||
| A bit pitchy, but tuna-ble. 0 Errors 1 Warning |
|
||||
===================================================================
|
||||
|
||||
|
||||
DEBUG:services:Copied files to final output directory: ['sushi-config.yaml', 'input/fsh/aliases.fsh', 'input/fsh/instances/vkc.fsh', 'input/input.json', 'fshing-trip-comparison.html']
|
||||
INFO:services:GoFSH executed successfully for /tmp/tmp_21icnfn/input.json
|
||||
DEBUG:__main__:Successfully removed temp directory: /tmp/tmp_21icnfn
|
||||
INFO:__main__:FSH conversion successful
|
||||
DEBUG:__main__:Returning partial HTML for AJAX POST request.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:02:41] "POST /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:02:41] "[36mGET /static/animations/loading-dark.json HTTP/1.1[0m" 304 -
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Processing input: mode=text, has_file=False, has_text=True, has_alias=False
|
||||
DEBUG:services:Processed input: ('/tmp/tmp_k0pky49/input.json', None)
|
||||
DEBUG:__main__:Running GoFSH with input: /tmp/tmp_k0pky49/input.json, output_dir: /app/static/uploads/fsh_output
|
||||
DEBUG:services:Wrapper script contents:
|
||||
#!/bin/bash
|
||||
exec 3>/dev/null
|
||||
"gofsh" "/tmp/tmp_k0pky49/input.json" "-o" "/tmp/tmpvnwz2fsh" "-s" "file-per-definition" "-l" "error" </dev/null >/tmp/gofsh_output.log 2>&1
|
||||
|
||||
DEBUG:services:Temp output directory contents before GoFSH: []
|
||||
DEBUG:__main__:Scanning packages directory: /app/instance/fhir_packages
|
||||
DEBUG:__main__:Found 9 .tgz files: ['hl7.fhir.au.base-5.1.0-preview.tgz', 'hl7.fhir.au.core-1.1.0-preview.tgz', 'hl7.fhir.r4.core-4.0.1.tgz', 'hl7.fhir.uv.extensions.r4-5.2.0.tgz', 'hl7.fhir.uv.ipa-1.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.0.0.tgz', 'hl7.fhir.uv.smart-app-launch-2.1.0.tgz', 'hl7.terminology.r4-5.0.0.tgz', 'hl7.terminology.r4-6.2.0.tgz']
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.base#5.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.au.core#1.1.0-preview
|
||||
DEBUG:__main__:Added package: hl7.fhir.r4.core#4.0.1
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.extensions.r4#5.2.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.ipa#1.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.0.0
|
||||
DEBUG:__main__:Added package: hl7.fhir.uv.smart-app-launch#2.1.0
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#5.0.0
|
||||
DEBUG:services:GoFSH output:
|
||||
|
||||
╔═════════════════════════ GoFSH RESULTS ═════════════════════════╗
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Profiles │ Extensions │ Logicals │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Resources │ ValueSets │ CodeSystems │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Instances │ Invariants │ Mappings │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 1 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Aliases │ │ │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 3 │ │ │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ║
|
||||
╠═════════════════════════════════════════════════════════════════╣
|
||||
║ Not bad, but it cod be batter! 0 Errors 2 Warnings ║
|
||||
╚═════════════════════════════════════════════════════════════════╝
|
||||
|
||||
DEBUG:__main__:Added package: hl7.terminology.r4#6.2.0
|
||||
DEBUG:__main__:Set package choices: [('', 'None'), ('hl7.fhir.au.base#5.1.0-preview', 'hl7.fhir.au.base#5.1.0-preview'), ('hl7.fhir.au.core#1.1.0-preview', 'hl7.fhir.au.core#1.1.0-preview'), ('hl7.fhir.r4.core#4.0.1', 'hl7.fhir.r4.core#4.0.1'), ('hl7.fhir.uv.extensions.r4#5.2.0', 'hl7.fhir.uv.extensions.r4#5.2.0'), ('hl7.fhir.uv.ipa#1.0.0', 'hl7.fhir.uv.ipa#1.0.0'), ('hl7.fhir.uv.smart-app-launch#2.0.0', 'hl7.fhir.uv.smart-app-launch#2.0.0'), ('hl7.fhir.uv.smart-app-launch#2.1.0', 'hl7.fhir.uv.smart-app-launch#2.1.0'), ('hl7.terminology.r4#5.0.0', 'hl7.terminology.r4#5.0.0'), ('hl7.terminology.r4#6.2.0', 'hl7.terminology.r4#6.2.0')]
|
||||
DEBUG:__main__:Handling GET request for FSH converter page.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:03:11] "GET /fsh-converter HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:03:11] "GET /static/FHIRFLARE.png HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:03:11] "GET /static/js/lottie.min.js HTTP/1.1" 200 -
|
||||
DEBUG:services:GoFSH fishing-trip wrapper script contents:
|
||||
#!/bin/bash
|
||||
exec 3>/dev/null
|
||||
exec >/dev/null 2>&1
|
||||
"gofsh" "/tmp/tmp_k0pky49/input.json" "-o" "/tmp/tmp_hia6e3c" "-s" "file-per-definition" "-l" "error" "--fshing-trip" </dev/null >/tmp/gofsh_output.log 2>&1
|
||||
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:03:11] "GET /static/animations/loading-light.json HTTP/1.1" 200 -
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:03:12] "GET /static/favicon.ico HTTP/1.1" 200 -
|
||||
DEBUG:services:GoFSH fishing-trip output:
|
||||
|
||||
╔═════════════════════════ GoFSH RESULTS ═════════════════════════╗
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Profiles │ Extensions │ Logicals │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Resources │ ValueSets │ CodeSystems │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 0 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Instances │ Invariants │ Mappings │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 1 │ 0 │ 0 │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ╭────────────────────┬───────────────────┬────────────────────╮ ║
|
||||
║ │ Aliases │ │ │ ║
|
||||
║ ├────────────────────┼───────────────────┼────────────────────┤ ║
|
||||
║ │ 3 │ │ │ ║
|
||||
║ ╰────────────────────┴───────────────────┴────────────────────╯ ║
|
||||
║ ║
|
||||
╠═════════════════════════════════════════════════════════════════╣
|
||||
║ A bit pitchy, but may be tuna-ble. 0 Errors 2 Warnings ║
|
||||
╚═════════════════════════════════════════════════════════════════╝
|
||||
╔═════════════════════════════════════════════════════════════════╗
|
||||
║ Generating round trip results via SUSHI ║
|
||||
╚═════════════════════════════════════════════════════════════════╝
|
||||
info Running SUSHI v3.15.0 (implements FHIR Shorthand specification v3.0.0)
|
||||
info Arguments:
|
||||
info /tmp/tmp_hia6e3c
|
||||
info No output path specified. Output to /tmp/tmp_hia6e3c
|
||||
info Using configuration file: /tmp/tmp_hia6e3c/sushi-config.yaml
|
||||
warn The FSHOnly property is set to true, so no output specific to IG creation will be generated. The following properties are unused and only relevant for IG creation: id, name. Consider removing these properties from sushi-config.yaml.
|
||||
File: /tmp/tmp_hia6e3c/sushi-config.yaml
|
||||
info Importing FSH text...
|
||||
info Preprocessed 2 documents with 3 aliases.
|
||||
info Imported 0 definitions and 1 instances.
|
||||
info Loaded virtual package sushi-r5forR4#1.0.0 with 7 resources
|
||||
info Resolved hl7.fhir.uv.tools.r4#latest to concrete version 0.5.0
|
||||
info Loaded hl7.fhir.uv.tools.r4#0.5.0 with 88 resources
|
||||
info Resolved hl7.terminology.r4#latest to concrete version 6.2.0
|
||||
info Loaded hl7.terminology.r4#6.2.0 with 4323 resources
|
||||
info Resolved hl7.fhir.uv.extensions.r4#latest to concrete version 5.2.0
|
||||
info Loaded hl7.fhir.uv.extensions.r4#5.2.0 with 759 resources
|
||||
info Loaded hl7.fhir.r4.core#4.0.1 with 4581 resources
|
||||
info Loaded virtual package sushi-local#LOCAL with 0 resources
|
||||
info Converting FSH to FHIR resources...
|
||||
info Converted 1 FHIR instances.
|
||||
info Exporting FHIR resources as JSON...
|
||||
info Exported 1 FHIR resources as JSON.
|
||||
info Exporting FSH definitions only. No IG related content will be exported.
|
||||
|
||||
========================= SUSHI RESULTS ===========================
|
||||
| ------------------------------------------------------------- |
|
||||
| | Profiles | Extensions | Logicals | Resources | |
|
||||
| |-------------------------------------------------------------| |
|
||||
| | 0 | 0 | 0 | 0 | |
|
||||
| ------------------------------------------------------------- |
|
||||
| ------------------------------------------------------------- |
|
||||
| | ValueSets | CodeSystems | Instances | |
|
||||
| |-------------------------------------------------------------| |
|
||||
| | 0 | 0 | 1 | |
|
||||
| ------------------------------------------------------------- |
|
||||
| |
|
||||
===================================================================
|
||||
| Don't get stuck in the doldrums. 0 Errors 1 Warning |
|
||||
===================================================================
|
||||
|
||||
|
||||
DEBUG:services:Copied files to final output directory: ['sushi-config.yaml', 'input/fsh/aliases.fsh', 'input/fsh/instances/vkc.fsh', 'input/input.json', 'fshing-trip-comparison.html']
|
||||
INFO:services:GoFSH executed successfully for /tmp/tmp_k0pky49/input.json
|
||||
DEBUG:__main__:Successfully removed temp directory: /tmp/tmp_k0pky49
|
||||
INFO:__main__:FSH conversion successful
|
||||
DEBUG:__main__:Returning partial HTML for AJAX POST request.
|
||||
INFO:werkzeug:172.18.0.1 - - [18/Apr/2025 15:03:28] "POST /fsh-converter HTTP/1.1" 200 -
|
||||
|
@ -1,17 +1,56 @@
|
||||
2025-04-17 06:25:17,514 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-17 06:25:17,521 INFO supervisord started with pid 1
|
||||
2025-04-17 06:25:18,537 INFO spawned: 'flask' with pid 7
|
||||
2025-04-17 06:25:18,542 INFO spawned: 'tomcat' with pid 8
|
||||
2025-04-17 06:25:29,060 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-17 06:25:48,549 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
2025-04-17 07:05:48,346 WARN received SIGTERM indicating exit request
|
||||
2025-04-17 07:05:48,354 INFO waiting for flask, tomcat to die
|
||||
2025-04-17 07:05:51,475 WARN stopped: tomcat (exit status 143)
|
||||
2025-04-17 07:05:51,483 INFO waiting for flask to die
|
||||
2025-04-17 07:05:52,495 WARN stopped: flask (terminated by SIGTERM)
|
||||
2025-04-17 07:08:06,100 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-17 07:08:06,109 INFO supervisord started with pid 1
|
||||
2025-04-17 07:08:07,117 INFO spawned: 'flask' with pid 7
|
||||
2025-04-17 07:08:07,122 INFO spawned: 'tomcat' with pid 8
|
||||
2025-04-17 07:08:17,381 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-17 07:08:37,990 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
2025-04-18 14:38:01,410 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-18 14:38:01,416 INFO supervisord started with pid 1
|
||||
2025-04-18 14:38:02,423 INFO spawned: 'flask' with pid 7
|
||||
2025-04-18 14:38:02,429 INFO spawned: 'tomcat' with pid 8
|
||||
2025-04-18 14:38:12,439 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-18 14:38:32,593 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
2025-04-18 14:40:50,270 WARN received SIGTERM indicating exit request
|
||||
2025-04-18 14:40:50,271 INFO waiting for flask, tomcat to die
|
||||
2025-04-18 14:40:51,200 WARN stopped: tomcat (exit status 143)
|
||||
2025-04-18 14:40:51,204 WARN stopped: flask (terminated by SIGTERM)
|
||||
2025-04-18 14:45:28,046 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-18 14:45:28,051 INFO supervisord started with pid 1
|
||||
2025-04-18 14:45:29,057 INFO spawned: 'flask' with pid 8
|
||||
2025-04-18 14:45:29,060 INFO spawned: 'tomcat' with pid 9
|
||||
2025-04-18 14:45:39,314 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-18 14:45:59,118 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
2025-04-18 14:48:15,641 WARN received SIGTERM indicating exit request
|
||||
2025-04-18 14:48:15,642 INFO waiting for flask, tomcat to die
|
||||
2025-04-18 14:48:16,755 WARN stopped: tomcat (exit status 143)
|
||||
2025-04-18 14:48:16,762 WARN stopped: flask (terminated by SIGTERM)
|
||||
2025-04-18 14:50:03,021 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-18 14:50:03,030 INFO supervisord started with pid 1
|
||||
2025-04-18 14:50:04,035 INFO spawned: 'flask' with pid 7
|
||||
2025-04-18 14:50:04,041 INFO spawned: 'tomcat' with pid 8
|
||||
2025-04-18 14:50:14,298 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-18 14:50:34,529 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
2025-04-18 14:51:37,046 WARN received SIGTERM indicating exit request
|
||||
2025-04-18 14:51:37,047 INFO waiting for flask, tomcat to die
|
||||
2025-04-18 14:51:38,220 WARN stopped: tomcat (exit status 143)
|
||||
2025-04-18 14:51:38,225 WARN stopped: flask (terminated by SIGTERM)
|
||||
2025-04-18 14:53:15,586 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-18 14:53:15,594 INFO supervisord started with pid 1
|
||||
2025-04-18 14:53:16,598 INFO spawned: 'flask' with pid 7
|
||||
2025-04-18 14:53:16,601 INFO spawned: 'tomcat' with pid 8
|
||||
2025-04-18 14:53:27,378 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-18 14:53:47,426 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
2025-04-18 14:55:41,989 WARN received SIGTERM indicating exit request
|
||||
2025-04-18 14:55:41,989 INFO waiting for flask, tomcat to die
|
||||
2025-04-18 14:55:43,011 WARN stopped: tomcat (exit status 143)
|
||||
2025-04-18 14:55:43,018 WARN stopped: flask (terminated by SIGTERM)
|
||||
2025-04-18 14:57:22,683 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-18 14:57:22,688 INFO supervisord started with pid 1
|
||||
2025-04-18 14:57:23,693 INFO spawned: 'flask' with pid 7
|
||||
2025-04-18 14:57:23,697 INFO spawned: 'tomcat' with pid 8
|
||||
2025-04-18 14:57:34,418 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-18 14:57:53,722 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
2025-04-18 14:59:18,910 WARN received SIGTERM indicating exit request
|
||||
2025-04-18 14:59:18,925 INFO waiting for flask, tomcat to die
|
||||
2025-04-18 14:59:20,423 WARN stopped: tomcat (exit status 143)
|
||||
2025-04-18 14:59:20,430 WARN stopped: flask (terminated by SIGTERM)
|
||||
2025-04-18 15:00:50,025 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
|
||||
2025-04-18 15:00:50,043 INFO supervisord started with pid 1
|
||||
2025-04-18 15:00:51,049 INFO spawned: 'flask' with pid 7
|
||||
2025-04-18 15:00:51,053 INFO spawned: 'tomcat' with pid 8
|
||||
2025-04-18 15:01:01,646 INFO success: flask entered RUNNING state, process has stayed up for > than 10 seconds (startsecs)
|
||||
2025-04-18 15:01:21,365 INFO success: tomcat entered RUNNING state, process has stayed up for > than 30 seconds (startsecs)
|
||||
|
1266
logs/tomcat.log
1266
logs/tomcat.log
File diff suppressed because it is too large
Load Diff
@ -1,83 +1,259 @@
|
||||
17-Apr-2025 06:25:19.367 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
17-Apr-2025 06:25:19.375 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
17-Apr-2025 06:25:19.375 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
17-Apr-2025 06:25:19.375 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
17-Apr-2025 06:25:19.375 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
17-Apr-2025 06:25:19.375 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
17-Apr-2025 06:25:19.376 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
17-Apr-2025 06:25:19.376 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
17-Apr-2025 06:25:19.376 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
17-Apr-2025 06:25:19.376 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
17-Apr-2025 06:25:19.376 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
17-Apr-2025 06:25:19.400 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
17-Apr-2025 06:25:19.401 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
17-Apr-2025 06:25:19.402 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
17-Apr-2025 06:25:19.402 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
17-Apr-2025 06:25:19.402 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
17-Apr-2025 06:25:19.402 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
17-Apr-2025 06:25:19.411 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
17-Apr-2025 06:25:19.416 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
17-Apr-2025 06:25:19.821 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
17-Apr-2025 06:25:19.882 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [794] milliseconds
|
||||
17-Apr-2025 06:25:20.017 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
17-Apr-2025 06:25:20.017 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
17-Apr-2025 06:25:20.048 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
17-Apr-2025 06:25:38.970 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
17-Apr-2025 06:26:26.803 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [66,753] ms
|
||||
17-Apr-2025 06:26:26.804 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
17-Apr-2025 06:26:26.847 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [42] ms
|
||||
17-Apr-2025 06:26:26.854 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
17-Apr-2025 06:26:26.893 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [67014] milliseconds
|
||||
17-Apr-2025 07:05:48.360 INFO [Thread-5] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
|
||||
17-Apr-2025 07:05:48.381 INFO [Thread-5] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
|
||||
17-Apr-2025 07:05:49.774 SEVERE [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [org.springframework.boot.SpringBootExceptionHandler.LoggedExceptionHandlerThreadLocal] (value [org.springframework.boot.SpringBootExceptionHandler$LoggedExceptionHandlerThreadLocal@60f94e9]) and a value of type [org.springframework.boot.SpringBootExceptionHandler] (value [org.springframework.boot.SpringBootExceptionHandler@46b9f0e9]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
|
||||
17-Apr-2025 07:05:49.827 INFO [Thread-5] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
|
||||
17-Apr-2025 07:05:49.841 INFO [Thread-5] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
|
||||
17-Apr-2025 07:08:07.777 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
17-Apr-2025 07:08:07.785 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
17-Apr-2025 07:08:07.786 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
17-Apr-2025 07:08:07.786 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
17-Apr-2025 07:08:07.786 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
17-Apr-2025 07:08:07.786 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
17-Apr-2025 07:08:07.787 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
17-Apr-2025 07:08:07.787 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
17-Apr-2025 07:08:07.787 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
17-Apr-2025 07:08:07.787 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
17-Apr-2025 07:08:07.787 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
17-Apr-2025 07:08:07.813 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
17-Apr-2025 07:08:07.813 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
17-Apr-2025 07:08:07.814 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
17-Apr-2025 07:08:07.814 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
17-Apr-2025 07:08:07.814 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
17-Apr-2025 07:08:07.814 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
17-Apr-2025 07:08:07.814 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
17-Apr-2025 07:08:07.815 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
17-Apr-2025 07:08:07.826 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
17-Apr-2025 07:08:07.831 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
17-Apr-2025 07:08:08.209 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
17-Apr-2025 07:08:08.251 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [759] milliseconds
|
||||
17-Apr-2025 07:08:08.340 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
17-Apr-2025 07:08:08.340 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
17-Apr-2025 07:08:08.368 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
17-Apr-2025 07:08:22.061 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
17-Apr-2025 07:09:08.525 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [60,155] ms
|
||||
17-Apr-2025 07:09:08.528 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
17-Apr-2025 07:09:08.565 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [37] ms
|
||||
17-Apr-2025 07:09:08.575 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
17-Apr-2025 07:09:08.662 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [60427] milliseconds
|
||||
18-Apr-2025 14:38:02.924 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
18-Apr-2025 14:38:02.930 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
18-Apr-2025 14:38:02.930 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
18-Apr-2025 14:38:02.930 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
18-Apr-2025 14:38:02.930 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
18-Apr-2025 14:38:02.930 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
18-Apr-2025 14:38:02.931 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
18-Apr-2025 14:38:02.931 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
18-Apr-2025 14:38:02.931 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
18-Apr-2025 14:38:02.931 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
18-Apr-2025 14:38:02.931 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
18-Apr-2025 14:38:02.945 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
18-Apr-2025 14:38:02.945 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
18-Apr-2025 14:38:02.945 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
18-Apr-2025 14:38:02.945 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
18-Apr-2025 14:38:02.945 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
18-Apr-2025 14:38:02.946 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
18-Apr-2025 14:38:02.947 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
18-Apr-2025 14:38:02.947 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
18-Apr-2025 14:38:02.952 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
18-Apr-2025 14:38:02.956 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
18-Apr-2025 14:38:03.277 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:38:03.304 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [599] milliseconds
|
||||
18-Apr-2025 14:38:03.391 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
18-Apr-2025 14:38:03.392 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
18-Apr-2025 14:38:03.427 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
18-Apr-2025 14:38:17.518 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
18-Apr-2025 14:39:04.055 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [60,627] ms
|
||||
18-Apr-2025 14:39:04.057 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
18-Apr-2025 14:39:04.087 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [29] ms
|
||||
18-Apr-2025 14:39:04.096 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:39:04.146 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [60844] milliseconds
|
||||
18-Apr-2025 14:40:50.273 INFO [Thread-5] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:40:50.283 INFO [Thread-5] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
|
||||
18-Apr-2025 14:40:50.970 SEVERE [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [org.springframework.boot.SpringBootExceptionHandler.LoggedExceptionHandlerThreadLocal] (value [org.springframework.boot.SpringBootExceptionHandler$LoggedExceptionHandlerThreadLocal@29edc901]) and a value of type [org.springframework.boot.SpringBootExceptionHandler] (value [org.springframework.boot.SpringBootExceptionHandler@2c8e3172]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
|
||||
18-Apr-2025 14:40:50.981 INFO [Thread-5] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:40:50.993 INFO [Thread-5] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:45:29.517 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
18-Apr-2025 14:45:29.521 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
18-Apr-2025 14:45:29.522 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
18-Apr-2025 14:45:29.522 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
18-Apr-2025 14:45:29.522 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
18-Apr-2025 14:45:29.522 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
18-Apr-2025 14:45:29.523 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
18-Apr-2025 14:45:29.523 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
18-Apr-2025 14:45:29.523 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
18-Apr-2025 14:45:29.523 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
18-Apr-2025 14:45:29.523 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
18-Apr-2025 14:45:29.532 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
18-Apr-2025 14:45:29.533 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
18-Apr-2025 14:45:29.534 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
18-Apr-2025 14:45:29.534 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
18-Apr-2025 14:45:29.534 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
18-Apr-2025 14:45:29.553 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
18-Apr-2025 14:45:29.557 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
18-Apr-2025 14:45:29.908 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:45:29.937 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [626] milliseconds
|
||||
18-Apr-2025 14:45:29.997 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
18-Apr-2025 14:45:29.998 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
18-Apr-2025 14:45:30.021 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
18-Apr-2025 14:45:43.372 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
18-Apr-2025 14:46:30.445 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [60,422] ms
|
||||
18-Apr-2025 14:46:30.448 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
18-Apr-2025 14:46:30.489 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [40] ms
|
||||
18-Apr-2025 14:46:30.497 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:46:30.524 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [60589] milliseconds
|
||||
18-Apr-2025 14:48:15.644 INFO [Thread-5] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:48:15.649 INFO [Thread-5] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
|
||||
18-Apr-2025 14:48:16.499 SEVERE [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [org.springframework.boot.SpringBootExceptionHandler.LoggedExceptionHandlerThreadLocal] (value [org.springframework.boot.SpringBootExceptionHandler$LoggedExceptionHandlerThreadLocal@68d0e5a1]) and a value of type [org.springframework.boot.SpringBootExceptionHandler] (value [org.springframework.boot.SpringBootExceptionHandler@6bf4dac9]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
|
||||
18-Apr-2025 14:48:16.515 INFO [Thread-5] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:48:16.526 INFO [Thread-5] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:50:04.628 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
18-Apr-2025 14:50:04.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
18-Apr-2025 14:50:04.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
18-Apr-2025 14:50:04.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
18-Apr-2025 14:50:04.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
18-Apr-2025 14:50:04.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
18-Apr-2025 14:50:04.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
18-Apr-2025 14:50:04.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
18-Apr-2025 14:50:04.637 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
18-Apr-2025 14:50:04.637 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
18-Apr-2025 14:50:04.637 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
18-Apr-2025 14:50:04.650 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
18-Apr-2025 14:50:04.651 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
18-Apr-2025 14:50:04.651 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
18-Apr-2025 14:50:04.651 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
18-Apr-2025 14:50:04.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
18-Apr-2025 14:50:04.653 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
18-Apr-2025 14:50:04.653 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
18-Apr-2025 14:50:04.656 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
18-Apr-2025 14:50:04.661 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
18-Apr-2025 14:50:05.024 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:50:05.054 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [708] milliseconds
|
||||
18-Apr-2025 14:50:05.116 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
18-Apr-2025 14:50:05.117 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
18-Apr-2025 14:50:05.141 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
18-Apr-2025 14:50:23.688 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
18-Apr-2025 14:51:15.950 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [70,808] ms
|
||||
18-Apr-2025 14:51:15.956 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
18-Apr-2025 14:51:15.985 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [30] ms
|
||||
18-Apr-2025 14:51:15.992 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:51:16.020 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [70970] milliseconds
|
||||
18-Apr-2025 14:51:37.050 INFO [Thread-5] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:51:37.058 INFO [Thread-5] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
|
||||
18-Apr-2025 14:51:38.039 SEVERE [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [org.springframework.boot.SpringBootExceptionHandler.LoggedExceptionHandlerThreadLocal] (value [org.springframework.boot.SpringBootExceptionHandler$LoggedExceptionHandlerThreadLocal@1665f69a]) and a value of type [org.springframework.boot.SpringBootExceptionHandler] (value [org.springframework.boot.SpringBootExceptionHandler@67158754]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
|
||||
18-Apr-2025 14:51:38.047 INFO [Thread-5] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:51:38.057 INFO [Thread-5] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:53:17.329 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
18-Apr-2025 14:53:17.336 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
18-Apr-2025 14:53:17.336 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
18-Apr-2025 14:53:17.336 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
18-Apr-2025 14:53:17.336 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
18-Apr-2025 14:53:17.336 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
18-Apr-2025 14:53:17.336 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
18-Apr-2025 14:53:17.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
18-Apr-2025 14:53:17.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
18-Apr-2025 14:53:17.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
18-Apr-2025 14:53:17.337 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
18-Apr-2025 14:53:17.351 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
18-Apr-2025 14:53:17.351 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
18-Apr-2025 14:53:17.352 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
18-Apr-2025 14:53:17.352 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
18-Apr-2025 14:53:17.352 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
18-Apr-2025 14:53:17.352 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
18-Apr-2025 14:53:17.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
18-Apr-2025 14:53:17.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
18-Apr-2025 14:53:17.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
18-Apr-2025 14:53:17.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
18-Apr-2025 14:53:17.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
18-Apr-2025 14:53:17.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
18-Apr-2025 14:53:17.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
18-Apr-2025 14:53:17.354 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
18-Apr-2025 14:53:17.354 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
18-Apr-2025 14:53:17.359 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
18-Apr-2025 14:53:17.364 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
18-Apr-2025 14:53:17.765 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:53:17.807 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [770] milliseconds
|
||||
18-Apr-2025 14:53:17.902 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
18-Apr-2025 14:53:17.903 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
18-Apr-2025 14:53:17.949 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
18-Apr-2025 14:53:31.647 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
18-Apr-2025 14:54:10.823 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [52,873] ms
|
||||
18-Apr-2025 14:54:10.824 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
18-Apr-2025 14:54:10.839 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [15] ms
|
||||
18-Apr-2025 14:54:10.844 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:54:10.883 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [53079] milliseconds
|
||||
18-Apr-2025 14:55:42.003 INFO [Thread-5] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:55:42.011 INFO [Thread-5] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
|
||||
18-Apr-2025 14:55:42.785 SEVERE [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [org.springframework.boot.SpringBootExceptionHandler.LoggedExceptionHandlerThreadLocal] (value [org.springframework.boot.SpringBootExceptionHandler$LoggedExceptionHandlerThreadLocal@4499a303]) and a value of type [org.springframework.boot.SpringBootExceptionHandler] (value [org.springframework.boot.SpringBootExceptionHandler@55a8471b]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
|
||||
18-Apr-2025 14:55:42.796 INFO [Thread-5] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:55:42.806 INFO [Thread-5] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:57:24.205 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
18-Apr-2025 14:57:24.211 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
18-Apr-2025 14:57:24.211 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
18-Apr-2025 14:57:24.211 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
18-Apr-2025 14:57:24.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
18-Apr-2025 14:57:24.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
18-Apr-2025 14:57:24.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
18-Apr-2025 14:57:24.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
18-Apr-2025 14:57:24.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
18-Apr-2025 14:57:24.212 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
18-Apr-2025 14:57:24.213 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
18-Apr-2025 14:57:24.225 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
18-Apr-2025 14:57:24.225 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
18-Apr-2025 14:57:24.225 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
18-Apr-2025 14:57:24.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
18-Apr-2025 14:57:24.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
18-Apr-2025 14:57:24.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
18-Apr-2025 14:57:24.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
18-Apr-2025 14:57:24.226 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
18-Apr-2025 14:57:24.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
18-Apr-2025 14:57:24.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
18-Apr-2025 14:57:24.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
18-Apr-2025 14:57:24.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
18-Apr-2025 14:57:24.227 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
18-Apr-2025 14:57:24.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
18-Apr-2025 14:57:24.228 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
18-Apr-2025 14:57:24.233 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
18-Apr-2025 14:57:24.238 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
18-Apr-2025 14:57:24.647 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:57:24.679 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [714] milliseconds
|
||||
18-Apr-2025 14:57:24.756 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
18-Apr-2025 14:57:24.756 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
18-Apr-2025 14:57:24.793 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
18-Apr-2025 14:57:47.875 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
18-Apr-2025 14:58:39.770 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [74,974] ms
|
||||
18-Apr-2025 14:58:39.772 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
18-Apr-2025 14:58:39.797 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [25] ms
|
||||
18-Apr-2025 14:58:39.810 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:58:39.865 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [75190] milliseconds
|
||||
18-Apr-2025 14:59:18.937 INFO [Thread-5] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:59:18.944 INFO [Thread-5] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
|
||||
18-Apr-2025 14:59:19.923 SEVERE [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [org.springframework.boot.SpringBootExceptionHandler.LoggedExceptionHandlerThreadLocal] (value [org.springframework.boot.SpringBootExceptionHandler$LoggedExceptionHandlerThreadLocal@831147a]) and a value of type [org.springframework.boot.SpringBootExceptionHandler] (value [org.springframework.boot.SpringBootExceptionHandler@1c2c8399]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
|
||||
18-Apr-2025 14:59:19.942 INFO [Thread-5] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 14:59:19.958 INFO [Thread-5] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 15:00:51.636 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.40
|
||||
18-Apr-2025 15:00:51.643 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 1 2025 17:20:53 UTC
|
||||
18-Apr-2025 15:00:51.643 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.40.0
|
||||
18-Apr-2025 15:00:51.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
|
||||
18-Apr-2025 15:00:51.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 5.15.167.4-microsoft-standard-WSL2
|
||||
18-Apr-2025 15:00:51.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
|
||||
18-Apr-2025 15:00:51.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /opt/java/openjdk
|
||||
18-Apr-2025 15:00:51.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 17.0.14+7
|
||||
18-Apr-2025 15:00:51.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Eclipse Adoptium
|
||||
18-Apr-2025 15:00:51.645 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
|
||||
18-Apr-2025 15:00:51.645 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
|
||||
18-Apr-2025 15:00:51.655 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
|
||||
18-Apr-2025 15:00:51.655 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
|
||||
18-Apr-2025 15:00:51.656 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
|
||||
18-Apr-2025 15:00:51.657 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
18-Apr-2025 15:00:51.657 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
|
||||
18-Apr-2025 15:00:51.657 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
|
||||
18-Apr-2025 15:00:51.657 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
|
||||
18-Apr-2025 15:00:51.657 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
|
||||
18-Apr-2025 15:00:51.665 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [2.0.8] using APR version [1.7.2].
|
||||
18-Apr-2025 15:00:51.668 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.13 30 Jan 2024]
|
||||
18-Apr-2025 15:00:51.974 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 15:00:51.998 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [592] milliseconds
|
||||
18-Apr-2025 15:00:52.059 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
|
||||
18-Apr-2025 15:00:52.060 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.40]
|
||||
18-Apr-2025 15:00:52.081 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
|
||||
18-Apr-2025 15:01:15.491 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
|
||||
18-Apr-2025 15:02:15.015 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [82,933] ms
|
||||
18-Apr-2025 15:02:15.016 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/custom]
|
||||
18-Apr-2025 15:02:15.044 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/custom] has finished in [29] ms
|
||||
18-Apr-2025 15:02:15.049 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
|
||||
18-Apr-2025 15:02:15.126 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [83132] milliseconds
|
||||
|
230
services.py
230
services.py
@ -1,9 +1,11 @@
|
||||
# services.py
|
||||
import requests
|
||||
import os
|
||||
import tarfile
|
||||
import json
|
||||
import re
|
||||
import logging
|
||||
import shutil
|
||||
from flask import current_app, Blueprint, request, jsonify
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
@ -1442,71 +1444,245 @@ if __name__ == '__main__':
|
||||
print(f"\n--- Skipping Processing Test (Import failed for {pkg_name_to_test}#{pkg_version_to_test}) ---")
|
||||
|
||||
# Add new functions for GoFSH integration
|
||||
def run_gofsh(input_path, output_dir, output_style, log_level, fhir_version=None):
|
||||
"""Run GoFSH on the input FHIR resource and return the FSH output."""
|
||||
cmd = ["gofsh", input_path, "-o", output_dir, "-s", output_style, "-l", log_level]
|
||||
def run_gofsh(input_path, output_dir, output_style, log_level, fhir_version=None, fishing_trip=False, dependencies=None, indent_rules=False, meta_profile='only-one', alias_file=None, no_alias=False):
|
||||
"""Run GoFSH with advanced options and return FSH output and optional comparison report."""
|
||||
# Use a temporary output directory for initial GoFSH run
|
||||
temp_output_dir = tempfile.mkdtemp()
|
||||
os.chmod(temp_output_dir, 0o777)
|
||||
|
||||
cmd = ["gofsh", input_path, "-o", temp_output_dir, "-s", output_style, "-l", log_level]
|
||||
if fhir_version:
|
||||
cmd.extend(["-u", fhir_version])
|
||||
if dependencies:
|
||||
for dep in dependencies:
|
||||
cmd.extend(["--dependency", dep.strip()])
|
||||
if indent_rules:
|
||||
cmd.append("--indent")
|
||||
if no_alias:
|
||||
cmd.append("--no-alias")
|
||||
if alias_file:
|
||||
cmd.extend(["--alias-file", alias_file])
|
||||
if meta_profile != 'only-one':
|
||||
cmd.extend(["--meta-profile", meta_profile])
|
||||
|
||||
# Set environment to disable TTY interactions
|
||||
env = os.environ.copy()
|
||||
env["NODE_NO_READLINE"] = "1"
|
||||
env["NODE_NO_INTERACTIVE"] = "1"
|
||||
env["TERM"] = "dumb"
|
||||
env["CI"] = "true"
|
||||
env["FORCE_COLOR"] = "0"
|
||||
env["NODE_ENV"] = "production"
|
||||
|
||||
# Create a wrapper script in /tmp
|
||||
wrapper_script = "/tmp/gofsh_wrapper.sh"
|
||||
output_file = "/tmp/gofsh_output.log"
|
||||
try:
|
||||
with open(wrapper_script, 'w') as f:
|
||||
f.write("#!/bin/bash\n")
|
||||
# Redirect /dev/tty writes to /dev/null
|
||||
f.write("exec 3>/dev/null\n")
|
||||
f.write(" ".join([f'"{arg}"' for arg in cmd]) + f" </dev/null >{output_file} 2>&1\n")
|
||||
os.chmod(wrapper_script, 0o755)
|
||||
|
||||
# Log the wrapper script contents for debugging
|
||||
with open(wrapper_script, 'r') as f:
|
||||
logger.debug(f"Wrapper script contents:\n{f.read()}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create wrapper script {wrapper_script}: {str(e)}", exc_info=True)
|
||||
return None, None, f"Failed to create wrapper script: {str(e)}"
|
||||
|
||||
try:
|
||||
# Log directory contents before execution
|
||||
logger.debug(f"Temp output directory contents before GoFSH: {os.listdir(temp_output_dir)}")
|
||||
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
[wrapper_script],
|
||||
check=True,
|
||||
env=env
|
||||
)
|
||||
# Read all FSH files from the output directory
|
||||
# Read output from the log file
|
||||
with open(output_file, 'r', encoding='utf-8') as f:
|
||||
output = f.read()
|
||||
logger.debug(f"GoFSH output:\n{output}")
|
||||
|
||||
# Prepare final output directory
|
||||
if os.path.exists(output_dir):
|
||||
shutil.rmtree(output_dir)
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
os.chmod(output_dir, 0o777)
|
||||
|
||||
# Copy .fsh files, sushi-config.yaml, and input JSON to final output directory
|
||||
copied_files = []
|
||||
for root, _, files in os.walk(temp_output_dir):
|
||||
for file in files:
|
||||
src_path = os.path.join(root, file)
|
||||
if file.endswith(".fsh") or file == "sushi-config.yaml":
|
||||
relative_path = os.path.relpath(src_path, temp_output_dir)
|
||||
dst_path = os.path.join(output_dir, relative_path)
|
||||
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
|
||||
shutil.copy2(src_path, dst_path)
|
||||
copied_files.append(relative_path)
|
||||
|
||||
# Copy input JSON to final directory
|
||||
input_filename = os.path.basename(input_path)
|
||||
dst_input_path = os.path.join(output_dir, "input", input_filename)
|
||||
os.makedirs(os.path.dirname(dst_input_path), exist_ok=True)
|
||||
shutil.copy2(input_path, dst_input_path)
|
||||
copied_files.append(os.path.join("input", input_filename))
|
||||
|
||||
# Create a minimal sushi-config.yaml if missing
|
||||
sushi_config_path = os.path.join(output_dir, "sushi-config.yaml")
|
||||
if not os.path.exists(sushi_config_path):
|
||||
minimal_config = {
|
||||
"id": "fhirflare.temp",
|
||||
"canonical": "http://fhirflare.org",
|
||||
"name": "FHIRFLARETempIG",
|
||||
"version": "0.1.0",
|
||||
"fhirVersion": fhir_version or "4.0.1",
|
||||
"FSHOnly": True,
|
||||
"dependencies": dependencies or []
|
||||
}
|
||||
with open(sushi_config_path, 'w') as f:
|
||||
json.dump(minimal_config, f, indent=2)
|
||||
copied_files.append("sushi-config.yaml")
|
||||
|
||||
# Run GoFSH with --fshing-trip in a fresh temporary directory
|
||||
comparison_report = None
|
||||
if fishing_trip:
|
||||
fishing_temp_dir = tempfile.mkdtemp()
|
||||
os.chmod(fishing_temp_dir, 0o777)
|
||||
gofsh_fishing_cmd = ["gofsh", input_path, "-o", fishing_temp_dir, "-s", output_style, "-l", log_level, "--fshing-trip"]
|
||||
if fhir_version:
|
||||
gofsh_fishing_cmd.extend(["-u", fhir_version])
|
||||
if dependencies:
|
||||
for dep in dependencies:
|
||||
gofsh_fishing_cmd.extend(["--dependency", dep.strip()])
|
||||
if indent_rules:
|
||||
gofsh_fishing_cmd.append("--indent")
|
||||
if no_alias:
|
||||
gofsh_fishing_cmd.append("--no-alias")
|
||||
if alias_file:
|
||||
gofsh_fishing_cmd.extend(["--alias-file", alias_file])
|
||||
if meta_profile != 'only-one':
|
||||
gofsh_fishing_cmd.extend(["--meta-profile", meta_profile])
|
||||
|
||||
try:
|
||||
with open(wrapper_script, 'w') as f:
|
||||
f.write("#!/bin/bash\n")
|
||||
f.write("exec 3>/dev/null\n")
|
||||
f.write("exec >/dev/null 2>&1\n") # Suppress all output to /dev/tty
|
||||
f.write(" ".join([f'"{arg}"' for arg in gofsh_fishing_cmd]) + f" </dev/null >{output_file} 2>&1\n")
|
||||
os.chmod(wrapper_script, 0o755)
|
||||
|
||||
logger.debug(f"GoFSH fishing-trip wrapper script contents:\n{open(wrapper_script, 'r').read()}")
|
||||
|
||||
result = subprocess.run(
|
||||
[wrapper_script],
|
||||
check=True,
|
||||
env=env
|
||||
)
|
||||
with open(output_file, 'r', encoding='utf-8') as f:
|
||||
fishing_output = f.read()
|
||||
logger.debug(f"GoFSH fishing-trip output:\n{fishing_output}")
|
||||
|
||||
# Copy fshing-trip-comparison.html to final directory
|
||||
for root, _, files in os.walk(fishing_temp_dir):
|
||||
for file in files:
|
||||
if file.endswith(".html") and "fshing-trip-comparison" in file.lower():
|
||||
src_path = os.path.join(root, file)
|
||||
dst_path = os.path.join(output_dir, file)
|
||||
shutil.copy2(src_path, dst_path)
|
||||
copied_files.append(file)
|
||||
with open(dst_path, 'r', encoding='utf-8') as f:
|
||||
comparison_report = f.read()
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_output = ""
|
||||
if os.path.exists(output_file):
|
||||
with open(output_file, 'r', encoding='utf-8') as f:
|
||||
error_output = f.read()
|
||||
logger.error(f"GoFSH fishing-trip failed: {error_output}")
|
||||
return None, None, f"GoFSH fishing-trip failed: {error_output}"
|
||||
finally:
|
||||
if os.path.exists(fishing_temp_dir):
|
||||
shutil.rmtree(fishing_temp_dir, ignore_errors=True)
|
||||
|
||||
# Read FSH files from final output directory
|
||||
fsh_content = []
|
||||
for root, _, files in os.walk(output_dir):
|
||||
for file in files:
|
||||
if file.endswith(".fsh"):
|
||||
with open(os.path.join(root, file), 'r', encoding='utf-8') as f:
|
||||
fsh_content.append(f.read())
|
||||
fsh_output = "\n\n".join(fsh_content)
|
||||
|
||||
# Log copied files
|
||||
logger.debug(f"Copied files to final output directory: {copied_files}")
|
||||
|
||||
logger.info(f"GoFSH executed successfully for {input_path}")
|
||||
return "\n\n".join(fsh_content), None
|
||||
return fsh_output, comparison_report, None
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"GoFSH failed: {e.stderr}")
|
||||
return None, f"GoFSH failed: {e.stderr}"
|
||||
error_output = ""
|
||||
if os.path.exists(output_file):
|
||||
with open(output_file, 'r', encoding='utf-8') as f:
|
||||
error_output = f.read()
|
||||
logger.error(f"GoFSH failed: {error_output}")
|
||||
return None, None, f"GoFSH failed: {error_output}"
|
||||
except Exception as e:
|
||||
logger.error(f"Error running GoFSH: {str(e)}", exc_info=True)
|
||||
return None, f"Error running GoFSH: {str(e)}"
|
||||
return None, None, f"Error running GoFSH: {str(e)}"
|
||||
finally:
|
||||
# Clean up temporary files
|
||||
if os.path.exists(wrapper_script):
|
||||
os.remove(wrapper_script)
|
||||
if os.path.exists(output_file):
|
||||
os.remove(output_file)
|
||||
if os.path.exists(temp_output_dir):
|
||||
shutil.rmtree(temp_output_dir, ignore_errors=True)
|
||||
|
||||
def process_fhir_input(input_mode, fhir_file, fhir_text):
|
||||
"""Process user input (file or text) and save to a temporary file."""
|
||||
def process_fhir_input(input_mode, fhir_file, fhir_text, alias_file=None):
|
||||
"""Process user input (file or text) and save to temporary files."""
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
temp_file = None
|
||||
input_file = None
|
||||
alias_path = None
|
||||
|
||||
try:
|
||||
if input_mode == 'file' and fhir_file:
|
||||
content = fhir_file.read().decode('utf-8')
|
||||
file_type = 'json' if content.strip().startswith('{') else 'xml'
|
||||
temp_file = os.path.join(temp_dir, f"input.{file_type}")
|
||||
with open(temp_file, 'w', encoding='utf-8') as f:
|
||||
input_file = os.path.join(temp_dir, f"input.{file_type}")
|
||||
with open(input_file, 'w') as f:
|
||||
f.write(content)
|
||||
elif input_mode == 'text' and fhir_text:
|
||||
content = fhir_text.strip()
|
||||
file_type = 'json' if content.startswith('{') else 'xml'
|
||||
temp_file = os.path.join(temp_dir, f"input.{file_type}")
|
||||
with open(temp_file, 'w', encoding='utf-8') as f:
|
||||
file_type = 'json' if content.strip().startswith('{') else 'xml'
|
||||
input_file = os.path.join(temp_dir, f"input.{file_type}")
|
||||
with open(input_file, 'w') as f:
|
||||
f.write(content)
|
||||
else:
|
||||
return None, None, "No input provided"
|
||||
return None, None, None, "No input provided"
|
||||
|
||||
# Basic validation
|
||||
if file_type == 'json':
|
||||
try:
|
||||
json.loads(content)
|
||||
except json.JSONDecodeError:
|
||||
return None, None, "Invalid JSON format"
|
||||
return None, None, None, "Invalid JSON format"
|
||||
elif file_type == 'xml':
|
||||
try:
|
||||
ET.fromstring(content)
|
||||
except ET.ParseError:
|
||||
return None, None, "Invalid XML format"
|
||||
return None, None, None, "Invalid XML format"
|
||||
|
||||
logger.debug(f"Processed input: {temp_file}")
|
||||
return temp_file, temp_dir, None
|
||||
# Process alias file if provided
|
||||
if alias_file:
|
||||
alias_content = alias_file.read().decode('utf-8')
|
||||
alias_path = os.path.join(temp_dir, "aliases.fsh")
|
||||
with open(alias_path, 'w') as f:
|
||||
f.write(alias_content)
|
||||
|
||||
logger.debug(f"Processed input: {(input_file, alias_path)}")
|
||||
return input_file, temp_dir, alias_path, None
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing input: {str(e)}", exc_info=True)
|
||||
return None, None, f"Error processing input: {str(e)}"
|
||||
|
||||
return None, None, None, f"Error processing input: {str(e)}"
|
1
static/animations/loading-dark.json
Normal file
1
static/animations/loading-dark.json
Normal file
File diff suppressed because one or more lines are too long
49070
static/animations/loading-light.json
Normal file
49070
static/animations/loading-light.json
Normal file
File diff suppressed because it is too large
Load Diff
1
static/js/lottie.min.js
vendored
Normal file
1
static/js/lottie.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
299
static/uploads/fsh_output/fshing-trip-comparison.html
Normal file
299
static/uploads/fsh_output/fshing-trip-comparison.html
Normal file
@ -0,0 +1,299 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>FSHing Trip Comparison</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/github.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const targetElement = document.getElementById('diff');
|
||||
const diff2htmlUi = new Diff2HtmlUI(targetElement);
|
||||
diff2htmlUi.fileListToggle(false);
|
||||
diff2htmlUi.synchronisedScroll();
|
||||
diff2htmlUi.highlightCode();
|
||||
const diffs = document.getElementsByClassName('d2h-file-wrapper');
|
||||
for (const diff of diffs) {
|
||||
diff.innerHTML = `
|
||||
<details>
|
||||
<summary>${diff.getElementsByClassName('d2h-file-name')[0].innerHTML}</summary>
|
||||
${diff.innerHTML}
|
||||
</details>`
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body style="text-align: center; font-family: 'Source Sans Pro', sans-serif">
|
||||
<h1>FSHing Trip Comparison</a></h1>
|
||||
|
||||
<div id="diff">
|
||||
<div class="d2h-file-list-wrapper d2h-light-color-scheme">
|
||||
<div class="d2h-file-list-header">
|
||||
<span class="d2h-file-list-title">Files changed (1)</span>
|
||||
<a class="d2h-file-switch d2h-hide">hide</a>
|
||||
<a class="d2h-file-switch d2h-show">show</a>
|
||||
</div>
|
||||
<ol class="d2h-file-list">
|
||||
<li class="d2h-file-list-line">
|
||||
<span class="d2h-file-name-wrapper">
|
||||
<svg aria-hidden="true" class="d2h-icon d2h-moved" height="16" title="renamed" version="1.1"
|
||||
viewBox="0 0 14 16" width="14">
|
||||
<path d="M6 9H3V7h3V4l5 4-5 4V9z m8-7v12c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h12c0.55 0 1 0.45 1 1z m-1 0H1v12h12V2z"></path>
|
||||
</svg> <a href="#d2h-150321" class="d2h-file-name">../tmp/{tmp_k0pky49/input.json → tmp_hia6e3c/fsh-generated/data}/fsh-index.json</a>
|
||||
<span class="d2h-file-stats">
|
||||
<span class="d2h-lines-added">+10</span>
|
||||
<span class="d2h-lines-deleted">-0</span>
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div><div class="d2h-wrapper d2h-light-color-scheme">
|
||||
<div id="d2h-150321" class="d2h-file-wrapper" data-lang="json">
|
||||
<div class="d2h-file-header">
|
||||
<span class="d2h-file-name-wrapper">
|
||||
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
|
||||
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
|
||||
</svg> <span class="d2h-file-name">../tmp/{tmp_k0pky49/input.json → tmp_hia6e3c/fsh-generated/data}/fsh-index.json</span>
|
||||
<span class="d2h-tag d2h-moved d2h-moved-tag">RENAMED</span></span>
|
||||
<label class="d2h-file-collapse">
|
||||
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
|
||||
Viewed
|
||||
</label>
|
||||
</div>
|
||||
<div class="d2h-files-diff">
|
||||
<div class="d2h-file-side-diff">
|
||||
<div class="d2h-code-wrapper">
|
||||
<table class="d2h-diff-table">
|
||||
<tbody class="d2h-diff-tbody">
|
||||
<tr>
|
||||
<td class="d2h-code-side-linenumber d2h-info"></td>
|
||||
<td class="d2h-info">
|
||||
<div class="d2h-code-side-line">@@ -0,0 +1,10 @@</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
|
||||
|
||||
</td>
|
||||
<td class="d2h-cntx d2h-emptyplaceholder">
|
||||
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
|
||||
<span class="d2h-code-line-prefix"> </span>
|
||||
<span class="d2h-code-line-ctn"><br></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d2h-file-side-diff">
|
||||
<div class="d2h-code-wrapper">
|
||||
<table class="d2h-diff-table">
|
||||
<tbody class="d2h-diff-tbody">
|
||||
<tr>
|
||||
<td class="d2h-code-side-linenumber d2h-info"></td>
|
||||
<td class="d2h-info">
|
||||
<div class="d2h-code-side-line"> </div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
1
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn">[</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
2
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> {</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
3
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> "outputFile": "Condition-vkc.json",</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
4
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> "fshName": "vkc",</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
5
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> "fshType": "Instance",</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
6
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> "fshFile": "instances/vkc.fsh",</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
7
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> "startLine": 1,</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
8
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> "endLine": 15</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
9
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn"> }</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="d2h-code-side-linenumber d2h-ins">
|
||||
10
|
||||
</td>
|
||||
<td class="d2h-ins">
|
||||
<div class="d2h-code-side-line">
|
||||
<span class="d2h-code-line-prefix">+</span>
|
||||
<span class="d2h-code-line-ctn">]</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,3 @@
|
||||
Alias: $sct = http://snomed.info/sct
|
||||
Alias: $loinc = http://loinc.org
|
||||
Alias: $ihi-status-1 = https://healthterminologies.gov.au/fhir/CodeSystem/ihi-status-1
|
||||
Alias: $ihi-record-status-1 = https://healthterminologies.gov.au/fhir/CodeSystem/ihi-record-status-1
|
||||
Alias: $v2-0203 = http://terminology.hl7.org/CodeSystem/v2-0203
|
||||
Alias: $condition-clinical = http://terminology.hl7.org/CodeSystem/condition-clinical
|
||||
Alias: $condition-category = http://terminology.hl7.org/CodeSystem/condition-category
|
||||
Alias: $sct = http://snomed.info/sct
|
15
static/uploads/fsh_output/input/fsh/instances/vkc.fsh
Normal file
15
static/uploads/fsh_output/input/fsh/instances/vkc.fsh
Normal file
@ -0,0 +1,15 @@
|
||||
Instance: vkc
|
||||
InstanceOf: Condition
|
||||
Usage: #example
|
||||
* meta.profile = "http://hl7.org.au/fhir/core/StructureDefinition/au-core-condition"
|
||||
* clinicalStatus = $condition-clinical#active "Active"
|
||||
* category = $condition-category#encounter-diagnosis "Encounter Diagnosis"
|
||||
* severity = $sct#24484000 "Severe"
|
||||
* code = $sct#317349009 "Vernal keratoconjunctivitis"
|
||||
* bodySite = $sct#368601006 "Entire conjunctiva of left eye"
|
||||
* subject = Reference(Patient/italia-sofia)
|
||||
* onsetDateTime = "2023-10-01"
|
||||
* recordedDate = "2023-10-02"
|
||||
* recorder = Reference(PractitionerRole/generalpractitioner-guthridge-jarred)
|
||||
* asserter = Reference(PractitionerRole/generalpractitioner-guthridge-jarred)
|
||||
* note.text = "Itchy and burning eye, foreign body sensation. Mucoid discharge."
|
74
static/uploads/fsh_output/input/input.json
Normal file
74
static/uploads/fsh_output/input/input.json
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"resourceType": "Condition",
|
||||
"id": "vkc",
|
||||
"meta": {
|
||||
"profile": [
|
||||
"http://hl7.org.au/fhir/core/StructureDefinition/au-core-condition"
|
||||
]
|
||||
},
|
||||
"clinicalStatus": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/condition-clinical",
|
||||
"code": "active",
|
||||
"display": "Active"
|
||||
}
|
||||
]
|
||||
},
|
||||
"category": [
|
||||
{
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
|
||||
"code": "encounter-diagnosis",
|
||||
"display": "Encounter Diagnosis"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"severity": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"code": "24484000",
|
||||
"display": "Severe"
|
||||
}
|
||||
]
|
||||
},
|
||||
"code": {
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"code": "317349009",
|
||||
"display": "Vernal keratoconjunctivitis"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodySite": [
|
||||
{
|
||||
"coding": [
|
||||
{
|
||||
"system": "http://snomed.info/sct",
|
||||
"code": "368601006",
|
||||
"display": "Entire conjunctiva of left eye"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"subject": {
|
||||
"reference": "Patient/italia-sofia"
|
||||
},
|
||||
"onsetDateTime": "2023-10-01",
|
||||
"recordedDate": "2023-10-02",
|
||||
"recorder": {
|
||||
"reference": "PractitionerRole/generalpractitioner-guthridge-jarred"
|
||||
},
|
||||
"asserter": {
|
||||
"reference": "PractitionerRole/generalpractitioner-guthridge-jarred"
|
||||
},
|
||||
"note": [
|
||||
{
|
||||
"text": "Itchy and burning eye, foreign body sensation. Mucoid discharge."
|
||||
}
|
||||
]
|
||||
}
|
@ -1,26 +1,42 @@
|
||||
{# app/templates/_form_helpers.html #}
|
||||
{% macro render_field(field, label_visible=true) %}
|
||||
<div class="form-group mb-3"> {# Add margin bottom for spacing #}
|
||||
{% if label_visible and field.label %}
|
||||
{{ field.label(class="form-label") }} {# Render label with Bootstrap class #}
|
||||
{% endif %}
|
||||
|
||||
{# Add is-invalid class if errors exist #}
|
||||
{% set css_class = 'form-control ' + kwargs.pop('class', '') %}
|
||||
{% if field.errors %}
|
||||
{% set css_class = css_class + ' is-invalid' %}
|
||||
{% endif %}
|
||||
|
||||
{# Render the field itself, passing any extra attributes #}
|
||||
{{ field(class=css_class, **kwargs) }}
|
||||
|
||||
{# Display validation errors #}
|
||||
{% if field.errors %}
|
||||
<div class="invalid-feedback">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br>
|
||||
{% endfor %}
|
||||
<div class="form-group mb-3">
|
||||
{% if field.type == "BooleanField" %}
|
||||
<div class="form-check">
|
||||
{{ field(class="form-check-input" + (" is-invalid" if field.errors else ""), **kwargs) }}
|
||||
{% if label_visible and field.label %}
|
||||
<label class="form-check-label" for="{{ field.id }}">{{ field.label.text }}</label>
|
||||
{% endif %}
|
||||
{% if field.description %}
|
||||
<small class="form-text text-muted">{{ field.description }}</small>
|
||||
{% endif %}
|
||||
{% if field.errors %}
|
||||
<div class="invalid-feedback">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% if label_visible and field.label %}
|
||||
{{ field.label(class="form-label") }}
|
||||
{% endif %}
|
||||
{% set css_class = 'form-control ' + kwargs.pop('class', '') %}
|
||||
{% if field.errors %}
|
||||
{% set css_class = css_class + ' is-invalid' %}
|
||||
{% endif %}
|
||||
{{ field(class=css_class, **kwargs) }}
|
||||
{% if field.description %}
|
||||
<small class="form-text text-muted">{{ field.description }}</small>
|
||||
{% endif %}
|
||||
{% if field.errors %}
|
||||
<div class="invalid-feedback">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
60
templates/_fsh_output.html
Normal file
60
templates/_fsh_output.html
Normal file
@ -0,0 +1,60 @@
|
||||
{% from "_form_helpers.html" import render_field %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form id="fsh-converter-form" method="POST" enctype="multipart/form-data" class="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ render_field(form.package) }}
|
||||
{{ render_field(form.input_mode) }}
|
||||
<div id="file-upload" style="display: none;">
|
||||
{{ render_field(form.fhir_file) }}
|
||||
</div>
|
||||
<div id="text-input" style="display: none;">
|
||||
{{ render_field(form.fhir_text) }}
|
||||
</div>
|
||||
{{ render_field(form.output_style) }}
|
||||
{{ render_field(form.log_level) }}
|
||||
{{ render_field(form.fhir_version) }}
|
||||
{{ render_field(form.fishing_trip) }}
|
||||
{{ render_field(form.dependencies, placeholder="One per line, e.g., hl7.fhir.us.core@6.1.0") }}
|
||||
{{ render_field(form.indent_rules) }}
|
||||
{{ render_field(form.meta_profile) }}
|
||||
{{ render_field(form.alias_file) }}
|
||||
{{ render_field(form.no_alias) }}
|
||||
<div class="d-grid gap-2 d-sm-flex">
|
||||
{{ form.submit(class="btn btn-success", id="submit-btn") }}
|
||||
<a href="{{ url_for('index') }}" class="btn btn-secondary">Back</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if error %}
|
||||
<div class="alert alert-danger mt-4">{{ error }}</div>
|
||||
{% endif %}
|
||||
{% if fsh_output %}
|
||||
<div class="alert alert-success mt-4">Conversion successful!</div>
|
||||
<h3 class="mt-4">FSH Output</h3>
|
||||
<pre class="bg-light p-3">{{ fsh_output }}</pre>
|
||||
<a href="{{ url_for('download_fsh') }}" class="btn btn-primary">Download FSH</a>
|
||||
{% if comparison_report %}
|
||||
<h3 class="mt-4">Fishing Trip Comparison Report</h3>
|
||||
<a href="{{ url_for('static', filename='uploads/fsh_output/fshing-trip-comparison.html') }}" class="badge bg-primary text-white text-decoration-none mb-3" target="_blank">Click here for SUSHI Validation</a>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
{% if comparison_report.differences %}
|
||||
<p class="text-warning">Differences found in round-trip validation:</p>
|
||||
<ul>
|
||||
{% for diff in comparison_report.differences %}
|
||||
<li>{{ diff.path }}: {{ diff.description }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="text-success">No differences found in round-trip validation.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
@ -5,89 +5,819 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<title>{% if title %}{{ title }} - {% endif %}{{ site_name }}</title>
|
||||
<style>
|
||||
/* Default (Light Theme) Styles */
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background-color: #f8f9fa;
|
||||
color: #212529;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
main {
|
||||
flex-grow: 1;
|
||||
}
|
||||
h1, h5 {
|
||||
font-weight: 600;
|
||||
}
|
||||
.navbar-light {
|
||||
background-color: #ffffff !important;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
.navbar-brand {
|
||||
font-weight: bold;
|
||||
color: #007bff !important;
|
||||
}
|
||||
.nav-link {
|
||||
color: #333 !important;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
.nav-link:hover {
|
||||
color: #007bff !important;
|
||||
}
|
||||
.nav-link.active {
|
||||
color: #007bff !important;
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid #007bff;
|
||||
}
|
||||
.dropdown-menu {
|
||||
list-style: none !important;
|
||||
position: absolute;
|
||||
background-color: #ffffff;
|
||||
border: none;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
padding: 0;
|
||||
min-width: 160px;
|
||||
z-index: 1000;
|
||||
}
|
||||
.dropdown-item {
|
||||
padding: 0.5rem 1rem;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
.dropdown-item:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
.dropdown-item.active {
|
||||
background-color: #007bff;
|
||||
color: white !important;
|
||||
}
|
||||
.card {
|
||||
background-color: #ffffff;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
.card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
.text-muted {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
.form-check-input {
|
||||
width: 1.25rem !important;
|
||||
height: 1.25rem !important;
|
||||
margin-top: 0.25rem;
|
||||
display: inline-block !important;
|
||||
border: 1px solid #6c757d;
|
||||
}
|
||||
.form-check-input:checked {
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
.form-check-label {
|
||||
font-size: 1rem;
|
||||
margin-left: 0.5rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.form-check-label i {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
.form-check {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.navbar-controls {
|
||||
gap: 0.5rem;
|
||||
padding-right: 0;
|
||||
}
|
||||
/* Footer Styles */
|
||||
footer {
|
||||
background-color: #ffffff;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 1rem;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
.footer-left,
|
||||
.footer-right {
|
||||
display: inline-flex;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
}
|
||||
.footer-left a,
|
||||
.footer-right a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.footer-left a:hover,
|
||||
.footer-right a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(-10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
/* Alert Styles */
|
||||
.alert {
|
||||
border-radius: 8px;
|
||||
}
|
||||
.alert-danger {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
border-color: #f5c6cb;
|
||||
}
|
||||
.alert-success {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
border-color: #c3e6cb;
|
||||
}
|
||||
.alert-info {
|
||||
background-color: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border-color: #bee5eb;
|
||||
}
|
||||
|
||||
/* --- Unified Button and Badge Styles --- */
|
||||
|
||||
/* General Button Theme (Primary, Secondary) */
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
border-color: #004085;
|
||||
}
|
||||
.btn-outline-primary {
|
||||
color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
.btn-outline-primary:hover {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
border-color: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background-color: #5a6268;
|
||||
border-color: #545b62;
|
||||
}
|
||||
.btn-outline-secondary {
|
||||
color: #6c757d;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* --- Theme Styles for FSH Code Blocks --- */
|
||||
pre, pre code {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 0.875em;
|
||||
white-space: pre-wrap; /* Allow wrapping */
|
||||
word-break: break-all; /* Break long lines */
|
||||
}
|
||||
|
||||
/* Target pre blocks specifically used for FSH output if needed */
|
||||
/* If the pre block has a specific class or ID, use that */
|
||||
#fsh-output pre, /* Targets any pre within the output container */
|
||||
._fsh_output pre /* Targets any pre within the partial template content */
|
||||
{
|
||||
background-color: #e9ecef; /* Light theme background */
|
||||
color: #212529; /* Light theme text */
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
max-height: 600px; /* Adjust as needed */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#fsh-output pre code,
|
||||
._fsh_output pre code {
|
||||
background-color: transparent !important; /* Ensure code tag doesn't override pre bg */
|
||||
padding: 0;
|
||||
color: inherit; /* Inherit text color from pre */
|
||||
font-size: inherit; /* Inherit font size from pre */
|
||||
display: block; /* Make code fill pre */
|
||||
}
|
||||
|
||||
|
||||
/* Dark Theme Override */
|
||||
html[data-theme="dark"] #fsh-output pre,
|
||||
html[data-theme="dark"] ._fsh_output pre
|
||||
{
|
||||
background-color: #495057; /* Dark theme background */
|
||||
color: #f8f9fa; /* Dark theme text */
|
||||
border-color: #6c757d;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] #fsh-output pre code,
|
||||
html[data-theme="dark"] ._fsh_output pre code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* --- Theme Styles for FHIR UI Operations (fhir_ui_operations.html) --- */
|
||||
|
||||
/* Operation Block Container */
|
||||
.opblock {
|
||||
border: 1px solid #dee2e6; /* Light theme border */
|
||||
background: #ffffff; /* Light theme background */
|
||||
color: #212529; /* Light theme text */
|
||||
}
|
||||
html[data-theme="dark"] .opblock {
|
||||
border-color: #495057; /* Dark theme border */
|
||||
background: #343a40; /* Dark theme background (card bg) */
|
||||
color: #f8f9fa; /* Dark theme text */
|
||||
}
|
||||
|
||||
/* Operation Summary (Header) */
|
||||
.opblock-summary {
|
||||
background: #f8f9fa; /* Light theme summary bg */
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
color: #212529; /* Default text color for summary */
|
||||
}
|
||||
.opblock-summary:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
html[data-theme="dark"] .opblock-summary {
|
||||
background: #40464c; /* Darker summary bg */
|
||||
border-bottom-color: #495057;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
html[data-theme="dark"] .opblock-summary:hover {
|
||||
background: #495057;
|
||||
}
|
||||
/* Keep method badge colors fixed - DO NOT override .opblock-summary-method */
|
||||
.opblock-summary-description {
|
||||
color: #495057; /* Slightly muted description text */
|
||||
}
|
||||
html[data-theme="dark"] .opblock-summary-description {
|
||||
color: #adb5bd; /* Lighter muted text for dark */
|
||||
}
|
||||
|
||||
/* Operation Body (Expanded Section) */
|
||||
.opblock-body {
|
||||
border-top: 1px solid #dee2e6;
|
||||
}
|
||||
html[data-theme="dark"] .opblock-body {
|
||||
border-top-color: #495057;
|
||||
}
|
||||
|
||||
/* Section Headers within Body */
|
||||
.opblock-section-header {
|
||||
border-bottom: 1px solid #eee;
|
||||
color: inherit; /* Inherit from .opblock */
|
||||
}
|
||||
html[data-theme="dark"] .opblock-section-header {
|
||||
border-bottom-color: #495057;
|
||||
}
|
||||
.opblock-title {
|
||||
color: inherit; /* Inherit from .opblock */
|
||||
}
|
||||
|
||||
/* Parameters Table */
|
||||
.parameters-table th,
|
||||
.parameters-table td {
|
||||
border: 1px solid #dee2e6;
|
||||
color: inherit; /* Inherit from .opblock */
|
||||
}
|
||||
html[data-theme="dark"] .parameters-table th,
|
||||
html[data-theme="dark"] .parameters-table td {
|
||||
border-color: #495057;
|
||||
}
|
||||
.parameter__type,
|
||||
.parameter__in {
|
||||
color: #6c757d; /* Use standard muted color */
|
||||
}
|
||||
html[data-theme="dark"] .parameter__type,
|
||||
html[data-theme="dark"] .parameter__in {
|
||||
color: #adb5bd; /* Use standard dark muted color */
|
||||
}
|
||||
.parameters-col_description input[type="text"],
|
||||
.parameters-col_description input[type="number"] {
|
||||
background-color: #fff; /* Match light form controls */
|
||||
border: 1px solid #ced4da;
|
||||
color: #212529;
|
||||
}
|
||||
html[data-theme="dark"] .parameters-col_description input[type="text"],
|
||||
html[data-theme="dark"] .parameters-col_description input[type="number"] {
|
||||
background-color: #495057; /* Match dark form controls */
|
||||
border-color: #6c757d;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Request Body Textarea */
|
||||
.request-body-textarea {
|
||||
background-color: #fff; /* Match light form controls */
|
||||
border: 1px solid #ced4da;
|
||||
color: #212529;
|
||||
}
|
||||
html[data-theme="dark"] .request-body-textarea {
|
||||
background-color: #495057; /* Match dark form controls */
|
||||
border-color: #6c757d;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Responses Table */
|
||||
.responses-table th,
|
||||
.responses-table td {
|
||||
border: 1px solid #dee2e6;
|
||||
color: inherit;
|
||||
}
|
||||
html[data-theme="dark"] .responses-table th,
|
||||
html[data-theme="dark"] .responses-table td {
|
||||
border-color: #495057;
|
||||
}
|
||||
|
||||
/* Example/Schema Tabs & Controls */
|
||||
.response-control-media-type {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
html[data-theme="dark"] .response-control-media-type {
|
||||
background-color: #40464c; /* Match summary header bg */
|
||||
}
|
||||
.tablinks.badge { /* Default inactive tab */
|
||||
background: #dee2e6 !important; /* Light grey inactive */
|
||||
color: #333 !important;
|
||||
}
|
||||
.tablinks.badge.active { /* Default active tab */
|
||||
background: #007bff !important; /* Use primary color */
|
||||
color: white !important;
|
||||
}
|
||||
html[data-theme="dark"] .tablinks.badge { /* Dark inactive tab */
|
||||
background: #6c757d !important; /* Dark grey inactive */
|
||||
color: white !important;
|
||||
}
|
||||
html[data-theme="dark"] .tablinks.badge.active { /* Dark active tab */
|
||||
background: #4dabf7 !important; /* Use dark primary color */
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
/* Code/Output Blocks */
|
||||
.highlight-code,
|
||||
.request-url-output,
|
||||
.curl-output,
|
||||
.execute-wrapper pre.response-output-content {
|
||||
background: #e9ecef; /* Light theme pre background */
|
||||
color: #212529;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
html[data-theme="dark"] .highlight-code,
|
||||
html[data-theme="dark"] .request-url-output,
|
||||
html[data-theme="dark"] .curl-output,
|
||||
html[data-theme="dark"] .execute-wrapper pre.response-output-content {
|
||||
background: #495057; /* Dark theme pre background */
|
||||
color: #f8f9fa;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
|
||||
/* Narrative Response Box */
|
||||
.execute-wrapper div.response-output-narrative {
|
||||
background: #ffffff;
|
||||
color: #212529;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
html[data-theme="dark"] .execute-wrapper div.response-output-narrative {
|
||||
background: #343a40; /* Match card body */
|
||||
color: #f8f9fa;
|
||||
border: 1px solid #495057;
|
||||
}
|
||||
|
||||
/* Response Status Text */
|
||||
.execute-wrapper .response-status[style*="color: green"] { color: #198754 !important; }
|
||||
.execute-wrapper .response-status[style*="color: red"] { color: #dc3545 !important; }
|
||||
html[data-theme="dark"] .execute-wrapper .response-status[style*="color: green"] { color: #20c997 !important; }
|
||||
html[data-theme="dark"] .execute-wrapper .response-status[style*="color: red"] { color: #e63946 !important; }
|
||||
|
||||
|
||||
/* Specific Action Buttons (Success, Danger, Warning, Info) */
|
||||
.btn-success { background-color: #198754; border-color: #198754; color: white; }
|
||||
.btn-success:hover { background-color: #157347; border-color: #146c43; }
|
||||
.btn-outline-success { color: #198754; border-color: #198754; }
|
||||
.btn-outline-success:hover { background-color: #198754; color: white; }
|
||||
|
||||
.btn-danger { background-color: #dc3545; border-color: #dc3545; color: white; }
|
||||
.btn-danger:hover { background-color: #bb2d3b; border-color: #b02a37; }
|
||||
.btn-outline-danger { color: #dc3545; border-color: #dc3545; }
|
||||
.btn-outline-danger:hover { background-color: #dc3545; color: white; }
|
||||
|
||||
.btn-warning { background-color: #ffc107; border-color: #ffc107; color: #000; }
|
||||
.btn-warning:hover { background-color: #ffca2c; border-color: #ffc720; }
|
||||
.btn-outline-warning { color: #ffc107; border-color: #ffc107; }
|
||||
.btn-outline-warning:hover { background-color: #ffc107; color: #000; }
|
||||
|
||||
.btn-info { background-color: #0dcaf0; border-color: #0dcaf0; color: #000; }
|
||||
.btn-info:hover { background-color: #31d2f2; border-color: #25cff2; }
|
||||
.btn-outline-info { color: #0dcaf0; border-color: #0dcaf0; }
|
||||
.btn-outline-info:hover { background-color: #0dcaf0; color: #000; }
|
||||
|
||||
/* General Badge Theme */
|
||||
.badge {
|
||||
padding: 0.4em 0.6em; /* Slightly larger padding */
|
||||
font-size: 0.85em;
|
||||
font-weight: 600;
|
||||
}
|
||||
/* Specific Badge Backgrounds (Add more as needed) */
|
||||
.badge.bg-primary { background-color: #007bff !important; color: white !important; }
|
||||
.badge.bg-secondary { background-color: #6c757d !important; color: white !important; }
|
||||
.badge.bg-success { background-color: #198754 !important; color: white !important; }
|
||||
.badge.bg-danger { background-color: #dc3545 !important; color: white !important; }
|
||||
.badge.bg-warning { background-color: #ffc107 !important; color: #000 !important; }
|
||||
.badge.bg-info { background-color: #0dcaf0 !important; color: #000 !important; }
|
||||
.badge.bg-light { background-color: #f8f9fa !important; color: #000 !important; border: 1px solid #dee2e6; }
|
||||
.badge.bg-dark { background-color: #343a40 !important; color: white !important; }
|
||||
|
||||
/* Copy Button Specific Style */
|
||||
.btn-copy { /* Optional: Add a specific class if needed, or style .btn-outline-secondary directly */
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* --- Dark Theme Overrides --- */
|
||||
html[data-theme="dark"] .btn-primary { background-color: #4dabf7; border-color: #4dabf7; color: #000; }
|
||||
html[data-theme="dark"] .btn-primary:hover { background-color: #68bcef; border-color: #5fb7ea; }
|
||||
html[data-theme="dark"] .btn-outline-primary { color: #4dabf7; border-color: #4dabf7; }
|
||||
html[data-theme="dark"] .btn-outline-primary:hover { background-color: #4dabf7; color: #000; }
|
||||
|
||||
html[data-theme="dark"] .btn-secondary { background-color: #6c757d; border-color: #6c757d; color: white; }
|
||||
html[data-theme="dark"] .btn-secondary:hover { background-color: #5a6268; border-color: #545b62; }
|
||||
html[data-theme="dark"] .btn-outline-secondary { color: #adb5bd; border-color: #6c757d; } /* Lighter text/border */
|
||||
html[data-theme="dark"] .btn-outline-secondary:hover { background-color: #6c757d; color: white; }
|
||||
|
||||
html[data-theme="dark"] .btn-success { background-color: #20c997; border-color: #20c997; color: #000; }
|
||||
html[data-theme="dark"] .btn-success:hover { background-color: #3ce0ac; border-color: #36d8a3; }
|
||||
html[data-theme="dark"] .btn-outline-success { color: #20c997; border-color: #20c997; }
|
||||
html[data-theme="dark"] .btn-outline-success:hover { background-color: #20c997; color: #000; }
|
||||
|
||||
/* Keep danger as is */
|
||||
html[data-theme="dark"] .btn-danger { background-color: #e63946; border-color: #e63946; color: white; }
|
||||
html[data-theme="dark"] .btn-danger:hover { background-color: #c82b39; border-color: #bd2130; }
|
||||
html[data-theme="dark"] .btn-outline-danger { color: #e63946; border-color: #e63946; }
|
||||
html[data-theme="dark"] .btn-outline-danger:hover { background-color: #e63946; color: white; }
|
||||
|
||||
html[data-theme="dark"] .btn-warning { background-color: #ffca2c; border-color: #ffca2c; color: #000; }
|
||||
html[data-theme="dark"] .btn-warning:hover { background-color: #ffd24a; border-color: #ffce3d; }
|
||||
html[data-theme="dark"] .btn-outline-warning { color: #ffca2c; border-color: #ffca2c; }
|
||||
html[data-theme="dark"] .btn-outline-warning:hover { background-color: #ffca2c; color: #000; }
|
||||
|
||||
html[data-theme="dark"] .btn-info { background-color: #22b8cf; border-color: #22b8cf; color: #000; }
|
||||
html[data-theme="dark"] .btn-info:hover { background-color: #44cee3; border-color: #38cae0; }
|
||||
html[data-theme="dark"] .btn-outline-info { color: #22b8cf; border-color: #22b8cf; }
|
||||
html[data-theme="dark"] .btn-outline-info:hover { background-color: #22b8cf; color: #000; }
|
||||
|
||||
/* Dark Theme Badges */
|
||||
html[data-theme="dark"] .badge.bg-primary { background-color: #4dabf7 !important; color: #000 !important; }
|
||||
html[data-theme="dark"] .badge.bg-secondary { background-color: #6c757d !important; color: white !important; }
|
||||
html[data-theme="dark"] .badge.bg-success { background-color: #20c997 !important; color: #000 !important; }
|
||||
html[data-theme="dark"] .badge.bg-danger { background-color: #e63946 !important; color: white !important; }
|
||||
html[data-theme="dark"] .badge.bg-warning { background-color: #ffca2c !important; color: #000 !important; }
|
||||
html[data-theme="dark"] .badge.bg-info { background-color: #22b8cf !important; color: #000 !important; }
|
||||
html[data-theme="dark"] .badge.bg-light { background-color: #495057 !important; color: #f8f9fa !important; border: 1px solid #6c757d; }
|
||||
html[data-theme="dark"] .badge.bg-dark { background-color: #adb5bd !important; color: #000 !important; }
|
||||
|
||||
/* --- Themed Backgrounds for Code/Structure View (cp_view_processed_ig.html) --- */
|
||||
|
||||
/* Styling for <pre> blocks containing code */
|
||||
#raw-structure-wrapper pre,
|
||||
#example-content-wrapper pre {
|
||||
background-color: #e9ecef; /* Light theme background */
|
||||
color: #212529; /* Light theme text */
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
max-height: 400px; /* Keep existing max-height */
|
||||
overflow-y: auto; /* Keep existing overflow */
|
||||
white-space: pre-wrap; /* Ensure wrapping */
|
||||
word-break: break-all; /* Break long strings */
|
||||
}
|
||||
|
||||
/* Ensure code tag inside inherits background and has appropriate font */
|
||||
#raw-structure-wrapper pre code,
|
||||
#example-content-wrapper pre code {
|
||||
background-color: transparent !important; /* Let pre handle background */
|
||||
padding: 0;
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 0.875em;
|
||||
color: inherit; /* Inherit text color from pre */
|
||||
display: block; /* Make code block fill pre */
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* Styling for the Structure Definition tree list items */
|
||||
.structure-tree-root .list-group-item {
|
||||
background-color: #ffffff; /* Light theme default background */
|
||||
border-color: #dee2e6;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.structure-tree-root .list-group-item-warning {
|
||||
background-color: #fff3cd; /* Bootstrap light theme warning */
|
||||
border-color: #ffeeba;
|
||||
/*color: #856404; Ensure text is readable */
|
||||
}
|
||||
|
||||
/* --- Dark Theme Overrides for Code/Structure View --- */
|
||||
html[data-theme="dark"] #raw-structure-wrapper pre,
|
||||
html[data-theme="dark"] #example-content-wrapper pre {
|
||||
background-color: #495057; /* Dark theme background */
|
||||
color: #f8f9fa; /* Dark theme text */
|
||||
border-color: #6c757d;
|
||||
}
|
||||
|
||||
/* Dark theme code text color already inherited, but explicit doesn't hurt */
|
||||
html[data-theme="dark"] #raw-structure-wrapper pre code,
|
||||
html[data-theme="dark"] #example-content-wrapper pre code {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Dark theme structure list items */
|
||||
html[data-theme="dark"] .structure-tree-root .list-group-item {
|
||||
background-color: #343a40; /* Dark theme card background */
|
||||
border-color: #495057;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .structure-tree-root .list-group-item-warning {
|
||||
background-color: #664d03; /* Darker warning background */
|
||||
border-color: #997404;
|
||||
/*color: #ffecb5; Lighter text for contrast */
|
||||
}
|
||||
|
||||
/* Dark Theme Styles */
|
||||
html[data-theme="dark"] body {
|
||||
background-color: #212529;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
html[data-theme="dark"] .navbar-light {
|
||||
background-color: #343a40 !important;
|
||||
border-bottom: 1px solid #495057;
|
||||
}
|
||||
html[data-theme="dark"] .navbar-brand {
|
||||
color: #4dabf7 !important;
|
||||
}
|
||||
html[data-theme="dark"] .nav-link {
|
||||
color: #f8f9fa !important;
|
||||
}
|
||||
html[data-theme="dark"] .nav-link:hover,
|
||||
html[data-theme="dark"] .nav-link.active {
|
||||
color: #4dabf7 !important;
|
||||
border-bottom-color: #4dabf7;
|
||||
}
|
||||
html[data-theme="dark"] .dropdown-menu {
|
||||
background-color: #495057;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
html[data-theme="dark"] .dropdown-item {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
html[data-theme="dark"] .dropdown-item:hover {
|
||||
background-color: #6c757d;
|
||||
}
|
||||
html[data-theme="dark"] .dropdown-item.active {
|
||||
background-color: #4dabf7;
|
||||
color: white !important;
|
||||
}
|
||||
html[data-theme="dark"] .card {
|
||||
background-color: #343a40;
|
||||
border: 1px solid #495057;
|
||||
}
|
||||
html[data-theme="dark"] .text-muted {
|
||||
color: #adb5bd !important;
|
||||
}
|
||||
html[data-theme="dark"] h1,
|
||||
html[data-theme="dark"] h5 {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
html[data-theme="dark"] .form-label {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
html[data-theme="dark"] .form-control {
|
||||
background-color: #495057;
|
||||
color: #f8f9fa;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
html[data-theme="dark"] .form-control::placeholder {
|
||||
color: #adb5bd;
|
||||
}
|
||||
html[data-theme="dark"] .form-select {
|
||||
background-color: #495057;
|
||||
color: #f8f9fa;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
html[data-theme="dark"] .alert-danger {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border-color: #dc3545;
|
||||
}
|
||||
html[data-theme="dark"] .alert-success {
|
||||
background-color: #198754;
|
||||
color: white;
|
||||
border-color: #198754;
|
||||
}
|
||||
html[data-theme="dark"] .alert-info {
|
||||
background-color: #0dcaf0;
|
||||
color: white;
|
||||
border-color: #0dcaf0;
|
||||
}
|
||||
html[data-theme="dark"] .form-check-input {
|
||||
border-color: #adb5bd;
|
||||
}
|
||||
html[data-theme="dark"] .form-check-input:checked {
|
||||
background-color: #4dabf7;
|
||||
border-color: #4dabf7;
|
||||
}
|
||||
html[data-theme="dark"] footer {
|
||||
background-color: #343a40;
|
||||
border-top: 1px solid #495057;
|
||||
}
|
||||
html[data-theme="dark"] .footer-left a,
|
||||
html[data-theme="dark"] .footer-right a {
|
||||
color: #4dabf7;
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.navbar-controls {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-controls .form-check {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
footer {
|
||||
height: auto;
|
||||
padding: 0.5rem;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.footer-left,
|
||||
.footer-right {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.footer-left a,
|
||||
.footer-right a {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-4">
|
||||
<nav class="navbar navbar-expand-lg navbar-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="{{ url_for('index') }}">{{ site_name }}</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<div class="collapse navbar-collapse d-flex justify-content-between" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'index' else '' }}" aria-current="page" href="{{ url_for('index') }}"><i class="bi bi-house-door me-1"></i> Home</a>
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'index' else '' }}" aria-current="page" href="{{ url_for('index') }}"><i class="fas fa-house me-1"></i> Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'view_igs' else '' }}" href="{{ url_for('view_igs') }}"><i class="bi bi-journal-arrow-down me-1"></i> Manage FHIR Packages</a>
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'view_igs' else '' }}" href="{{ url_for('view_igs') }}"><i class="fas fa-folder-open me-1"></i> Manage FHIR Packages</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'import_ig' else '' }}" href="{{ url_for('import_ig') }}"><i class="bi bi-download me-1"></i> Import IGs</a>
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'import_ig' else '' }}" href="{{ url_for('import_ig') }}"><i class="fas fa-download me-1"></i> Import IGs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'push_igs' else '' }}" href="{{ url_for('push_igs') }}"><i class="bi bi-upload me-1"></i> Push IGs</a>
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'push_igs' else '' }}" href="{{ url_for('push_igs') }}"><i class="fas fa-upload me-1"></i> Push IGs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'validate_sample' else '' }}" href="{{ url_for('validate_sample') }}"><i class="bi bi-check-circle me-1"></i> Validate FHIR Sample</a>
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'validate_sample' else '' }}" href="{{ url_for('validate_sample') }}"><i class="fas fa-check-circle me-1"></i> Validate FHIR Sample</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'fhir_ui' else '' }}" href="{{ url_for('fhir_ui') }}"><i class="bi bi-cloud-arrow-down me-1"></i> FHIR API Explorer</a>
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'fhir_ui' else '' }}" href="{{ url_for('fhir_ui') }}"><i class="fas fa-cloud-download-alt me-1"></i> FHIR API Explorer</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'fhir_ui_operations' else '' }}" href="{{ url_for('fhir_ui_operations') }}"><i class="bi bi-gear me-1"></i> FHIR UI Operations</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'fsh_converter' else '' }}" href="{{ url_for('fsh_converter') }}"><i class="bi bi-file-code me-1"></i> FSH Converter</a>
|
||||
<a class="nav-link {{ 'active' if request.endpoint == 'fsh_converter' else '' }}" href="{{ url_for('fsh_converter') }}"><i class="fas fa-file-code me-1"></i> FSH Converter</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="navbar-controls d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="themeToggle" onchange="toggleTheme()" aria-label="Toggle dark mode" {% if request.cookies.get('theme') == 'dark' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="themeToggle">
|
||||
<i class="fas fa-sun"></i>
|
||||
<i class="fas fa-moon d-none"></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container flex-grow-1">
|
||||
<!-- Flashed Messages Section -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="mt-3">
|
||||
{% for category, message in messages %}
|
||||
<div class="alert
|
||||
{{ 'alert-danger' if category == 'error' else
|
||||
'alert-success' if category == 'success' else
|
||||
'alert-info' }}
|
||||
alert-dismissible fade show" role="alert">
|
||||
<!-- Add an icon based on the category -->
|
||||
<i class="bi
|
||||
{{ 'bi-exclamation-triangle-fill me-2' if category == 'error' else
|
||||
'bi-check-circle-fill me-2' if category == 'success' else
|
||||
'bi-info-circle-fill me-2' }}"></i>
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% block content %}{% endblock %}
|
||||
<main class="flex-grow-1">
|
||||
<div class="container mt-4">
|
||||
<!-- Flashed Messages Section -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="mt-3">
|
||||
{% for category, message in messages %}
|
||||
<div class="alert
|
||||
{{ 'alert-danger' if category == 'error' else
|
||||
'alert-success' if category == 'success' else
|
||||
'alert-info' }}
|
||||
alert-dismissible fade show" role="alert">
|
||||
<i class="fas
|
||||
{{ 'fa-exclamation-triangle me-2' if category == 'error' else
|
||||
'fa-check-circle me-2' if category == 'success' else
|
||||
'fa-info-circle me-2' }}"></i>
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="footer mt-auto py-3 bg-light">
|
||||
<div class="container text-center">
|
||||
{% set current_year = now.year %}
|
||||
<span class="text-muted">© {{ current_year }} {{ site_name }}. All rights reserved.</span>
|
||||
<footer class="main-footer" role="contentinfo">
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="footer-left">
|
||||
<a href="https://github.com/Sudo-JHare/FHIRFLARE-IG-Toolkit" target="_blank" rel="noreferrer" aria-label="Project Github">Project Github</a>
|
||||
<a href="/about" aria-label="Learn about this project">What is FHIRFLARE</a>
|
||||
<a href="https://www.hl7.org/fhir/" target="_blank" rel="noreferrer" aria-label="Visit FHIR website">FHIR</a>
|
||||
<a href="https://github.com/Sudo-JHare/FHIRFLARE-IG-Toolkit/issues/new/choose" class="text-danger text-decoration-none" aria-label="FHIRFLARE support"><i class="fas fa-exclamation-circle me-1"></i> Raise an Issue</a>
|
||||
</div>
|
||||
<div class="footer-right">
|
||||
<a href="https://github.com/Sudo-JHare/FHIRFLARE-IG-Toolkit/discussions" target="_blank" rel="noreferrer" aria-label="Project Discussion">Project Discussions</a>
|
||||
<a href="https://github.com/Sudo-JHare" aria-label="Developer">Developer</a>
|
||||
<a href="https://github.com/Sudo-JHare/FHIRFLARE-IG-Toolkit/blob/main/LICENSE.md" aria-label="License">License</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
function toggleTheme() {
|
||||
const html = document.documentElement;
|
||||
const toggle = document.getElementById('themeToggle');
|
||||
const sunIcon = document.querySelector('.fa-sun');
|
||||
const moonIcon = document.querySelector('.fa-moon');
|
||||
if (toggle.checked) {
|
||||
html.setAttribute('data-theme', 'dark');
|
||||
localStorage.setItem('theme', 'dark');
|
||||
sunIcon.classList.add('d-none');
|
||||
moonIcon.classList.remove('d-none');
|
||||
} else {
|
||||
html.removeAttribute('data-theme');
|
||||
localStorage.setItem('theme', 'light');
|
||||
sunIcon.classList.remove('d-none');
|
||||
moonIcon.classList.add('d-none');
|
||||
}
|
||||
// Set cookie to persist theme
|
||||
document.cookie = `theme=${toggle.checked ? 'dark' : 'light'}; path=/; max-age=31536000`;
|
||||
}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl) })
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const savedTheme = localStorage.getItem('theme') || (document.cookie.includes('theme=dark') ? 'dark' : 'light');
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
const sunIcon = document.querySelector('.fa-sun');
|
||||
const moonIcon = document.querySelector('.fa-moon');
|
||||
if (savedTheme === 'dark' && themeToggle) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
themeToggle.checked = true;
|
||||
sunIcon.classList.add('d-none');
|
||||
moonIcon.classList.remove('d-none');
|
||||
}
|
||||
const tooltips = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
tooltips.forEach(t => new bootstrap.Tooltip(t));
|
||||
});
|
||||
</script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
@ -147,11 +147,11 @@
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span>Raw Structure Definition for <code id="raw-structure-title"></code></span>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" id="copy-raw-def-button"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Copy Raw Definition JSON">
|
||||
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Copy Raw Definition JSON to clipboard</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary btn-copy" id="copy-raw-def-button"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Copy Raw Definition JSON">
|
||||
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Copy Raw Definition JSON to clipboard</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="raw-structure-loading" class="text-center py-3" style="display: none;">
|
||||
@ -179,22 +179,22 @@
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<h6>Raw Content</h6>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="copy-raw-content-button"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Copy Raw Content">
|
||||
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Copy raw example content to clipboard</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary btn-copy" id="copy-raw-def-button"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Copy Raw Definition JSON">
|
||||
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Copy Raw Definition JSON to clipboard</span>
|
||||
</button>
|
||||
</div>
|
||||
<pre><code id="example-content-raw" class="p-2 d-block border bg-light" style="max-height: 400px; overflow-y: auto;"></code></pre>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<h6>Pretty-Printed JSON</h6>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="copy-pretty-json-button"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Copy JSON">
|
||||
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Copy JSON example to clipboard</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary btn-copy" id="copy-pretty-json-button"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Copy JSON">
|
||||
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">Copy JSON example to clipboard</span>
|
||||
</button>
|
||||
</div>
|
||||
<pre><code id="example-content-json" class="p-2 d-block border bg-light" style="max-height: 400px; overflow-y: auto;"></code></pre>
|
||||
</div>
|
||||
|
@ -56,7 +56,7 @@
|
||||
<div class="mb-3" id="requestBodyGroup" style="display: none;">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<label for="requestBody" class="form-label me-2 mb-0">Request Body</label>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="copyRequestBody" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm btn-copy" id="copyRequestBody" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
|
||||
</div>
|
||||
<textarea class="form-control" id="requestBody" name="request_body" rows="6" placeholder="For POST: JSON resource (e.g., {'resourceType': 'Patient', ...}) or search params (e.g., name=John&birthdate=gt2000)"></textarea>
|
||||
<div id="jsonError" class="text-danger mt-1" style="display: none;"></div>
|
||||
@ -72,12 +72,12 @@
|
||||
<h5>Status: <span id="responseStatus" class="badge"></span></h5>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<h6 class="me-2 mb-0">Headers</h6>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="copyResponseHeaders" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm btn-copy" id="copyResponseHeaders" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
|
||||
</div>
|
||||
<pre id="responseHeaders" class="border p-2 bg-light mb-3" style="max-height: 200px; overflow-y: auto;"></pre>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<h6 class="me-2 mb-0">Body</h6>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="copyResponseBody" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm btn-copy" id="copyResponseBody" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
|
||||
</div>
|
||||
<pre id="responseBody" class="border p-2 bg-light" style="max-height: 400px; overflow-y: auto;"></pre>
|
||||
</div>
|
||||
|
@ -76,7 +76,10 @@
|
||||
.example-panel, .schema-panel { border: 1px solid #eee; border-radius: 4px; margin-top: -1px; }
|
||||
|
||||
/* Code Highlighting */
|
||||
/*
|
||||
.highlight-code { background: #333; color: #f8f8f2; padding: 10px; border-radius: 4px; overflow-x: auto; font-family: monospace; margin: 0; }
|
||||
*/
|
||||
/* Keep the .highlight-code pre rule below it if desired, although the theme styles should handle it */
|
||||
.highlight-code pre { margin: 0; padding: 0; background: transparent; border: none; font-family: inherit; font-size: inherit; color: inherit; }
|
||||
|
||||
/* Execution Response */
|
||||
@ -335,7 +338,59 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
let currentSelectedResource = '';
|
||||
let availableSystemOperations = [];
|
||||
let fetchedMetadataCache = null;
|
||||
let operationDefinitionCache = {}; // <<< ADD THIS LINE: Cache for fetched OperationDefinitions
|
||||
|
||||
// <<< ADD THIS NEW ASYNC FUNCTION >>>
|
||||
async function fetchOperationDefinition(url) {
|
||||
if (!url) return null; // No definition URL provided
|
||||
|
||||
// Check cache first
|
||||
if (operationDefinitionCache.hasOwnProperty(url)) {
|
||||
console.log(`Using cached OperationDefinition: ${url}`);
|
||||
return operationDefinitionCache[url]; // Return cached definition (could be null if fetch failed before)
|
||||
}
|
||||
|
||||
// Determine actual fetch URL
|
||||
// Simplification: Assume the URL is directly fetchable or the /fhir proxy handles it if relative.
|
||||
// Production code might need more robust logic to handle base URLs.
|
||||
const fetchUrl = url;
|
||||
console.log(`Fetching OperationDefinition: ${fetchUrl}`);
|
||||
|
||||
try {
|
||||
const response = await fetch(fetchUrl, {
|
||||
headers: { 'Accept': 'application/fhir+json' }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
// Don't cache HTTP errors permanently, maybe allow retry later?
|
||||
// For now, just log and return null.
|
||||
console.error(`HTTP ${response.status} fetching OperationDefinition ${url}`);
|
||||
operationDefinitionCache[url] = null; // Cache failure for this session
|
||||
return null;
|
||||
}
|
||||
|
||||
const definition = await response.json();
|
||||
|
||||
if (definition.resourceType !== 'OperationDefinition') {
|
||||
console.error(`Expected OperationDefinition, got ${definition.resourceType} from ${url}`);
|
||||
operationDefinitionCache[url] = null; // Cache invalid response
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`Successfully fetched and parsed OperationDefinition: ${url}`);
|
||||
operationDefinitionCache[url] = definition; // Cache successful fetch
|
||||
return definition;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch or parse OperationDefinition ${url}:`, error);
|
||||
operationDefinitionCache[url] = null; // Cache fetch/parse failure
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// <<< END OF NEW FUNCTION >>>
|
||||
|
||||
|
||||
|
||||
// --- Helper Function to Update Toggle Button/Input UI ---
|
||||
function updateServerToggleUI() {
|
||||
if (!toggleLabel || !fhirServerUrlInput) {
|
||||
@ -374,25 +429,75 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
console.error("Toggle server button (#toggleServer) not found!");
|
||||
}
|
||||
|
||||
// --- Generate Query Examples (Unchanged) ---
|
||||
// --- Generate Query Examples (Defining sinceParam) ---
|
||||
function getQueryExamplesForResourceType(resourceType) {
|
||||
if (!fetchedMetadataCache?.rest?.[0]) return [];
|
||||
const restSection = fetchedMetadataCache.rest[0];
|
||||
const resourceMetadata = restSection.resource?.find(r => r.type === resourceType);
|
||||
const supportedInteractions = resourceMetadata?.interaction?.map(i => i.code) || [];
|
||||
const resourceSpecificOperations = resourceMetadata?.operation || [];
|
||||
const allSearchParameters = resourceMetadata?.searchParam || [];
|
||||
|
||||
if (!resourceMetadata) {
|
||||
console.warn(`No metadata found for resource type: ${resourceType}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
const supportedInteractions = resourceMetadata.interaction?.map(i => i.code) || [];
|
||||
const resourceSpecificOperations = resourceMetadata.operation || [];
|
||||
const allSearchParameters = resourceMetadata.searchParam || [];
|
||||
const queries = [];
|
||||
|
||||
// --- Define Standard Parameters ---
|
||||
const formatParam = { name: '_format', in: 'query', type: 'string', required: false, description: 'Response format (e.g., json, xml)', example: 'json' };
|
||||
const idPathParam = { name: 'id', in: 'path', type: 'string', required: true, description: 'Resource logical ID', example: 'example' };
|
||||
const versionIdPathParam = { name: 'version_id', in: 'path', type: 'string', required: true, description: 'Version ID', example: '1' };
|
||||
const countQueryParam = { name: '_count', in: 'query', type: 'integer', required: false, description: 'Results per page', example: '10' };
|
||||
const idQueryParam = { name: '_id', in: 'query', type: 'string', required: false, description: 'Search by ID', example: 'example' };
|
||||
const lastUpdatedQueryParam = { name: '_lastUpdated', in: 'query', type: 'date', required: false, description: 'Last updated date', example: 'ge2024-01-01' };
|
||||
const commonSearchParams = [idQueryParam, lastUpdatedQueryParam];
|
||||
const specificSearchParams = allSearchParameters.filter(sp => !['_id', '_lastUpdated'].includes(sp.name)).slice(0, 3).map(sp => ({ name: sp.name, in: 'query', type: sp.type, required: false, description: sp.documentation || `Search by ${sp.name} (${sp.type})`, example: `${sp.type}-example` }));
|
||||
const searchGetParams = [countQueryParam, formatParam, ...commonSearchParams, ...specificSearchParams];
|
||||
const sinceParam = { name: '_since', in: 'query', type: 'instant', required: false, description: 'Only return updates after this time', example: new Date().toISOString() }; // <<< DEFINE sinceParam HERE
|
||||
|
||||
// --- Define Common Search Parameters Separately ---
|
||||
const commonStandardParams = [
|
||||
{ name: '_id', in: 'query', type: 'token', required: false, description: 'Search by resource logical ID', example: 'example' },
|
||||
{ name: '_lastUpdated', in: 'query', type: 'date', required: false, description: 'Search by last updated date', example: 'ge2024-01-01' },
|
||||
{ name: '_profile', in: 'query', type: 'uri', required: false, description: 'Search by profile canonical URL', example: ''},
|
||||
{ name: '_tag', in: 'query', type: 'token', required: false, description: 'Search by tag (code or system|code)', example: ''},
|
||||
{ name: '_security', in: 'query', type: 'token', required: false, description: 'Search by security label (system|code)', example: ''},
|
||||
{ name: '_text', in: 'query', type: 'string', required: false, description: 'Search narrative content', example: ''},
|
||||
{ name: '_content', in: 'query', type: 'string', required: false, description: 'Search all resource content', example: ''},
|
||||
{ name: '_list', in: 'query', type: 'string', required: false, description: 'Search within a list', example: ''},
|
||||
{ name: '_has', in: 'query', type: 'string', required: false, description: 'Reverse chaining search', example: ''},
|
||||
{ name: '_type', in: 'query', type: 'string', required: false, description: 'Specify resource type (in compartment search)', example: resourceType },
|
||||
{ name: '_source', in: 'query', type: 'uri', required: false, description: 'Search by source URI', example: ''},
|
||||
{ name: '_filter', in: 'query', type: 'string', required: false, description: 'Advanced search filter', example: ''}
|
||||
];
|
||||
const commonStandardParamNames = new Set(commonStandardParams.map(p => p.name));
|
||||
|
||||
// --- Map ALL Search Parameters from Metadata ---
|
||||
const specificSearchParams = allSearchParameters
|
||||
.map(sp => ({
|
||||
name: sp.name,
|
||||
in: 'query',
|
||||
type: sp.type,
|
||||
required: false,
|
||||
description: sp.documentation || `Search by ${sp.name} (${sp.type})`,
|
||||
example: sp.type === 'reference' ? `${resourceType}/example` :
|
||||
sp.type === 'token' ? 'system|code' :
|
||||
sp.type === 'date' ? '2024-01-01' :
|
||||
sp.type === 'number' ? '10' :
|
||||
sp.type === 'quantity' ? '5|mg' :
|
||||
sp.type === 'uri' ? 'http://example.com' :
|
||||
''
|
||||
}));
|
||||
|
||||
// Combine common params (_count, _format), specific params from metadata, and standard _params
|
||||
const allUniqueParamsMap = new Map();
|
||||
specificSearchParams.forEach(p => allUniqueParamsMap.set(p.name, p));
|
||||
commonStandardParams.forEach(p => { if (!allUniqueParamsMap.has(p.name)) allUniqueParamsMap.set(p.name, p); });
|
||||
if (!allUniqueParamsMap.has(countQueryParam.name)) allUniqueParamsMap.set(countQueryParam.name, countQueryParam);
|
||||
if (!allUniqueParamsMap.has(formatParam.name)) allUniqueParamsMap.set(formatParam.name, formatParam);
|
||||
|
||||
const searchGetParams = Array.from(allUniqueParamsMap.values()).sort((a, b) => a.name.localeCompare(b.name));
|
||||
const searchPostParams = [countQueryParam, formatParam];
|
||||
|
||||
// --- Define Example Schemas and Payloads ---
|
||||
// (Keep existing schema/payload definitions)
|
||||
const baseExample = { resourceType, id: "example", text: { status: "generated", div: `<div xmlns="http://www.w3.org/1999/xhtml">Example ${resourceType}</div>` } };
|
||||
const baseExampleString = JSON.stringify(baseExample, null, 2);
|
||||
const createExampleString = JSON.stringify({ ...baseExample, id: undefined }, null, 2);
|
||||
@ -404,7 +509,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const bundleHistoryExample = JSON.stringify({ resourceType: "Bundle", type: "history", total: 1, entry: [{ resource: baseExample }] }, null, 2);
|
||||
const patchExample = JSON.stringify({ resourceType: "Parameters", parameter: [{ name: "operation", part: [{ name: 'type', valueCode: 'replace' }, { name: 'path', valueString: `${resourceType}.active` }, { name: 'value', valueBoolean: false }] }] }, null, 2);
|
||||
const deleteExample = JSON.stringify({ resourceType: "OperationOutcome", issue: [{ severity: "information", code: "informational", diagnostics: "Successful deletion" }] }, null, 2);
|
||||
const postSearchExample = searchGetParams.filter(p => p.in === 'query' && p.example).map(p => `${p.name}=${encodeURIComponent(p.example)}`).join('&');
|
||||
const postSearchExample = searchGetParams
|
||||
.filter(p => p.in === 'query' && p.example && !['_count', '_format'].includes(p.name))
|
||||
.map(p => `${p.name}=${encodeURIComponent(p.example)}`)
|
||||
.join('&');
|
||||
|
||||
// --- Define Interaction Map ---
|
||||
// (Use the defined sinceParam variable)
|
||||
const interactionMap = {
|
||||
'read': { label: `Read ${resourceType}`, method: 'GET', path: `${resourceType}/:id`, description: `Read a ${resourceType} by ID`, parameters: [idPathParam, formatParam], schema: baseSchema, example: baseExampleString },
|
||||
'vread': { label: `VRead ${resourceType}`, method: 'GET', path: `${resourceType}/:id/_history/:version_id`, description: `Read specific version`, parameters: [idPathParam, versionIdPathParam, formatParam], schema: baseSchema, example: JSON.stringify({ ...baseExample, meta: { versionId: "1" } }, null, 2) },
|
||||
@ -413,181 +524,178 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
'delete': { label: `Delete ${resourceType}`, method: 'DELETE', path: `${resourceType}/:id`, description: `Delete ${resourceType}`, parameters: [idPathParam, formatParam], schema: outcomeSchema, example: deleteExample },
|
||||
'create': { label: `Create ${resourceType}`, method: 'POST', path: `${resourceType}`, description: `Create new ${resourceType}`, parameters: [formatParam], requestBody: true, schema: baseSchema, example: createExampleString },
|
||||
'search-type': { label: `Search ${resourceType} (GET)`, method: 'GET', path: `${resourceType}`, description: `Search ${resourceType} using GET`, parameters: searchGetParams, schema: bundleSchema, example: bundleSearchExample },
|
||||
'history-type': { label: `Type History ${resourceType}`, method: 'GET', path: `${resourceType}/_history`, description: `History for all ${resourceType}`, parameters: [countQueryParam, formatParam, lastUpdatedQueryParam], schema: bundleSchema, example: bundleHistoryExample },
|
||||
'history-instance': { label: `Instance History ${resourceType}`, method: 'GET', path: `${resourceType}/:id/_history`, description: `History for specific ${resourceType}`, parameters: [idPathParam, countQueryParam, formatParam, lastUpdatedQueryParam], schema: bundleSchema, example: bundleHistoryExample },
|
||||
'history-type': { label: `Type History ${resourceType}`, method: 'GET', path: `${resourceType}/_history`, description: `History for all ${resourceType}`, parameters: [countQueryParam, formatParam, sinceParam], schema: bundleSchema, example: bundleHistoryExample }, // <<< Use sinceParam
|
||||
'history-instance': { label: `Instance History ${resourceType}`, method: 'GET', path: `${resourceType}/:id/_history`, description: `History for specific ${resourceType}`, parameters: [idPathParam, countQueryParam, formatParam, sinceParam], schema: bundleSchema, example: bundleHistoryExample }, // <<< Use sinceParam
|
||||
};
|
||||
|
||||
// --- Build Query List ---
|
||||
// (Rest of the function remains the same)
|
||||
supportedInteractions.forEach(code => { if (interactionMap[code]) queries.push(interactionMap[code]); });
|
||||
if (supportedInteractions.includes('search-type')) { queries.push({ label: `Search ${resourceType} (POST)`, method: 'POST', path: `${resourceType}/_search`, description: `Search ${resourceType} using POST`, parameters: searchPostParams, requestBody: true, schema: bundleSchema, example: postSearchExample }); }
|
||||
resourceSpecificOperations.forEach(opDef => { const opName = opDef.name.startsWith('$') ? opDef.name : `$${opDef.name}`; const opDoc = opDef.documentation || `Execute ${opName} on ${resourceType}`; const opExample = JSON.stringify({ resourceType: "Parameters", parameter: [{ name: "example-param", valueString: "example-value" }] }, null, 2); const opMethod = opDef.definition?.toLowerCase().includes('get') ? 'GET' : 'POST'; const isInstanceLevel = opDef.definition?.toLowerCase().includes('/{id}/$'); queries.push({ label: `${opName} (${isInstanceLevel ? 'Instance' : 'Type'})`, method: opMethod, path: isInstanceLevel ? `${resourceType}/:id/${opName}` : `${resourceType}/${opName}`, description: opDoc, parameters: isInstanceLevel ? [idPathParam, formatParam] : [formatParam], requestBody: opMethod !== 'GET', schema: paramsSchema, example: opExample }); });
|
||||
availableSystemOperations.forEach(op => { const opName = op.name.startsWith('$') ? op.name : `$${op.name}`; const opParams = [formatParam]; const opExample = JSON.stringify({ resourceType: "Parameters", parameter: [{ name: "info", valueString: `Input for ${opName}` }] }, null, 2); if (op.levels.includes('type')) { op.methods.forEach(method => { queries.push({ label: `${opName} (Type)`, method, path: `${resourceType}/${opName}`, description: op.documentation || `Type-level ${opName} on ${resourceType}`, parameters: opParams, requestBody: method !== 'GET', schema: paramsSchema, example: opExample }); }); } if (op.levels.includes('instance')) { op.methods.forEach(method => { queries.push({ label: `${opName} (Instance)`, method, path: `${resourceType}/:id/${opName}`, description: op.documentation || `Instance-level ${opName} on ${resourceType}`, parameters: [idPathParam, ...opParams], requestBody: method !== 'GET', schema: paramsSchema, example: opExample }); }); } });
|
||||
if (supportedInteractions.includes('search-type')) { queries.push({ label: `Search ${resourceType} (POST)`, method: 'POST', path: `${resourceType}/_search`, description: `Search ${resourceType} using POST (parameters in x-www-form-urlencoded body)`, parameters: searchPostParams, requestBody: true, schema: bundleSchema, example: postSearchExample }); }
|
||||
resourceSpecificOperations.forEach(opDef => { const opName = opDef.name.startsWith('$') ? opDef.name : `$${opDef.name}`; const opDoc = opDef.documentation || `Execute ${opName} on ${resourceType}`; const opExample = JSON.stringify({ resourceType: "Parameters", parameter: [{ name: "example-param", valueString: "example-value" }] }, null, 2); const opMethod = opDef.definition?.toLowerCase().includes('get') ? 'GET' : 'POST'; const isInstanceLevel = opDef.definition?.toLowerCase().includes('/{id}/$') || opDef.instance === true; const opParams = [formatParam]; if (isInstanceLevel) opParams.unshift(idPathParam); queries.push({ label: `${opName} (${isInstanceLevel ? 'Instance' : 'Type'})`, method: opMethod, path: isInstanceLevel ? `${resourceType}/:id/${opName}` : `${resourceType}/${opName}`, description: opDoc, parameters: opParams, requestBody: opMethod !== 'GET', schema: paramsSchema, example: opExample }); });
|
||||
availableSystemOperations.forEach(op => { const opName = op.name.startsWith('$') ? op.name : `$${op.name}`; const opParams = [formatParam]; const opExample = JSON.stringify({ resourceType: "Parameters", parameter: [{ name: "info", valueString: `Input for ${opName}` }] }, null, 2); if (op.levels.includes('type')) { op.methods.forEach(method => { queries.push({ label: `${opName} (Type)`, method: method, path: `${resourceType}/${opName}`, description: op.documentation || `Type-level ${opName} on ${resourceType}`, parameters: opParams, requestBody: method !== 'GET', schema: paramsSchema, example: opExample }); }); } if (op.levels.includes('instance')) { op.methods.forEach(method => { queries.push({ label: `${opName} (Instance)`, method: method, path: `${resourceType}/:id/${opName}`, description: op.documentation || `Instance-level ${opName} on ${resourceType}`, parameters: [idPathParam, ...opParams], requestBody: method !== 'GET', schema: paramsSchema, example: opExample }); }); } });
|
||||
return queries.filter((q, i, arr) => i === arr.findIndex(x => x.path === q.path && x.method === q.method));
|
||||
}
|
||||
} // End getQueryExamplesForResourceType
|
||||
|
||||
// --- Generate System-Level Queries (Revised based on metadata example) ---
|
||||
function getSystemLevelQueries() {
|
||||
if (!fetchedMetadataCache?.rest?.[0]) return [];
|
||||
// --- Generate System-Level Queries (ASYNC VERSION fetching OperationDefinitions - CORRECTED) ---
|
||||
async function getSystemLevelQueries() { // Added async keyword
|
||||
if (!fetchedMetadataCache?.rest?.[0]) return [];
|
||||
|
||||
const restSection = fetchedMetadataCache.rest[0];
|
||||
const supportedInteractions = restSection.interaction?.map(i => i.code) || [];
|
||||
const queries = [];
|
||||
const addedPaths = new Set(); // Track METHOD + PATH to avoid duplicates
|
||||
const restSection = fetchedMetadataCache.rest[0];
|
||||
const supportedInteractions = restSection.interaction?.map(i => i.code) || [];
|
||||
const queries = [];
|
||||
const addedPaths = new Set();
|
||||
|
||||
const formatParam = { name: '_format', in: 'query', type: 'string', required: false, description: 'Response format', example: 'json' };
|
||||
const countParam = { name: '_count', in: 'query', type: 'integer', required: false, description: 'Results per page', example: '10' };
|
||||
const sinceParam = { name: '_since', in: 'query', type: 'instant', required: false, description: 'Changes after this time', example: new Date().toISOString() };
|
||||
const contentParam = { name: '_content', in: 'query', type: 'string', required: false, description: 'Search content', example: 'example' };
|
||||
const paramsSchema = { resourceType: "Parameters" };
|
||||
const paramsExample = JSON.stringify({ resourceType: "Parameters", parameter: [] }, null, 2);
|
||||
// --- Define Common & Specific Parameters ---
|
||||
const formatParam = { name: '_format', in: 'query', type: 'string', required: false, description: 'Response format', example: 'json' };
|
||||
const countParam = { name: '_count', in: 'query', type: 'integer', required: false, description: 'Results per page', example: '10' };
|
||||
const sinceParam = { name: '_since', in: 'query', type: 'instant', required: false, description: 'Changes after this time', example: new Date().toISOString() };
|
||||
const contentParam = { name: '_content', in: 'query', type: 'string', required: false, description: 'Search content', example: 'example' };
|
||||
const defaultParamsSchema = { resourceType: "Parameters" }; // Default schema
|
||||
const defaultParamsExample = JSON.stringify({ resourceType: "Parameters", parameter: [] }, null, 2); // Default example
|
||||
|
||||
// --- Add Metadata (Capabilities) Operation ---
|
||||
// Always include GET /metadata as it's a standard FHIR endpoint
|
||||
const metadataPath = 'metadata';
|
||||
const metadataKey = `GET/${metadataPath}`;
|
||||
if (!addedPaths.has(metadataKey)) {
|
||||
queries.push({
|
||||
name: 'metadata',
|
||||
label: 'GET /metadata',
|
||||
method: 'GET',
|
||||
path: metadataPath,
|
||||
description: 'server-capabilities: Fetch the server FHIR CapabilityStatement',
|
||||
parameters: [formatParam],
|
||||
schema: { resourceType: "CapabilityStatement" },
|
||||
example: JSON.stringify(fetchedMetadataCache || { resourceType: "CapabilityStatement" }, null, 2)
|
||||
});
|
||||
addedPaths.add(metadataKey);
|
||||
}
|
||||
|
||||
// --- Add Other Standard System Interactions ---
|
||||
// Transaction/Batch
|
||||
if (supportedInteractions.includes('transaction') || supportedInteractions.includes('batch')) {
|
||||
const path = '';
|
||||
const key = `POST/${path}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
queries.push({
|
||||
name: 'server-transaction',
|
||||
label: 'POST /',
|
||||
method: 'POST',
|
||||
path: path,
|
||||
description: 'server-transaction: Execute a FHIR Transaction (or FHIR Batch) Bundle',
|
||||
parameters: [formatParam],
|
||||
requestBody: true,
|
||||
schema: { resourceType: "Bundle" },
|
||||
example: JSON.stringify({ resourceType: "Bundle", type: "transaction", entry: [] }, null, 2)
|
||||
});
|
||||
addedPaths.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
// System History
|
||||
if (supportedInteractions.includes('history-system')) {
|
||||
const path = '_history';
|
||||
const key = `GET/${path}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
queries.push({
|
||||
name: 'server-history',
|
||||
label: 'GET /_history',
|
||||
method: 'GET',
|
||||
path: path,
|
||||
description: 'server-history: Fetch the resource change history across all resource types on the server',
|
||||
parameters: [formatParam, countParam, sinceParam],
|
||||
schema: { resourceType: "Bundle" },
|
||||
example: JSON.stringify({ resourceType: "Bundle", type: "history" }, null, 2)
|
||||
});
|
||||
addedPaths.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
// System Search (if supported, less common)
|
||||
if (supportedInteractions.includes('search-system')) {
|
||||
const path = '';
|
||||
const key = `GET/${path}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
queries.push({
|
||||
name: 'search-system',
|
||||
label: 'GET /',
|
||||
method: 'GET',
|
||||
path: path,
|
||||
description: 'Search across all resource types (limited support usually)',
|
||||
parameters: [formatParam, countParam, contentParam],
|
||||
schema: { resourceType: "Bundle" },
|
||||
example: JSON.stringify({ resourceType: "Bundle", type: "searchset" }, null, 2)
|
||||
});
|
||||
addedPaths.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Add System-Level Named Operations ---
|
||||
(restSection.operation || []).forEach(op => {
|
||||
const opName = op.name;
|
||||
const opPath = opName.startsWith('$') ? opName : `$${opName}`;
|
||||
const defUrl = op.definition || '';
|
||||
const doc = op.documentation || `Execute ${opName} at system level`;
|
||||
|
||||
// Skip metadata if already added
|
||||
if (opName === 'metadata' || opName === 'capabilities') return;
|
||||
|
||||
// Determine methods based on operation name and definition
|
||||
let methods = [];
|
||||
if (['diff', 'meta', 'get-resource-counts'].includes(opName)) {
|
||||
methods = ['GET', 'POST'];
|
||||
} else if (['reindex', 'perform-reindexing-pass', 'mark-all-resources-for-reindexing', 'expunge', 'reindex-terminology', 'hapi.fhir.replace-references'].includes(opName)) {
|
||||
methods = ['POST'];
|
||||
} else {
|
||||
methods = ['POST']; // Default to POST for unknown operations
|
||||
if (defUrl.toLowerCase().includes('get')) methods.push('GET');
|
||||
// --- Add Metadata (Capabilities) Operation ---
|
||||
const metadataPath = 'metadata';
|
||||
const metadataKey = `GET/${metadataPath}`;
|
||||
if (!addedPaths.has(metadataKey)) {
|
||||
queries.push({ name: 'metadata', label: 'GET /metadata', method: 'GET', path: metadataPath, description: 'server-capabilities: Fetch the server FHIR CapabilityStatement', parameters: [formatParam], schema: { resourceType: "CapabilityStatement" }, example: JSON.stringify(fetchedMetadataCache || { resourceType: "CapabilityStatement" }, null, 2) });
|
||||
addedPaths.add(metadataKey);
|
||||
}
|
||||
|
||||
methods.forEach(method => {
|
||||
const key = `${method}/${opPath}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
let label = `${method} /${opPath}`;
|
||||
let description = doc;
|
||||
|
||||
// Customize labels and descriptions to match expected output
|
||||
if (opName === 'diff') {
|
||||
description = 'Compare two resources or two versions of a single resource';
|
||||
} else if (opName === 'get-resource-counts') {
|
||||
description = 'Provides the number of resources currently stored on the server, broken down by resource type';
|
||||
} else if (opName === 'hapi.fhir.replace-references') {
|
||||
description = 'Repoints referencing resources to another resource instance';
|
||||
} else {
|
||||
description = `${method}: /${opPath}`; // Fallback for operations like reindex, expunge, etc.
|
||||
}
|
||||
|
||||
queries.push({
|
||||
name: opName,
|
||||
label: label,
|
||||
method: method,
|
||||
path: opPath,
|
||||
description: description,
|
||||
parameters: [formatParam],
|
||||
requestBody: method !== 'GET',
|
||||
schema: paramsSchema,
|
||||
example: paramsExample
|
||||
});
|
||||
addedPaths.add(key);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return queries;
|
||||
}
|
||||
// --- Add Other Standard System Interactions ---
|
||||
// (Keep Transaction/Batch, History, Search sections as is)
|
||||
// Transaction/Batch
|
||||
if (supportedInteractions.includes('transaction') || supportedInteractions.includes('batch')) {
|
||||
const path = ''; const key = `POST/${path}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
queries.push({ name: 'server-transaction', label: 'POST /', method: 'POST', path: path, description: 'server-transaction: Execute a FHIR Transaction (or FHIR Batch) Bundle', parameters: [formatParam], requestBody: true, schema: { resourceType: "Bundle" }, example: JSON.stringify({ resourceType: "Bundle", type: "transaction", entry: [] }, null, 2) });
|
||||
addedPaths.add(key);
|
||||
}
|
||||
}
|
||||
// System History
|
||||
if (supportedInteractions.includes('history-system')) {
|
||||
const path = '_history'; const key = `GET/${path}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
queries.push({ name: 'server-history', label: 'GET /_history', method: 'GET', path: path, description: 'server-history: Fetch the resource change history across all resource types on the server', parameters: [formatParam, countParam, sinceParam], schema: { resourceType: "Bundle" }, example: JSON.stringify({ resourceType: "Bundle", type: "history" }, null, 2) });
|
||||
addedPaths.add(key);
|
||||
}
|
||||
}
|
||||
// System Search
|
||||
if (supportedInteractions.includes('search-system')) {
|
||||
const path = ''; const key = `GET/${path}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
queries.push({ name: 'search-system', label: 'GET /', method: 'GET', path: path, description: 'Search across all resource types (limited support usually)', parameters: [formatParam, countParam, contentParam], schema: { resourceType: "Bundle" }, example: JSON.stringify({ resourceType: "Bundle", type: "searchset" }, null, 2) });
|
||||
addedPaths.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Update Query List UI (FIXED Variable Scope) ---
|
||||
function updateQueryListUI(resourceType) {
|
||||
// --- Add System-Level Named Operations (Fetching Definitions) ---
|
||||
const operationPromises = (restSection.operation || [])
|
||||
// Apply the filter using the 'op' parameter consistently
|
||||
.filter(op => op.name && op.name !== 'metadata' && op.name !== 'capabilities') // <<< CORRECTED HERE
|
||||
.map(async op => { // Use map with async to create promises
|
||||
const opName = op.name; // Define opName *inside* map if needed later
|
||||
const opPath = opName.startsWith('$') ? opName : `$${opName}`;
|
||||
const definitionUrl = op.definition;
|
||||
const doc = op.documentation || `Execute ${opName} at system level`;
|
||||
|
||||
let methods = [];
|
||||
// (Keep existing method detection logic...)
|
||||
if (['diff', 'meta', 'get-resource-counts'].includes(opName)) { methods = ['GET', 'POST']; }
|
||||
else if (['reindex', 'perform-reindexing-pass', 'mark-all-resources-for-reindexing', 'expunge', 'reindex-terminology', 'hapi.fhir.replace-references'].includes(opName)) { methods = ['POST']; }
|
||||
else { methods = ['POST']; if (op.definition?.toLowerCase().includes('get')) methods.push('GET'); }
|
||||
|
||||
|
||||
const operationQueries = []; // Store queries for this operation's methods
|
||||
|
||||
// Attempt to fetch the definition *once* per operation
|
||||
const opDef = await fetchOperationDefinition(definitionUrl); // <<< AWAIT FETCH
|
||||
|
||||
for (const method of methods) { // Now loop through methods
|
||||
const key = `${method}/${opPath}`;
|
||||
if (!addedPaths.has(key)) {
|
||||
let label = `${method} /${opPath}`;
|
||||
let description = doc;
|
||||
let operationParameters = [formatParam]; // Default
|
||||
let operationExample = defaultParamsExample; // Default
|
||||
let operationSchema = defaultParamsSchema; // Default
|
||||
|
||||
if (opDef && opDef.parameter) {
|
||||
try {
|
||||
const parsedParams = opDef.parameter
|
||||
.filter(p => p.use === 'in')
|
||||
.map(p => ({
|
||||
name: p.name || 'unknown',
|
||||
in: (method === 'GET' || p.searchType) ? 'query' : 'body (Parameters)', // Basic guess
|
||||
type: p.type || 'string',
|
||||
required: (p.min || 0) > 0,
|
||||
description: p.documentation || `Parameter ${p.name || ''}`,
|
||||
example: `(${p.type || 'string'})`
|
||||
}));
|
||||
operationParameters = [formatParam, ...parsedParams];
|
||||
operationSchema = opDef;
|
||||
if (method !== 'GET' && parsedParams.length > 0) {
|
||||
const exampleParamBody = { resourceType: "Parameters", parameter: parsedParams.map(p => ({ name: p.name, valueString: `example-${p.type}` })) };
|
||||
operationExample = JSON.stringify(exampleParamBody, null, 2);
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error(`Error parsing parameters for ${opName} from definition ${definitionUrl}:`, parseError);
|
||||
operationParameters = [formatParam]; // Fallback
|
||||
}
|
||||
} else {
|
||||
operationParameters = [formatParam]; // Fallback if fetch failed
|
||||
}
|
||||
|
||||
// Customize description (optional)
|
||||
if (opName === 'diff') description = 'Compare two resources or two versions of a single resource';
|
||||
else if (opName === 'get-resource-counts') description = 'Provides the number of resources currently stored on the server, broken down by resource type';
|
||||
// ... etc ...
|
||||
|
||||
operationQueries.push({
|
||||
name: opName, label: label, method: method, path: opPath,
|
||||
description: description, parameters: operationParameters,
|
||||
requestBody: method !== 'GET', schema: operationSchema, example: operationExample
|
||||
});
|
||||
addedPaths.add(key);
|
||||
} // end if !addedPaths
|
||||
} // end for method
|
||||
|
||||
return operationQueries; // Return array of queries generated for this operation
|
||||
}); // end map
|
||||
|
||||
// Wait for all fetches and processing to complete
|
||||
const results = await Promise.all(operationPromises); // <<< AWAIT ALL PROMISES
|
||||
|
||||
// Flatten the results
|
||||
results.forEach(opQueries => queries.push(...opQueries));
|
||||
|
||||
console.log("Generated system queries:", queries);
|
||||
return queries;
|
||||
} // End getSystemLevelQueries (async)
|
||||
|
||||
|
||||
async function updateQueryListUI(resourceType) { // <<< Added async
|
||||
currentSelectedResource = resourceType;
|
||||
selectedResourceSpan.textContent = resourceType === 'System' ? 'System Operations' : resourceType;
|
||||
queryListContainer.innerHTML = '';
|
||||
queryListContainer.innerHTML = '<p class="text-muted">Loading operations...</p>'; // Show loading state
|
||||
swaggerUiContainer.style.display = 'block'; // Show container early
|
||||
|
||||
// <<< Use await when calling the potentially async function
|
||||
const queries = resourceType === 'System'
|
||||
? await getSystemLevelQueries()
|
||||
: getQueryExamplesForResourceType(resourceType); // Assume this one is still sync for now
|
||||
|
||||
queryListContainer.innerHTML = ''; // Clear loading message
|
||||
|
||||
const queries = resourceType === 'System' ? getSystemLevelQueries() : getQueryExamplesForResourceType(resourceType);
|
||||
if (!queries || !queries.length) {
|
||||
// (rest of the function remains the same)
|
||||
queryListContainer.innerHTML = '<p>No operations defined or supported for this type.</p>';
|
||||
swaggerUiContainer.style.display = 'block';
|
||||
return;
|
||||
swaggerUiContainer.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
queries.sort((a, b) => { const pathA = a.path || ''; const pathB = b.path || ''; if (pathA < pathB) return -1; if (pathA > pathB) return 1; return a.method < b.method ? -1 : a.method > b.method ? 1 : 0; })
|
||||
queries.sort(/* ... */)
|
||||
.forEach((query, i) => {
|
||||
const blockId = `opblock-${i}`;
|
||||
const block = document.createElement('div');
|
||||
@ -600,10 +708,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
block.innerHTML = `
|
||||
<div class="opblock-summary"><span class="opblock-summary-method ${query.method.toLowerCase()}">${query.method}</span><span class="opblock-summary-path">${query.path}</span><span class="opblock-summary-description">${query.description}</span><svg class="arrow" viewBox="0 0 20 20"><path fill="currentColor" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg></div>
|
||||
<div class="opblock-body">
|
||||
<div class="opblock-section parameters-section"><div class="opblock-section-header"><h4 class="opblock-title">Parameters</h4><div class="try-out"><button class="btn btn-sm try-out__btn">Try it out</button></div></div><div class="parameters-container"><table class="parameters-table"><thead><tr><th class="parameters-col_name">Name</th><th class="parameters-col_description">Description</th></tr></thead><tbody>${query.parameters && query.parameters.length ? query.parameters.map(p => `<tr data-param-name="${p.name}" data-param-in="${p.in}"><td class="parameters-col_name"><div class="parameter__name ${p.required ? 'required' : ''}">${p.name}${p.required ? '<span>*</span>' : ''}</div><div class="parameter__type">${p.type}</div><div class="parameter__in">(${p.in})</div></td><td class="parameters-col_description"><div class="renderedMarkdown"><p>${p.description || 'No description'}</p></div>${p.example ? `<div class="renderedMarkdown"><p><i>Example:</i> ${p.example}</p></div>` : ''}<input type="${p.type === 'integer' ? 'number' : 'text'}" placeholder="${p.example || p.name}" data-example="${p.example || ''}" value="" aria-label="${p.name} parameter value" disabled></td></tr>`).join('') : `<tr><td colspan="2"><div class="renderedMarkdown"><p>No parameters defined.</p></div></td></tr>`}</tbody></table></div></div>
|
||||
<div class="opblock-section parameters-section"><div class="opblock-section-header"><h4 class="opblock-title">Parameters</h4><div class="try-out"><button class="btn btn-sm btn-primary try-out__btn">Try it out</button></div></div><div class="parameters-container"><table class="parameters-table"><thead><tr><th class="parameters-col_name">Name</th><th class="parameters-col_description">Description</th></tr></thead><tbody>${query.parameters && query.parameters.length ? query.parameters.map(p => `<tr data-param-name="${p.name}" data-param-in="${p.in}"><td class="parameters-col_name"><div class="parameter__name ${p.required ? 'required' : ''}">${p.name}${p.required ? '<span>*</span>' : ''}</div><div class="parameter__type">${p.type}</div><div class="parameter__in">(${p.in})</div></td><td class="parameters-col_description"><div class="renderedMarkdown"><p>${p.description || 'No description'}</p></div>${p.example ? `<div class="renderedMarkdown"><p><i>Example:</i> ${p.example}</p></div>` : ''}<input type="${p.type === 'integer' ? 'number' : 'text'}" placeholder="${p.example || p.name}" data-example="${p.example || ''}" value="" aria-label="${p.name} parameter value" disabled></td></tr>`).join('') : `<tr><td colspan="2"><div class="renderedMarkdown"><p>No parameters defined.</p></div></td></tr>`}</tbody></table></div></div>
|
||||
${query.requestBody ? `<div class="opblock-section request-body-section"><div class="opblock-section-header"><h4 class="opblock-title">Request Body</h4> <div class="content-type-wrapper"><label for="${blockId}-request-content-type" class="visually-hidden">Request Content Type</label><select id="${blockId}-request-content-type" class="content-type request-content-type" aria-label="Request body content type" disabled><option value="application/fhir+json" selected>application/fhir+json</option><option value="application/fhir+xml">application/fhir+xml</option>${query.method === 'POST' && query.path.endsWith('_search') ? '<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>' : ''}</select></div></div><textarea class="request-body-textarea" placeholder="Enter request body..." aria-label="Request body input" disabled>${(query.method === 'POST' && query.path.endsWith('_search')) ? query.example : ''}</textarea><div class="model-example request-body-example" style="margin-top: 10px; ${(query.method === 'POST' && query.path.endsWith('_search')) ? 'display: none;' : ''}"><ul class="tab" role="tablist"><li class="tabitem active"><button class="tablinks badge active" data-name="example">Example Body</button></li></ul><div class="example-panel" style="display: block;"><div class="highlight-code"><pre class="request-example-code"><code class="language-json">${query.example && typeof query.example === 'string' && query.example.startsWith('{') ? query.example : '{}'}</code></pre></div></div></div></div> ` : ''}
|
||||
<div class="opblock-section execute-section"><button class="btn execute__btn" disabled>Execute</button></div>
|
||||
<div class="execute-wrapper" style="display: none;"><div class="opblock-section request-url-section"><h5 class="opblock-title">Request URL</h5><pre class="request-url-output"><code></code></pre></div><div class="opblock-section curl-section"><div class="opblock-section-header"><h5 class="opblock-title">Curl</h5><button type="button" class="btn btn-sm btn-secondary copy-curl-btn" title="Copy Curl Command"><i class="bi bi-clipboard"></i> Copy</button></div><pre class="curl-output"><code></code></pre></div><div class="opblock-section-header"><h4 class="opblock-title">Server Response</h4> <div class="response-controls"> <select class="response-format-select" aria-label="Response display format" style="display: none;"><option value="json">JSON</option><option value="xml">XML</option><option value="narrative">Narrative</option></select><button type="button" class="btn btn-sm btn-secondary copy-response-btn" title="Copy Response Body" style="display: none;"><i class="bi bi-clipboard"></i> Copy</button> <button type="button" class="btn btn-sm btn-secondary download-response-btn" title="Download Response Body" style="display: none;"><i class="bi bi-download"></i> Download</button></div></div><pre class="response-output-content"><code></code></pre><div class="response-output-narrative" style="display:none;"></div><div class="response-status" style="margin-top: 5px; font-weight: bold;"></div></div>
|
||||
<div class="opblock-section execute-section"><button class="btn btn-success execute__btn" disabled>Execute</button></div>
|
||||
<div class="execute-wrapper" style="display: none;"><div class="opblock-section request-url-section"><h5 class="opblock-title">Request URL</h5><pre class="request-url-output"><code></code></pre></div><div class="opblock-section curl-section"><div class="opblock-section-header"><h5 class="opblock-title">Curl</h5><button type="button" class="btn btn-sm btn-outline-secondary btn-copy copy-curl-btn" title="Copy Curl Command"><i class="bi bi-clipboard"></i> Copy</button></div><pre class="curl-output"><code></code></pre></div><div class="opblock-section-header"><h4 class="opblock-title">Server Response</h4> <div class="response-controls"> <select class="response-format-select" aria-label="Response display format" style="display: none;"><option value="json">JSON</option><option value="xml">XML</option><option value="narrative">Narrative</option></select><button type="button" class="btn btn-sm btn-outline-secondary btn-copy copy-response-btn" title="Copy Response Body" style="display: none;"><i class="bi bi-clipboard"></i> Copy</button> <button type="button" class="btn btn-sm btn-outline-secondary btn-copy download-response-btn" title="Download Response Body" style="display: none;"><i class="bi bi-download"></i> Download</button></div></div><pre class="response-output-content"><code></code></pre><div class="response-output-narrative" style="display:none;"></div><div class="response-status" style="margin-top: 5px; font-weight: bold;"></div></div>
|
||||
<div class="opblock-section responses-section"><div class="opblock-section-header"><h4>Example Response / Schema</h4></div><table class="responses-table"><thead><tr class="responses-header"><td class="response-col_status">Code</td><td class="response-col_description">Description</td></tr></thead><tbody><tr class="response" data-code="200"><td class="response-col_status">200</td><td class="response-col_description"><div class="response-col_description__inner"><div class="renderedMarkdown"><p>Success</p></div></div><section class="response-controls"><div class="response-control-media-type"><label for="${blockId}-example-media-type" class="response-control-media-type__title">Example Format:</label><div class="content-type-wrapper d-inline-block"><select id="${blockId}-example-media-type" aria-label="Example Media Type" class="content-type example-media-type-select"><option value="application/fhir+json">JSON</option><option value="application/fhir+xml">XML</option></select></div><small class="response-control-media-type__accept-message">Controls example/schema format.</small></div></section><div class="model-example"><ul class="tab" role="tablist"><li class="tabitem active"><button class="tablinks badge active" data-name="example">Example Value</button></li><li class="tabitem"><button class="tablinks badge" data-name="schema">Schema</button></li></ul><div class="example-panel" style="display: block;"><div class="highlight-code"><pre class="example-code-display"><code class="language-json">${query.example && typeof query.example === 'string' ? query.example : '{}'}</code></pre></div></div><div class="schema-panel" style="display: none;"><div class="highlight-code"><pre class="schema-code-display"><code class="language-json">${JSON.stringify(query.schema || {}, null, 2)}</code></pre></div></div></div></td></tr><tr class="response" data-code="4xx/5xx"><td class="response-col_status">4xx/5xx</td><td class="response-col_description"><p>Error (e.g., Not Found, Server Error)</p></td></tr></tbody></table></div>
|
||||
</div>`;
|
||||
queryListContainer.appendChild(block);
|
||||
@ -700,8 +808,28 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
if (exampleTabs.length && examplePanel && schemaPanel) {
|
||||
exampleTabs.forEach(tab => { tab.addEventListener('click', () => { exampleTabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); const target = tab.dataset.name; examplePanel.style.display = target === 'example' ? 'block' : 'none'; schemaPanel.style.display = target === 'schema' ? 'block' : 'none'; updateStaticExampleFormat(block); }); });
|
||||
}
|
||||
exampleTabs.forEach(tab => { // Outer forEach loop for each tab
|
||||
tab.addEventListener('click', () => { // Add click listener to the current tab
|
||||
// When a tab is clicked:
|
||||
// 1. Make all tabs look inactive
|
||||
exampleTabs.forEach(t => { // Loop through ALL tabs
|
||||
t.classList.remove('active', 'bg-primary'); // Remove active state and primary bg
|
||||
t.classList.add('bg-secondary'); // Make it look inactive (secondary bg)
|
||||
});
|
||||
// 2. Make the clicked tab look active
|
||||
tab.classList.add('active', 'bg-primary'); // Add active state and primary bg
|
||||
tab.classList.remove('bg-secondary'); // Remove inactive look
|
||||
|
||||
// 3. Show/hide the correct panel (Example or Schema)
|
||||
const target = tab.dataset.name;
|
||||
examplePanel.style.display = target === 'example' ? 'block' : 'none';
|
||||
schemaPanel.style.display = target === 'schema' ? 'block' : 'none';
|
||||
|
||||
// 4. Update the content format if needed (e.g., JSON/XML)
|
||||
updateStaticExampleFormat(block);
|
||||
}); // << End of the arrow function for the click listener
|
||||
}); // << End of the arrow function for the outer exampleTabs.forEach loop
|
||||
} // << End of the if block
|
||||
|
||||
if (exampleMediaTypeSelect) {
|
||||
exampleMediaTypeSelect.addEventListener('change', () => updateStaticExampleFormat(block));
|
||||
@ -803,7 +931,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
|
||||
// --- Display Metadata & Parse Operations (FIXED Method Parsing Logic) ---
|
||||
// --- Display Metadata & Parse Operations (Applying async to listeners) ---
|
||||
function displayMetadataAndResourceButtons(data) {
|
||||
const rest = data?.rest?.[0];
|
||||
if (!rest) { resourceButtonsContainer.innerHTML = `<span class="text-danger">Error: Invalid CapabilityStatement (missing 'rest').</span>`; resourceTypesDisplayDiv.style.display = 'block'; swaggerUiContainer.style.display = 'none'; availableSystemOperations = []; return; }
|
||||
@ -811,91 +939,85 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const interactions = rest.interaction?.map(i => i.code) || [];
|
||||
|
||||
// --- PARSE OPERATIONS (Revised Method/Level Detection) ---
|
||||
// This part remains synchronous - parsing the already fetched metadata
|
||||
availableSystemOperations = (rest.operation || []).map(op => {
|
||||
const name = op.name || '';
|
||||
const defUrl = op.definition || '';
|
||||
let levels = new Set();
|
||||
let methods = new Set(); // Start with empty set
|
||||
let methods = new Set();
|
||||
|
||||
// Determine Levels (same logic as before, seems reasonable)
|
||||
if (defUrl.includes('System') || name.includes('system') || ['transaction', 'batch', 'metadata', 'history-system'].includes(name)) levels.add('system');
|
||||
if (defUrl.includes('Type') || name.includes('type') || name.startsWith('$')) levels.add('type');
|
||||
if (defUrl.includes('Instance') || name.includes('instance') || (name.startsWith('$') && !name.endsWith('-system'))) levels.add('instance');
|
||||
if (!levels.size) { if (name.startsWith('$') || ['transaction', 'batch', 'metadata', 'history-system', 'capabilities'].includes(name)) levels.add('system'); else { levels.add('type'); levels.add('instance'); } }
|
||||
// (Keep existing level detection logic...)
|
||||
if (defUrl.includes('System') || name.includes('system') || ['transaction', 'batch', 'metadata', 'history-system'].includes(name)) levels.add('system');
|
||||
if (defUrl.includes('Type') || name.includes('type') || name.startsWith('$')) levels.add('type');
|
||||
if (defUrl.includes('Instance') || name.includes('instance') || (name.startsWith('$') && !name.endsWith('-system'))) levels.add('instance');
|
||||
if (!levels.size) { if (name.startsWith('$') || ['transaction', 'batch', 'metadata', 'history-system', 'capabilities'].includes(name)) levels.add('system'); else { levels.add('type'); levels.add('instance'); } }
|
||||
|
||||
// Determine Methods (Improved based on metadata example)
|
||||
if (['metadata', 'history-system', 'history-type', 'history-instance', 'capabilities'].includes(name)) {
|
||||
methods.add('GET');
|
||||
} else if (name === 'transaction' || name === 'batch' || name === 'server-transaction') {
|
||||
methods.add('POST');
|
||||
levels = new Set(['system']); // Force system level for transaction/batch
|
||||
} else if (['diff', 'meta', 'get-resource-counts'].includes(name)) {
|
||||
// These support both GET and POST according to the example metadata
|
||||
methods.add('GET');
|
||||
methods.add('POST');
|
||||
} else if (['reindex', 'perform-reindexing-pass', 'mark-all-resources-for-reindexing', 'expunge', 'reindex-terminology', 'hapi.fhir.replace-references'].includes(name)) {
|
||||
// These are typically POST only
|
||||
methods.add('POST');
|
||||
} else {
|
||||
// Default guess: If documentation or def URL mentions GET, add it, otherwise default to POST
|
||||
methods.add('POST'); // Assume POST by default for unknown operations
|
||||
if (op.documentation?.toLowerCase().includes(' http get') || defUrl.toLowerCase().includes('get')) {
|
||||
methods.add('GET');
|
||||
}
|
||||
}
|
||||
|
||||
// (Keep existing method detection logic...)
|
||||
if (['metadata', 'history-system', 'history-type', 'history-instance', 'capabilities'].includes(name)) { methods.add('GET'); }
|
||||
else if (name === 'transaction' || name === 'batch' || name === 'server-transaction') { methods.add('POST'); levels = new Set(['system']); }
|
||||
else if (['diff', 'meta', 'get-resource-counts'].includes(name)) { methods.add('GET'); methods.add('POST'); }
|
||||
else if (['reindex', 'perform-reindexing-pass', 'mark-all-resources-for-reindexing', 'expunge', 'reindex-terminology', 'hapi.fhir.replace-references'].includes(name)) { methods.add('POST'); }
|
||||
else { methods.add('POST'); if (op.documentation?.toLowerCase().includes(' http get') || defUrl.toLowerCase().includes('get')) { methods.add('GET'); } }
|
||||
|
||||
return { name, methods: Array.from(methods), documentation: op.documentation || '', definition: defUrl, levels: Array.from(levels) };
|
||||
}).filter(op => op.name); // Filter out operations without a name
|
||||
|
||||
// Add standard interactions as fallback if not present as named operations (Optional, handled in generator)
|
||||
// Example: if (!availableSystemOperations.some(...) && interactions.includes(...)) { ... }
|
||||
}).filter(op => op.name);
|
||||
|
||||
console.log("Final Parsed Operations List:", availableSystemOperations);
|
||||
|
||||
resourceButtonsContainer.innerHTML = ''; // Clear previous buttons
|
||||
const supportsSystemLevel = interactions.some(code => ['transaction', 'batch', 'history-system', 'search-system', 'capabilities'].includes(code)) || availableSystemOperations.some(op => op.levels.includes('system'));
|
||||
|
||||
// --- Create Buttons and Attach ASYNC Listeners ---
|
||||
if (supportsSystemLevel) {
|
||||
const systemButton = document.createElement('button');
|
||||
systemButton.type = 'button'; systemButton.className = 'btn btn-outline-success btn-sm me-2 mb-2'; systemButton.textContent = 'System';
|
||||
systemButton.addEventListener('click', (event) => handleResourceOrSystemButtonClick(event.target, 'System'));
|
||||
// Make the event listener callback async and use await
|
||||
systemButton.addEventListener('click', async (event) => { // <<< Added async
|
||||
await handleResourceOrSystemButtonClick(event.target, 'System'); // <<< Added await
|
||||
});
|
||||
resourceButtonsContainer.appendChild(systemButton);
|
||||
}
|
||||
|
||||
resourceTypes.sort().forEach(resType => {
|
||||
const resourceButton = document.createElement('button');
|
||||
resourceButton.type = 'button'; resourceButton.className = 'btn btn-outline-dark-blue btn-sm me-2 mb-2'; resourceButton.textContent = resType;
|
||||
resourceButton.addEventListener('click', (event) => handleResourceOrSystemButtonClick(event.target, resType));
|
||||
resourceButton.type = 'button'; resourceButton.className = 'btn btn-outline-primary btn-sm me-2 mb-2'; resourceButton.textContent = resType;
|
||||
// Make the event listener callback async and use await
|
||||
resourceButton.addEventListener('click', async (event) => { // <<< Added async
|
||||
await handleResourceOrSystemButtonClick(event.target, resType); // <<< Added await
|
||||
});
|
||||
resourceButtonsContainer.appendChild(resourceButton);
|
||||
});
|
||||
|
||||
resourceTypesDisplayDiv.style.display = 'block'; // Show the buttons container
|
||||
|
||||
// --- Trigger Action for First Button ---
|
||||
const firstBtn = resourceButtonsContainer.querySelector('button');
|
||||
if (firstBtn) { firstBtn.click(); }
|
||||
else { resourceButtonsContainer.innerHTML = '<span class="text-warning">No resources or system operations found in metadata.</span>'; swaggerUiContainer.style.display = 'none'; }
|
||||
}
|
||||
if (firstBtn) {
|
||||
// Instead of firstBtn.click(), directly call the async handler
|
||||
// Use setTimeout to allow the current rendering cycle to finish first
|
||||
setTimeout(async () => {
|
||||
// Ensure the button isn't already active from a previous state if possible
|
||||
if (!firstBtn.classList.contains('active')) {
|
||||
await handleResourceOrSystemButtonClick(firstBtn, firstBtn.textContent);
|
||||
}
|
||||
}, 0);
|
||||
} else {
|
||||
resourceButtonsContainer.innerHTML = '<span class="text-warning">No resources or system operations found in metadata.</span>';
|
||||
swaggerUiContainer.style.display = 'none';
|
||||
}
|
||||
} // End displayMetadataAndResourceButtons
|
||||
|
||||
// --- Handle Resource/System Button Clicks (FIXED color classes) ---
|
||||
function handleResourceOrSystemButtonClick(clickedButton, resourceOrSystemName) {
|
||||
resourceButtonsContainer.querySelectorAll('.btn').forEach(button => {
|
||||
button.classList.remove('active', 'btn-success', 'btn-dark-blue', 'btn-outline-success', 'btn-outline-dark-blue'); // Remove all relevant classes
|
||||
// Re-apply the correct OUTLINE class
|
||||
if (button.textContent === 'System') {
|
||||
button.classList.add('btn-outline-success');
|
||||
} else {
|
||||
button.classList.add('btn-outline-dark-blue');
|
||||
}
|
||||
// --- Handle Resource/System Button Clicks (NOW ASYNC) ---
|
||||
async function handleResourceOrSystemButtonClick(clickedButton, resourceOrSystemName) { // <<< Added async
|
||||
// (Keep the button class manipulation logic as is)
|
||||
resourceButtonsContainer.querySelectorAll('.btn').forEach(button => {
|
||||
// ... remove/add classes ...
|
||||
});
|
||||
// Activate the clicked button
|
||||
clickedButton.classList.add('active');
|
||||
if (resourceOrSystemName === 'System') {
|
||||
clickedButton.classList.remove('btn-outline-success'); // Remove outline
|
||||
clickedButton.classList.add('btn-success'); // Add solid
|
||||
} else {
|
||||
clickedButton.classList.remove('btn-outline-dark-blue'); // Remove outline
|
||||
clickedButton.classList.add('btn-dark-blue'); // Add solid
|
||||
}
|
||||
updateQueryListUI(resourceOrSystemName); // Update the operation list
|
||||
// ... add/remove classes ...
|
||||
|
||||
await updateQueryListUI(resourceOrSystemName); // <<< Use await
|
||||
}
|
||||
|
||||
// --- Initial Page State Setup ---
|
||||
|
1788
templates/fhir_ui_operations.html.bak
Normal file
1788
templates/fhir_ui_operations.html.bak
Normal file
File diff suppressed because it is too large
Load Diff
@ -18,58 +18,206 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Spinner Overlay -->
|
||||
<div id="spinner-overlay" class="d-none position-fixed top-0 start-0 w-100 h-100 bg-dark bg-opacity-50 d-flex align-items-center justify-content-center" style="z-index: 1050;">
|
||||
<div class="text-center">
|
||||
<div id="spinner-animation" style="width: 200px; height: 200px;"></div>
|
||||
<p class="text-white mt-3">Waiting, don't leave this page...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2><i class="bi bi-file-code me-2"></i>Convert FHIR to FSH</h2>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="POST" enctype="multipart/form-data" class="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ render_field(form.package) }}
|
||||
{{ render_field(form.input_mode) }}
|
||||
<div id="file-upload" style="display: none;">
|
||||
{{ render_field(form.fhir_file) }}
|
||||
</div>
|
||||
<div id="text-input" style="display: none;">
|
||||
{{ render_field(form.fhir_text) }}
|
||||
</div>
|
||||
{{ render_field(form.output_style) }}
|
||||
{{ render_field(form.log_level) }}
|
||||
{{ render_field(form.fhir_version) }}
|
||||
<div class="d-grid gap-2 d-sm-flex">
|
||||
{{ form.submit(class="btn btn-success") }}
|
||||
<a href="{{ url_for('index') }}" class="btn btn-secondary">Back</a>
|
||||
</div>
|
||||
</form>
|
||||
<div id="fsh-output">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form id="fsh-converter-form" method="POST" enctype="multipart/form-data" class="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ render_field(form.package) }}
|
||||
{{ render_field(form.input_mode) }}
|
||||
<div id="file-upload" style="display: none;">
|
||||
{{ render_field(form.fhir_file) }}
|
||||
</div>
|
||||
<div id="text-input" style="display: none;">
|
||||
{{ render_field(form.fhir_text) }}
|
||||
</div>
|
||||
{{ render_field(form.output_style) }}
|
||||
{{ render_field(form.log_level) }}
|
||||
{{ render_field(form.fhir_version) }}
|
||||
{{ render_field(form.fishing_trip) }}
|
||||
{{ render_field(form.dependencies, placeholder="One per line, e.g., hl7.fhir.us.core@6.1.0") }}
|
||||
{{ render_field(form.indent_rules) }}
|
||||
{{ render_field(form.meta_profile) }}
|
||||
{{ render_field(form.alias_file) }}
|
||||
{{ render_field(form.no_alias) }}
|
||||
<div class="d-grid gap-2 d-sm-flex">
|
||||
{{ form.submit(class="btn btn-success", id="submit-btn") }}
|
||||
<a href="{{ url_for('index') }}" class="btn btn-secondary">Back</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if error %}
|
||||
<div class="alert alert-danger mt-4">{{ error }}</div>
|
||||
{% endif %}
|
||||
{% if fsh_output %}
|
||||
<div class="alert alert-success mt-4">Conversion successful!</div>
|
||||
<h3 class="mt-4">FSH Output</h3>
|
||||
<pre class="bg-light p-3">{{ fsh_output }}</pre>
|
||||
<a href="{{ url_for('download_fsh') }}" class="btn btn-primary">Download FSH</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/lottie.min.js') }}"></script>
|
||||
<script>
|
||||
document.getElementById('input_mode').addEventListener('change', function() {
|
||||
const fileUpload = document.getElementById('file-upload');
|
||||
const textInput = document.getElementById('text-input');
|
||||
if (this.value === 'file') {
|
||||
fileUpload.style.display = 'block';
|
||||
textInput.style.display = 'none';
|
||||
} else {
|
||||
fileUpload.style.display = 'none';
|
||||
textInput.style.display = 'block';
|
||||
// --- Global Variables and Helper Functions (Defined *outside* DOMContentLoaded) ---
|
||||
let currentLottieAnimation = null;
|
||||
|
||||
function loadLottieAnimation(theme) {
|
||||
// console.log(`loadLottieAnimation called with theme: ${theme}`); // Optional debug log
|
||||
const spinnerContainer = document.getElementById('spinner-animation');
|
||||
// console.log(`Found spinnerContainer: ${!!spinnerContainer}`); // Optional debug log
|
||||
if (!spinnerContainer) return;
|
||||
if (currentLottieAnimation) {
|
||||
// console.log("Destroying previous Lottie animation."); // Optional debug log
|
||||
currentLottieAnimation.destroy();
|
||||
currentLottieAnimation = null;
|
||||
}
|
||||
});
|
||||
// Trigger change on page load to set initial state
|
||||
document.getElementById('input_mode').dispatchEvent(new Event('change'));
|
||||
const animationPath = (theme === 'dark')
|
||||
? '{{ url_for('static', filename='animations/loading-dark.json') }}'
|
||||
: '{{ url_for('static', filename='animations/loading-light.json') }}';
|
||||
// console.log(`Determined animation path: ${animationPath}`); // Optional debug log
|
||||
try {
|
||||
currentLottieAnimation = lottie.loadAnimation({ container: spinnerContainer, renderer: 'svg', loop: true, autoplay: true, path: animationPath });
|
||||
// console.log("New Lottie animation loaded."); // Optional debug log
|
||||
} catch(lottieError) {
|
||||
console.error("Error loading Lottie animation:", lottieError);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Function to handle input mode changes (for SELECT element) ---
|
||||
function handleInputModeChange(selectElement) {
|
||||
if (!selectElement) { console.error("handleInputModeChange called with no selectElement"); return; }
|
||||
const selectedValue = selectElement.value; // Get value from the select element
|
||||
console.log(`handleInputModeChange called for value: ${selectedValue}`); // Keep this log for now
|
||||
|
||||
const form = selectElement.closest('form');
|
||||
if (!form) { console.error('Could not find parent form for input mode toggle.'); return; }
|
||||
|
||||
const fileUploadDiv = form.querySelector('#file-upload');
|
||||
const textInputDiv = form.querySelector('#text-input');
|
||||
// console.log(`Found fileUploadDiv: ${!!fileUploadDiv}, Found textInputDiv: ${!!textInputDiv}`); // Optional debug log
|
||||
|
||||
if (fileUploadDiv && textInputDiv) {
|
||||
// Show/hide based on the SELECTED VALUE
|
||||
if (selectedValue === 'file') {
|
||||
fileUploadDiv.style.display = 'block';
|
||||
textInputDiv.style.display = 'none';
|
||||
} else { // Assuming 'text' is the other value
|
||||
fileUploadDiv.style.display = 'none';
|
||||
textInputDiv.style.display = 'block';
|
||||
}
|
||||
// console.log(`Set display - file: ${fileUploadDiv.style.display}, text: ${textInputDiv.style.display}`); // Optional debug log
|
||||
} else {
|
||||
console.error('Could not find file-upload or text-input divs within the form.');
|
||||
}
|
||||
}
|
||||
|
||||
// --- Function to initialize UI elements within a container (for SELECT element) ---
|
||||
function initializeFshConverterUI(containerElement) {
|
||||
console.log("Initializing FSH Converter UI within:", containerElement === document ? "document" : "outputContainer"); // Keep this log for now
|
||||
// --- Input Mode Toggle Initialization ---
|
||||
// Select the dropdown using its ID
|
||||
const inputModeSelect = containerElement.querySelector('#input_mode'); // Use ID selector for the select
|
||||
|
||||
if (inputModeSelect) {
|
||||
// Attach the listener directly to the select element
|
||||
inputModeSelect.addEventListener('change', (event) => {
|
||||
// Pass the select element itself to the handler
|
||||
handleInputModeChange(event.target);
|
||||
});
|
||||
|
||||
// Set initial state based on the select element's current value
|
||||
console.log(`Initial input mode detected: ${inputModeSelect.value}`); // Keep this log
|
||||
handleInputModeChange(inputModeSelect); // Call handler directly with the select element
|
||||
|
||||
} else {
|
||||
// This error should hopefully not appear now
|
||||
console.error('Input mode select element (#input_mode) not found within container:', containerElement);
|
||||
}
|
||||
|
||||
// Only load initial Lottie when initializing the whole document
|
||||
if (containerElement === document) {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
|
||||
// Make sure loadLottieAnimation function exists before calling
|
||||
if (typeof loadLottieAnimation === 'function') {
|
||||
loadLottieAnimation(currentTheme);
|
||||
} else {
|
||||
console.error("loadLottieAnimation function not defined.");
|
||||
}
|
||||
}
|
||||
} // End initializeFshConverterUI
|
||||
|
||||
// --- Main Execution on DOMContentLoaded ---
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// --- Initial UI Setup ---
|
||||
// Use setTimeout for the initial call to ensure form elements are ready
|
||||
setTimeout(() => {
|
||||
initializeFshConverterUI(document);
|
||||
}, 50); // Using a slightly longer delay just in case 0 isn't enough
|
||||
|
||||
// --- Form submission with AJAX (Event Delegation) ---
|
||||
const outputContainer = document.getElementById('fsh-output');
|
||||
if (outputContainer) {
|
||||
outputContainer.addEventListener('submit', async function(event) {
|
||||
// Check if the event originated from our specific form
|
||||
if (event.target && event.target.id === 'fsh-converter-form') {
|
||||
event.preventDefault(); // Prevent default only if it's our form
|
||||
|
||||
const form = event.target;
|
||||
const submitBtn = form.querySelector('#submit-btn');
|
||||
const spinnerOverlay = document.getElementById('spinner-overlay'); // Spinner is outside the form
|
||||
|
||||
if (!submitBtn || !spinnerOverlay) {
|
||||
console.error("Submit button or spinner overlay not found.");
|
||||
return; // Stop if critical elements missing
|
||||
}
|
||||
|
||||
submitBtn.disabled = true;
|
||||
spinnerOverlay.classList.remove('d-none'); // Show spinner
|
||||
|
||||
const formData = new FormData(form);
|
||||
try {
|
||||
const response = await fetch('{{ url_for('fsh_converter') }}', { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest' }, body: formData });
|
||||
if (!response.ok) { let errorText = response.statusText; try { const errorData = await response.json(); errorText = errorData.error || errorText; } catch (e) {} throw new Error(`Network response was not ok: ${response.status} ${errorText}`); }
|
||||
const html = await response.text();
|
||||
|
||||
const themeNow = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
|
||||
// Check function exists before calling, just in case
|
||||
if (typeof loadLottieAnimation === 'function') {
|
||||
loadLottieAnimation(themeNow); // Ensure animation theme is updated before showing result
|
||||
}
|
||||
|
||||
outputContainer.innerHTML = html; // Replace content
|
||||
|
||||
initializeFshConverterUI(outputContainer); // Re-initialize controls for new content
|
||||
|
||||
// Hide spinner AFTER content replaced and potentially re-initialized
|
||||
spinnerOverlay.classList.add('d-none');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error during FSH conversion AJAX:', error);
|
||||
if(spinnerOverlay) spinnerOverlay.classList.add('d-none');
|
||||
// No need to re-enable submitBtn as the form was replaced
|
||||
|
||||
const alertDiv = document.createElement('div');
|
||||
alertDiv.className = 'alert alert-danger mt-4';
|
||||
alertDiv.textContent = `An error occurred during conversion: ${error.message}. Please check input and try again.`;
|
||||
outputContainer.innerHTML = ''; // Clear previous content before showing only error
|
||||
outputContainer.appendChild(alertDiv);
|
||||
}
|
||||
} // End if event target is form
|
||||
}); // End submit listener
|
||||
} else {
|
||||
console.error("#fsh-output container not found for attaching delegated event listener.");
|
||||
}
|
||||
}); // End DOMContentLoaded Listener
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user