Cornflow-UI is a Vue.js application that serves as the user interface for Cornflow. This is the base project, and it provides the general structure and functionalities for creating new applications.
To create a new project based on this base project, follow these steps:
Copy and paste all the code from this repository into your new repository.
src/app/config.ts for UI preferences and featuresnpm run dev to verify configurationThe application uses a two-layer configuration system with clear separation of concerns:
src/config.ts)values.json (automatically detected)src/app/config.ts)Key principle: External config is "what must be changed without touching code", internal config is "what is part of the application logic".
Create a .env file (for local development only) or set environment variables on your server. The application automatically uses this method when VITE_APP_SCHEMA or VITE_APP_BACKEND_URL are detected.
# Core configuration
VITE_APP_BACKEND_URL=https://your-backend-url
VITE_APP_SCHEMA=rostering
VITE_APP_NAME=Rostering
# Application behavior
VITE_APP_EXTERNAL_APP=true # true/false (also accepts 1/0)
VITE_APP_IS_STAGING_ENVIRONMENT=false # true/false (also accepts 1/0)
VITE_APP_USE_HASH_MODE=false # true/false (also accepts 1/0)
VITE_APP_DEFAULT_LANGUAGE=en # en, es, fr
VITE_APP_IS_DEVELOPER_MODE=false # true/false (also accepts 1/0)
VITE_APP_ENABLE_SIGNUP=false # true/false (also accepts 1/0)
# Authentication configuration
VITE_APP_AUTH_TYPE=cornflow # Options: cornflow, azure, cognito
VITE_APP_AUTH_CLIENT_ID=your-client-id
VITE_APP_AUTH_AUTHORITY=your-authority
VITE_APP_AUTH_REDIRECT_URI=your-redirect-uri
VITE_APP_AUTH_REGION=your-region
VITE_APP_AUTH_USER_POOL_ID=your-user-pool-id
VITE_APP_AUTH_DOMAIN=your-domain
VITE_APP_AUTH_PROVIDERS=google,microsoft # For Cognito: comma-separated list
Copy public/values.template.json to public/values.json and configure your values (for local development only). For production, configure this json in an accesible path. Defined path by default is /values.json but this can be overwritten in app/config.ts with valuesJsonPath. Used automatically when no environment variables are detected.
{
"backend_url": "https://your-backend-url",
"schema": "rostering",
"name": "Rostering",
"hasExternalApp": false,
"isStagingEnvironment": false,
"useHashMode": false,
"defaultLanguage": "en",
"isDeveloperMode": false,
"enableSignup": false,
"auth_type": "cornflow",
"cognito": {
"region": "your-region",
"user_pool_id": "your-user-pool-id",
"client_id": "your-client-id",
"domain": "your-domain",
"providers": ["google", "microsoft"]
},
"azure": {
"client_id": "your-client-id",
"authority": "your-authority",
"redirect_uri": "your-redirect-uri"
}
}
The application automatically chooses the configuration method:
values.jsonvalues.json or defined pathFor production: Recomended environment variables for security and flexibility, but accepts json For development: Hardcode values in your .env or values.json file. This can't be uploaded
// External configuration (from env/json)
import config from '@/config'
config.schema // ✅ Schema name
config.backend // ✅ Backend URL
config.isDeveloperMode // ✅ Developer mode flag
config.auth.type // ✅ Authentication type
// Internal configuration (from source code)
import internalConfig from '@/app/config'
internalConfig.getCore().parameters.showUserFullname // ✅ UI preferences
internalConfig.getCore().parameters.solverConfig // ✅ App logic
src/app/config.ts)This file contains internal application-specific configuration that is part of the codebase and not configurable externally:
{
core: {
// Core application components
Experiment: ExperimentRostering,
Instance: InstanceRostering,
Solution: SolutionRostering,
parameters: {
// Json path
valuesJsonPath: '/values.json',
// Project execution table configuration
showUserFullname: true,
showTablesWithoutSchema: true,
showExtraProjectExecutionColumns: {
showUserName: false,
showEndCreationDate: false,
showTimeLimit: true,
showUserFullName: false,
},
// Dashboard configuration
showDashboardMainView: false,
dashboardLayout: [...],
dashboardPages: [...],
dashboardRoutes: [...],
// Create execution steps configuration
executionSolvers: ['mip-gurobi'],
solverConfig: {
showSolverStep: false,
defaultSolver: 'mip.gurobi',
},
configFieldsConfig: {
showConfigFieldsStep: false,
autoLoadValues: true,
},
configFields: [...],
// Instance file processing
fileProcessors: {
'mtrx': 'processMatrix',
'config': ['processConfig', 'processCleanData'],
'all': ['processCleanData', 'processBooleansFromStrings']
},
// States for execution and solution
executionStates: {
'1': { color: 'green', message: 'Success execution', code: 'Success' }
},
solutionStates: {
'1': { color: 'green', message: 'Success solution', code: 'Success' }
},
}
}
}
Inside the app folder, there are several changes that can be done to configurate your client project. This folder is meant to be for all customizations done for the client.
assets/logo: This directory should contain the logo images for the application. The name should be the same as the default ones (logo.png and full_logo.png)app/assets/style/variables.css: This file should define the main colors of the application. Mantain the variable names and only change the colors.models: This directory should define the instance, solution, experiment, and execution models for the application. It always extends the main classes but methods can be overwritten.views: This directory should contain all the custom views needed for the application.components: This directory should contain any additional components that are not in the core components.store/app.ts: This file should define any additional store-specific configurations for the application.plugins/locales: This folder contains three files (en.ts, es.ts, fr.ts) to add any text needed in the app views and components. Be careful not to duplicate the names with the original locales files (src/plugins/locales).public/manual directory with the following naming convention:
user_manual_en.pdf for Englishuser_manual_es.pdf for Spanishuser_manual_fr.pdf for FrenchIt's important not to edit any other file or folders. Only the folders, files and images just mentioned can be edited.
| Parameter | Description | Environment Variable | JSON Key | Values |
|---|---|---|---|---|
| Backend URL | API server endpoint | VITE_APP_BACKEND_URL | backend_url | URL string |
| Schema | Application schema name | VITE_APP_SCHEMA | schema | String identifier |
| App Name | Application display name | VITE_APP_NAME | name | String |
| Hash Mode | Router mode (hash vs history) | VITE_APP_USE_HASH_MODE | useHashMode | true/false (accepts 1/0) |
| Default Language | UI language | VITE_APP_DEFAULT_LANGUAGE | defaultLanguage | en, es, fr |
| Developer Mode | Enable dev features | VITE_APP_IS_DEVELOPER_MODE | isDeveloperMode | true/false (accepts 1/0) |
| Enable Signup | Show registration option | VITE_APP_ENABLE_SIGNUP | enableSignup | true/false (accepts 1/0) |
| External App | API URL prefix mode | VITE_APP_EXTERNAL_APP | hasExternalApp | true/false (accepts 1/0) |
| Staging Environment | Show staging banner | VITE_APP_IS_STAGING_ENVIRONMENT | isStagingEnvironment | true/false (accepts 1/0) |
| Parameter | Description | Environment Variable | JSON Key | Values |
|---|---|---|---|---|
| Auth Type | Authentication method | VITE_APP_AUTH_TYPE | auth_type | cornflow, azure, cognito |
| Client ID | OAuth client identifier | VITE_APP_AUTH_CLIENT_ID | client_id | String |
| Authority | Azure authority URL | VITE_APP_AUTH_AUTHORITY | authority | URL string |
| Redirect URI | OAuth redirect URL | VITE_APP_AUTH_REDIRECT_URI | redirect_uri | URL string |
| Region | AWS Cognito region | VITE_APP_AUTH_REGION | region | AWS region code |
| User Pool ID | Cognito user pool | VITE_APP_AUTH_USER_POOL_ID | user_pool_id | Pool identifier |
| Domain | Cognito domain | VITE_APP_AUTH_DOMAIN | domain | Domain string |
| OAuth Providers | Enabled OAuth providers | VITE_APP_AUTH_PROVIDERS | providers | Comma-separated / Array |
All boolean parameters accept multiple formats for flexibility:
true or false (case-insensitive)1 (true) or 0 (false)"true", "false", "1", "0"true/false or numbers 1/0The application automatically converts these formats to proper boolean values.
true: Hash mode routing (URLs include #)false: HTML5 history mode (clean URLs)true: Shows solution upload in execution creationfalse: Standard user experiencetrue: Prefixes requests with /cornflowfalse: Direct API requestsgoogle, microsoft, facebookThe application supports three authentication methods. The server must be properly configured for the chosen method.
VITE_APP_AUTH_TYPE=cornflow
VITE_APP_AUTH_TYPE=azure
VITE_APP_AUTH_CLIENT_ID=your_azure_client_id
VITE_APP_AUTH_AUTHORITY=your_azure_authority
VITE_APP_AUTH_REDIRECT_URI=your-redirect-uri
VITE_APP_AUTH_TYPE=cognito
VITE_APP_AUTH_CLIENT_ID=your_cognito_client_id
VITE_APP_AUTH_REGION=your_cognito_region
VITE_APP_AUTH_USER_POOL_ID=your_cognito_user_pool_id
VITE_APP_AUTH_DOMAIN=your_cognito_domain
VITE_APP_AUTH_PROVIDERS=google,microsoft
To save dashboard preferences for a single execution, including filters, checks, and date ranges, utilize the setDashboardPreference method from the LoadedExecution.ts class. Subsequently, retrieve these preferences using the getDashboardPreference method. The data type is custom, allowing for flexible usage as needed.
The application supports custom file processing for instances based on filename prefixes. This feature is useful when you need to handle files with special formats or structures before merging them with other files to create an instance.
Custom file processing is entirely optional. By default, the system will merge all uploaded files without any special processing. If you don't need custom file processing, you can leave the fileProcessors object empty or omit it entirely.
If you do need custom processing for specific file types, add a fileProcessors object to the core parameters in src/app/config.ts:
parameters: {
// other parameters
fileProcessors: {
// Single processor for a prefix
'mtrx': 'processMatrix',
// Multiple processors for a prefix (applied in sequence)
'config': ['processConfig', 'processCleanData'],
// Special 'all' prefix to process all files regardless of their names
'all': ['processCleanData', 'processBooleansFromStrings']
},
// other parameters
}
Each key in the fileProcessors object is a filename prefix that triggers special processing, and each value is either:
The special prefix 'all' can be used to apply processors to all files regardless of their names.
The actual processing logic must be implemented in the src/app/composables/useFileProcessors.ts file. You need to add your processor methods to the processors object in this file.
Each processor method should:
When multiple processors are specified for a prefix (or for the 'all' prefix), they are applied in sequence, with each processor receiving the output of the previous one.
Important: The processor methods don't create the final, complete instance. Instead, they each process a specific part of the data needed for the complete instance. After all files are processed, the system will automatically merge all the processed parts to create the complete instance.
For example, in a scheduling application, one file might contain employee data, another might contain shift requirements, and a third might contain constraints. Each file would be processed separately and then merged to create the complete instance.
The system automatically detects files that match the configured prefixes and processes them using the corresponding methods before merging all the processed parts into the final instance. Files that don't match any configured prefix are processed using the standard method.
Controls the solver selection step and default solver for executions.
showSolverStep (boolean):
defaultSolver automatically.defaultSolver (string):
showSolverStep is false.newExecution.config.solver.Controls the config fields step and value loading for execution parameters.
showConfigFieldsStep (boolean):
autoLoadValues (boolean):
Defines the configuration fields for execution parameters. Each field can have:
key (string): Unique identifier for the field (used as config property).title (string): Translation key for the field label.placeholder (string): Translation key for the field placeholder.suffix (string): Translation key for the field suffix (e.g., units).icon (string): Material Design icon name.type ('number' | 'float' | 'boolean' | 'text' | 'select'): Field type.source (string, optional): Table name in instance.data to get the value from (e.g., 'eParametros').param (string, optional): Key or ID to look up in the source table/array.lookupType (string, optional): How to look up the value in the source. Supported:
lookupParam (string, optional, for arrayByValue): The property to match in the array (e.g., 'ID').lookupValue (string, optional, for arrayByValue): The property to return from the found object (e.g., 'VALOR').default (any, optional): Default value if not found in the instance.options (Array<{label: string, value: any}>, for select type): Options for select fields.solverConfig is used to determine if the solver step is shown and to set the default solver.configFieldsConfig is used to determine if the config fields step is shown and to auto-load values.configFields is used to render the config fields step, auto-load values from the instance, and display the config summary in the confirmation step.The application supports two routing modes controlled by the useHashMode configuration parameter:
This is the default routing mode that creates clean URLs without the hash (#). It requires proper server configuration to handle the URLs correctly.
If you're deploying in an environment where you don't have control over the server configuration or are experiencing issues with route handling, you can enable hash mode:
Environment variable: VITE_APP_USE_HASH_MODE=1
JSON: "useHashMode": true
When hash mode is enabled, all routes will include a hash (#) in the URL (e.g., http://example.com/#/project-execution instead of http://example.com/project-execution).
The application supports multiple languages (English, Spanish, and French). You can configure the default language:
Environment variable: VITE_APP_DEFAULT_LANGUAGE=es
JSON: "defaultLanguage": "es"
Available language codes:
'en' - English'es' - Spanish'fr' - FrenchWhen using JSON configuration (when no environment variables are detected), you can customize the path where the application looks for the values.json file:
Environment variable: VITE_APP_VALUES_JSON_PATH=/config/values.json
The default value is /values.json. The application will:
/config/values.json)https://example.com/config/values.json)This is useful when you need to place the configuration file in a different location than the root of your domain.
The application includes a comprehensive unit testing setup using Vitest and Vue Test Utils. Tests are organized in a specific structure to separate core functionality from application-specific tests.
Unit tests are located in the tests/unit/ directory, which is organized as follows:
tests/unit/
├── core/ # Core tests (DO NOT MODIFY)
│ ├── components/ # Tests for core Vue components
│ ├── services/ # Tests for core services
│ ├── stores/ # Tests for Pinia stores
│ ├── repositories/ # Tests for data repositories
│ ├── views/ # Tests for core views
│ ├── setup.ts # Test setup configuration
│ └── vuetify-setup.ts # Vuetify test configuration
└── app/ # Application-specific tests
└── (your custom tests go here)
tests/unit/core/)tests/unit/app/)The following npm scripts are available for testing:
# Run all tests
npm run test
# Run tests with coverage report
npm run test:coverage
# Run tests with UI interface
npm run test:ui
# Run tests in watch mode (development)
npm run test -- --watch
The test coverage is configured with the following thresholds:
Coverage reports are generated in multiple formats:
coverage/ directoryWhen writing new tests for your application:
Place tests in the correct location:
tests/unit/core/ (DO NOT MODIFY)tests/unit/app/Follow naming conventions:
.spec.tsdescribe blocksUse the provided setup:
Example test structure:
import { describe, test, expect, vi, beforeEach } from 'vitest'
import { mount } from '@vue/test-utils'
import YourComponent from '@/app/components/YourComponent.vue'
import vuetify from '../../core/vuetify-setup'
describe('YourComponent', () => {
beforeEach(() => {
vi.clearAllMocks()
})
test('renders correctly', () => {
const wrapper = mount(YourComponent, {
global: {
plugins: [vuetify]
}
})
expect(wrapper.exists()).toBe(true)
})
})
npm install.env file or values.json to add necessary configurationnpm run dev to start a local development serverContent type
Image
Digest
sha256:ba5cfddd2…
Size
27.4 MB
Last updated
about 1 year ago
docker pull baobabsoluciones/cornflow-ui