Add JSDoc documentation and file headers to all source files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 18:55:36 +08:00
parent 3b7b6ae859
commit 7fec6cb63f
199 changed files with 2764 additions and 503 deletions

View File

@@ -1,4 +1,16 @@
/* eslint-env node */ /* eslint-env node */
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/8/12
// imacat.yang@dsp.im (imacat), 2026/3/5
/**
* @module cypress.config
* Cypress E2E test configuration with viewport
* settings and base URL.
*/
const { defineConfig } = require("cypress"); const { defineConfig } = require("cypress");
module.exports = defineConfig({ module.exports = defineConfig({

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Account Management', () => { describe('Account Management', () => {

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../../support/intercept'; import { loginWithFixtures } from '../../support/intercept';
const MSG_ACCOUNT_NOT_UNIQUE = 'Account has already been registered.'; const MSG_ACCOUNT_NOT_UNIQUE = 'Account has already been registered.';

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/02
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../../support/intercept'; import { loginWithFixtures } from '../../support/intercept';
describe('Password validation on create account.', () => { describe('Password validation on create account.', () => {

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/02
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../../support/intercept'; import { loginWithFixtures } from '../../support/intercept';
describe('Create an Account', () => { describe('Create an Account', () => {

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../../support/intercept'; import { loginWithFixtures } from '../../support/intercept';
describe('Delete an Account', () => { describe('Delete an Account', () => {

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../../support/intercept'; import { loginWithFixtures } from '../../support/intercept';
const MODAL_TITLE_ACCOUNT_EDIT = 'Account Edit'; const MODAL_TITLE_ACCOUNT_EDIT = 'Account Edit';

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Account Management CRUD', () => { describe('Account Management CRUD', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Account Info Modal', () => { describe('Account Info Modal', () => {

View File

@@ -1,3 +1,10 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2024/02/22
// cindy.chang@dsp.im (Cindy Chang), 2024/05/30
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Compare', () => { describe('Compare', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Discover Conformance Page', () => { describe('Discover Conformance Page', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Discover Map Page', () => { describe('Discover Map Page', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Discover Performance Page', () => { describe('Discover Performance Page', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Discover Tab Navigation', () => { describe('Discover Tab Navigation', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Edge Cases', () => { describe('Edge Cases', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('File Operations', () => { describe('File Operations', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Files Page', () => { describe('Files Page', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Files Page - COMPARE Tab', () => { describe('Files Page - COMPARE Tab', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Files to Discover Entry Flow', () => { describe('Files to Discover Entry Flow', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { setupApiIntercepts, loginWithFixtures } from '../support/intercept'; import { setupApiIntercepts, loginWithFixtures } from '../support/intercept';
describe('Login Flow', () => { describe('Login Flow', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Logout Flow', () => { describe('Logout Flow', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('My Account Page', () => { describe('My Account Page', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures, setupApiIntercepts } from '../support/intercept'; import { loginWithFixtures, setupApiIntercepts } from '../support/intercept';
describe('Navigation and Routing', () => { describe('Navigation and Routing', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('404 Not Found Page', () => { describe('404 Not Found Page', () => {

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/06/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('Discover page navigation tabs', () => { describe('Discover page navigation tabs', () => {

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/06/11
// imacat.yang@dsp.im (imacat), 2026/03/05
import { setupApiIntercepts } from '../support/intercept'; import { setupApiIntercepts } from '../support/intercept';
describe('Paste URL login redirect', () => { describe('Paste URL login redirect', () => {

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from '../support/intercept'; import { loginWithFixtures } from '../support/intercept';
describe('SweetAlert2 Modals', () => { describe('SweetAlert2 Modals', () => {

View File

@@ -1,3 +1,9 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/01/31
// imacat.yang@dsp.im (imacat), 2026/03/06
// *********************************************** // ***********************************************
// This example commands.js shows you how to // This example commands.js shows you how to
// create various custom commands and overwrite // create various custom commands and overwrite

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/01/31
// *********************************************************** // ***********************************************************
// This example support/index.js is processed and // This example support/index.js is processed and
// loaded automatically before your test files. // loaded automatically before your test files.

View File

@@ -1,3 +1,8 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
/** /**
* Sets up cy.intercept for all API endpoints using fixture files. * Sets up cy.intercept for all API endpoints using fixture files.
* Call setupApiIntercepts() in beforeEach to mock the entire backend. * Call setupApiIntercepts() in beforeEach to mock the entire backend.

View File

@@ -1,3 +1,13 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/3/6
/**
* @module eslint.config
* ESLint flat configuration for Vue, Cypress, and
* Prettier integration.
*/
import js from "@eslint/js"; import js from "@eslint/js";
import pluginVue from "eslint-plugin-vue"; import pluginVue from "eslint-plugin-vue";
import pluginCypress from "eslint-plugin-cypress"; import pluginCypress from "eslint-plugin-cypress";

View File

@@ -1,3 +1,10 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31
cindy.chang@dsp.im (Cindy Chang), 2024/7/9
Application entry point HTML template. -->
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>

View File

@@ -1,3 +1,13 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2026/3/6
/**
* @module postcss.config
* PostCSS configuration with Tailwind CSS plugin.
*/
module.exports = { module.exports = {
plugins: { plugins: {
"@tailwindcss/postcss": {}, "@tailwindcss/postcss": {},

View File

@@ -3,5 +3,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
/**
* @module App Root application component that renders the router view.
*/
import { RouterView } from "vue-router"; import { RouterView } from "vue-router";
</script> </script>

View File

@@ -1,10 +1,21 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2023/9/23
/** @module auth Authentication token refresh utilities. */
import axios from 'axios'; import axios from 'axios';
import { getCookie, setCookie, setCookieWithoutExpiration } from '@/utils/cookieUtil.js'; import { getCookie, setCookie, setCookieWithoutExpiration } from '@/utils/cookieUtil.js';
/** /**
* Refresh the access token using the refresh token cookie. * Refreshes the access token using the stored refresh token cookie.
* Uses plain axios (not apiClient) to avoid interceptor loops. *
* Uses plain axios (not apiClient) to avoid interceptor loops. Updates
* both the access token (session cookie) and refresh token (6-month
* expiry) cookies.
*
* @returns {Promise<string>} The new access token. * @returns {Promise<string>} The new access token.
* @throws {Error} If the refresh request fails.
*/ */
export async function refreshTokenAndGetNew() { export async function refreshTokenAndGetNew() {
const api = '/api/oauth/token'; const api = '/api/oauth/token';

View File

@@ -1,6 +1,17 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module apiClient Centralized axios instance with request/response
* interceptors for authentication token management and automatic
* 401 token refresh with request queuing.
*/
import axios from 'axios'; import axios from 'axios';
import { getCookie, deleteCookie } from '@/utils/cookieUtil.js'; import { getCookie, deleteCookie } from '@/utils/cookieUtil.js';
/** Axios instance configured with auth interceptors. */
const apiClient = axios.create(); const apiClient = axios.create();
// Request interceptor: automatically attach Authorization header // Request interceptor: automatically attach Authorization header
@@ -16,11 +27,19 @@ apiClient.interceptors.request.use((config) => {
let isRefreshing = false; let isRefreshing = false;
let pendingRequests = []; let pendingRequests = [];
/**
* Resolves all pending requests with the new access token.
* @param {string} newToken - The refreshed access token.
*/
function onRefreshSuccess(newToken) { function onRefreshSuccess(newToken) {
pendingRequests.forEach((cb) => cb(newToken)); pendingRequests.forEach((cb) => cb(newToken));
pendingRequests = []; pendingRequests = [];
} }
/**
* Rejects all pending requests with the refresh error.
* @param {Error} error - The token refresh error.
*/
function onRefreshFailure(error) { function onRefreshFailure(error) {
pendingRequests.forEach((cb) => cb(null, error)); pendingRequests.forEach((cb) => cb(null, error));
pendingRequests = []; pendingRequests = [];

View File

@@ -1,3 +1,12 @@
/* The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/4/18
cindy.chang@dsp.im (Cindy Chang), 2024/8/16
Base CSS layer with global font, validation, height,
and PrimeVue sidebar overrides. */
/* 全域字型 */ /* 全域字型 */
@layer base { @layer base {
html { html {

View File

@@ -1,3 +1,11 @@
/* The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/2/17
Reusable component styles including loaders, scrollbar,
buttons, and toggle buttons. */
/* loading */ /* loading */
.loader { .loader {
width: 64px; width: 64px;

View File

@@ -1,3 +1,10 @@
/* The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/4/18
Layout styles for navbar and heading elements. */
/* Navbar */ /* Navbar */
nav ul>li { nav ul>li {
@apply px-2 py-3.5 duration-300 hover:bg-neutral-900 hover:text-neutral-10 ; @apply px-2 py-3.5 duration-300 hover:bg-neutral-900 hover:text-neutral-10 ;

View File

@@ -1,3 +1,11 @@
/* The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31
cindy.chang@dsp.im (Cindy Chang), 2024/6/18
Main CSS entry point that imports all stylesheet modules. */
@import './tailwind.css'; @import './tailwind.css';
@import './base.css'; @import './base.css';
@import './components.css'; @import './components.css';

View File

@@ -1,3 +1,12 @@
/* The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31
imacat.yang@dsp.im (imacat), 2026/3/6
Tailwind CSS theme configuration with custom colors,
font sizes, breakpoints, and animations. */
/* 引入 Google fonts */ /* 引入 Google fonts */
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');

View File

@@ -1,3 +1,12 @@
/* The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/3/14
cindy.chang@dsp.im (Cindy Chang), 2024/7/26
Third-party vendor style overrides for Google Material
Icons, vue-toast-notification, and PrimeVue components. */
/* import Google font icon */ /* import Google font icon */
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200'); @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');

View File

@@ -1,3 +1,10 @@
/* The Lucia project.
Copyright 2024-2026 DSP, inc. All rights reserved.
Authors:
cindy.chang@dsp.im (Cindy Chang), 2024/6/18
Z-index and positioning rules for the main content area. */
main.w-full { main.w-full {
z-index: 1; z-index: 1;
position: absolute; /*if it were static, the acct mgmt menu would be overlapped*/ position: absolute; /*if it were static, the acct mgmt menu would be overlapped*/

View File

@@ -30,6 +30,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/AccountMenu/AcctMenu Dropdown account menu
* with links to account management, my account, and logout.
*/
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import i18next from '@/i18n/i18n'; import i18next from '@/i18n/i18n';
@@ -58,6 +68,7 @@ const loginUserData = ref(null);
const currentViewingUserDetail = computed(() => acctMgmtStore.currentViewingUser.detail); const currentViewingUserDetail = computed(() => acctMgmtStore.currentViewingUser.detail);
const isAdmin = ref(false); const isAdmin = ref(false);
/** Fetches user data and determines if the current user is an admin. */
const getIsAdminValue = async () => { const getIsAdminValue = async () => {
await loginStore.getUserData(); await loginStore.getUserData();
loginUserData.value = loginStore.userData; loginUserData.value = loginStore.userData;
@@ -65,6 +76,7 @@ const getIsAdminValue = async () => {
isAdmin.value = acctMgmtStore.currentViewingUser.is_admin; isAdmin.value = acctMgmtStore.currentViewingUser.is_admin;
}; };
/** Navigates to the My Account page. */
const onBtnMyAccountClick = async () => { const onBtnMyAccountClick = async () => {
acctMgmtStore.closeAcctMenu(); acctMgmtStore.closeAcctMenu();
await acctMgmtStore.getAllUserAccounts(); // in case we haven't fetched yet await acctMgmtStore.getAllUserAccounts(); // in case we haven't fetched yet
@@ -72,6 +84,7 @@ const onBtnMyAccountClick = async () => {
await router.push('/my-account'); await router.push('/my-account');
}; };
/** Registers a click listener to close the menu when clicking outside. */
const clickOtherPlacesThenCloseMenu = () => { const clickOtherPlacesThenCloseMenu = () => {
const acctMgmtButton = document.getElementById('acct_mgmt_button'); const acctMgmtButton = document.getElementById('acct_mgmt_button');
const acctMgmtMenu = document.getElementById('account_menu'); const acctMgmtMenu = document.getElementById('account_menu');
@@ -83,11 +96,13 @@ const clickOtherPlacesThenCloseMenu = () => {
}); });
}; };
/** Navigates to the Account Admin page. */
const onBtnAcctMgmtClick = () => { const onBtnAcctMgmtClick = () => {
router.push({name: 'AcctAdmin'}); router.push({name: 'AcctAdmin'});
acctMgmtStore.closeAcctMenu(); acctMgmtStore.closeAcctMenu();
}; };
/** Handles logout with unsaved-changes confirmation for Map and Conformance pages. */
const onLogoutBtnClick = () => { const onLogoutBtnClick = () => {
if ((route.name === 'Map' || route.name === 'CheckMap') && tempFilterId.value) { if ((route.name === 'Map' || route.name === 'CheckMap') && tempFilterId.value) {
// 傳給 Map通知 Sidebar 要關閉。 // 傳給 Map通知 Sidebar 要關閉。

View File

@@ -10,6 +10,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/AccountMenu/SearchBar Search input bar for
* filtering accounts, emits search query on click or Enter key.
*/
import { ref } from 'vue'; import { ref } from 'vue';
import i18next from '@/i18n/i18n.js'; import i18next from '@/i18n/i18n.js';
@@ -17,11 +27,19 @@ const emit = defineEmits(['on-search-account-button-click']);
const inputQuery = ref(""); const inputQuery = ref("");
/**
* Emits the search query when the search icon is clicked.
* @param {Event} event - The click event.
*/
const onSearchClick = (event) => { const onSearchClick = (event) => {
event.preventDefault(); event.preventDefault();
emit('on-search-account-button-click', inputQuery.value); emit('on-search-account-button-click', inputQuery.value);
}; };
/**
* Emits the search query when Enter key is pressed.
* @param {KeyboardEvent} event - The keypress event.
*/
const handleKeyPressOfSearch = (event) => { const handleKeyPressOfSearch = (event) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
emit('on-search-account-button-click', inputQuery.value); emit('on-search-account-button-click', inputQuery.value);

View File

@@ -13,6 +13,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Badge Status badge component that displays
* an activated/deactivated state with colored background.
*/
defineProps({ defineProps({
isActivated: { isActivated: {
type: Boolean, type: Boolean,

View File

@@ -16,6 +16,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Button Outlined button component with
* press-state ring effect.
*/
import { ref } from 'vue'; import { ref } from 'vue';
defineProps({ defineProps({

View File

@@ -17,6 +17,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/ButtonFilled Filled button component with
* solid background and press-state ring effect.
*/
import { ref } from 'vue'; import { ref } from 'vue';
defineProps({ defineProps({

View File

@@ -147,6 +147,17 @@
</Sidebar> </Sidebar>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Compare/SidebarStates Summary sidebar for
* the Compare view showing side-by-side statistics (cases,
* traces, activities, timeframes, durations) of two files.
*/
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useCompareStore } from '@/stores/compare'; import { useCompareStore } from '@/stores/compare';
@@ -175,9 +186,9 @@ const primaryStatData = ref(null);
const secondaryStatData = ref(null); const secondaryStatData = ref(null);
/** /**
* Number to percentage * Converts a ratio (01) to a percentage number (0100), capped at 100.
* @param {number} val 原始數字 * @param {number} val - The ratio value to convert.
* @returns {string} 轉換完成的百分比字串 * @returns {number} The percentage value.
*/ */
const getPercentLabel = (val) => { const getPercentLabel = (val) => {
if((val * 100).toFixed(1) >= 100) return 100; if((val * 100).toFixed(1) >= 100) return 100;
@@ -185,10 +196,10 @@ const getPercentLabel = (val) => {
}; };
/** /**
* setting stats data * Transforms raw API stats into display-ready stat data.
* @param { object } data fetch API stats data * @param {Object} data - The raw stats from the API.
* @param { string } fileName file Name * @param {string} fileName - The file name to display.
* @returns { object } primaryStatData | secondaryStatData回傳 primaryStatData 或 secondaryStatData * @returns {Object} The formatted stat data object.
*/ */
const getStatData = (data, fileName) => { const getStatData = (data, fileName) => {
return { return {
@@ -224,9 +235,7 @@ const getStatData = (data, fileName) => {
} }
}; };
/** /** Populates progress bar values when the sidebar is shown. */
* Behavior when show
*/
const show = () => { const show = () => {
primaryValueCases.value = primaryStatData.value.cases.ratio; primaryValueCases.value = primaryStatData.value.cases.ratio;
primaryValueTraces.value = primaryStatData.value.traces.ratio; primaryValueTraces.value = primaryStatData.value.traces.ratio;
@@ -238,9 +247,7 @@ const show = () => {
secondaryValueTasks.value = secondaryStatData.value.tasks.ratio; secondaryValueTasks.value = secondaryStatData.value.tasks.ratio;
}; };
/** /** Resets all progress bar values to zero when the sidebar is hidden. */
* Behavior when hidden
*/
const hide = () => { const hide = () => {
primaryValueCases.value = 0; primaryValueCases.value = 0;
primaryValueTraces.value = 0; primaryValueTraces.value = 0;

View File

@@ -192,6 +192,18 @@
</section> </section>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceResults
* Conformance checking results panel displaying rule
* check outcomes in a data table with status indicators.
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useConformanceStore } from '@/stores/conformance'; import { useConformanceStore } from '@/stores/conformance';
@@ -274,8 +286,8 @@ const tooltip = ref({
/** /**
* set progress bar width * set progress bar width
* @param {number} value 百分比數字 * @param {number} value - The percentage value.
* @returns {string} 樣式的寬度設定 * @returns {string} The CSS width style string.
*/ */
const progressWidth = (value) => { const progressWidth = (value) => {
return `width:${value}%;` return `width:${value}%;`
@@ -283,8 +295,8 @@ const progressWidth = (value) => {
/** /**
* Number to percentage * Number to percentage
* @param {number} val 原始數字 * @param {number} val - The raw ratio value.
* @returns {string} 轉換完成的百分比字串 * @returns {string} The formatted percentage string.
*/ */
const getPercentLabel = (val) => { const getPercentLabel = (val) => {
if((val * 100).toFixed(1) >= 100) return 100; if((val * 100).toFixed(1) >= 100) return 100;
@@ -293,7 +305,7 @@ const getPercentLabel = (val) => {
/** /**
* Convert seconds to days * Convert seconds to days
* @param {number} sec 秒數 * @param {number} sec - The number of seconds.
* @returns {number} day * @returns {number} day
*/ */
const convertSecToDay = (sec) => { const convertSecToDay = (sec) => {
@@ -302,7 +314,7 @@ const convertSecToDay = (sec) => {
/** /**
* Open Issues Modal. * Open Issues Modal.
* @param {number} no trace 編號 * @param {number} no - The trace number.
*/ */
const openMore = async (no) => { const openMore = async (no) => {
// async await 解決非同步資料延遲傳遞導致未讀取到而出錯的問題 // async await 解決非同步資料延遲傳遞導致未讀取到而出錯的問題
@@ -315,7 +327,7 @@ const openMore = async (no) => {
/** /**
* Open Loop Modal. * Open Loop Modal.
* @param {number} no trace 編號 * @param {number} no - The trace number.
*/ */
const openLoopMore = async (no) => { const openLoopMore = async (no) => {
// async await 解決非同步資料延遲傳遞導致未讀取到而出錯的問題 // async await 解決非同步資料延遲傳遞導致未讀取到而出錯的問題
@@ -328,7 +340,7 @@ const openLoopMore = async (no) => {
/** /**
* set conformance report data * set conformance report data
* @param {object} data new watch's value 監聽到後端傳來的報告 data * @param {object} data - The report data received from the backend.
*/ */
const setConformanceTempReportData = (newData) => { const setConformanceTempReportData = (newData) => {
const total = getNumberLabel(Object.values(newData.counts).reduce((acc, val) => acc + val, 0)); const total = getNumberLabel(Object.values(newData.counts).reduce((acc, val) => acc + val, 0));

View File

@@ -122,6 +122,19 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
/**
* @module components/Discover/Conformance/ConformanceSidebar
* Main sidebar for conformance checking with rule
* configuration, activity selection, and submit/reset
* actions.
*/
import { ref, computed, watch, onBeforeUnmount } from 'vue'; import { ref, computed, watch, onBeforeUnmount } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useToast } from 'vue-toast-notification'; import { useToast } from 'vue-toast-notification';
@@ -622,14 +635,14 @@ watch(conformanceTempReportData, (newValue) => {
// methods // methods
/** /**
* get min total seconds * get min total seconds
* @param {Number} e 最小值總秒數 * @param {number} e - The minimum total seconds.
*/ */
function minTotalSeconds(e) { function minTotalSeconds(e) {
selectTimeRangeMin.value = e; selectTimeRangeMin.value = e;
} }
/** /**
* get min total seconds * get min total seconds
* @param {Number} e 最大值總秒數 * @param {number} e - The maximum total seconds.
*/ */
function maxTotalSeconds(e) { function maxTotalSeconds(e) {
selectTimeRangeMax.value = e; selectTimeRangeMax.value = e;
@@ -715,7 +728,7 @@ function isSubmitReset() {
isSubmitTimeCfmCtEteSE.value = { base: {}, rule: {}}; isSubmitTimeCfmCtEteSE.value = { base: {}, rule: {}};
} }
/** /**
* 清空選單的行為 * Clears all form selections and resets the sidebar state.
*/ */
function reset() { function reset() {
// Results page Cover Plate(遮罩為 ture) // Results page Cover Plate(遮罩為 ture)
@@ -733,7 +746,7 @@ function reset() {
isShowBarOpen.value = true; isShowBarOpen.value = true;
} }
/** /**
* 設定 Start & End Data 連動資料 * Sets linked Start & End data for activity selection.
* @param {string} start task * @param {string} start task
* @param {string} end task * @param {string} end task
* @returns {object} * @returns {object}
@@ -758,7 +771,7 @@ function setSubmitShowDataByStartEnd(start, end) {
} }
} }
/** /**
* Apply button 發送選項,取得 Check Id. * Submits the selected options via the Apply button and retrieves the Check ID.
*/ */
async function submitConformance() { async function submitConformance() {
let dataToSave; let dataToSave;
@@ -810,6 +823,9 @@ async function submitConformance() {
$toast.success(i18next.t("Conformance.RuleApplied")); $toast.success(i18next.t("Conformance.RuleApplied"));
} }
/** Builds the data payload for the 'Have activity' rule.
* @returns {object} The rule data to submit.
*/
function getHaveActivityData() { function getHaveActivityData() {
const dataToSave = { const dataToSave = {
type: 'contains-tasks', type: 'contains-tasks',
@@ -820,6 +836,9 @@ function getHaveActivityData() {
return dataToSave; return dataToSave;
} }
/** Builds the data payload for the 'Activity sequence' rule.
* @returns {object} The rule data to submit.
*/
function getActivitySequenceData() { function getActivitySequenceData() {
let dataToSave; let dataToSave;
switch (selectedActivitySequence.value) { switch (selectedActivitySequence.value) {
@@ -843,6 +862,9 @@ function getActivitySequenceData() {
return dataToSave; return dataToSave;
} }
/** Builds the data payload for sequence sub-rules.
* @returns {object} The rule data to submit.
*/
function getSequenceData() { function getSequenceData() {
let dataToSave; let dataToSave;
switch (selectedMode.value) { switch (selectedMode.value) {
@@ -872,6 +894,9 @@ function getSequenceData() {
return dataToSave; return dataToSave;
} }
/** Builds the data payload for the 'Activity duration' rule.
* @returns {object} The rule data to submit.
*/
function getActivityDurationData() { function getActivityDurationData() {
const dataToSave = { const dataToSave = {
type: 'task-duration', type: 'task-duration',
@@ -885,6 +910,9 @@ function getActivityDurationData() {
return dataToSave; return dataToSave;
} }
/** Builds the data payload for the 'Processing time' rule.
* @returns {object} The rule data to submit.
*/
function getProcessingTimeData() { function getProcessingTimeData() {
let dataToSave; let dataToSave;
switch (selectedProcessScope.value) { switch (selectedProcessScope.value) {
@@ -898,6 +926,9 @@ function getProcessingTimeData() {
return dataToSave; return dataToSave;
} }
/** Builds end-to-end processing time rule data.
* @returns {object} The rule data to submit.
*/
function getEndToEndProcessingTimeData() { function getEndToEndProcessingTimeData() {
let dataToSave; let dataToSave;
switch (selectedActSeqMore.value) { switch (selectedActSeqMore.value) {
@@ -952,6 +983,9 @@ function getEndToEndProcessingTimeData() {
return dataToSave; return dataToSave;
} }
/** Builds partial processing time rule data.
* @returns {object} The rule data to submit.
*/
function getPartialProcessingTimeData() { function getPartialProcessingTimeData() {
let dataToSave; let dataToSave;
switch (selectedActSeqFromTo.value) { switch (selectedActSeqFromTo.value) {
@@ -997,6 +1031,9 @@ function getPartialProcessingTimeData() {
return dataToSave; return dataToSave;
} }
/** Builds the data payload for the 'Waiting time' rule.
* @returns {object} The rule data to submit.
*/
function getWaitingTimeData() { function getWaitingTimeData() {
let dataToSave; let dataToSave;
switch (selectedProcessScope.value) { switch (selectedProcessScope.value) {
@@ -1010,6 +1047,9 @@ function getWaitingTimeData() {
return dataToSave; return dataToSave;
} }
/** Builds end-to-end waiting time rule data.
* @returns {object} The rule data to submit.
*/
function getEndToEndWaitingTimeData() { function getEndToEndWaitingTimeData() {
let dataToSave; let dataToSave;
switch (selectedActSeqMore.value) { switch (selectedActSeqMore.value) {
@@ -1064,6 +1104,9 @@ function getEndToEndWaitingTimeData() {
return dataToSave; return dataToSave;
} }
/** Builds partial waiting time rule data.
* @returns {object} The rule data to submit.
*/
function getPartialWaitingTimeData() { function getPartialWaitingTimeData() {
let dataToSave; let dataToSave;
switch (selectedActSeqFromTo.value) { switch (selectedActSeqFromTo.value) {
@@ -1109,6 +1152,9 @@ function getPartialWaitingTimeData() {
return dataToSave; return dataToSave;
} }
/** Builds the data payload for the 'Cycle time' rule.
* @returns {object} The rule data to submit.
*/
function getCycleTimeData() { function getCycleTimeData() {
let dataToSave; let dataToSave;
switch (selectedActSeqMore.value) { switch (selectedActSeqMore.value) {
@@ -1164,7 +1210,7 @@ function getCycleTimeData() {
} }
/** /**
* 設置根據類別的任務選擇邏輯 * Sets up category-based task selection logic.
*/ */
function setTaskByCategoryOnRadioEmitting() { function setTaskByCategoryOnRadioEmitting() {
emitter.on('actRadioData', (data) => { emitter.on('actRadioData', (data) => {
@@ -1201,6 +1247,10 @@ function setTaskByCategoryOnRadioEmitting() {
}); });
} }
/**
* Handles start task selection for activity sequence.
* @param {string} task - The selected task.
*/
function handleCfmSeqStart(task) { function handleCfmSeqStart(task) {
if (isStartSelected.value && task !== selectCfmSeqStart.value) { if (isStartSelected.value && task !== selectCfmSeqStart.value) {
selectCfmSeqEnd.value = null; selectCfmSeqEnd.value = null;
@@ -1208,6 +1258,10 @@ function handleCfmSeqStart(task) {
selectCfmSeqStart.value = task; selectCfmSeqStart.value = task;
} }
/**
* Handles end task selection for activity sequence.
* @param {string} task - The selected task.
*/
function handleCfmSeqEnd(task) { function handleCfmSeqEnd(task) {
if (isEndSelected.value && task !== selectCfmSeqEnd.value) { if (isEndSelected.value && task !== selectCfmSeqEnd.value) {
selectCfmSeqStart.value = null; selectCfmSeqStart.value = null;
@@ -1215,64 +1269,109 @@ function handleCfmSeqEnd(task) {
selectCfmSeqEnd.value = task; selectCfmSeqEnd.value = task;
} }
/**
* Sets a simple task selection on a ref field.
* @param {object} field - The ref to set.
* @param {string} task - The selected task.
*/
function handleSimpleSelection(field, task) { function handleSimpleSelection(field, task) {
selectFieldRefs[field].value = task; selectFieldRefs[field].value = task;
} }
/**
* Handles start task for end-to-end processing time.
* @param {string} task - The selected task.
*/
function handleCfmPtEteSEStart(task) { function handleCfmPtEteSEStart(task) {
if (isStartSelected.value && task !== selectCfmPtEteSEStart.value) { if (isStartSelected.value && task !== selectCfmPtEteSEStart.value) {
selectCfmPtEteSEEnd.value = null; selectCfmPtEteSEEnd.value = null;
} }
selectCfmPtEteSEStart.value = task; selectCfmPtEteSEStart.value = task;
} }
/**
* Handles end task for end-to-end processing time.
* @param {string} task - The selected task.
*/
function handleCfmPtEteSEEnd(task) { function handleCfmPtEteSEEnd(task) {
if (isEndSelected.value && task !== selectCfmPtEteSEEnd.value) { if (isEndSelected.value && task !== selectCfmPtEteSEEnd.value) {
selectCfmPtEteSEStart.value = null; selectCfmPtEteSEStart.value = null;
} }
selectCfmPtEteSEEnd.value = task; selectCfmPtEteSEEnd.value = task;
} }
/**
* Handles start task for partial processing time.
* @param {string} task - The selected task.
*/
function handleCfmPtPSEStart(task) { function handleCfmPtPSEStart(task) {
if (isStartSelected.value && task !== selectCfmPtPSEStart.value) { if (isStartSelected.value && task !== selectCfmPtPSEStart.value) {
selectCfmPtPSEEnd.value = null; selectCfmPtPSEEnd.value = null;
} }
selectCfmPtPSEStart.value = task; selectCfmPtPSEStart.value = task;
} }
/**
* Handles end task for partial processing time.
* @param {string} task - The selected task.
*/
function handleCfmPtPSEEnd(task) { function handleCfmPtPSEEnd(task) {
if (isEndSelected.value && task !== selectCfmPtPSEEnd.value) { if (isEndSelected.value && task !== selectCfmPtPSEEnd.value) {
selectCfmPtPSEStart.value = null; selectCfmPtPSEStart.value = null;
} }
selectCfmPtPSEEnd.value = task; selectCfmPtPSEEnd.value = task;
} }
/**
* Handles start task for end-to-end waiting time.
* @param {string} task - The selected task.
*/
function handleCfmWtEteSEStart(task) { function handleCfmWtEteSEStart(task) {
if (isStartSelected.value && task !== selectCfmWtEteSEStart.value) { if (isStartSelected.value && task !== selectCfmWtEteSEStart.value) {
selectCfmWtEteSEEnd.value = null; selectCfmWtEteSEEnd.value = null;
} }
selectCfmWtEteSEStart.value = task; selectCfmWtEteSEStart.value = task;
} }
/**
* Handles end task for end-to-end waiting time.
* @param {string} task - The selected task.
*/
function handleCfmWtEteSEEnd(task) { function handleCfmWtEteSEEnd(task) {
if (isEndSelected.value && task !== selectCfmWtEteSEEnd.value) { if (isEndSelected.value && task !== selectCfmWtEteSEEnd.value) {
selectCfmWtEteSEStart.value = null; selectCfmWtEteSEStart.value = null;
} }
selectCfmWtEteSEEnd.value = task; selectCfmWtEteSEEnd.value = task;
} }
/**
* Handles start task for partial waiting time.
* @param {string} task - The selected task.
*/
function handleCfmWtPSEStart(task) { function handleCfmWtPSEStart(task) {
if (isStartSelected.value && task !== selectCfmWtPSEStart.value) { if (isStartSelected.value && task !== selectCfmWtPSEStart.value) {
selectCfmWtPSEEnd.value = null; selectCfmWtPSEEnd.value = null;
} }
selectCfmWtPSEStart.value = task; selectCfmWtPSEStart.value = task;
} }
/**
* Handles end task for partial waiting time.
* @param {string} task - The selected task.
*/
function handleCfmWtPSEEnd(task) { function handleCfmWtPSEEnd(task) {
if (isEndSelected.value && task !== selectCfmWtPSEEnd.value) { if (isEndSelected.value && task !== selectCfmWtPSEEnd.value) {
selectCfmWtPSEStart.value = null; selectCfmWtPSEStart.value = null;
} }
selectCfmWtPSEEnd.value = task; selectCfmWtPSEEnd.value = task;
} }
/**
* Handles start task for end-to-end cycle time.
* @param {string} task - The selected task.
*/
function handleCfmCtEteSEStart(task) { function handleCfmCtEteSEStart(task) {
if (isStartSelected.value && task !== selectCfmCtEteSEStart.value) { if (isStartSelected.value && task !== selectCfmCtEteSEStart.value) {
selectCfmCtEteSEEnd.value = null; selectCfmCtEteSEEnd.value = null;
} }
selectCfmCtEteSEStart.value = task; selectCfmCtEteSEStart.value = task;
} }
/**
* Handles end task for end-to-end cycle time.
* @param {string} task - The selected task.
*/
function handleCfmCtEteSEEnd(task) { function handleCfmCtEteSEEnd(task) {
if (isEndSelected.value && task !== selectCfmCtEteSEEnd.value) { if (isEndSelected.value && task !== selectCfmCtEteSEEnd.value) {
selectCfmCtEteSEStart.value = null; selectCfmCtEteSEStart.value = null;
@@ -1280,6 +1379,7 @@ function handleCfmCtEteSEEnd(task) {
selectCfmCtEteSEEnd.value = task; selectCfmCtEteSEEnd.value = task;
} }
/** Sets task data when the list sequence emits a change. */
function setTaskByCategoryOnListSeqEmitting(){ function setTaskByCategoryOnListSeqEmitting(){
emitter.on('getListSequence', (data) => { emitter.on('getListSequence', (data) => {
switch (data.category) { switch (data.category) {
@@ -1295,15 +1395,21 @@ function setTaskByCategoryOnListSeqEmitting(){
}); });
} }
/** Checks if the 'Have activity' rule has valid selections.
* @returns {boolean} Whether the button should be disabled.
*/
function checkHaveActivity() { function checkHaveActivity() {
return !(selectConformanceTask.value?.length); return !(selectConformanceTask.value?.length);
} }
/** Checks if the 'Activity duration' rule has valid selections.
* @returns {boolean} Whether the button should be disabled.
*/
function checkActivityDuration() { function checkActivityDuration() {
return !selectDurationData.value?.length; return !selectDurationData.value?.length;
} }
/** /**
* 檢查活動序列的邏輯 * Checks the activity sequence logic.
* @returns {boolean} 是否禁用按鈕 * @returns {boolean} Whether the button should be disabled.
*/ */
function checkActivitySequence() { function checkActivitySequence() {
switch (selectedActivitySequence.value) { switch (selectedActivitySequence.value) {
@@ -1316,15 +1422,18 @@ function checkActivitySequence() {
} }
} }
/** /**
* 檢查 Start & End 活動序列 * Checks the Start & End activity sequence.
* @param {string} start 活動開始 * @param {string} start - The start activity.
* @param {string} end 活動結束 * @param {string} end - The end activity.
* @returns {boolean} 是否禁用按鈕 * @returns {boolean} Whether the button should be disabled.
*/ */
function checkStartAndEndSequence(start, end) { function checkStartAndEndSequence(start, end) {
return !(start && end); return !(start && end);
} }
/** Checks if the 'Processing time' rule has valid selections.
* @returns {boolean} Whether the button should be disabled.
*/
function checkProcessingTime() { function checkProcessingTime() {
let disabled = true; let disabled = true;
switch (selectedProcessScope.value) { switch (selectedProcessScope.value) {
@@ -1339,6 +1448,9 @@ function checkProcessingTime() {
} }
return disabled; return disabled;
} }
/** Checks end-to-end scope selections.
* @returns {boolean} Whether the button should be disabled.
*/
function checkEndToEnd() { function checkEndToEnd() {
let disabled = true; let disabled = true;
switch (selectedActSeqMore.value) { switch (selectedActSeqMore.value) {
@@ -1362,6 +1474,9 @@ function checkEndToEnd() {
} }
return disabled; return disabled;
} }
/** Checks partial scope selections.
* @returns {boolean} Whether the button should be disabled.
*/
function checkPartial() { function checkPartial() {
let disabled = true; let disabled = true;
switch (selectedActSeqFromTo.value) { switch (selectedActSeqFromTo.value) {

View File

@@ -10,6 +10,16 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ActList
* Checkbox-based activity list for conformance checking input.
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { sortNumEngZhtw } from '@/module/sortNumEngZhtw.js'; import { sortNumEngZhtw } from '@/module/sortNumEngZhtw.js';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';
@@ -27,9 +37,7 @@ watch(() => props.select, (newValue) => {
actList.value = newValue; actList.value = newValue;
}); });
/** /** Emits the selected activities list via the event bus. */
* 將選取的 Activities 傳出去
*/
function actListData() { function actListData() {
emitter.emit('actListData', actList.value); emitter.emit('actListData', actList.value);
} }

View File

@@ -10,6 +10,18 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ActRadio
* Radio-button activity selector for conformance checking
* start/end activity input.
*/
import { ref, computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import { useConformanceInputStore } from "@/stores/conformanceInput"; import { useConformanceInputStore } from "@/stores/conformanceInput";
import { sortNumEngZhtw } from '@/module/sortNumEngZhtw.js'; import { sortNumEngZhtw } from '@/module/sortNumEngZhtw.js';
@@ -37,9 +49,7 @@ const inputActivityRadioData = computed(() => ({
task: selectedRadio.value, task: selectedRadio.value,
})); }));
/** /** Emits the selected activity via event bus and updates the store. */
* 將選取的 Activity 傳出去
*/
function actRadioData() { function actRadioData() {
localSelect.value = null; localSelect.value = null;
emitter.emit('actRadioData', inputActivityRadioData.value); emitter.emit('actRadioData', inputActivityRadioData.value);
@@ -47,6 +57,7 @@ function actRadioData() {
conformanceInputStore.setActivityRadioStartEndData(inputActivityRadioData.value.task); conformanceInputStore.setActivityRadioStartEndData(inputActivityRadioData.value.task);
} }
/** Sets the global activity radio data state in the conformance input store. */
function setGlobalActivityRadioDataState() { function setGlobalActivityRadioDataState() {
//this.title: value might be "From" or "To" //this.title: value might be "From" or "To"
conformanceInputStore.setActivityRadioStartEndData(inputActivityRadioData.value.task, props.title); conformanceInputStore.setActivityRadioStartEndData(inputActivityRadioData.value.task, props.title);

View File

@@ -42,6 +42,18 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ActSeqDrag
* Drag-and-drop activity sequence builder for
* conformance rule configuration.
*/
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { sortNumEngZhtw } from '@/module/sortNumEngZhtw.js'; import { sortNumEngZhtw } from '@/module/sortNumEngZhtw.js';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';

View File

@@ -51,6 +51,17 @@
</section> </section>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ConformanceRadioGroup
* Radio button groups for conformance rule type, activity
* sequence, mode, and process scope selection.
*/
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useConformanceStore } from '@/stores/conformance'; import { useConformanceStore } from '@/stores/conformance';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';
@@ -92,9 +103,7 @@ const actSeqFromTo = [
{id: 3, name: 'From & To'}, {id: 3, name: 'From & To'},
]; ];
/** /** Resets dependent selections when the rule type radio changes. */
* 切換 Rule Type 的選項時的行為
*/
function changeRadio() { function changeRadio() {
selectedActivitySequence.value = 'Start & End'; selectedActivitySequence.value = 'Start & End';
selectedMode.value = 'Directly follows'; selectedMode.value = 'Directly follows';
@@ -103,27 +112,19 @@ function changeRadio() {
selectedActSeqFromTo.value = 'From'; selectedActSeqFromTo.value = 'From';
emitter.emit('isRadioChange', true); // Radio 切換時,資料要清空 emitter.emit('isRadioChange', true); // Radio 切換時,資料要清空
} }
/** /** Emits event when the activity sequence radio changes. */
* 切換 Activity sequence 的選項時的行為
*/
function changeRadioSeq() { function changeRadioSeq() {
emitter.emit('isRadioSeqChange',true); emitter.emit('isRadioSeqChange',true);
} }
/** /** Emits event when the process scope radio changes. */
* 切換 Processing time 的選項時的行為
*/
function changeRadioProcessScope() { function changeRadioProcessScope() {
emitter.emit('isRadioProcessScopeChange', true); emitter.emit('isRadioProcessScopeChange', true);
} }
/** /** Emits event when the extended activity sequence radio changes. */
* 切換 Process Scope 的選項時的行為
*/
function changeRadioActSeqMore() { function changeRadioActSeqMore() {
emitter.emit('isRadioActSeqMoreChange', true); emitter.emit('isRadioActSeqMoreChange', true);
} }
/** /** Emits event when the from/to activity sequence radio changes. */
* 切換 Activity Sequence 的選項時的行為
*/
function changeRadioActSeqFromTo() { function changeRadioActSeqFromTo() {
emitter.emit('isRadioActSeqFromToChange', true); emitter.emit('isRadioActSeqFromToChange', true);
} }

View File

@@ -29,6 +29,18 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ConformanceSelectResult
* Conformance result list with selectable items and
* scrollable display of check results.
*/
import { reactive, computed } from 'vue'; import { reactive, computed } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useConformanceStore } from '@/stores/conformance'; import { useConformanceStore } from '@/stores/conformance';

View File

@@ -98,6 +98,18 @@
</section> </section>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ConformanceShowBar
* Horizontal bar chart component displaying conformance
* check result statistics.
*/
import { ref, computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useLoadingStore } from '@/stores/loading'; import { useLoadingStore } from '@/stores/loading';
@@ -239,10 +251,9 @@ watch(() => props.isSubmitShowDataCt, (newValue) => {
}); });
/** /**
* 設定 start and end 的 Radio Data * Sets the start and end radio data.
* @param {object} data cfmSeqStart | cfmSeqEnd | cfmPtEteSE | cfmPtPSE | cfmWtEteSE | cfmWtPSE | cfmCtEteSE * @param {object} data - Activities list data from the backend (cfmSeqStart, cfmSeqEnd, cfmPtEteSE, etc.).
* 傳入以上任一後端接到的 Activities 列表 Data。 * @param {string} category - 'start' or 'end'.
* @param {string} category 'start' | 'end',傳入 'start' 或 'end'。
* @returns {array} * @returns {array}
*/ */
function setTaskData(data, category) { function setTaskData(data, category) {
@@ -251,11 +262,10 @@ function setTaskData(data, category) {
return newData; return newData;
} }
/** /**
* 重新設定連動的 start and end 的 Radio Data * Resets the linked start and end radio data.
* @param {object} data cfmPtEteSE | cfmPtPSE | cfmWtEteSE | cfmWtPSE | cfmCtEteSE * @param {object} data - Activities list data from the backend (cfmPtEteSE, cfmPtPSE, etc.).
* 傳入以上任一後端接到的 Activities 列表 Data。 * @param {string} category - 'start' or 'end'.
* @param {string} category 'start' | 'end',傳入 'start' 或 'end'。 * @param {string} task - The selected activity task.
* @param {string} task 已選擇的 Activity task
* @returns {array} * @returns {array}
*/ */
function setStartAndEndData(data, category, taskVal) { function setStartAndEndData(data, category, taskVal) {
@@ -270,10 +280,10 @@ function setStartAndEndData(data, category, taskVal) {
return newData; return newData;
} }
/** /**
* 重新設定 Activity sequence 連動的 start and end 的 Radio Data * Resets the activity sequence linked start and end radio data.
* @param {object} data cfmSeqStart | cfmSeqEnd,傳入以上任一後端接到的 Activities 列表 Data。 * @param {object} data - Activities list data from the backend (cfmSeqStart or cfmSeqEnd).
* @param {string} category 'sources' | 'sinks',傳入 'sources' 或 'sinks' * @param {string} category - 'sources' or 'sinks'.
* @param {string} task 已選擇的 Activity task * @param {string} task - The selected activity task.
* @returns {array} * @returns {array}
*/ */
function setSeqStartAndEndData(data, category, taskVal) { function setSeqStartAndEndData(data, category, taskVal) {
@@ -283,7 +293,7 @@ function setSeqStartAndEndData(data, category, taskVal) {
} }
/** /**
* select start list's task * select start list's task
* @param {event} e 觸發 input 的詳細事件 * @param {Event} e - The input event.
*/ */
function selectStart(e) { function selectStart(e) {
taskStart.value = e; taskStart.value = e;
@@ -300,7 +310,7 @@ function selectStart(e) {
} }
/** /**
* select End list's task * select End list's task
* @param {event} e 觸發 input 的詳細事件 * @param {Event} e - The input event.
*/ */
function selectEnd(e) { function selectEnd(e) {
taskEnd.value = e; taskEnd.value = e;
@@ -326,8 +336,8 @@ function reset() {
taskEnd.value = null; taskEnd.value = null;
} }
/** /**
* Radio 切換時,Start & End Data 連動改變 * Updates linked Start & End data when radio selection changes.
* @param {boolean} data true | false傳入 true 或 false * @param {boolean} data - Whether data should be restored from submission state.
*/ */
function setResetData(data) { function setResetData(data) {
if(data) { if(data) {

View File

@@ -68,6 +68,18 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ConformanceTimeRange
* Time range picker for conformance time-based rule
* configuration with calendar inputs.
*/
import { reactive } from 'vue'; import { reactive } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useConformanceStore } from '@/stores/conformance'; import { useConformanceStore } from '@/stores/conformance';
@@ -149,22 +161,22 @@ const storeRefs = {
/** /**
* get min total seconds * get min total seconds
* @param {Number} e 最小值總秒數 * @param {number} e - The minimum total seconds.
*/ */
function minTotalSeconds(e) { function minTotalSeconds(e) {
emit('min-total-seconds', e); emit('min-total-seconds', e);
} }
/** /**
* get min total seconds * get min total seconds
* @param {Number} e 最大值總秒數 * @param {number} e - The maximum total seconds.
*/ */
function maxTotalSeconds(e) { function maxTotalSeconds(e) {
emit('max-total-seconds', e); emit('max-total-seconds', e);
} }
/** /**
* get Time Range(duration) * get Time Range(duration)
* @param {array} data API dataActivity 列表 * @param {Array} data - Activity list data from the API.
* @param {string} category 'act' | 'single' | 'double',傳入以上任一值。 * @param {string} category - 'act', 'single', or 'double'.
* @param {string} task select Radio task or start * @param {string} task select Radio task or start
* @param {string} taskTwo end * @param {string} taskTwo end
* @returns {object} {min:12, max:345} * @returns {object} {min:12, max:345}

View File

@@ -9,5 +9,16 @@
</ul> </ul>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ResultArrow
* Conformance result display with arrow icons showing activity
* sequences.
*/
defineProps(['data', 'select']); defineProps(['data', 'select']);
</script> </script>

View File

@@ -9,6 +9,17 @@
</ul> </ul>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ResultCheck
* Conformance result display with check-circle icons showing
* matched activities.
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';

View File

@@ -8,6 +8,17 @@
</ul> </ul>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/ResultDot
* Conformance result display with dot icons showing category
* and task pairs.
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';

View File

@@ -10,6 +10,18 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/ConformanceSidebar/TimeRangeDuration
* Time range duration picker with min/max duration inputs
* for conformance time-based rules.
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import Durationjs from '@/components/durationjs.vue'; import Durationjs from '@/components/durationjs.vue';
@@ -28,9 +40,7 @@ const updateMin = ref(null);
const durationMin = ref(null); const durationMin = ref(null);
const durationMax = ref(null); const durationMax = ref(null);
/** /** Deep-copies timeData min/max values to the Vue component boundaries. */
* set props values
*/
function setTimeValue() { function setTimeValue() {
// 深拷貝原始 timeData 的內容 // 深拷貝原始 timeData 的內容
minVuemin.value = JSON.parse(JSON.stringify(timeData.value.min)); minVuemin.value = JSON.parse(JSON.stringify(timeData.value.min));
@@ -40,8 +50,8 @@ function setTimeValue() {
} }
/** /**
* get min total seconds * Handles the minimum duration total seconds update.
* @param {Number} e 元件傳來的最小值總秒數 * @param {number} e - The total seconds from the min duration component.
*/ */
function minTotalSeconds(e) { function minTotalSeconds(e) {
timeRangeMin.value = e; timeRangeMin.value = e;
@@ -50,8 +60,8 @@ function minTotalSeconds(e) {
} }
/** /**
* get min total seconds * Handles the maximum duration total seconds update.
* @param {Number} e 元件傳來的最大值總秒數 * @param {number} e - The total seconds from the max duration component.
*/ */
function maxTotalSeconds(e) { function maxTotalSeconds(e) {
timeRangeMax.value = e; timeRangeMax.value = e;

View File

@@ -62,6 +62,18 @@
</Dialog> </Dialog>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Conformance/MoreModal
* Modal dialog showing detailed conformance check
* results with expandable activity sequences.
*/
import { ref, computed, watch, nextTick, useTemplateRef } from 'vue'; import { ref, computed, watch, nextTick, useTemplateRef } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useConformanceStore } from '@/stores/conformance'; import { useConformanceStore } from '@/stores/conformance';
@@ -169,8 +181,8 @@ watch(infinite404, (newValue) => {
// methods // methods
/** /**
* Number to percentage * Number to percentage
* @param {number} val 原始數字 * @param {number} val - The raw ratio value.
* @returns {string} 轉換完成的百分比字串 * @returns {string} The formatted percentage string.
*/ */
function getPercentLabel(val){ function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return 100; if((val * 100).toFixed(1) >= 100) return 100;
@@ -178,8 +190,8 @@ function getPercentLabel(val){
} }
/** /**
* set progress bar width * set progress bar width
* @param {number} value 百分比數字 * @param {number} value - The percentage value.
* @returns {string} 樣式的寬度設定 * @returns {string} The CSS width style string.
*/ */
function progressWidth(value){ function progressWidth(value){
return `width:${value}%;` return `width:${value}%;`
@@ -201,7 +213,7 @@ async function switchCaseData(id) {
showTraceId.value = id; // 放 getDetail 為了 case table 載入完再切換 showTraceId showTraceId.value = id; // 放 getDetail 為了 case table 載入完再切換 showTraceId
} }
/** /**
* trace element nodes 資料彙整 * Assembles the trace element nodes data for Cytoscape rendering.
*/ */
function setNodesData(){ function setNodesData(){
// 避免每次渲染都重複累加 // 避免每次渲染都重複累加
@@ -224,7 +236,7 @@ function setNodesData(){
}; };
} }
/** /**
* trace edge line 資料彙整 * Assembles the trace edge line data for Cytoscape rendering.
*/ */
function setEdgesData(){ function setEdgesData(){
processMap.value.edges = []; processMap.value.edges = [];
@@ -256,7 +268,7 @@ function createCy(){
}); });
} }
/** /**
* 無限滾動: 載入數據 * Infinite scroll: loads more data.
*/ */
async function fetchData() { async function fetchData() {
try { try {
@@ -270,8 +282,8 @@ async function fetchData() {
} }
} }
/** /**
* 無限滾動: 監聽 scroll 有沒有滾到底部 * Infinite scroll: listens for scroll reaching the bottom.
* @param {element} event 監聽時回傳的事件 * @param {Event} event - The scroll event.
*/ */
function handleScroll(event) { function handleScroll(event) {
if(maxItems.value || infiniteData.value.length < 20 || infiniteFinish.value === false) return; if(maxItems.value || infiniteData.value.length < 20 || infiniteFinish.value === false) return;

View File

@@ -58,6 +58,16 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/Filter/ActAndSeq Activity list
* with drag-and-drop sequence builder for creating filter
* rules.
*/
import { ref, computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import { sortNumEngZhtwForFilter } from '@/module/sortNumEngZhtw.js'; import { sortNumEngZhtwForFilter } from '@/module/sortNumEngZhtw.js';
@@ -100,33 +110,31 @@ watch(() => props.filterTaskData, (newval) => {
}); });
/** /**
* double click Activity List * Moves an activity from the list to the sequence on double-click.
* @param {number} index data item index * @param {number} index - The item index in the activity list.
* @param {object} element data item * @param {Object} element - The activity data object.
*/ */
function moveActItem(index, element) { function moveActItem(index, element) {
listSequence.value.push(element); listSequence.value.push(element);
} }
/** /**
* double click Sequence List * Removes an activity from the sequence on double-click.
* @param {number} index data item index * @param {number} index - The item index in the sequence.
* @param {object} element data item * @param {Object} element - The activity data object.
*/ */
function moveSeqItem(index, element) { function moveSeqItem(index, element) {
listSequence.value.splice(index, 1); listSequence.value.splice(index, 1);
} }
/** /** Emits the current sequence list to the parent component. */
* get listSequence
*/
function getComponentData() { function getComponentData() {
emit('update:listSeq', listSequence.value); emit('update:listSeq', listSequence.value);
} }
/** /**
* Element dragging started * Handles drag start: hides original element and last arrow.
* @param {event} evt input 傳入的事件 * @param {Event} evt - The drag start event.
*/ */
function onStart(evt) { function onStart(evt) {
const lastChild = evt.to.lastChild.lastChild; const lastChild = evt.to.lastChild.lastChild;
@@ -140,8 +148,8 @@ function onStart(evt) {
} }
/** /**
* Element dragging ended * Handles drag end: restores element visibility.
* @param {event} evt input 傳入的事件 * @param {Event} evt - The drag end event.
*/ */
function onEnd(evt) { function onEnd(evt) {
// 顯示拖曳元素 // 顯示拖曳元素

View File

@@ -29,6 +29,15 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/Filter/ActOcc Activity
* occurrences filter table with single-row radio selection.
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
const props = defineProps({ const props = defineProps({
@@ -60,8 +69,8 @@ watch(() => props.tableSelect, (newval) => {
}); });
/** /**
* 將選取的 row 傳到父層 * Emits the selected row to the parent component.
* @param {event} e input 傳入的事件 * @param {Event} e - The row selection event.
*/ */
function onRowSelect(e) { function onRowSelect(e) {
emit('on-row-select', e); emit('on-row-select', e);

View File

@@ -40,6 +40,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/Filter/ActOccCase Activity
* occurrences and cases filter table with multi-row checkbox
* selection.
*/
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
const props = defineProps(['tableTitle', 'tableData', 'tableSelect', 'progressWidth']); const props = defineProps(['tableTitle', 'tableData', 'tableSelect', 'progressWidth']);
@@ -53,23 +63,19 @@ watch(() => props.tableSelect, (newval) => {
select.value = newval; select.value = newval;
}); });
/** /** Emits the current selection when a row is selected. */
* 選擇 Row 的行為
*/
function onRowSelect() { function onRowSelect() {
emit('on-row-select', select.value); emit('on-row-select', select.value);
} }
/** /** Emits the current selection when a row is unselected. */
* 取消選取 Row 的行為
*/
function onRowUnselect() { function onRowUnselect() {
emit('on-row-select', select.value); emit('on-row-select', select.value);
} }
/** /**
* 全選 Row 的行為 * Handles select-all rows action.
* @param {event} e input 傳入的事件 * @param {Event} e - The select-all event with data property.
*/ */
function onRowSelectAll(e) { function onRowSelectAll(e) {
select.value = e.data; select.value = e.data;
@@ -77,8 +83,8 @@ function onRowSelectAll(e) {
} }
/** /**
* 取消全選 Row 的行為 * Handles unselect-all rows action.
* @param {event} e input 傳入的事件 * @param {Event} e - The unselect-all event.
*/ */
function onRowUnelectAll(e) { function onRowUnelectAll(e) {
select.value = null; select.value = null;

View File

@@ -120,6 +120,18 @@
</section> </section>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Discover/Map/Filter/Attributes
* Case attribute filter with dynamic form fields
* for filtering by attribute values.
*/
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'; import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useAllMapDataStore } from '@/stores/allMapData'; import { useAllMapDataStore } from '@/stores/allMapData';
@@ -313,7 +325,7 @@ const labelsData = computed(() => {
}); });
/** /**
* 選取類別型 table 的選項 * Selects an option in the categorical table.
*/ */
function onRowSelect() { function onRowSelect() {
const type = selectedAttName.value.type; const type = selectedAttName.value.type;
@@ -325,7 +337,7 @@ function onRowSelect() {
} }
/** /**
* 取消類別型 table 的選項 * Deselects an option in the categorical table.
*/ */
function onRowUnselect() { function onRowUnselect() {
const type = selectedAttName.value.type; const type = selectedAttName.value.type;
@@ -337,8 +349,8 @@ function onRowUnselect() {
} }
/** /**
* 選取類別型 table 的全選項 * Selects all options in the categorical table.
* @param {event} e input 傳入的事件 * @param {Event} e - The input event.
*/ */
function onRowSelectAll(e) { function onRowSelectAll(e) {
selectedAttRange.value = e.data; selectedAttRange.value = e.data;
@@ -351,7 +363,7 @@ function onRowSelectAll(e) {
} }
/** /**
* 取消類別型 table 的全選項 * Deselects all options in the categorical table.
*/ */
function onRowUnelectAll() { function onRowUnelectAll() {
selectedAttRange.value = null; selectedAttRange.value = null;
@@ -364,8 +376,8 @@ function onRowUnelectAll() {
} }
/** /**
* 切換 Attribute Name Radio * Switches the attribute name radio selection.
* @param {event} e input 傳入的事件 * @param {Event} e - The input event.
*/ */
function switchAttNameRadio(e) { function switchAttNameRadio(e) {
selectedAttRange.value = null; selectedAttRange.value = null;
@@ -416,8 +428,8 @@ function switchAttNameRadio(e) {
/** /**
* set progress bar width * set progress bar width
* @param {number} value 百分比數字 * @param {number} value - The percentage value.
* @returns {string} 樣式的寬度設定 * @returns {string} The CSS width style string.
*/ */
function progressWidth(value){ function progressWidth(value){
return `width:${value}%;` return `width:${value}%;`
@@ -425,8 +437,8 @@ function progressWidth(value){
/** /**
* Number to percentage * Number to percentage
* @param {number} val 原始數字 * @param {number} val - The raw ratio value.
* @returns {string} 轉換完成的百分比字串 * @returns {string} The formatted percentage string.
*/ */
function getPercentLabel(val){ function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return `100%`; if((val * 100).toFixed(1) >= 100) return `100%`;
@@ -434,8 +446,8 @@ function getPercentLabel(val){
} }
/** /**
* 調整遮罩大小 * Adjusts the overlay mask size.
* @param {object} chart 取得 chart.js 資料 * @param {object} chart - The Chart.js instance data.
*/ */
function resizeMask(chart) { function resizeMask(chart) {
const from = (selectArea.value[0] * 0.01) / (selectRange.value * 0.01); const from = (selectArea.value[0] * 0.01) / (selectRange.value * 0.01);
@@ -445,8 +457,8 @@ function resizeMask(chart) {
} }
/** /**
* 調整左邊遮罩大小 * Adjusts the left overlay mask size.
* @param {object} chart 取得 chart.js 資料 * @param {object} chart - The Chart.js instance data.
*/ */
function resizeLeftMask(chart, from) { function resizeLeftMask(chart, from) {
const canvas = document.querySelector('#chartCanvasId canvas'); const canvas = document.querySelector('#chartCanvasId canvas');
@@ -458,8 +470,8 @@ function resizeLeftMask(chart, from) {
} }
/** /**
* 調整右邊遮罩大小 * Adjusts the right overlay mask size.
* @param {object} chart 取得 chart.js 資料 * @param {object} chart - The Chart.js instance data.
*/ */
function resizeRightMask(chart, to) { function resizeRightMask(chart, to) {
const canvas = document.querySelector('#chartCanvasId canvas'); const canvas = document.querySelector('#chartCanvasId canvas');
@@ -471,7 +483,7 @@ function resizeRightMask(chart, to) {
} }
/** /**
* create chart * Creates and renders the Chart.js line chart for attribute data.
*/ */
function createChart() { function createChart() {
const vData = valueData.value; const vData = valueData.value;
@@ -632,7 +644,7 @@ function createChart() {
} }
/** /**
* 滑塊改變的時候 * Handles slider value changes.
* @param {array} e [1, 100] * @param {array} e [1, 100]
*/ */
function changeSelectArea(e) { function changeSelectArea(e) {
@@ -665,8 +677,8 @@ function changeSelectArea(e) {
} }
/** /**
* 選取開始或結束時間時,要改變滑塊跟圖表 * Updates the slider and chart when a start or end time is selected.
* @param {object} e Tue Jan 25 2022 00:00:00 GMT+0800 (台北標準時間) | Blur Event * @param {object} e - The date object or blur event.
* @param {string} direction start or end * @param {string} direction start or end
*/ */
function sliderValueRange(e, direction) { function sliderValueRange(e, direction) {

View File

@@ -39,6 +39,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/Filter/Funnel Filter funnel
* panel showing applied filter rules with toggle, delete, and
* apply-all actions.
*/
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useToast } from 'vue-toast-notification'; import { useToast } from 'vue-toast-notification';
import { useLoadingStore } from '@/stores/loading'; import { useLoadingStore } from '@/stores/loading';
@@ -54,8 +64,9 @@ const { isLoading } = storeToRefs(loadingStore);
const { hasResultRule, temporaryData, postRuleData, ruleData, isRuleData, tempFilterId } = storeToRefs(allMapDataStore); const { hasResultRule, temporaryData, postRuleData, ruleData, isRuleData, tempFilterId } = storeToRefs(allMapDataStore);
/** /**
* @param {boolean} e ture | false可選 ture 或 false * Toggles a filter rule on or off.
* @param {numble} index rule's index * @param {boolean} e - Whether the rule is enabled.
* @param {number} index - The rule index.
*/ */
function isRule(e, index){ function isRule(e, index){
const rule = isRuleData.value[index]; const rule = isRuleData.value[index];
@@ -66,8 +77,8 @@ function isRule(e, index){
} }
/** /**
* header:Funnel 刪除全部的 Funnel * Deletes a single filter rule or all rules.
* @param {numble|string} index rule's index 或 全部 * @param {number|string} index - The rule index, or 'all' to delete all.
*/ */
async function deleteRule(index) { async function deleteRule(index) {
if(index === 'all') { if(index === 'all') {
@@ -91,9 +102,7 @@ async function deleteRule(index) {
} }
} }
/** /** Submits all enabled filter rules and refreshes the map data. */
* header:Funnel 發送暫存的選取資料
*/
async function submitAll() { async function submitAll() {
postRuleData.value = temporaryData.value.filter(item => item !== 0); // 取得 submit 的資料,有 toggle button 的話,找出並刪除陣列中為 0 的項目 postRuleData.value = temporaryData.value.filter(item => item !== 0); // 取得 submit 的資料,有 toggle button 的話,找出並刪除陣列中為 0 的項目
if(!postRuleData.value?.length) return $toast.error('Not selected'); if(!postRuleData.value?.length) return $toast.error('Not selected');

View File

@@ -31,6 +31,16 @@
</div> </div>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/Filter/Timeframes
* Timeframe filter with date range pickers and
* duration range selectors.
*/
import { ref, computed, watch, onMounted } from 'vue'; import { ref, computed, watch, onMounted } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useAllMapDataStore } from '@/stores/allMapData'; import { useAllMapDataStore } from '@/stores/allMapData';
@@ -151,8 +161,8 @@ watch(selectTimeFrame, (newValue, oldValue) => {
}); });
/** /**
* 調整遮罩大小 * Adjusts the overlay mask size.
* @param {object} chartInstance 取得 chart.js 資料 * @param {object} chartInstance - The Chart.js instance.
*/ */
function resizeMask(chartInstance) { function resizeMask(chartInstance) {
const from = (selectArea.value[0] * 0.01) / (selectRange.value * 0.01); const from = (selectArea.value[0] * 0.01) / (selectRange.value * 0.01);
@@ -164,8 +174,8 @@ function resizeMask(chartInstance) {
} }
/** /**
* 調整左邊遮罩大小 * Adjusts the left overlay mask size.
* @param {object} chartInstance 取得 chart.js 資料 * @param {object} chartInstance - The Chart.js instance.
*/ */
function resizeLeftMask(chartInstance, from) { function resizeLeftMask(chartInstance, from) {
const canvas = document.getElementById("chartCanvasId"); const canvas = document.getElementById("chartCanvasId");
@@ -177,8 +187,8 @@ function resizeLeftMask(chartInstance, from) {
} }
/** /**
* 調整右邊遮罩大小 * Adjusts the right overlay mask size.
* @param {object} chartInstance 取得 chart.js 資料 * @param {object} chartInstance - The Chart.js instance.
*/ */
function resizeRightMask(chartInstance, to) { function resizeRightMask(chartInstance, to) {
const canvas = document.getElementById("chartCanvasId"); const canvas = document.getElementById("chartCanvasId");
@@ -190,7 +200,7 @@ function resizeRightMask(chartInstance, to) {
} }
/** /**
* create chart * Creates and renders the Chart.js area chart for timeframe data.
*/ */
function createChart() { function createChart() {
const max = filterTimeframe.value.y_axis.max * 1.1; const max = filterTimeframe.value.y_axis.max * 1.1;
@@ -289,7 +299,7 @@ function createChart() {
} }
/** /**
* 滑塊改變的時候 * Handles slider value changes.
* @param {array} e [1, 100] * @param {array} e [1, 100]
*/ */
function changeSelectArea(e) { function changeSelectArea(e) {
@@ -310,8 +320,8 @@ function changeSelectArea(e) {
} }
/** /**
* 選取開始或結束時間時,要改變滑塊跟圖表 * Updates the slider and chart when a start or end time is selected.
* @param {object} e Tue Jan 25 2022 00:00:00 GMT+0800 (台北標準時間) * @param {object} e - The selected date object.
* @param {string} direction start or end * @param {string} direction start or end
*/ */
function sliderTimeRange(e, direction) { function sliderTimeRange(e, direction) {

View File

@@ -69,6 +69,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/Filter/Trace
* Trace filter with trace selection table and
* trace detail display.
*/
import { ref, computed, watch, onMounted } from 'vue'; import { ref, computed, watch, onMounted } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useAllMapDataStore } from '@/stores/allMapData'; import { useAllMapDataStore } from '@/stores/allMapData';
@@ -238,8 +248,8 @@ function barOptions(){
/** /**
* Number to percentage * Number to percentage
* @param {number} val 原始數字 * @param {number} val - The raw ratio value.
* @returns {string} 轉換完成的百分比字串 * @returns {string} The formatted percentage string.
*/ */
function getPercentLabel(val){ function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return 100; if((val * 100).toFixed(1) >= 100) return 100;
@@ -248,8 +258,8 @@ function getPercentLabel(val){
/** /**
* set progress bar width * set progress bar width
* @param {number} value 百分比數字 * @param {number} value - The percentage value.
* @returns {string} 樣式的寬度設定 * @returns {string} The CSS width style string.
*/ */
function progressWidth(value){ function progressWidth(value){
return `width:${value}%;` return `width:${value}%;`
@@ -258,7 +268,7 @@ function progressWidth(value){
/** /**
* switch case data * switch case data
* @param {number} id case id * @param {number} id case id
* @param {number} count 所有的 case 數量 * @param {number} count - The total number of cases.
*/ */
async function switchCaseData(id, count) { async function switchCaseData(id, count) {
// 點同一筆 id 不要有動作 // 點同一筆 id 不要有動作
@@ -275,7 +285,7 @@ async function switchCaseData(id, count) {
} }
/** /**
* trace element nodes 資料彙整 * Assembles the trace element nodes data for Cytoscape rendering.
*/ */
function setNodesData(){ function setNodesData(){
// 避免每次渲染都重複累加 // 避免每次渲染都重複累加
@@ -297,7 +307,7 @@ function setNodesData(){
} }
/** /**
* trace edge line 資料彙整 * Assembles the trace edge line data for Cytoscape rendering.
*/ */
function setEdgesData(){ function setEdgesData(){
processMap.value.edges = []; processMap.value.edges = [];
@@ -327,8 +337,8 @@ function createCy(){
} }
/** /**
* 無限滾動: 監聽 scroll 有沒有滾到底部 * Infinite scroll: listens for scroll reaching the bottom.
* @param {element} event 滾動傳入的事件 * @param {Event} event - The scroll event.
*/ */
function handleScroll(event) { function handleScroll(event) {
if(infinitMaxItems.value || baseCases.value.length < 20 || infiniteFinish.value === false) return; if(infinitMaxItems.value || baseCases.value.length < 20 || infiniteFinish.value === false) return;
@@ -340,7 +350,7 @@ function handleScroll(event) {
} }
/** /**
* 無限滾動: 滾到底後,要載入數據 * Infinite scroll: loads more data when the bottom is reached.
*/ */
async function fetchData() { async function fetchData() {
try { try {

View File

@@ -97,6 +97,17 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/SidebarFilter
* Filter sidebar for the Map view with tabbed panels
* for activity, timeframe, attribute, and trace
* filters.
*/
import { ref, reactive, computed } from 'vue'; import { ref, reactive, computed } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useToast } from 'vue-toast-notification'; import { useToast } from 'vue-toast-notification';
@@ -227,6 +238,7 @@ const isDisabledButton = computed(() => {
/** /**
* Change Radio Filter Type * Change Radio Filter Type
*/ */
/** Checks if the apply button should be disabled based on filter type. */
function radioFilterType() { function radioFilterType() {
reset(); reset();
} }
@@ -234,6 +246,7 @@ function radioFilterType() {
/** /**
* Change Radio Act Seq * Change Radio Act Seq
*/ */
/** Checks if the apply button should be disabled for activity sequence. */
function radioActSeq() { function radioActSeq() {
reset(); reset();
} }
@@ -241,6 +254,7 @@ function radioActSeq() {
/** /**
* Change Radio Start And End * Change Radio Start And End
*/ */
/** Checks if the apply button should be disabled for start & end filter. */
function radioStartAndEnd() { function radioStartAndEnd() {
reset(); reset();
} }
@@ -254,8 +268,8 @@ function switchTab(newTab) {
/** /**
* Number to percentage * Number to percentage
* @param {number} val 原始數字 * @param {number} val - The raw ratio value.
* @returns {string} 轉換完成的百分比字串 * @returns {string} The formatted percentage string.
*/ */
function getPercentLabel(val){ function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return `100%`; if((val * 100).toFixed(1) >= 100) return `100%`;
@@ -264,8 +278,8 @@ function getPercentLabel(val){
/** /**
* set progress bar width * set progress bar width
* @param {number} value 百分比數字 * @param {number} value - The percentage value.
* @returns {string} 樣式的寬度設定 * @returns {string} The CSS width style string.
*/ */
function progressWidth(value){ function progressWidth(value){
return `width:${value}%;` return `width:${value}%;`
@@ -293,7 +307,7 @@ function setHaveAct(data){
// 調整 filterStartData / filterEndData / filterStartToEndData / filterEndToStartData 的內容 // 調整 filterStartData / filterEndData / filterStartToEndData / filterEndToStartData 的內容
/** /**
* @param {array} array filterStartToEnd / filterEndToStart,可傳入以上任一。 * @param {Array} array - filterStartToEnd or filterEndToStart data array.
*/ */
function setActData(array) { function setActData(array) {
const list = []; const list = [];
@@ -376,7 +390,7 @@ function endRow(e) {
// 重新設定連動的 filterStartToEndData / filterEndToStartData 內容 // 重新設定連動的 filterStartToEndData / filterEndToStartData 內容
/** /**
* @param {array} eventData Start or End List * @param {array} eventData Start or End List
* @param {object} rowDataVal 所選擇的 row's data * @param {object} rowDataVal - The selected row's data.
* @param {string} event sinks / sources * @param {string} event sinks / sources
*/ */
function setStartAndEndData(eventData, rowDataVal, event){ function setStartAndEndData(eventData, rowDataVal, event){
@@ -398,6 +412,11 @@ function setStartAndEndData(eventData, rowDataVal, event){
/** /**
* @param {object} e task's object * @param {object} e task's object
*/ */
/**
* Creates a display rule object from filter event data.
* @param {object} e - The filter rule data.
* @returns {object} The display rule with type, label, and toggle.
*/
function setRule(e) { function setRule(e) {
let label, type; let label, type;
const includeStr = e.is_exclude? "exclude" : "include"; const includeStr = e.is_exclude? "exclude" : "include";
@@ -449,7 +468,7 @@ function setRule(e) {
} }
/** /**
* @param {boolean} message true | false 清空選項,可選以上任一。 * @param {boolean} message - Whether to show the success toast message.
*/ */
function reset(message) { function reset(message) {
// Sequence // Sequence
@@ -480,7 +499,7 @@ function reset(message) {
} }
/** /**
* header:Filter 發送選取的資料 * Submits the selected filter data to the backend.
*/ */
async function submit() { async function submit() {
isLoading.value = true; isLoading.value = true;
@@ -520,10 +539,16 @@ async function submit() {
/** /**
* create map * create map
*/ */
/** Triggers the submit-all event to create the map. */
function sumbitAll() { function sumbitAll() {
emit('submit-all'); emit('submit-all');
} }
/**
* Checks if the sequence filter selection is valid.
* @param {Array} sele - The current selection values.
* @returns {boolean} Whether the button should be disabled.
*/
function handleSequenceSelection(sele) { function handleSequenceSelection(sele) {
const secondSelection = sele[1]; const secondSelection = sele[1];
@@ -539,6 +564,11 @@ function handleSequenceSelection(sele) {
} }
} }
/**
* Checks if the start & end sub-selection is valid.
* @param {string} option - 'Start', 'End', or 'Start & End'.
* @returns {boolean} Whether the button should be disabled.
*/
function handleStartEndSelection(option) { function handleStartEndSelection(option) {
switch (option) { switch (option) {
case 'Start': case 'Start':
@@ -552,6 +582,11 @@ function handleStartEndSelection(option) {
} }
} }
/**
* Checks if the attribute filter selection is valid.
* @param {string} type - The attribute type.
* @returns {boolean} Whether the button should be disabled.
*/
function handleAttributesSelection(type) { function handleAttributesSelection(type) {
switch (type) { switch (type) {
case 'string': case 'string':
@@ -567,14 +602,25 @@ function handleAttributesSelection(type) {
} }
} }
/** Checks if the trace filter selection is valid.
* @returns {boolean} Whether the button should be disabled.
*/
function handleTraceSelection() { function handleTraceSelection() {
return selectTraceArea.value[0] === selectTraceArea.value[1]; return selectTraceArea.value[0] === selectTraceArea.value[1];
} }
/** Checks if the timeframes filter selection is valid.
* @returns {boolean} Whether the button should be disabled.
*/
function handleTimeframesSelection() { function handleTimeframesSelection() {
return selectTimeFrame.value.length === 0; return selectTimeFrame.value.length === 0;
} }
/**
* Gets the display label for a task filter rule.
* @param {object} e - The filter rule data.
* @returns {string} The formatted label.
*/
function getTaskLabel(e) { function getTaskLabel(e) {
switch (e.type) { switch (e.type) {
case "contains-task": case "contains-task":
@@ -589,6 +635,11 @@ function getTaskLabel(e) {
} }
} }
/**
* Gets the display label for an attribute filter rule.
* @param {object} e - The filter rule data.
* @returns {string} The formatted label.
*/
function getAttributeLabel(e) { function getAttributeLabel(e) {
switch (e.type) { switch (e.type) {
case 'string-attr': case 'string-attr':
@@ -603,6 +654,13 @@ function getAttributeLabel(e) {
} }
} }
/**
* Builds filter data from the current selections.
* @param {Array} sele - The current selection values.
* @param {boolean} isExclude - Whether this is an exclude filter.
* @param {object} containmentMap - Containment type mapping.
* @returns {object|Array} The filter data to submit.
*/
function getFilterData(sele, isExclude, containmentMap) { function getFilterData(sele, isExclude, containmentMap) {
switch (sele[0]) { switch (sele[0]) {
case 'Sequence': case 'Sequence':
@@ -623,6 +681,12 @@ function getFilterData(sele, isExclude, containmentMap) {
} }
} }
/**
* Builds sequence filter data.
* @param {Array} sele - The current selection values.
* @param {boolean} isExclude - Whether this is an exclude filter.
* @returns {object} The sequence filter data.
*/
function getSequenceData(sele, isExclude) { function getSequenceData(sele, isExclude) {
switch (sele[1]) { switch (sele[1]) {
case 'Have activity(s)': case 'Have activity(s)':
@@ -644,6 +708,12 @@ function getSequenceData(sele, isExclude) {
} }
} }
/**
* Builds start & end filter data.
* @param {Array} sele - The current selection values.
* @param {boolean} isExclude - Whether this is an exclude filter.
* @returns {object} The start & end filter data.
*/
function getStartEndData(sele, isExclude) { function getStartEndData(sele, isExclude) {
switch (sele[2]) { switch (sele[2]) {
case 'Start': case 'Start':
@@ -670,6 +740,11 @@ function getStartEndData(sele, isExclude) {
} }
} }
/**
* Builds attributes filter data.
* @param {boolean} isExclude - Whether this is an exclude filter.
* @returns {object} The attributes filter data.
*/
function getAttributesData(isExclude) { function getAttributesData(isExclude) {
const attrTypeMap = { const attrTypeMap = {
'string': 'string-attr', 'string': 'string-attr',
@@ -704,6 +779,11 @@ function getAttributesData(isExclude) {
} }
} }
/**
* Builds trace filter data.
* @param {boolean} isExclude - Whether this is an exclude filter.
* @returns {object} The trace filter data.
*/
function getTraceData(isExclude) { function getTraceData(isExclude) {
const lowerIndex = filterTraceViewRef.value.selectArea[0]; const lowerIndex = filterTraceViewRef.value.selectArea[0];
const upperIndex = filterTraceViewRef.value.selectArea[1] - 1; const upperIndex = filterTraceViewRef.value.selectArea[1] - 1;
@@ -715,6 +795,10 @@ function getTraceData(isExclude) {
}; };
} }
/**
* Updates the rules list with newly submitted filter data.
* @param {Array} postData - The submitted filter data.
*/
function updateRules(postData) { function updateRules(postData) {
if (!temporaryData.value?.length) { if (!temporaryData.value?.length) {
temporaryData.value.push(...postData); temporaryData.value.push(...postData);
@@ -727,6 +811,11 @@ function updateRules(postData) {
} }
} }
/**
* Returns a promise that resolves after the given delay.
* @param {number} ms - The delay in milliseconds.
* @returns {Promise} Resolves after the delay.
*/
function delay(ms) { function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms)); return new Promise(resolve => setTimeout(resolve, ms));
} }

View File

@@ -242,6 +242,17 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/SidebarState
* Summary statistics sidebar for the Map view
* displaying cases, traces, activities, timeframe,
* and case duration.
*/
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { usePageAdminStore } from '@/stores/pageAdmin'; import { usePageAdminStore } from '@/stores/pageAdmin';
import { useMapPathStore } from '@/stores/mapPathStore'; import { useMapPathStore } from '@/stores/mapPathStore';
@@ -282,17 +293,26 @@ const valueTraces = ref(0);
const valueTaskInstances = ref(0); const valueTaskInstances = ref(0);
const valueTasks = ref(0); const valueTasks = ref(0);
/**
* Handles click on an active trace to highlight it.
* @param {number} clickedActiveTraceIndex - The clicked trace index.
*/
function onActiveTraceClick(clickedActiveTraceIndex) { function onActiveTraceClick(clickedActiveTraceIndex) {
mapPathStore.clearAllHighlight(); mapPathStore.clearAllHighlight();
activeTrace.value = clickedActiveTraceIndex; activeTrace.value = clickedActiveTraceIndex;
mapPathStore.highlightClickedPath(clickedActiveTraceIndex, clickedPathListIndex.value); mapPathStore.highlightClickedPath(clickedActiveTraceIndex, clickedPathListIndex.value);
} }
/**
* Handles click on a path option to highlight it.
* @param {number} clickedPath - The clicked path index.
*/
function onPathOptionClick(clickedPath) { function onPathOptionClick(clickedPath) {
clickedPathListIndex.value = clickedPath; clickedPathListIndex.value = clickedPath;
mapPathStore.highlightClickedPath(activeTrace.value, clickedPath); mapPathStore.highlightClickedPath(activeTrace.value, clickedPath);
} }
/** Resets the trace highlight to default. */
function onResetTraceBtnClick() { function onResetTraceBtnClick() {
if(isBPMNOn.value) { if(isBPMNOn.value) {
return; return;
@@ -326,8 +346,8 @@ function moment(time){
/** /**
* Number to percentage * Number to percentage
* @param {number} val 原始數字 * @param {number} val - The raw ratio value.
* @returns {string} 轉換完成的百分比字串 * @returns {string} The formatted percentage string.
*/ */
function getPercentLabel(val){ function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return `100%`; if((val * 100).toFixed(1) >= 100) return `100%`;

View File

@@ -60,6 +60,16 @@
</Sidebar> </Sidebar>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/SidebarTraces
* Traces sidebar showing path insights with
* clickable trace lists for highlighting on the map.
*/
import { ref, computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useLoadingStore } from '@/stores/loading'; import { useLoadingStore } from '@/stores/loading';
@@ -150,8 +160,8 @@ watch(infiniteFirstCases, (newValue) => {
/** /**
* Number to percentage * Number to percentage
* @param {number} val 原始數字 * @param {number} val - The raw ratio value.
* @returns {string} 轉換完成的百分比字串 * @returns {string} The formatted percentage string.
*/ */
function getPercentLabel(val){ function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return `100%`; if((val * 100).toFixed(1) >= 100) return `100%`;
@@ -160,8 +170,8 @@ function getPercentLabel(val){
/** /**
* set progress bar width * set progress bar width
* @param {number} value 百分比數字 * @param {number} value - The percentage value.
* @returns {string} 樣式的寬度設定 * @returns {string} The CSS width style string.
*/ */
function progressWidth(value){ function progressWidth(value){
return `width:${value}%;` return `width:${value}%;`
@@ -170,7 +180,7 @@ function progressWidth(value){
/** /**
* switch case data * switch case data
* @param {number} id case id * @param {number} id case id
* @param {number} count case 數量 * @param {number} count - The total number of cases.
*/ */
async function switchCaseData(id, count) { async function switchCaseData(id, count) {
// 點同一筆 id 不要有動作 // 點同一筆 id 不要有動作
@@ -184,7 +194,7 @@ async function switchCaseData(id, count) {
} }
/** /**
* trace element nodes 資料彙整 * Assembles the trace element nodes data for Cytoscape rendering.
*/ */
function setNodesData(){ function setNodesData(){
// 避免每次渲染都重複累加 // 避免每次渲染都重複累加
@@ -206,7 +216,7 @@ function setNodesData(){
} }
/** /**
* trace edge line 資料彙整 * Assembles the trace edge line data for Cytoscape rendering.
*/ */
function setEdgesData(){ function setEdgesData(){
processMap.value.edges = []; processMap.value.edges = [];
@@ -250,8 +260,8 @@ async function show() {
} }
/** /**
* 無限滾動: 監聽 scroll 有沒有滾到底部 * Infinite scroll: listens for scroll reaching the bottom.
* @param {element} event 滾動傳入的事件 * @param {Event} event - The scroll event.
*/ */
function handleScroll(event) { function handleScroll(event) {
if(infinitMaxItems.value || props.cases.length < 20 || infiniteFinish.value === false) return; if(infinitMaxItems.value || props.cases.length < 20 || infiniteFinish.value === false) return;
@@ -263,7 +273,7 @@ function handleScroll(event) {
} }
/** /**
* 無限滾動: 滾到底後,要載入數據 * Infinite scroll: loads more data when the bottom is reached.
*/ */
async function fetchData() { async function fetchData() {
try { try {

View File

@@ -70,6 +70,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/Map/SidebarView Visualization
* settings sidebar for map view type (process/BPMN), curve
* style, direction, and data layer selection.
*/
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useMapPathStore } from '@/stores/mapPathStore'; import { useMapPathStore } from '@/stores/mapPathStore';
@@ -117,8 +127,8 @@ const selectedDuration = ref('');
const rank = ref('LR'); // 直向 TB | 橫向 LR const rank = ref('LR'); // 直向 TB | 橫向 LR
/** /**
* switch map type * Switches the map type and emits the change event.
* @param {string} type 'processMap' | 'bpmn',可傳入以上任一。 * @param {string} type - 'processMap' or 'bpmn'.
*/ */
function switchMapType(type) { function switchMapType(type) {
mapType.value = type; mapType.value = type;
@@ -126,8 +136,8 @@ function switchMapType(type) {
} }
/** /**
* switch curve style * Switches the curve style and emits the change event.
* @param {string} style 直角 'unbundled-bezier' | 'taxi',可傳入以上任一。 * @param {string} style - 'unbundled-bezier' (curved) or 'taxi' (elbow).
*/ */
function switchCurveStyles(style) { function switchCurveStyles(style) {
curveStyle.value = style; curveStyle.value = style;
@@ -135,8 +145,8 @@ function switchCurveStyles(style) {
} }
/** /**
* switch rank * Switches the graph layout direction and emits the change event.
* @param {string} rank 直向 'TB' | 橫向 'LR',可傳入以上任一。 * @param {string} rankValue - 'TB' (vertical) or 'LR' (horizontal).
*/ */
function switchRank(rankValue) { function switchRank(rankValue) {
rank.value = rankValue; rank.value = rankValue;
@@ -144,9 +154,9 @@ function switchRank(rankValue) {
} }
/** /**
* switch Data Layoer Type or Option. * Switches the data layer type (frequency or duration) and option.
* @param {string} e 切換時傳入的選項 * @param {Event} e - The change event from the radio or select.
* @param {string} type 'freq' | 'duration',可傳入以上任一。 * @param {string} type - 'freq' or 'duration'.
*/ */
function switchDataLayerType(e, type) { function switchDataLayerType(e, type) {
let value = ''; let value = '';
@@ -169,11 +179,13 @@ function switchDataLayerType(e, type) {
emit('switch-data-layer-type', dataLayerType.value, dataLayerOption.value); emit('switch-data-layer-type', dataLayerType.value, dataLayerOption.value);
} }
/** Switches to Process Map view. */
function onProcessMapClick() { function onProcessMapClick() {
mapPathStore.setIsBPMNOn(false); mapPathStore.setIsBPMNOn(false);
switchMapType('processMap'); switchMapType('processMap');
} }
/** Switches to BPMN Model view. */
function onBPMNClick() { function onBPMNClick() {
mapPathStore.setIsBPMNOn(true); mapPathStore.setIsBPMNOn(true);
switchMapType('bpmn'); switchMapType('bpmn');

View File

@@ -79,6 +79,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
/**
* @module components/Discover/StatusBar Collapsible status bar
* showing dataset statistics (cases, traces, activities,
* timeframe, case duration) for the Discover page.
*/
import { ref, onMounted, } from 'vue'; import { ref, onMounted, } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -95,18 +105,16 @@ const isPanel = ref(false);
const statData = ref(null); const statData = ref(null);
/** /**
* Number to percentage * Converts a ratio (01) to a percentage number (0100), capped at 100.
* @param {number} val 原始數字 * @param {number} val - The ratio value to convert.
* @returns {string} 轉換完成的百分比字串 * @returns {number} The percentage value.
*/ */
function getPercentLabel(val){ function getPercentLabel(val){
if((val * 100).toFixed(1) >= 100) return 100; if((val * 100).toFixed(1) >= 100) return 100;
else return parseFloat((val * 100).toFixed(1)); else return parseFloat((val * 100).toFixed(1));
} }
/** /** Transforms raw stats into display-ready format with localized numbers and time labels. */
* setting stats data
*/
function getStatData() { function getStatData() {
statData.value = { statData.value = {
cases: { cases: {

View File

@@ -15,6 +15,17 @@
</Dialog> </Dialog>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/File/UploadModal File upload modal dialog
* with drag-and-drop support for CSV files (max 90 MB).
*/
import { onBeforeUnmount, } from 'vue'; import { onBeforeUnmount, } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import IconUploarding from '../icons/IconUploarding.vue'; import IconUploarding from '../icons/IconUploarding.vue';
@@ -30,8 +41,8 @@ const { uploadFileName } = storeToRefs(filesStore);
const contentClass = 'h-full'; const contentClass = 'h-full';
/** /**
* 上傳的行為 * Handles CSV file upload: validates size, sends to API, extracts filename.
* @param {event} event input 傳入的事件 * @param {Event} event - The file input change event.
*/ */
async function upload(event) { async function upload(event) {
const fileInput = document.getElementById('uploadFiles'); const fileInput = document.getElementById('uploadFiles');

View File

@@ -20,6 +20,17 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Header Application header with DSP logo and
* user account menu toggle button.
*/
import { ref, onMounted, } from 'vue'; import { ref, onMounted, } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { storeToRefs, } from 'pinia'; import { storeToRefs, } from 'pinia';
@@ -49,7 +60,8 @@ const toggleIsAcctMenuOpen = () => {
}; };
/** /**
* 登出的行為 * Handles logout with unsaved-changes confirmation for Map
* and Conformance pages.
*/ */
function logOutButton() { function logOutButton() {
if ((route.name === 'Map' || route.name === 'CheckMap') && tempFilterId.value) { if ((route.name === 'Map' || route.name === 'CheckMap') && tempFilterId.value) {

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<div class="w-full h-full fixed inset-0 m-auto flex justify-center items-center bg-gradient-to-tr from-neutral-500/50 to-neutral-900/50 z-[9999]"> <div class="w-full h-full fixed inset-0 m-auto flex justify-center items-center bg-gradient-to-tr from-neutral-500/50 to-neutral-900/50 z-[9999]">
<span class="loader block"></span> <span class="loader block"></span>

View File

@@ -45,6 +45,18 @@
</nav> </nav>
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Navbar Navigation bar with breadcrumb-style
* page tabs, import button for Files, and save button for
* Map/Conformance pages.
*/
import { ref, computed, watch, onMounted, } from 'vue'; import { ref, computed, watch, onMounted, } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { storeToRefs, } from 'pinia'; import { storeToRefs, } from 'pinia';
@@ -123,8 +135,8 @@ watch(filterName, (newVal) => {
}); });
/** /**
* switch navbar item * Handles navigation when a navbar tab is clicked.
* @param {event} event 選取 Navbar 選項後傳入的值 * @param {Event} event - The click event from the nav item.
*/ */
function onNavItemBtnClick(event) { function onNavItemBtnClick(event) {
let type; let type;
@@ -185,8 +197,8 @@ function onNavItemBtnClick(event) {
} }
/** /**
* Based on the route.name, decide the navViewName. * Determines the navbar view name and active page from the current route.
* @returns {string} the string of navigation name to return * @returns {string} The navigation item name to highlight.
*/ */
function getNavViewName() { function getNavViewName() {
@@ -244,9 +256,7 @@ function getNavViewName() {
return valueToSet; return valueToSet;
} }
/** /** Opens the save modal for Map or Conformance pages. */
* Save button' modal
*/
async function saveModal() { async function saveModal() {
// 協助判斷 MAP, CONFORMANCE 儲存有「送出」或「取消」。 // 協助判斷 MAP, CONFORMANCE 儲存有「送出」或「取消」。
// 傳給 Map通知 Sidebar 要關閉。 // 傳給 Map通知 Sidebar 要關閉。
@@ -268,15 +278,14 @@ async function saveModal() {
} }
} }
/** /** Sets nav item button background color when the active page is empty. */
* Set nav item button background color in case the variable is an empty string
*/
function handleNavItemBtn() { function handleNavItemBtn() {
if(activePageComputedByRoute.value === "") { if(activePageComputedByRoute.value === "") {
setActivePageComputedByRoute(route.matched[route.matched.length - 1].name); setActivePageComputedByRoute(route.matched[route.matched.length - 1].name);
} }
} }
/** Saves or creates a filter for the Map page. */
async function handleMapSave() { async function handleMapSave() {
if (createFilterId.value) { if (createFilterId.value) {
await allMapDataStore.updateFilter(); await allMapDataStore.updateFilter();
@@ -292,6 +301,7 @@ async function handleMapSave() {
} }
} }
/** Saves a filter from the Check Map page. */
async function handleCheckMapSave() { async function handleCheckMapSave() {
const isSaved = await saveFilter(allMapDataStore.addFilterId); const isSaved = await saveFilter(allMapDataStore.addFilterId);
if (isSaved) { if (isSaved) {
@@ -300,6 +310,7 @@ async function handleCheckMapSave() {
} }
} }
/** Saves or updates conformance check data. */
async function handleConformanceSave() { async function handleConformanceSave() {
if (conformanceFilterCreateCheckId.value || conformanceLogCreateCheckId.value) { if (conformanceFilterCreateCheckId.value || conformanceLogCreateCheckId.value) {
await conformanceStore.updateConformance(); await conformanceStore.updateConformance();

View File

@@ -17,6 +17,17 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/Search Search bar component with activity
* search input, settings icon, and search icon button.
*/
import IconSearch from '@/components/icons/IconSearch.vue'; import IconSearch from '@/components/icons/IconSearch.vue';
import IconSetting from '@/components/icons/IconSetting.vue'; import IconSetting from '@/components/icons/IconSetting.vue';
</script> </script>

View File

@@ -40,6 +40,18 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/durationjs
* Duration input component with day/hour/minute/second
* fields and bounded min/max validation.
*/
import { ref, computed, watch, onMounted } from 'vue'; import { ref, computed, watch, onMounted } from 'vue';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';
@@ -137,15 +149,24 @@ const inputTimeFields = computed(() => {
return paddedTimeFields; return paddedTimeFields;
}); });
/** Closes the time selection dropdown. */
function onClose() { function onClose() {
openTimeSelect.value = false; openTimeSelect.value = false;
} }
/**
* Selects all text in the focused input field.
* @param {FocusEvent} event - The focus event.
*/
function onFocus(event) { function onFocus(event) {
lastInput.value = event.target; lastInput.value = event.target;
lastInput.value.select(); lastInput.value.select();
} }
/**
* Validates and updates the duration value when an input changes.
* @param {Event} event - The change event from a duration input.
*/
function onChange(event) { function onChange(event) {
const baseInputValue = event.target.value; const baseInputValue = event.target.value;
let decoratedInputValue; let decoratedInputValue;
@@ -184,6 +205,10 @@ function onChange(event) {
calculateTotalSeconds(); calculateTotalSeconds();
} }
/**
* Handles arrow key up/down to increment/decrement duration values.
* @param {KeyboardEvent} event - The keyup event.
*/
function onKeyUp(event) { function onKeyUp(event) {
event.target.value = event.target.value.replace(/\D/g, ''); event.target.value = event.target.value.replace(/\D/g, '');
if (event.keyCode === 38 || event.keyCode === 40) { if (event.keyCode === 38 || event.keyCode === 40) {
@@ -191,6 +216,12 @@ function onKeyUp(event) {
}; };
} }
/**
* Increments or decrements a duration unit value with carry-over.
* @param {HTMLInputElement} input - The input element to update.
* @param {boolean} goUp - True to increment, false to decrement.
* @param {boolean} [selectIt=false] - Whether to select the input text after.
*/
function actionUpDown(input, goUp, selectIt = false) { function actionUpDown(input, goUp, selectIt = false) {
const tUnit = input.dataset.tunit; const tUnit = input.dataset.tunit;
let newVal = getNewValue(input); let newVal = getNewValue(input);
@@ -259,6 +290,11 @@ function updateInputValue(input, newVal, tUnit) {
} }
} }
/**
* Converts total seconds to day/hour/minute/second components.
* @param {number} totalSec - The total seconds to convert.
* @param {string} [size] - 'max' or 'min' to set boundary days.
*/
function secondToDate(totalSec, size) { function secondToDate(totalSec, size) {
totalSec = parseInt(totalSec); totalSec = parseInt(totalSec);
if(!isNaN(totalSec)) { if(!isNaN(totalSec)) {
@@ -276,6 +312,7 @@ function secondToDate(totalSec, size) {
}; };
} }
/** Calculates total seconds from all duration units and emits the result. */
function calculateTotalSeconds() { function calculateTotalSeconds() {
let total = 0; let total = 0;
@@ -299,6 +336,7 @@ function calculateTotalSeconds() {
emit('total-seconds', total); emit('total-seconds', total);
} }
/** Initializes the duration display based on min/max boundaries and preset value. */
async function createData() { async function createData() {
const size = props.size; const size = props.size;

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg <svg
width="124" width="124"

View File

@@ -9,6 +9,16 @@
</template> </template>
<script setup> <script setup>
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
// imacat.yang@dsp.im (imacat), 2023/9/23
/**
* @module components/icons/IconChecked Checkbox icon component
* that toggles between checked and unchecked states.
*/
import ImgCheckboxBlueFrame from "@/assets/icon-blue-checkbox.svg"; import ImgCheckboxBlueFrame from "@/assets/icon-blue-checkbox.svg";
import ImgCheckboxCheckedMark from "@/assets/icon-checkbox-checked.svg"; import ImgCheckboxCheckedMark from "@/assets/icon-checkbox-checked.svg";
import ImgCheckboxGrayFrame from "@/assets/icon-checkbox-empty.svg"; import ImgCheckboxGrayFrame from "@/assets/icon-checkbox-empty.svg";

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="32" height="32" viewBox="0 0 32 32" fill="black" xmlns="http://www.w3.org/2000/svg"> <svg width="32" height="32" viewBox="0 0 32 32" fill="black" xmlns="http://www.w3.org/2000/svg">
<path d="M28.8571 31H3.14286C2.57471 30.9994 2.03 30.7735 1.62825 30.3717C1.22651 29.97 1.00057 29.4253 1 28.8571V3.14286C1.00057 2.57471 1.22651 2.03 1.62825 1.62825C2.03 1.22651 2.57471 1.00057 3.14286 1H28.8571C29.4253 1.00057 29.97 1.22651 30.3717 1.62825C30.7735 2.03 30.9994 2.57471 31 3.14286V28.8571C30.9994 29.4253 30.7735 29.97 30.3717 30.3717C29.97 30.7735 29.4253 30.9994 28.8571 31ZM3.14286 3.14286V28.8571H28.8571V3.14286H3.14286Z"/> <path d="M28.8571 31H3.14286C2.57471 30.9994 2.03 30.7735 1.62825 30.3717C1.22651 29.97 1.00057 29.4253 1 28.8571V3.14286C1.00057 2.57471 1.22651 2.03 1.62825 1.62825C2.03 1.22651 2.57471 1.00057 3.14286 1H28.8571C29.4253 1.00057 29.97 1.22651 30.3717 1.62825C30.7735 2.03 30.9994 2.57471 31 3.14286V28.8571C30.9994 29.4253 30.7735 29.97 30.3717 30.3717C29.97 30.7735 29.4253 30.9994 28.8571 31ZM3.14286 3.14286V28.8571H28.8571V3.14286H3.14286Z"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.0529 3.24373C4.9174 3.10198 4.73177 3.01893 4.53578 3.01238C4.33979 3.00583 4.14903 3.07631 4.00437 3.20871C3.85971 3.34111 3.77266 3.5249 3.76187 3.7207C3.75108 3.9165 3.81741 4.10874 3.94665 4.25624L5.74665 6.23436C2.34352 8.32498 0.881025 11.55 0.8154 11.7C0.773866 11.7962 0.752441 11.8999 0.752441 12.0047C0.752441 12.1095 0.773866 12.2132 0.8154 12.3094C0.843525 12.375 1.6404 14.1375 3.4029 15.9094C5.75602 18.2531 8.7279 19.5 11.9998 19.5C13.6807 19.5067 15.3444 19.1618 16.8842 18.4875L18.9467 20.7562C19.0169 20.833 19.1023 20.8943 19.1976 20.9363C19.2928 20.9783 19.3957 21 19.4998 21C19.6869 20.9982 19.8669 20.9282 20.006 20.8031C20.0797 20.7373 20.1396 20.6574 20.1819 20.5681C20.2243 20.4789 20.2484 20.382 20.2528 20.2833C20.2571 20.1846 20.2417 20.086 20.2074 19.9933C20.173 19.9007 20.1205 19.8158 20.0529 19.7437L5.0529 3.24373ZM9.48727 10.3594L13.3966 14.6531C12.9666 14.8818 12.4868 15.0009 11.9998 15C11.4591 15.0001 10.9284 14.8542 10.4639 14.5775C9.99933 14.3009 9.61819 13.9038 9.36076 13.4283C9.10334 12.9528 8.97919 12.4166 9.00146 11.8764C9.02373 11.3362 9.19159 10.812 9.48727 10.3594V10.3594ZM11.9998 18C9.11228 18 6.5904 16.95 4.50915 14.8781C3.64691 14.0329 2.91685 13.0626 2.34352 12C2.78415 11.175 4.19978 8.85936 6.7779 7.36873L8.4654 9.22499C7.81494 10.0615 7.48054 11.1007 7.52112 12.1596C7.5617 13.2185 7.97465 14.2291 8.68723 15.0134C9.39981 15.7976 10.3663 16.3053 11.4164 16.4469C12.4666 16.5885 13.533 16.355 14.4279 15.7875L15.806 17.3062C14.5911 17.771 13.3005 18.0063 11.9998 18V18ZM23.1842 12.3094C23.1467 12.3937 22.1998 14.4937 20.0529 16.4156C19.9152 16.5359 19.7388 16.6025 19.556 16.6031C19.4509 16.6044 19.3467 16.5823 19.2511 16.5385C19.1555 16.4948 19.0707 16.4304 19.0029 16.35C18.937 16.2767 18.8862 16.1912 18.8534 16.0983C18.8205 16.0055 18.8063 15.907 18.8116 15.8086C18.8168 15.7103 18.8413 15.6139 18.8838 15.525C18.9263 15.4361 18.9859 15.3565 19.0592 15.2906C20.107 14.3507 20.9854 13.2376 21.656 12C21.0811 10.9356 20.3513 9.96244 19.4904 9.11248C17.4091 7.04998 14.8873 5.99999 11.9998 5.99999C11.3903 5.99753 10.7818 6.04772 10.181 6.14998C9.98493 6.17994 9.78489 6.13197 9.62371 6.01634C9.46252 5.90071 9.35299 5.72659 9.31852 5.53124C9.30244 5.43397 9.30569 5.33448 9.32809 5.23847C9.35049 5.14246 9.3916 5.0518 9.44907 4.9717C9.50654 4.89159 9.57924 4.8236 9.66301 4.77161C9.74678 4.71963 9.83998 4.68467 9.93727 4.66873C10.6189 4.55517 11.3088 4.49873 11.9998 4.49998C15.2717 4.49998 18.2435 5.74686 20.5966 8.09061C22.3591 9.86249 23.156 11.625 23.1842 11.7C23.2257 11.7962 23.2471 11.8999 23.2471 12.0047C23.2471 12.1095 23.2257 12.2132 23.1842 12.3094V12.3094ZM12.5623 9.05624C12.465 9.03777 12.3723 9.00032 12.2896 8.94604C12.2068 8.89176 12.1355 8.82171 12.0798 8.73987C11.9672 8.57461 11.925 8.37141 11.9623 8.17498C11.9996 7.97856 12.1134 7.80499 12.2786 7.69247C12.4439 7.57995 12.6471 7.53769 12.8435 7.57499C13.7999 7.76202 14.6703 8.25257 15.3257 8.97375C15.981 9.69494 16.3862 10.6083 16.481 11.5781C16.4993 11.7757 16.4385 11.9725 16.312 12.1254C16.1855 12.2782 16.0035 12.3747 15.806 12.3937H15.731C15.5455 12.3945 15.3664 12.3255 15.2292 12.2005C15.0921 12.0755 15.0068 11.9036 14.9904 11.7187C14.9257 11.0729 14.6546 10.4651 14.2172 9.98546C13.7798 9.50585 13.1995 9.18 12.5623 9.05624V9.05624Z" fill="#C4C4C4"/> <path d="M5.0529 3.24373C4.9174 3.10198 4.73177 3.01893 4.53578 3.01238C4.33979 3.00583 4.14903 3.07631 4.00437 3.20871C3.85971 3.34111 3.77266 3.5249 3.76187 3.7207C3.75108 3.9165 3.81741 4.10874 3.94665 4.25624L5.74665 6.23436C2.34352 8.32498 0.881025 11.55 0.8154 11.7C0.773866 11.7962 0.752441 11.8999 0.752441 12.0047C0.752441 12.1095 0.773866 12.2132 0.8154 12.3094C0.843525 12.375 1.6404 14.1375 3.4029 15.9094C5.75602 18.2531 8.7279 19.5 11.9998 19.5C13.6807 19.5067 15.3444 19.1618 16.8842 18.4875L18.9467 20.7562C19.0169 20.833 19.1023 20.8943 19.1976 20.9363C19.2928 20.9783 19.3957 21 19.4998 21C19.6869 20.9982 19.8669 20.9282 20.006 20.8031C20.0797 20.7373 20.1396 20.6574 20.1819 20.5681C20.2243 20.4789 20.2484 20.382 20.2528 20.2833C20.2571 20.1846 20.2417 20.086 20.2074 19.9933C20.173 19.9007 20.1205 19.8158 20.0529 19.7437L5.0529 3.24373ZM9.48727 10.3594L13.3966 14.6531C12.9666 14.8818 12.4868 15.0009 11.9998 15C11.4591 15.0001 10.9284 14.8542 10.4639 14.5775C9.99933 14.3009 9.61819 13.9038 9.36076 13.4283C9.10334 12.9528 8.97919 12.4166 9.00146 11.8764C9.02373 11.3362 9.19159 10.812 9.48727 10.3594V10.3594ZM11.9998 18C9.11228 18 6.5904 16.95 4.50915 14.8781C3.64691 14.0329 2.91685 13.0626 2.34352 12C2.78415 11.175 4.19978 8.85936 6.7779 7.36873L8.4654 9.22499C7.81494 10.0615 7.48054 11.1007 7.52112 12.1596C7.5617 13.2185 7.97465 14.2291 8.68723 15.0134C9.39981 15.7976 10.3663 16.3053 11.4164 16.4469C12.4666 16.5885 13.533 16.355 14.4279 15.7875L15.806 17.3062C14.5911 17.771 13.3005 18.0063 11.9998 18V18ZM23.1842 12.3094C23.1467 12.3937 22.1998 14.4937 20.0529 16.4156C19.9152 16.5359 19.7388 16.6025 19.556 16.6031C19.4509 16.6044 19.3467 16.5823 19.2511 16.5385C19.1555 16.4948 19.0707 16.4304 19.0029 16.35C18.937 16.2767 18.8862 16.1912 18.8534 16.0983C18.8205 16.0055 18.8063 15.907 18.8116 15.8086C18.8168 15.7103 18.8413 15.6139 18.8838 15.525C18.9263 15.4361 18.9859 15.3565 19.0592 15.2906C20.107 14.3507 20.9854 13.2376 21.656 12C21.0811 10.9356 20.3513 9.96244 19.4904 9.11248C17.4091 7.04998 14.8873 5.99999 11.9998 5.99999C11.3903 5.99753 10.7818 6.04772 10.181 6.14998C9.98493 6.17994 9.78489 6.13197 9.62371 6.01634C9.46252 5.90071 9.35299 5.72659 9.31852 5.53124C9.30244 5.43397 9.30569 5.33448 9.32809 5.23847C9.35049 5.14246 9.3916 5.0518 9.44907 4.9717C9.50654 4.89159 9.57924 4.8236 9.66301 4.77161C9.74678 4.71963 9.83998 4.68467 9.93727 4.66873C10.6189 4.55517 11.3088 4.49873 11.9998 4.49998C15.2717 4.49998 18.2435 5.74686 20.5966 8.09061C22.3591 9.86249 23.156 11.625 23.1842 11.7C23.2257 11.7962 23.2471 11.8999 23.2471 12.0047C23.2471 12.1095 23.2257 12.2132 23.1842 12.3094V12.3094ZM12.5623 9.05624C12.465 9.03777 12.3723 9.00032 12.2896 8.94604C12.2068 8.89176 12.1355 8.82171 12.0798 8.73987C11.9672 8.57461 11.925 8.37141 11.9623 8.17498C11.9996 7.97856 12.1134 7.80499 12.2786 7.69247C12.4439 7.57995 12.6471 7.53769 12.8435 7.57499C13.7999 7.76202 14.6703 8.25257 15.3257 8.97375C15.981 9.69494 16.3862 10.6083 16.481 11.5781C16.4993 11.7757 16.4385 11.9725 16.312 12.1254C16.1855 12.2782 16.0035 12.3747 15.806 12.3937H15.731C15.5455 12.3945 15.3664 12.3255 15.2292 12.2005C15.0921 12.0755 15.0068 11.9036 14.9904 11.7187C14.9257 11.0729 14.6546 10.4651 14.2172 9.98546C13.7798 9.50585 13.1995 9.18 12.5623 9.05624V9.05624Z" fill="#C4C4C4"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.1842 11.7C23.1561 11.625 22.3592 9.8625 20.5967 8.09063C18.2436 5.74688 15.2717 4.5 11.9998 4.5C8.72793 4.5 5.75606 5.74688 3.40293 8.09063C1.64043 9.8625 0.843558 11.625 0.815433 11.7C0.773576 11.7945 0.751953 11.8967 0.751953 12C0.751953 12.1033 0.773576 12.2055 0.815433 12.3C0.843558 12.375 1.64043 14.1375 3.40293 15.9094C5.75606 18.2531 8.72793 19.5 11.9998 19.5C15.2717 19.5 18.2436 18.2531 20.5967 15.9094C22.3592 14.1375 23.1561 12.375 23.1842 12.3C23.226 12.2055 23.2477 12.1033 23.2477 12C23.2477 11.8967 23.226 11.7945 23.1842 11.7ZM11.9998 18C9.11231 18 6.59043 16.95 4.50918 14.8781C3.64906 14.031 2.91925 13.0611 2.34356 12C2.91847 10.9356 3.64831 9.96245 4.50918 9.1125C6.59043 7.05 9.11231 6 11.9998 6C14.8873 6 17.4092 7.05 19.4904 9.1125C20.3513 9.96245 21.0811 10.9356 21.6561 12C20.9811 13.2656 18.0373 18 11.9998 18ZM11.9998 7.5C11.1098 7.5 10.2398 7.76392 9.49974 8.25839C8.75972 8.75285 8.18295 9.45566 7.84235 10.2779C7.50176 11.1002 7.41264 12.005 7.58628 12.8779C7.75991 13.7508 8.18849 14.5526 8.81783 15.182C9.44716 15.8113 10.249 16.2399 11.1219 16.4135C11.9948 16.5872 12.8996 16.4981 13.7219 16.1575C14.5442 15.8169 15.247 15.2401 15.7414 14.5001C16.2359 13.76 16.4998 12.89 16.4998 12C16.4998 10.8065 16.0257 9.66193 15.1818 8.81802C14.3379 7.97411 13.1933 7.5 11.9998 7.5ZM11.9998 15C11.4065 15 10.8264 14.8241 10.3331 14.4944C9.83975 14.1648 9.45523 13.6962 9.22817 13.1481C9.00111 12.5999 8.9417 11.9967 9.05745 11.4147C9.17321 10.8328 9.45893 10.2982 9.87849 9.87868C10.298 9.45912 10.8326 9.1734 11.4145 9.05764C11.9965 8.94189 12.5997 9.0013 13.1479 9.22836C13.696 9.45542 14.1646 9.83994 14.4942 10.3333C14.8239 10.8266 14.9998 11.4067 14.9998 12C14.9973 12.7949 14.6805 13.5565 14.1184 14.1186C13.5563 14.6807 12.7947 14.9975 11.9998 15Z" fill="#0099FF"/> <path d="M23.1842 11.7C23.1561 11.625 22.3592 9.8625 20.5967 8.09063C18.2436 5.74688 15.2717 4.5 11.9998 4.5C8.72793 4.5 5.75606 5.74688 3.40293 8.09063C1.64043 9.8625 0.843558 11.625 0.815433 11.7C0.773576 11.7945 0.751953 11.8967 0.751953 12C0.751953 12.1033 0.773576 12.2055 0.815433 12.3C0.843558 12.375 1.64043 14.1375 3.40293 15.9094C5.75606 18.2531 8.72793 19.5 11.9998 19.5C15.2717 19.5 18.2436 18.2531 20.5967 15.9094C22.3592 14.1375 23.1561 12.375 23.1842 12.3C23.226 12.2055 23.2477 12.1033 23.2477 12C23.2477 11.8967 23.226 11.7945 23.1842 11.7ZM11.9998 18C9.11231 18 6.59043 16.95 4.50918 14.8781C3.64906 14.031 2.91925 13.0611 2.34356 12C2.91847 10.9356 3.64831 9.96245 4.50918 9.1125C6.59043 7.05 9.11231 6 11.9998 6C14.8873 6 17.4092 7.05 19.4904 9.1125C20.3513 9.96245 21.0811 10.9356 21.6561 12C20.9811 13.2656 18.0373 18 11.9998 18ZM11.9998 7.5C11.1098 7.5 10.2398 7.76392 9.49974 8.25839C8.75972 8.75285 8.18295 9.45566 7.84235 10.2779C7.50176 11.1002 7.41264 12.005 7.58628 12.8779C7.75991 13.7508 8.18849 14.5526 8.81783 15.182C9.44716 15.8113 10.249 16.2399 11.1219 16.4135C11.9948 16.5872 12.8996 16.4981 13.7219 16.1575C14.5442 15.8169 15.247 15.2401 15.7414 14.5001C16.2359 13.76 16.4998 12.89 16.4998 12C16.4998 10.8065 16.0257 9.66193 15.1818 8.81802C14.3379 7.97411 13.1933 7.5 11.9998 7.5ZM11.9998 15C11.4065 15 10.8264 14.8241 10.3331 14.4944C9.83975 14.1648 9.45523 13.6962 9.22817 13.1481C9.00111 12.5999 8.9417 11.9967 9.05745 11.4147C9.17321 10.8328 9.45893 10.2982 9.87849 9.87868C10.298 9.45912 10.8326 9.1734 11.4145 9.05764C11.9965 8.94189 12.5997 9.0013 13.1479 9.22836C13.696 9.45542 14.1646 9.83994 14.4942 10.3333C14.8239 10.8266 14.9998 11.4067 14.9998 12C14.9973 12.7949 14.6805 13.5565 14.1184 14.1186C13.5563 14.6807 12.7947 14.9975 11.9998 15Z" fill="#0099FF"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2381_1348)"> <g clip-path="url(#clip0_2381_1348)">

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="24" height="24" viewBox="0 0 24 24" fill="#86909C" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="#86909C" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 3.58929C1.5 3.03517 1.72012 2.50375 2.11194 2.11194C2.50375 1.72012 3.03517 1.5 3.58929 1.5H7.76786C8.32197 1.5 8.85339 1.72012 9.24521 2.11194C9.63702 2.50375 9.85714 3.03517 9.85714 3.58929V7.76786C9.85714 8.32197 9.63702 8.85339 9.24521 9.24521C8.85339 9.63702 8.32197 9.85714 7.76786 9.85714H3.58929C3.03517 9.85714 2.50375 9.63702 2.11194 9.24521C1.72012 8.85339 1.5 8.32197 1.5 7.76786V3.58929ZM3.58929 2.89286C3.40458 2.89286 3.22744 2.96623 3.09684 3.09684C2.96623 3.22744 2.89286 3.40458 2.89286 3.58929V7.76786C2.89286 7.95256 2.96623 8.1297 3.09684 8.26031C3.22744 8.39091 3.40458 8.46429 3.58929 8.46429H7.76786C7.95256 8.46429 8.1297 8.39091 8.26031 8.26031C8.39091 8.1297 8.46429 7.95256 8.46429 7.76786V3.58929C8.46429 3.40458 8.39091 3.22744 8.26031 3.09684C8.1297 2.96623 7.95256 2.89286 7.76786 2.89286H3.58929ZM12.6429 3.58929C12.6429 3.03517 12.863 2.50375 13.2548 2.11194C13.6466 1.72012 14.178 1.5 14.7321 1.5H18.9107C19.4648 1.5 19.9962 1.72012 20.3881 2.11194C20.7799 2.50375 21 3.03517 21 3.58929V7.76786C21 8.32197 20.7799 8.85339 20.3881 9.24521C19.9962 9.63702 19.4648 9.85714 18.9107 9.85714H14.7321C14.178 9.85714 13.6466 9.63702 13.2548 9.24521C12.863 8.85339 12.6429 8.32197 12.6429 7.76786V3.58929ZM14.7321 2.89286C14.5474 2.89286 14.3703 2.96623 14.2397 3.09684C14.1091 3.22744 14.0357 3.40458 14.0357 3.58929V7.76786C14.0357 7.95256 14.1091 8.1297 14.2397 8.26031C14.3703 8.39091 14.5474 8.46429 14.7321 8.46429H18.9107C19.0954 8.46429 19.2726 8.39091 19.4032 8.26031C19.5338 8.1297 19.6071 7.95256 19.6071 7.76786V3.58929C19.6071 3.40458 19.5338 3.22744 19.4032 3.09684C19.2726 2.96623 19.0954 2.89286 18.9107 2.89286H14.7321ZM1.5 14.7321C1.5 14.178 1.72012 13.6466 2.11194 13.2548C2.50375 12.863 3.03517 12.6429 3.58929 12.6429H7.76786C8.32197 12.6429 8.85339 12.863 9.24521 13.2548C9.63702 13.6466 9.85714 14.178 9.85714 14.7321V18.9107C9.85714 19.4648 9.63702 19.9962 9.24521 20.3881C8.85339 20.7799 8.32197 21 7.76786 21H3.58929C3.03517 21 2.50375 20.7799 2.11194 20.3881C1.72012 19.9962 1.5 19.4648 1.5 18.9107V14.7321ZM3.58929 14.0357C3.40458 14.0357 3.22744 14.1091 3.09684 14.2397C2.96623 14.3703 2.89286 14.5474 2.89286 14.7321V18.9107C2.89286 19.0954 2.96623 19.2726 3.09684 19.4032C3.22744 19.5338 3.40458 19.6071 3.58929 19.6071H7.76786C7.95256 19.6071 8.1297 19.5338 8.26031 19.4032C8.39091 19.2726 8.46429 19.0954 8.46429 18.9107V14.7321C8.46429 14.5474 8.39091 14.3703 8.26031 14.2397C8.1297 14.1091 7.95256 14.0357 7.76786 14.0357H3.58929ZM12.6429 14.7321C12.6429 14.178 12.863 13.6466 13.2548 13.2548C13.6466 12.863 14.178 12.6429 14.7321 12.6429H18.9107C19.4648 12.6429 19.9962 12.863 20.3881 13.2548C20.7799 13.6466 21 14.178 21 14.7321V18.9107C21 19.4648 20.7799 19.9962 20.3881 20.3881C19.9962 20.7799 19.4648 21 18.9107 21H14.7321C14.178 21 13.6466 20.7799 13.2548 20.3881C12.863 19.9962 12.6429 19.4648 12.6429 18.9107V14.7321ZM14.7321 14.0357C14.5474 14.0357 14.3703 14.1091 14.2397 14.2397C14.1091 14.3703 14.0357 14.5474 14.0357 14.7321V18.9107C14.0357 19.0954 14.1091 19.2726 14.2397 19.4032C14.3703 19.5338 14.5474 19.6071 14.7321 19.6071H18.9107C19.0954 19.6071 19.2726 19.5338 19.4032 19.4032C19.5338 19.2726 19.6071 19.0954 19.6071 18.9107V14.7321C19.6071 14.5474 19.5338 14.3703 19.4032 14.2397C19.2726 14.1091 19.0954 14.0357 18.9107 14.0357H14.7321Z" /> <path d="M1.5 3.58929C1.5 3.03517 1.72012 2.50375 2.11194 2.11194C2.50375 1.72012 3.03517 1.5 3.58929 1.5H7.76786C8.32197 1.5 8.85339 1.72012 9.24521 2.11194C9.63702 2.50375 9.85714 3.03517 9.85714 3.58929V7.76786C9.85714 8.32197 9.63702 8.85339 9.24521 9.24521C8.85339 9.63702 8.32197 9.85714 7.76786 9.85714H3.58929C3.03517 9.85714 2.50375 9.63702 2.11194 9.24521C1.72012 8.85339 1.5 8.32197 1.5 7.76786V3.58929ZM3.58929 2.89286C3.40458 2.89286 3.22744 2.96623 3.09684 3.09684C2.96623 3.22744 2.89286 3.40458 2.89286 3.58929V7.76786C2.89286 7.95256 2.96623 8.1297 3.09684 8.26031C3.22744 8.39091 3.40458 8.46429 3.58929 8.46429H7.76786C7.95256 8.46429 8.1297 8.39091 8.26031 8.26031C8.39091 8.1297 8.46429 7.95256 8.46429 7.76786V3.58929C8.46429 3.40458 8.39091 3.22744 8.26031 3.09684C8.1297 2.96623 7.95256 2.89286 7.76786 2.89286H3.58929ZM12.6429 3.58929C12.6429 3.03517 12.863 2.50375 13.2548 2.11194C13.6466 1.72012 14.178 1.5 14.7321 1.5H18.9107C19.4648 1.5 19.9962 1.72012 20.3881 2.11194C20.7799 2.50375 21 3.03517 21 3.58929V7.76786C21 8.32197 20.7799 8.85339 20.3881 9.24521C19.9962 9.63702 19.4648 9.85714 18.9107 9.85714H14.7321C14.178 9.85714 13.6466 9.63702 13.2548 9.24521C12.863 8.85339 12.6429 8.32197 12.6429 7.76786V3.58929ZM14.7321 2.89286C14.5474 2.89286 14.3703 2.96623 14.2397 3.09684C14.1091 3.22744 14.0357 3.40458 14.0357 3.58929V7.76786C14.0357 7.95256 14.1091 8.1297 14.2397 8.26031C14.3703 8.39091 14.5474 8.46429 14.7321 8.46429H18.9107C19.0954 8.46429 19.2726 8.39091 19.4032 8.26031C19.5338 8.1297 19.6071 7.95256 19.6071 7.76786V3.58929C19.6071 3.40458 19.5338 3.22744 19.4032 3.09684C19.2726 2.96623 19.0954 2.89286 18.9107 2.89286H14.7321ZM1.5 14.7321C1.5 14.178 1.72012 13.6466 2.11194 13.2548C2.50375 12.863 3.03517 12.6429 3.58929 12.6429H7.76786C8.32197 12.6429 8.85339 12.863 9.24521 13.2548C9.63702 13.6466 9.85714 14.178 9.85714 14.7321V18.9107C9.85714 19.4648 9.63702 19.9962 9.24521 20.3881C8.85339 20.7799 8.32197 21 7.76786 21H3.58929C3.03517 21 2.50375 20.7799 2.11194 20.3881C1.72012 19.9962 1.5 19.4648 1.5 18.9107V14.7321ZM3.58929 14.0357C3.40458 14.0357 3.22744 14.1091 3.09684 14.2397C2.96623 14.3703 2.89286 14.5474 2.89286 14.7321V18.9107C2.89286 19.0954 2.96623 19.2726 3.09684 19.4032C3.22744 19.5338 3.40458 19.6071 3.58929 19.6071H7.76786C7.95256 19.6071 8.1297 19.5338 8.26031 19.4032C8.39091 19.2726 8.46429 19.0954 8.46429 18.9107V14.7321C8.46429 14.5474 8.39091 14.3703 8.26031 14.2397C8.1297 14.1091 7.95256 14.0357 7.76786 14.0357H3.58929ZM12.6429 14.7321C12.6429 14.178 12.863 13.6466 13.2548 13.2548C13.6466 12.863 14.178 12.6429 14.7321 12.6429H18.9107C19.4648 12.6429 19.9962 12.863 20.3881 13.2548C20.7799 13.6466 21 14.178 21 14.7321V18.9107C21 19.4648 20.7799 19.9962 20.3881 20.3881C19.9962 20.7799 19.4648 21 18.9107 21H14.7321C14.178 21 13.6466 20.7799 13.2548 20.3881C12.863 19.9962 12.6429 19.4648 12.6429 18.9107V14.7321ZM14.7321 14.0357C14.5474 14.0357 14.3703 14.1091 14.2397 14.2397C14.1091 14.3703 14.0357 14.5474 14.0357 14.7321V18.9107C14.0357 19.0954 14.1091 19.2726 14.2397 19.4032C14.3703 19.5338 14.5474 19.6071 14.7321 19.6071H18.9107C19.0954 19.6071 19.2726 19.5338 19.4032 19.4032C19.5338 19.2726 19.6071 19.0954 19.6071 18.9107V14.7321C19.6071 14.5474 19.5338 14.3703 19.4032 14.2397C19.2726 14.1091 19.0954 14.0357 18.9107 14.0357H14.7321Z" />

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="24" height="24" viewBox="0 0 24 24" fill="#86909C" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="#86909C" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 18C3.75 17.8011 3.82902 17.6103 3.96967 17.4697C4.11032 17.329 4.30109 17.25 4.5 17.25H19.5C19.6989 17.25 19.8897 17.329 20.0303 17.4697C20.171 17.6103 20.25 17.8011 20.25 18C20.25 18.1989 20.171 18.3897 20.0303 18.5303C19.8897 18.671 19.6989 18.75 19.5 18.75H4.5C4.30109 18.75 4.11032 18.671 3.96967 18.5303C3.82902 18.3897 3.75 18.1989 3.75 18ZM3.75 12C3.75 11.8011 3.82902 11.6103 3.96967 11.4697C4.11032 11.329 4.30109 11.25 4.5 11.25H19.5C19.6989 11.25 19.8897 11.329 20.0303 11.4697C20.171 11.6103 20.25 11.8011 20.25 12C20.25 12.1989 20.171 12.3897 20.0303 12.5303C19.8897 12.671 19.6989 12.75 19.5 12.75H4.5C4.30109 12.75 4.11032 12.671 3.96967 12.5303C3.82902 12.3897 3.75 12.1989 3.75 12ZM3.75 6C3.75 5.80109 3.82902 5.61032 3.96967 5.46967C4.11032 5.32902 4.30109 5.25 4.5 5.25H19.5C19.6989 5.25 19.8897 5.32902 20.0303 5.46967C20.171 5.61032 20.25 5.80109 20.25 6C20.25 6.19891 20.171 6.38968 20.0303 6.53033C19.8897 6.67098 19.6989 6.75 19.5 6.75H4.5C4.30109 6.75 4.11032 6.67098 3.96967 6.53033C3.82902 6.38968 3.75 6.19891 3.75 6Z" /> <path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 18C3.75 17.8011 3.82902 17.6103 3.96967 17.4697C4.11032 17.329 4.30109 17.25 4.5 17.25H19.5C19.6989 17.25 19.8897 17.329 20.0303 17.4697C20.171 17.6103 20.25 17.8011 20.25 18C20.25 18.1989 20.171 18.3897 20.0303 18.5303C19.8897 18.671 19.6989 18.75 19.5 18.75H4.5C4.30109 18.75 4.11032 18.671 3.96967 18.5303C3.82902 18.3897 3.75 18.1989 3.75 18ZM3.75 12C3.75 11.8011 3.82902 11.6103 3.96967 11.4697C4.11032 11.329 4.30109 11.25 4.5 11.25H19.5C19.6989 11.25 19.8897 11.329 20.0303 11.4697C20.171 11.6103 20.25 11.8011 20.25 12C20.25 12.1989 20.171 12.3897 20.0303 12.5303C19.8897 12.671 19.6989 12.75 19.5 12.75H4.5C4.30109 12.75 4.11032 12.671 3.96967 12.5303C3.82902 12.3897 3.75 12.1989 3.75 12ZM3.75 6C3.75 5.80109 3.82902 5.61032 3.96967 5.46967C4.11032 5.32902 4.30109 5.25 4.5 5.25H19.5C19.6989 5.25 19.8897 5.32902 20.0303 5.46967C20.171 5.61032 20.25 5.80109 20.25 6C20.25 6.19891 20.171 6.38968 20.0303 6.53033C19.8897 6.67098 19.6989 6.75 19.5 6.75H4.5C4.30109 6.75 4.11032 6.67098 3.96967 6.53033C3.82902 6.38968 3.75 6.19891 3.75 6Z" />

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 11.75C11.3713 11.7524 10.7643 11.9805 10.2895 12.3926C9.81465 12.8048 9.50353 13.3736 9.41271 13.9958C9.32189 14.6179 9.45738 15.252 9.79456 15.7827C10.1317 16.3134 10.6482 16.7054 11.25 16.8875V18.5C11.25 18.6989 11.329 18.8897 11.4697 19.0303C11.6103 19.171 11.8011 19.25 12 19.25C12.1989 19.25 12.3897 19.171 12.5303 19.0303C12.671 18.8897 12.75 18.6989 12.75 18.5V16.8875C13.3518 16.7054 13.8683 16.3134 14.2054 15.7827C14.5426 15.252 14.6781 14.6179 14.5873 13.9958C14.4965 13.3736 14.1854 12.8048 13.7105 12.3926C13.2357 11.9805 12.6287 11.7524 12 11.75ZM12 15.5C11.7775 15.5 11.56 15.434 11.375 15.3104C11.19 15.1868 11.0458 15.0111 10.9606 14.8055C10.8755 14.6 10.8532 14.3738 10.8966 14.1555C10.94 13.9373 11.0472 13.7368 11.2045 13.5795C11.3618 13.4222 11.5623 13.315 11.7805 13.2716C11.9988 13.2282 12.225 13.2505 12.4305 13.3356C12.6361 13.4208 12.8118 13.565 12.9354 13.75C13.059 13.935 13.125 14.1525 13.125 14.375C13.125 14.6734 13.0065 14.9595 12.7955 15.1705C12.5845 15.3815 12.2984 15.5 12 15.5ZM19.5 8.75H16.125V6.125C16.125 5.03098 15.6904 3.98177 14.9168 3.20818C14.1432 2.4346 13.094 2 12 2C10.906 2 9.85677 2.4346 9.08318 3.20818C8.3096 3.98177 7.875 5.03098 7.875 6.125V8.75H4.5C4.10218 8.75 3.72064 8.90804 3.43934 9.18934C3.15804 9.47064 3 9.85218 3 10.25V20.75C3 21.1478 3.15804 21.5294 3.43934 21.8107C3.72064 22.092 4.10218 22.25 4.5 22.25H19.5C19.8978 22.25 20.2794 22.092 20.5607 21.8107C20.842 21.5294 21 21.1478 21 20.75V10.25C21 9.85218 20.842 9.47064 20.5607 9.18934C20.2794 8.90804 19.8978 8.75 19.5 8.75ZM9.375 6.125C9.375 5.42881 9.65156 4.76113 10.1438 4.26884C10.6361 3.77656 11.3038 3.5 12 3.5C12.6962 3.5 13.3639 3.77656 13.8562 4.26884C14.3484 4.76113 14.625 5.42881 14.625 6.125V8.75H9.375V6.125ZM19.5 20.75H4.5V10.25H19.5V20.75Z" fill="#1A1A1A"/> <path d="M12 11.75C11.3713 11.7524 10.7643 11.9805 10.2895 12.3926C9.81465 12.8048 9.50353 13.3736 9.41271 13.9958C9.32189 14.6179 9.45738 15.252 9.79456 15.7827C10.1317 16.3134 10.6482 16.7054 11.25 16.8875V18.5C11.25 18.6989 11.329 18.8897 11.4697 19.0303C11.6103 19.171 11.8011 19.25 12 19.25C12.1989 19.25 12.3897 19.171 12.5303 19.0303C12.671 18.8897 12.75 18.6989 12.75 18.5V16.8875C13.3518 16.7054 13.8683 16.3134 14.2054 15.7827C14.5426 15.252 14.6781 14.6179 14.5873 13.9958C14.4965 13.3736 14.1854 12.8048 13.7105 12.3926C13.2357 11.9805 12.6287 11.7524 12 11.75ZM12 15.5C11.7775 15.5 11.56 15.434 11.375 15.3104C11.19 15.1868 11.0458 15.0111 10.9606 14.8055C10.8755 14.6 10.8532 14.3738 10.8966 14.1555C10.94 13.9373 11.0472 13.7368 11.2045 13.5795C11.3618 13.4222 11.5623 13.315 11.7805 13.2716C11.9988 13.2282 12.225 13.2505 12.4305 13.3356C12.6361 13.4208 12.8118 13.565 12.9354 13.75C13.059 13.935 13.125 14.1525 13.125 14.375C13.125 14.6734 13.0065 14.9595 12.7955 15.1705C12.5845 15.3815 12.2984 15.5 12 15.5ZM19.5 8.75H16.125V6.125C16.125 5.03098 15.6904 3.98177 14.9168 3.20818C14.1432 2.4346 13.094 2 12 2C10.906 2 9.85677 2.4346 9.08318 3.20818C8.3096 3.98177 7.875 5.03098 7.875 6.125V8.75H4.5C4.10218 8.75 3.72064 8.90804 3.43934 9.18934C3.15804 9.47064 3 9.85218 3 10.25V20.75C3 21.1478 3.15804 21.5294 3.43934 21.8107C3.72064 22.092 4.10218 22.25 4.5 22.25H19.5C19.8978 22.25 20.2794 22.092 20.5607 21.8107C20.842 21.5294 21 21.1478 21 20.75V10.25C21 9.85218 20.842 9.47064 20.5607 9.18934C20.2794 8.90804 19.8978 8.75 19.5 8.75ZM9.375 6.125C9.375 5.42881 9.65156 4.76113 10.1438 4.26884C10.6361 3.77656 11.3038 3.5 12 3.5C12.6962 3.5 13.3639 3.77656 13.8562 4.26884C14.3484 4.76113 14.625 5.42881 14.625 6.125V8.75H9.375V6.125ZM19.5 20.75H4.5V10.25H19.5V20.75Z" fill="#1A1A1A"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="40" height="40" viewBox="0 0 40 40" fill="black" xmlns="http://www.w3.org/2000/svg" id="iconMember"> <svg width="40" height="40" viewBox="0 0 40 40" fill="black" xmlns="http://www.w3.org/2000/svg" id="iconMember">
<circle cx="20" cy="20" r="20" fill="white"/> <circle cx="20" cy="20" r="20" fill="white"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="16" height="16" viewBox="3 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="3 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_4086_5522)"> <g filter="url(#filter0_d_4086_5522)">

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 16H22V18H10V16ZM10 10H22V12H10V10Z" fill="#191C21"/> <path d="M10 16H22V18H10V16ZM10 10H22V12H10V10Z" fill="#191C21"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5 19C15.1944 19 19 15.1944 19 10.5C19 5.80558 15.1944 2 10.5 2C5.80558 2 2 5.80558 2 10.5C2 15.1944 5.80558 19 10.5 19Z" stroke="#4E5969" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M10.5 19C15.1944 19 19 15.1944 19 10.5C19 5.80558 15.1944 2 10.5 2C5.80558 2 2 5.80558 2 10.5C2 15.1944 5.80558 19 10.5 19Z" stroke="#4E5969" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5 6H19.425C19.05 4.275 17.55 3 15.75 3C13.95 3 12.45 4.275 12.075 6H1.5V7.5H12.075C12.45 9.225 13.95 10.5 15.75 10.5C17.55 10.5 19.05 9.225 19.425 7.5H22.5V6ZM15.75 9C14.475 9 13.5 8.025 13.5 6.75C13.5 5.475 14.475 4.5 15.75 4.5C17.025 4.5 18 5.475 18 6.75C18 8.025 17.025 9 15.75 9ZM1.5 18H4.575C4.95 19.725 6.45 21 8.25 21C10.05 21 11.55 19.725 11.925 18H22.5V16.5H11.925C11.55 14.775 10.05 13.5 8.25 13.5C6.45 13.5 4.95 14.775 4.575 16.5H1.5V18ZM8.25 15C9.525 15 10.5 15.975 10.5 17.25C10.5 18.525 9.525 19.5 8.25 19.5C6.975 19.5 6 18.525 6 17.25C6 15.975 6.975 15 8.25 15Z" fill="#64748B"/> <path d="M22.5 6H19.425C19.05 4.275 17.55 3 15.75 3C13.95 3 12.45 4.275 12.075 6H1.5V7.5H12.075C12.45 9.225 13.95 10.5 15.75 10.5C17.55 10.5 19.05 9.225 19.425 7.5H22.5V6ZM15.75 9C14.475 9 13.5 8.025 13.5 6.75C13.5 5.475 14.475 4.5 15.75 4.5C17.025 4.5 18 5.475 18 6.75C18 8.025 17.025 9 15.75 9ZM1.5 18H4.575C4.95 19.725 6.45 21 8.25 21C10.05 21 11.55 19.725 11.925 18H22.5V16.5H11.925C11.55 14.775 10.05 13.5 8.25 13.5C6.45 13.5 4.95 14.775 4.575 16.5H1.5V18ZM8.25 15C9.525 15 10.5 15.975 10.5 17.25C10.5 18.525 9.525 19.5 8.25 19.5C6.975 19.5 6 18.525 6 17.25C6 15.975 6.975 15 8.25 15Z" fill="#64748B"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">
<g clip-path="url(#clip0_2395_2657)"> <g clip-path="url(#clip0_2395_2657)">

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="16" height="16" viewBox="0 0 16 16" fill="black" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="black" xmlns="http://www.w3.org/2000/svg">
<path d="M7.9999 16C7.71657 16 7.47924 15.904 7.2879 15.712C7.0959 15.5207 6.9999 15.2833 6.9999 15V3.82499L2.1249 8.69999C1.9249 8.89999 1.68724 8.99999 1.4119 8.99999C1.13724 8.99999 0.899902 8.89999 0.699902 8.69999C0.499902 8.49999 0.399902 8.26665 0.399902 7.99999C0.399902 7.73332 0.499902 7.49999 0.699902 7.29999L7.2999 0.699987C7.3999 0.599987 7.50824 0.528988 7.6249 0.486988C7.74157 0.445654 7.86657 0.424988 7.9999 0.424988C8.13324 0.424988 8.26257 0.445654 8.3879 0.486988C8.51257 0.528988 8.61657 0.599987 8.6999 0.699987L15.2999 7.29999C15.4999 7.49999 15.5999 7.73332 15.5999 7.99999C15.5999 8.26665 15.4999 8.49999 15.2999 8.69999C15.0999 8.89999 14.8622 8.99999 14.5869 8.99999C14.3122 8.99999 14.0749 8.89999 13.8749 8.69999L8.9999 3.82499V15C8.9999 15.2833 8.90424 15.5207 8.7129 15.712C8.5209 15.904 8.28324 16 7.9999 16Z"/> <path d="M7.9999 16C7.71657 16 7.47924 15.904 7.2879 15.712C7.0959 15.5207 6.9999 15.2833 6.9999 15V3.82499L2.1249 8.69999C1.9249 8.89999 1.68724 8.99999 1.4119 8.99999C1.13724 8.99999 0.899902 8.89999 0.699902 8.69999C0.499902 8.49999 0.399902 8.26665 0.399902 7.99999C0.399902 7.73332 0.499902 7.49999 0.699902 7.29999L7.2999 0.699987C7.3999 0.599987 7.50824 0.528988 7.6249 0.486988C7.74157 0.445654 7.86657 0.424988 7.9999 0.424988C8.13324 0.424988 8.26257 0.445654 8.3879 0.486988C8.51257 0.528988 8.61657 0.599987 8.6999 0.699987L15.2999 7.29999C15.4999 7.49999 15.5999 7.73332 15.5999 7.99999C15.5999 8.26665 15.4999 8.49999 15.2999 8.69999C15.0999 8.89999 14.8622 8.99999 14.5869 8.99999C14.3122 8.99999 14.0749 8.89999 13.8749 8.69999L8.9999 3.82499V15C8.9999 15.2833 8.90424 15.5207 8.7129 15.712C8.5209 15.904 8.28324 16 7.9999 16Z"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.78488 2.03878C9.62343 1.72766 9.37026 1.46508 9.05455 1.28129C8.73885 1.09751 8.37345 1 8.00047 1C7.62748 1 7.26209 1.09751 6.94638 1.28129C6.63068 1.46508 6.37751 1.72766 6.21605 2.03878L0.521086 12.4048C-0.160262 13.6423 0.70072 15.2857 2.3048 15.2857H13.6954C15.3002 15.2857 16.1598 13.643 15.4799 12.4048L9.78488 2.03878ZM8.00047 5.54628C8.18657 5.54628 8.36505 5.61468 8.49664 5.73645C8.62824 5.85822 8.70216 6.02337 8.70216 6.19557V9.44205C8.70216 9.61425 8.62824 9.77941 8.49664 9.90117C8.36505 10.0229 8.18657 10.0913 8.00047 10.0913C7.81437 10.0913 7.63589 10.0229 7.50429 9.90117C7.3727 9.77941 7.29877 9.61425 7.29877 9.44205V6.19557C7.29877 6.02337 7.3727 5.85822 7.50429 5.73645C7.63589 5.61468 7.81437 5.54628 8.00047 5.54628ZM8.00047 11.0653C8.18657 11.0653 8.36505 11.1337 8.49664 11.2555C8.62824 11.3772 8.70216 11.5424 8.70216 11.7146V12.0392C8.70216 12.2114 8.62824 12.3766 8.49664 12.4984C8.36505 12.6201 8.18657 12.6885 8.00047 12.6885C7.81437 12.6885 7.63589 12.6201 7.50429 12.4984C7.3727 12.3766 7.29877 12.2114 7.29877 12.0392V11.7146C7.29877 11.5424 7.3727 11.3772 7.50429 11.2555C7.63589 11.1337 7.81437 11.0653 8.00047 11.0653Z" fill="#FF3366"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.78488 2.03878C9.62343 1.72766 9.37026 1.46508 9.05455 1.28129C8.73885 1.09751 8.37345 1 8.00047 1C7.62748 1 7.26209 1.09751 6.94638 1.28129C6.63068 1.46508 6.37751 1.72766 6.21605 2.03878L0.521086 12.4048C-0.160262 13.6423 0.70072 15.2857 2.3048 15.2857H13.6954C15.3002 15.2857 16.1598 13.643 15.4799 12.4048L9.78488 2.03878ZM8.00047 5.54628C8.18657 5.54628 8.36505 5.61468 8.49664 5.73645C8.62824 5.85822 8.70216 6.02337 8.70216 6.19557V9.44205C8.70216 9.61425 8.62824 9.77941 8.49664 9.90117C8.36505 10.0229 8.18657 10.0913 8.00047 10.0913C7.81437 10.0913 7.63589 10.0229 7.50429 9.90117C7.3727 9.77941 7.29877 9.61425 7.29877 9.44205V6.19557C7.29877 6.02337 7.3727 5.85822 7.50429 5.73645C7.63589 5.61468 7.81437 5.54628 8.00047 5.54628ZM8.00047 11.0653C8.18657 11.0653 8.36505 11.1337 8.49664 11.2555C8.62824 11.3772 8.70216 11.5424 8.70216 11.7146V12.0392C8.70216 12.2114 8.62824 12.3766 8.49664 12.4984C8.36505 12.6201 8.18657 12.6885 8.00047 12.6885C7.81437 12.6885 7.63589 12.6201 7.50429 12.4984C7.3727 12.3766 7.29877 12.2114 7.29877 12.0392V11.7146C7.29877 11.5424 7.3727 11.3772 7.50429 11.2555C7.63589 11.1337 7.81437 11.0653 8.00047 11.0653Z" fill="#FF3366"/>

View File

@@ -1,3 +1,7 @@
<!-- The Lucia project.
Copyright 2023-2026 DSP, inc. All rights reserved.
Authors:
chiayin.kuo@dsp.im (chiayin), 2023/1/31 -->
<template> <template>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 9.33333C22.6274 9.33333 28 8.13943 28 6.66667C28 5.19391 22.6274 4 16 4C9.37258 4 4 5.19391 4 6.66667C4 8.13943 9.37258 9.33333 16 9.33333Z" stroke="#191C21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M16 9.33333C22.6274 9.33333 28 8.13943 28 6.66667C28 5.19391 22.6274 4 16 4C9.37258 4 4 5.19391 4 6.66667C4 8.13943 9.37258 9.33333 16 9.33333Z" stroke="#191C21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>

View File

@@ -1,18 +1,40 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// imacat.yang@dsp.im (imacat), 2023/9/23
// cindy.chang@dsp.im (Cindy Chang), 2024/5/30
/** @module constants Application-wide constants and chart configuration. */
/** @constant {number} Maximum number of ticks on PrimeVue chart axes. */
export const PRIME_VUE_TICKS_LIMIT = 6; export const PRIME_VUE_TICKS_LIMIT = 6;
/** @constant {number} Number of data items to render per batch. */
export const ONCE_RENDER_NUM_OF_DATA = 9; export const ONCE_RENDER_NUM_OF_DATA = 9;
/** @constant {number} Minimum valid password length. */
export const PWD_VALID_LENGTH = 6; export const PWD_VALID_LENGTH = 6;
/** @constant {string} Default grid line color (Tailwind slate-500). */
export const GRID_COLOR = '#64748b'; export const GRID_COLOR = '#64748b';
/** @constant {string} Modal type for creating a new account. */
export const MODAL_CREATE_NEW = 'MODAL_CREATE_NEW'; export const MODAL_CREATE_NEW = 'MODAL_CREATE_NEW';
/** @constant {string} Modal type for editing an account. */
export const MODAL_ACCT_EDIT = 'MODAL_ACCT_EDIT'; export const MODAL_ACCT_EDIT = 'MODAL_ACCT_EDIT';
/** @constant {string} Modal type for viewing account info. */
export const MODAL_ACCT_INFO = 'MODAL_ACCT_INFO'; export const MODAL_ACCT_INFO = 'MODAL_ACCT_INFO';
/** @constant {string} Modal type for deleting an account. */
export const MODAL_DELETE = 'MODAL_DELETE'; export const MODAL_DELETE = 'MODAL_DELETE';
/** @constant {string} LocalStorage key for saved Cytoscape node positions. */
export const SAVE_KEY_NAME = 'CYTOSCAPE_NODE_POSITION'; export const SAVE_KEY_NAME = 'CYTOSCAPE_NODE_POSITION';
/** @constant {number} Duration (minutes) to highlight newly created accounts. */
export const JUST_CREATE_ACCOUNT_HOT_DURATION_MINS = 2; export const JUST_CREATE_ACCOUNT_HOT_DURATION_MINS = 2;
/**
* @constant {Array<[string, string]>} Field keys and display labels for
* process insights (self-loops, short-loops, traces).
*/
export const INSIGHTS_FIELDS_AND_LABELS = [ export const INSIGHTS_FIELDS_AND_LABELS = [
['self_loops', 'Self-Loop'], ['self_loops', 'Self-Loop'],
['short_loops', 'Short-Loop'], ['short_loops', 'Short-Loop'],
@@ -21,6 +43,7 @@ export const INSIGHTS_FIELDS_AND_LABELS = [
['most_freq_traces', 'Most Frequent Trace'], ['most_freq_traces', 'Most Frequent Trace'],
]; ];
/** @constant {Object} Default Chart.js layout padding options. */
export const knownLayoutChartOption = { export const knownLayoutChartOption = {
padding: { padding: {
top: 16, top: 16,
@@ -29,6 +52,7 @@ export const knownLayoutChartOption = {
} }
}; };
/** @constant {Object} Default Chart.js scale options for line charts. */
export const knownScaleLineChartOptions = { export const knownScaleLineChartOptions = {
x: { x: {
type: 'time', type: 'time',
@@ -84,6 +108,7 @@ y: {
}, },
}, },
}; };
/** @constant {Object} Default Chart.js scale options for horizontal charts. */
export const knownScaleHorizontalChartOptions = { export const knownScaleHorizontalChartOptions = {
x: { x: {
title: { title: {
@@ -131,6 +156,7 @@ y: {
}, },
}, },
}; };
/** @constant {Object} Default Chart.js scale options for bar charts. */
export const knownScaleBarChartOptions = { export const knownScaleBarChartOptions = {
x: { x: {
title: { title: {

Some files were not shown because too many files have changed in this diff Show More