ui
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# Directory Structure for Angular Clarity Boilerplate
|
||||
|
||||
This document outlines the directory structure for the Angular Clarity boilerplate project.
|
||||
/
|
||||
├── .vscode/ # VSCode settings
|
||||
├── node_modules/ # Node.js modules
|
||||
├── src/ # Application source code
|
||||
│ ├── app/ # Application components and modules
|
||||
│ │ ├── core/ # Core module (singleton services, guards, etc.)
|
||||
│ │ ├── shared/ # Shared module (common components, pipes, etc.)
|
||||
│ │ ├── app-routing.module.ts
|
||||
│ │ ├── app.component.html
|
||||
│ │ ├── app.component.scss
|
||||
│ │ └── app.module.ts
|
||||
│ ├── assets/ # Static assets (images, icons, etc.)
|
||||
│ ├── environments/ # Environment-specific configuration
|
||||
│ ├── index.html # Main HTML file
|
||||
│ ├── main.ts # Main entry point
|
||||
│ └── styles.scss # Global styles
|
||||
├── .editorconfig # Editor configuration
|
||||
├── .gitignore # Git ignore file
|
||||
├── angular.json # Angular CLI configuration
|
||||
├── package.json # Project dependencies and scripts
|
||||
├── README.txt # Project README file ignore the README.md file
|
||||
└── tsconfig.json # TypeScript configuration
|
||||
|
||||
## Detailed Content and Customizations:
|
||||
|
||||
### Project Root: `/`
|
||||
- This is the base directory for the entire Angular Clarity boilerplate.
|
||||
|
||||
### `.vscode/`
|
||||
- Contains VSCode-specific settings to help with development consistency.
|
||||
|
||||
### `node_modules/`
|
||||
- Contains all the npm packages and dependencies for the project.
|
||||
|
||||
### `src/`
|
||||
- Contains the main source code for the application.
|
||||
- `app/`: The root component and module for the application.
|
||||
- `core/`: Provides singleton services and modules that are used across the application.
|
||||
- `shared/`: Contains shared components, directives, and pipes.
|
||||
- `app-routing.module.ts`: Defines the main routes for the application.
|
||||
- `app.component.html`: The main HTML template for the root component.
|
||||
- `app.component.scss`: The main stylesheet for the root component.
|
||||
- `app.module.ts`: The root module that ties everything together.
|
||||
- `assets/`: Contains static assets like images, fonts, and icons.
|
||||
- `environments/`: Contains environment-specific configuration files (e.g., for development and production).
|
||||
- `index.html`: The main HTML file that is served to the browser.
|
||||
- `main.ts`: The main entry point for the application.
|
||||
- `styles.scss`: The global stylesheet for the application.
|
||||
|
||||
### Root Level Configuration Files:
|
||||
- These files are crucial for the project's configuration, build process, and development environment.
|
||||
- `.editorconfig`: Ensures consistent coding styles across different editors.
|
||||
- `.gitignore`: Specifies which files and folders should be ignored by Git.
|
||||
- `angular.json`: The configuration file for the Angular CLI.
|
||||
- `package.json`: Defines the project's dependencies and scripts.
|
||||
- `README.txt`: The main documentation file for the project.
|
||||
- `tsconfig.json`: The configuration file for the TypeScript compiler.
|
||||
@@ -0,0 +1,68 @@
|
||||
### io8coder_breakdown.md
|
||||
|
||||
**io8coder Breakdown for "Angular Clarity Boilerplate":**
|
||||
|
||||
**B - Business Understanding:**
|
||||
|
||||
* **Goal:** To provide a robust and scalable boilerplate for developing Angular applications using the Clarity Design System.
|
||||
* **Target Audience:** Angular developers looking to quickly start new projects with a pre-configured, best-practice project structure.
|
||||
* **Key Features:**
|
||||
* Pre-configured Angular project with Clarity Design System.
|
||||
* Responsive layout and navigation.
|
||||
* Scalable architecture with core and shared modules.
|
||||
* Example components and routing.
|
||||
* **Monetization/Value:** An open-source project that accelerates development, ensures consistency, and reduces setup time.
|
||||
|
||||
**M - Model Definition:**
|
||||
|
||||
* **Data Model (Example):**
|
||||
* `User`:
|
||||
* `id` (unique identifier)
|
||||
* `username` (string)
|
||||
* `email` (string)
|
||||
* `Product`:
|
||||
* `id` (unique identifier)
|
||||
* `name` (string)
|
||||
* `description` (string)
|
||||
* `price` (number)
|
||||
* **User Interface (UI) Model:**
|
||||
* **Layout:** Main layout with a header, sidebar, and content area.
|
||||
* **Navigation:** Vertical navigation in the sidebar with collapsible sections.
|
||||
* **Header:** Main header with branding and user profile/actions.
|
||||
* **Components:** Examples of Clarity components such as data grids, forms, modals, and alerts.
|
||||
* **API Model (Example - to be implemented by the developer):**
|
||||
* `GET /api/users`: Retrieve a list of users.
|
||||
* `GET /api/users/{id}`: Retrieve a single user.
|
||||
* `POST /api/users`: Create a new user.
|
||||
* `PUT /api/users/{id}`: Update an existing user.
|
||||
* `DELETE /api/users/{id}`: Delete a user.
|
||||
|
||||
**A - Architecture Design:**
|
||||
|
||||
* **Frontend:** Angular, TypeScript, HTML, SCSS.
|
||||
* **UI Framework:** Clarity Design System.
|
||||
* **State Management (Optional - to be integrated):** NgRx or other state management libraries.
|
||||
* **Backend:** This is a frontend boilerplate and is backend-agnostic. It can be connected to any backend (e.g., Node.js, Python, Java) via RESTful or GraphQL APIs.
|
||||
* **Database:** Not applicable for the frontend boilerplate.
|
||||
* **Deployment:** Can be deployed to any static web hosting service (e.g., Firebase Hosting, Netlify, Vercel, AWS S3).
|
||||
|
||||
**D - Development Plan:**
|
||||
|
||||
* **Phase 1: Initial Setup & Customization**
|
||||
* Clone the boilerplate repository.
|
||||
* Install dependencies.
|
||||
* Customize the theme (branding, colors, logos).
|
||||
* Configure environment variables.
|
||||
* **Phase 2: Feature Development**
|
||||
* Create new feature modules.
|
||||
* Develop components using Clarity components.
|
||||
* Implement routing for new pages.
|
||||
* Integrate with backend APIs.
|
||||
* Add state management if needed.
|
||||
* **Phase 3: Testing**
|
||||
* Write unit tests for components and services.
|
||||
* Write end-to-end tests for user flows.
|
||||
* **Phase 4: Build & Deployment**
|
||||
* Build the application for production.
|
||||
* Deploy to a hosting service.
|
||||
* Set up CI/CD pipelines for automated builds and deployments.
|
||||
59
frontend/angular-clarity-master/.sureai/.io8coder_plan.md
Normal file
59
frontend/angular-clarity-master/.sureai/.io8coder_plan.md
Normal file
@@ -0,0 +1,59 @@
|
||||
**io8coder Plan for "Angular Clarity Boilerplate":**
|
||||
|
||||
**Project Title:** Angular Clarity Boilerplate
|
||||
|
||||
**Project Goal:** To provide developers with a feature-rich, scalable, and easy-to-use boilerplate for building enterprise-grade Angular applications with the Clarity Design System.
|
||||
|
||||
**Key Deliverables:**
|
||||
|
||||
1. A pre-configured Angular project.
|
||||
2. Integration with the Clarity Design System.
|
||||
3. A responsive layout with a header, sidebar, and content area.
|
||||
4. Example modules (core, shared) and components.
|
||||
5. A clear and well-documented project structure.
|
||||
|
||||
**Technology Stack:**
|
||||
|
||||
* **Frontend:** Angular, TypeScript, HTML, SCSS.
|
||||
* **UI Framework:** Clarity Design System.
|
||||
* **Package Manager:** npm.
|
||||
* **Build Tool:** Angular CLI.
|
||||
|
||||
**Phased Approach:**
|
||||
|
||||
**Phase 1: Project Setup and Core Architecture (Estimated: 1 day)**
|
||||
|
||||
* **Task 1.1:** Initialize a new Angular project.
|
||||
* **Task 1.2:** Integrate the Clarity Design System.
|
||||
* **Task 1.3:** Set up the core and shared modules.
|
||||
* **Task 1.4:** Create the main layout component with a header, sidebar, and content area.
|
||||
|
||||
**Phase 2: Navigation and Routing (Estimated: 1 day)**
|
||||
|
||||
* **Task 2.1:** Implement the main routing module (`app-routing.module.ts`).
|
||||
* **Task 2.2:** Create a navigation service to manage sidebar menu items.
|
||||
* **Task 2.3:** Add example routes and components (e.g., dashboard, about page).
|
||||
* **Task 2.4:** Implement lazy loading for feature modules.
|
||||
|
||||
**Phase 3: Example Components and Theming (Estimated: 2 days)**
|
||||
|
||||
* **Task 3.1:** Create example components using various Clarity components (datagrid, forms, modals, etc.).
|
||||
* **Task 3.2:** Implement a theme service for switching between light and dark themes.
|
||||
* **Task 3.3:** Add custom styles and branding.
|
||||
|
||||
**Phase 4: Documentation and Finalization (Estimated: 1 day)**
|
||||
|
||||
* **Task 4.1:** Write a comprehensive `README.txt` file.
|
||||
* **Task 4.2:** Add comments and documentation to the code.
|
||||
* **Task 4.3:** Clean up the codebase and remove any unnecessary files.
|
||||
|
||||
**Testing Strategy:**
|
||||
|
||||
* **Unit Tests:** Use Jasmine and Karma to write unit tests for components and services.
|
||||
* **End-to-End Tests:** Use Protractor or Cypress for end-to-end testing of user flows.
|
||||
* **Manual Testing:** Perform manual testing to ensure the application is working as expected.
|
||||
|
||||
**Assumptions:**
|
||||
|
||||
* The developer has a basic understanding of Angular and the Clarity Design System.
|
||||
* The developer has Node.js and the Angular CLI installed.
|
||||
63
frontend/angular-clarity-master/.sureai/analysis_document.md
Normal file
63
frontend/angular-clarity-master/.sureai/analysis_document.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Analysis Document
|
||||
Generated: Tuesday, September 16, 2025
|
||||
|
||||
## Project Overview
|
||||
The project is an **Angular Clarity Boilerplate**, designed to serve as a foundational template for building modern, scalable, and feature-rich web applications. It provides a pre-configured Angular project integrated with the VMware Clarity Design System, enabling developers to kickstart new projects with a robust and consistent architecture, thereby accelerating the development lifecycle.
|
||||
|
||||
## Business Analysis
|
||||
The primary business need is to **streamline the initial setup phase of new Angular projects** within an organization or for individual developers. The target audience is **Angular developers and development teams** who require a standardized, best-practice project structure. The value proposition is centered around increasing development efficiency, enforcing UI/UX consistency through the Clarity Design System, and reducing the boilerplate code that developers need to write for every new project.
|
||||
|
||||
## User Requirements (Developer Requirements)
|
||||
The "users" of this boilerplate are developers. Their core requirements are:
|
||||
- Developers must be able to **quickly set up a new project** by cloning the repository and installing dependencies.
|
||||
- Developers must be provided with a **clear and understandable project structure** that promotes scalability and maintainability.
|
||||
- The boilerplate must include a **pre-built, responsive application layout** (e.g., header, sidebar, content area).
|
||||
- Developers must have access to **pre-configured core and shared modules** for common functionalities like services, guards, and reusable components.
|
||||
- The boilerplate must be **easily extendable** with new feature modules and components.
|
||||
|
||||
## Functional Requirements
|
||||
The boilerplate will provide the following functional capabilities out-of-the-box:
|
||||
|
||||
- **Pre-configured Angular Environment:** A ready-to-use Angular CLI project with all necessary dependencies and build configurations.
|
||||
- **Clarity Design System Integration:** Full integration of Clarity UI components and styles, ready for immediate use.
|
||||
- **Scalable Architecture:** A modular structure featuring a `CoreModule` for singleton services and a `SharedModule` for reusable UI components, directives, and pipes.
|
||||
- **Responsive Layout:** A default application shell with a responsive header, navigation sidebar, and main content area.
|
||||
- **Routing:** A pre-configured routing module with examples of lazy-loaded feature modules.
|
||||
- **Theming:** Basic support for Clarity's light and dark themes.
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
- **Performance:** The initial boilerplate should be lightweight, ensuring fast development server startup times and optimized production builds.
|
||||
- **Usability (Developer Experience):** The codebase must be clean, well-commented, and logically organized to provide an excellent developer experience.
|
||||
- **Maintainability:** The modular architecture must facilitate easy updates to dependencies and allow for the addition of new features without introducing breaking changes to the core structure.
|
||||
- **Scalability:** The architecture is designed to support the growth of large, enterprise-scale applications.
|
||||
- **Extensibility:** The boilerplate should be easy to customize and extend with additional libraries, modules, and configurations as per project-specific needs.
|
||||
|
||||
## User Stories (Developer Stories)
|
||||
|
||||
### User Story 1: Quick Project Initialization
|
||||
- **As a developer, I want to clone the repository and run `npm install` and `ng serve` to get a live development server running, so that I can bypass manual setup and start building features immediately.**
|
||||
- **Acceptance Criteria:**
|
||||
- Given I have Node.js and Angular CLI installed,
|
||||
- When I clone the repository, install dependencies, and run the start command,
|
||||
- Then the application compiles successfully and is accessible in my browser at `localhost:4200`.
|
||||
|
||||
### User Story 2: Add a New Feature
|
||||
- **As a developer, I want to create a new lazy-loaded feature module with its own components and routing, so that I can add new sections to the application in a scalable way.**
|
||||
- **Acceptance Criteria:**
|
||||
- Given the boilerplate is running,
|
||||
- When I use the Angular CLI to generate a new module and add it to the main routing configuration,
|
||||
- Then I can navigate to the new feature's route, and its components are rendered correctly.
|
||||
|
||||
### User Story 3: Utilize Shared Components
|
||||
- **As a developer, I want to use a component from the `SharedModule` within a new feature module, so that I can reuse common UI elements and maintain consistency.**
|
||||
- **Acceptance Criteria:**
|
||||
- Given I have a new feature module,
|
||||
- When I import the `SharedModule` into my feature module,
|
||||
- Then I can use the shared components (e.g., a custom card or loader) in my feature's templates without errors.
|
||||
|
||||
## Business Rules (Architectural Principles)
|
||||
- Singleton services (e.g., logging, authentication) must be provided in the `CoreModule`.
|
||||
- Reusable components, pipes, and directives that do not have a dependency on services must be declared and exported in the `SharedModule`.
|
||||
- All major application features should be encapsulated within their own lazy-loaded modules.
|
||||
- Environment-specific variables (e.g., API endpoints) must be managed in the `environments` folder.
|
||||
138
frontend/angular-clarity-master/.sureai/architecture_document.md
Normal file
138
frontend/angular-clarity-master/.sureai/architecture_document.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Architecture Document
|
||||
Generated: Tuesday, September 16, 2025
|
||||
|
||||
## System Overview
|
||||
The Angular Clarity Boilerplate is a frontend-only, single-page application (SPA) template. It is designed to serve as a foundational starting point for developing enterprise-grade web applications. The system provides a pre-configured, modular, and scalable architecture using the Angular framework and is visually styled with the VMware Clarity Design System. Its primary purpose is to accelerate development by providing a structured and feature-rich starting point.
|
||||
|
||||
## Architecture Pattern
|
||||
The boilerplate is built upon a **Component-Based Architecture**, which is fundamental to the Angular framework. The UI is composed of a tree of reusable and encapsulated components.
|
||||
|
||||
The overall architectural pattern follows best practices for scalable Angular applications, emphasizing a **Modular Design**. The application is segregated into a `CoreModule`, a `SharedModule`, and is designed for the addition of multiple `FeatureModules`. This structure promotes separation of concerns, reusability, and maintainability.
|
||||
|
||||
## Component Design (Frontend)
|
||||
|
||||
- **AppModule:** The root module of the application, responsible for bootstrapping the `AppComponent` and importing essential modules like the `CoreModule` and `AppRoutingModule`.
|
||||
|
||||
- **AppComponent:** The main application shell component. It contains the primary layout, including the Clarity header, sidebar navigation, and the main content area where routed components are displayed via `<router-outlet>`.
|
||||
|
||||
- **CoreModule:** This module is designed to be imported only once by the `AppModule`. It contains singleton services, route guards, and other one-time setup logic (e.g., HTTP interceptors). This pattern prevents services from being provided multiple times across the application.
|
||||
|
||||
- **SharedModule:** This module contains commonly used components, directives, and pipes that can be reused across different feature modules. It is imported by feature modules whenever they need access to these shared elements. It primarily exports common Angular modules (like `CommonModule`, `FormsModule`) and Clarity UI modules.
|
||||
|
||||
- **Feature Modules (Conceptual):** The architecture is designed for developers to create new feature modules (e.g., `DashboardModule`, `AdminModule`). These modules encapsulate all the components, services, and routing related to a specific business domain. They are typically **lazy-loaded** to improve initial application load performance.
|
||||
|
||||
## Data Architecture
|
||||
|
||||
### Primary Database
|
||||
- Not applicable. As a frontend-only boilerplate, this project does not include a database. It is designed to connect to any backend with a data persistence layer.
|
||||
|
||||
### Data Model (Client-Side)
|
||||
- Data models will be defined using **TypeScript interfaces or classes** within feature modules. These models will represent the structure of data objects retrieved from or sent to the backend API.
|
||||
- **Example `User` model:**
|
||||
```typescript
|
||||
export interface User {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
role: 'admin' | 'user';
|
||||
}
|
||||
|
||||
Of course. Here is the architecture_document.md for the Angular Clarity boilerplate project, presented in a single code block for easy copying.
|
||||
|
||||
Markdown
|
||||
|
||||
# Architecture Document
|
||||
Generated: Tuesday, September 16, 2025
|
||||
|
||||
## System Overview
|
||||
The Angular Clarity Boilerplate is a frontend-only, single-page application (SPA) template. It is designed to serve as a foundational starting point for developing enterprise-grade web applications. The system provides a pre-configured, modular, and scalable architecture using the Angular framework and is visually styled with the VMware Clarity Design System. Its primary purpose is to accelerate development by providing a structured and feature-rich starting point.
|
||||
|
||||
## Architecture Pattern
|
||||
The boilerplate is built upon a **Component-Based Architecture**, which is fundamental to the Angular framework. The UI is composed of a tree of reusable and encapsulated components.
|
||||
|
||||
The overall architectural pattern follows best practices for scalable Angular applications, emphasizing a **Modular Design**. The application is segregated into a `CoreModule`, a `SharedModule`, and is designed for the addition of multiple `FeatureModules`. This structure promotes separation of concerns, reusability, and maintainability.
|
||||
|
||||
## Component Design (Frontend)
|
||||
|
||||
- **AppModule:** The root module of the application, responsible for bootstrapping the `AppComponent` and importing essential modules like the `CoreModule` and `AppRoutingModule`.
|
||||
|
||||
- **AppComponent:** The main application shell component. It contains the primary layout, including the Clarity header, sidebar navigation, and the main content area where routed components are displayed via `<router-outlet>`.
|
||||
|
||||
- **CoreModule:** This module is designed to be imported only once by the `AppModule`. It contains singleton services, route guards, and other one-time setup logic (e.g., HTTP interceptors). This pattern prevents services from being provided multiple times across the application.
|
||||
|
||||
- **SharedModule:** This module contains commonly used components, directives, and pipes that can be reused across different feature modules. It is imported by feature modules whenever they need access to these shared elements. It primarily exports common Angular modules (like `CommonModule`, `FormsModule`) and Clarity UI modules.
|
||||
|
||||
- **Feature Modules (Conceptual):** The architecture is designed for developers to create new feature modules (e.g., `DashboardModule`, `AdminModule`). These modules encapsulate all the components, services, and routing related to a specific business domain. They are typically **lazy-loaded** to improve initial application load performance.
|
||||
|
||||
## Data Architecture
|
||||
|
||||
### Primary Database
|
||||
- Not applicable. As a frontend-only boilerplate, this project does not include a database. It is designed to connect to any backend with a data persistence layer.
|
||||
|
||||
### Data Model (Client-Side)
|
||||
- Data models will be defined using **TypeScript interfaces or classes** within feature modules. These models will represent the structure of data objects retrieved from or sent to the backend API.
|
||||
- **Example `User` model:**
|
||||
```typescript
|
||||
export interface User {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
role: 'admin' | 'user';
|
||||
}
|
||||
Data Flow
|
||||
API Call: A component's method calls a function in its corresponding service (e.g., userService.getUsers()).
|
||||
|
||||
Service Layer: The service uses Angular's HttpClient to make an HTTP request to the backend API.
|
||||
|
||||
Data Retrieval: The service receives the HTTP response and typically returns an Observable of the data, typed with the appropriate TypeScript interface.
|
||||
|
||||
Component Update: The component subscribes to the Observable. Once the data is received, it updates its local state, triggering Angular's change detection to re-render the template and display the new data.
|
||||
|
||||
API Design (Backend Communication)
|
||||
This boilerplate is backend-agnostic. It is designed to communicate with any backend that exposes a RESTful or GraphQL API.
|
||||
|
||||
Communication Protocol
|
||||
HTTP/HTTPS: Communication is handled via standard HTTP requests using Angular's HttpClient service.
|
||||
|
||||
Example Service Implementation
|
||||
An example of a service making API calls:
|
||||
// in user.service.ts
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { User } from '../models/user.model';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService {
|
||||
private apiUrl = `${environment.apiBaseUrl}/users`;
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
getUsers(): Observable<User[]> {
|
||||
return this.http.get<User[]>(this.apiUrl);
|
||||
}
|
||||
|
||||
getUserById(id: number): Observable<User> {
|
||||
return this.http.get<User>(`${this.apiUrl}/${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
Error Handling
|
||||
HTTP interceptors can be provided in the CoreModule to handle API errors globally (e.g., logging errors, redirecting on 401 Unauthorized responses).
|
||||
|
||||
Security Architecture
|
||||
Authentication: Authentication logic (e.g., handling JWTs, interacting with OAuth providers) should be encapsulated within an AuthService provided in the CoreModule.
|
||||
|
||||
Authorization (Route Guards): The architecture uses Angular's Route Guards to protect routes. An AuthGuard can be implemented to prevent unauthorized users from accessing certain parts of the application.
|
||||
|
||||
Client-Side Security: The boilerplate does not inherently protect against all client-side vulnerabilities. Developers should follow best practices for preventing XSS and CSRF attacks.
|
||||
|
||||
Scalability Considerations
|
||||
Lazy Loading: The architecture strongly encourages the use of lazy-loaded feature modules. This ensures that the initial application bundle size remains small, leading to faster load times. As new features are added, they do not impact the initial load performance.
|
||||
|
||||
Modular Design: The strict separation of concerns into Core, Shared, and Feature modules makes the codebase easier to manage, test, and scale as the application grows in complexity.
|
||||
|
||||
State Management: For applications with complex state, a state management library like NgRx or Akita can be easily integrated into this architecture without requiring significant refactoring.
|
||||
62
frontend/angular-clarity-master/.sureai/prd_document.md
Normal file
62
frontend/angular-clarity-master/.sureai/prd_document.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Product Requirements Document (PRD) - Angular Clarity Boilerplate
|
||||
|
||||
## 1. Product Vision
|
||||
|
||||
To provide a robust, scalable, and feature-rich boilerplate that serves as a foundational template for building modern, enterprise-grade web applications using Angular and the VMware Clarity Design System. The vision is to accelerate the development lifecycle by offering a pre-configured, best-practice project structure.
|
||||
|
||||
## 2. Target Audience
|
||||
|
||||
The primary target audience consists of **Angular developers and development teams** who require a standardized, efficient, and consistent starting point for new projects. This includes:
|
||||
|
||||
* **Enterprise Development Teams:** Teams that need to maintain a consistent look and feel across multiple applications.
|
||||
* **Independent Developers:** Individuals looking to quickly bootstrap new projects without spending significant time on initial setup and configuration.
|
||||
|
||||
## 3. User Stories (Developer Stories)
|
||||
|
||||
### User Story 1: Quick Project Initialization
|
||||
- **As a developer, I want to clone the repository and run `npm install` and `ng serve` to get a live development server running, so that I can bypass manual setup and start building features immediately.**
|
||||
- **Acceptance Criteria:**
|
||||
- Given I have Node.js and Angular CLI installed,
|
||||
- When I clone the repository, install dependencies, and run the start command,
|
||||
- Then the application compiles successfully and is accessible in my browser at `localhost:4200`.
|
||||
|
||||
### User Story 2: Add a New Feature
|
||||
- **As a developer, I want to create a new lazy-loaded feature module with its own components and routing, so that I can add new sections to the application in a scalable way.**
|
||||
- **Acceptance Criteria:**
|
||||
- Given the boilerplate is running,
|
||||
- When I use the Angular CLI to generate a new module and add it to the main routing configuration,
|
||||
- Then I can navigate to the new feature's route, and its components are rendered correctly.
|
||||
|
||||
### User Story 3: Utilize Shared Components
|
||||
- **As a developer, I want to use a component from the `SharedModule` within a new feature module, so that I can reuse common UI elements and maintain consistency.**
|
||||
- **Acceptance Criteria:**
|
||||
- Given I have a new feature module,
|
||||
- When I import the `SharedModule` into my feature module,
|
||||
- Then I can use the shared components (e.g., a custom card or loader) in my feature's templates without errors.
|
||||
|
||||
## 4. Functional Requirements
|
||||
|
||||
- **FR-001: Pre-configured Angular Environment:** A ready-to-use Angular CLI project with all necessary dependencies and build configurations.
|
||||
- **FR-002: Clarity Design System Integration:** Full integration of Clarity UI components and styles, ready for immediate use.
|
||||
- **FR-003: Scalable Architecture:** A modular structure featuring a `CoreModule` for singleton services and a `SharedModule` for reusable UI components, directives, and pipes.
|
||||
- **FR-004: Responsive Layout:** A default application shell with a responsive header, navigation sidebar, and main content area.
|
||||
- **FR-005: Routing:** A pre-configured routing module with examples of lazy-loaded feature modules.
|
||||
- **FR-006: Theming:** Basic support for Clarity's light and dark themes.
|
||||
|
||||
## 5. Non-Functional Requirements
|
||||
|
||||
- **NFR-001: Performance:** The initial boilerplate should be lightweight, ensuring fast development server startup times and optimized production builds.
|
||||
- **NFR-002: Usability (Developer Experience):** The codebase must be clean, well-commented, and logically organized to provide an excellent developer experience.
|
||||
- **NFR-003: Maintainability:** The modular architecture must facilitate easy updates to dependencies and allow for the addition of new features without introducing breaking changes to the core structure.
|
||||
- **NFR-004: Scalability:** The architecture is designed to support the growth of large, enterprise-scale applications.
|
||||
- **NFR-005: Extensibility:** The boilerplate should be easy to customize and extend with additional libraries, modules, and configurations as per project-specific needs.
|
||||
|
||||
## 6. Out of Scope
|
||||
|
||||
The following features and functionalities are explicitly out of scope for the boilerplate:
|
||||
|
||||
- **Backend Implementation:** This is a frontend-only boilerplate and does not include any backend code or database.
|
||||
- **Authentication/Authorization Logic:** While the architecture supports the implementation of security features, no pre-built authentication or authorization logic is included.
|
||||
- **State Management:** The boilerplate does not include a state management library (e.g., NgRx, Akita) by default, allowing developers to choose the best solution for their needs.
|
||||
- **Business Logic:** No specific business logic or application features are included beyond the basic structural components.
|
||||
- **CI/CD Pipelines:** While the project is ready for CI/CD, no pre-configured pipelines are included.
|
||||
73
frontend/angular-clarity-master/.sureai/project_plan.md
Normal file
73
frontend/angular-clarity-master/.sureai/project_plan.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Project Plan - Angular Clarity Boilerplate
|
||||
|
||||
## 1. Project Goal
|
||||
|
||||
To develop and deliver a comprehensive, scalable, and well-documented Angular boilerplate. The final product will serve as a foundational template, enabling developers to rapidly bootstrap new enterprise-grade web applications using the VMware Clarity Design System.
|
||||
|
||||
## 2. Methodology
|
||||
|
||||
The project will follow an iterative development approach, focusing on establishing a solid architectural foundation first. The goal is to create a robust Minimum Viable Product (MVP) boilerplate that is immediately useful and can be enhanced over time with additional features and refinements based on developer feedback.
|
||||
|
||||
## 3. Key Phases & Workflow
|
||||
|
||||
1. **Phase 1: Foundation & Architecture Definition:** Define the core architectural patterns, including the modular structure (`Core`, `Shared`, `Feature` modules) and establish the base project setup.
|
||||
2. **Phase 2: MVP Scope & Requirements:** Outline the essential features for the initial boilerplate release, including Clarity integration, responsive layout, and routing. Document these in the PRD and Architecture Document.
|
||||
3. **Phase 3: Backlog Creation & Planning:** Break down the architectural and functional requirements into a prioritized list of development tasks.
|
||||
4. **Phase 4: Development & Integration:** Implement the core architecture, integrate the Clarity Design System, and build out the foundational components and modules.
|
||||
5. **Phase 5: Quality Assurance & Documentation:** Thoroughly test the boilerplate for stability and ease of use. Ensure all key architectural decisions are well-documented within the code and in project documents like the `README.txt`.
|
||||
6. **Phase 6: Release & Future Iteration:** Package and release the initial version of the boilerplate. Plan for future enhancements based on potential developer needs and feedback.
|
||||
|
||||
## 4. Initial Backlog (MVP Focus)
|
||||
|
||||
The following tasks represent the initial backlog for creating the boilerplate:
|
||||
|
||||
### Architecture & Setup Tasks
|
||||
- Initialize a new project using the Angular CLI.
|
||||
- Define and implement the `CoreModule` for singleton services.
|
||||
- Define and implement the `SharedModule` for reusable components, pipes, and directives.
|
||||
- Configure the main `AppRoutingModule` and set up a basic routing structure.
|
||||
- Establish the environment configuration files (`environments` folder).
|
||||
|
||||
### Clarity Design System Integration
|
||||
- Install all necessary Clarity npm packages (`@clr/angular`, `@clr/ui`, `@cds/core`).
|
||||
- Import Clarity's global styles and icon assets into the project.
|
||||
- Implement the main application layout (`AppComponent`) using Clarity's header, sidebar, and content area components.
|
||||
- Ensure the layout is fully responsive.
|
||||
|
||||
### Boilerplate Feature Tasks
|
||||
- Create an example of a lazy-loaded `FeatureModule` to demonstrate the pattern.
|
||||
- Add a dashboard or home page component as a default view.
|
||||
- Include examples of common Clarity components (e.g., a datagrid, a form) on example pages to showcase usage.
|
||||
- Implement basic support for switching between Clarity's light and dark themes.
|
||||
|
||||
### Documentation Tasks
|
||||
- Create a comprehensive `README.txt` with setup instructions, an overview of the architecture, and usage guidelines.
|
||||
- Add inline comments to the code to explain key architectural patterns and configurations.
|
||||
- Generate all required project documentation (`analysis_document.md`, `architecture_document.md`, etc.).
|
||||
|
||||
## 5. Feature Prioritization Strategy
|
||||
|
||||
Prioritization will focus on establishing a stable and usable foundation. **Must-have** features include the core modular architecture and full integration of the Clarity layout. **Should-have** features include example pages and components. **Could-have** features for future iterations might include state management integration or CI/CD templates.
|
||||
|
||||
## 6. Key Technologies
|
||||
|
||||
- **Frontend Framework:** Angular
|
||||
- **Programming Language:** TypeScript
|
||||
- **UI Library:** VMware Clarity Design System
|
||||
- **Styling:** SCSS
|
||||
- **Package Manager:** npm
|
||||
- **Build Tool:** Angular CLI
|
||||
|
||||
## 7. Success Metrics (MVP)
|
||||
|
||||
- The boilerplate can be successfully cloned and set up with just `npm install` and `ng serve`.
|
||||
- The resulting application is stable, responsive, and free of console errors.
|
||||
- The project structure is logical and easy for an Angular developer to understand.
|
||||
- All core architectural patterns (Core/Shared/Feature modules, lazy loading) are correctly implemented and demonstrated.
|
||||
|
||||
## 8. Future Considerations (Post-MVP)
|
||||
|
||||
- Integrating a state management library (e.g., NgRx, Akita) with an example implementation.
|
||||
- Adding more complex example pages (e.g., a settings page, a user profile).
|
||||
- Creating custom Angular Schematics to automate the creation of new feature modules that follow the boilerplate's conventions.
|
||||
- Including pre-configured templates for CI/CD pipelines (e.g., GitHub Actions).
|
||||
@@ -0,0 +1,95 @@
|
||||
# Requirements Document
|
||||
Generated: Tuesday, September 16, 2025
|
||||
|
||||
## Functional Requirements (Developer-Facing)
|
||||
|
||||
### FR-001: Project Initialization
|
||||
- **Description:** The system shall provide a developer-ready Angular project that can be set up with minimal effort.
|
||||
- **Acceptance Criteria:**
|
||||
- A developer shall be able to clone the project from a Git repository.
|
||||
- A developer shall be able to install all required dependencies using a single `npm install` command.
|
||||
- A developer shall be able to start the local development server using the `ng serve` command.
|
||||
- The boilerplate shall compile without errors and be viewable in a web browser.
|
||||
- **Priority:** High
|
||||
|
||||
### FR-002: Modular Architecture
|
||||
- **Description:** The system shall be structured with a scalable and maintainable modular architecture.
|
||||
- **Acceptance Criteria:**
|
||||
- The project shall include a `CoreModule` for providing singleton services and one-time imports.
|
||||
- The project shall include a `SharedModule` for reusable components, directives, and pipes.
|
||||
- The architecture shall support the creation of lazy-loaded `FeatureModules` to encapsulate business domain logic.
|
||||
- **Priority:** High
|
||||
|
||||
### FR-003: Clarity Design System Integration
|
||||
- **Description:** The system shall be fully integrated with the VMware Clarity Design System for UI components and styling.
|
||||
- **Acceptance Criteria:**
|
||||
- All necessary Clarity npm packages shall be included as dependencies.
|
||||
- Clarity's global stylesheets and assets shall be correctly configured and loaded.
|
||||
- The boilerplate shall use Clarity components for its core layout (header, sidebar, etc.).
|
||||
- Developers shall be able to use any Clarity component within their feature modules.
|
||||
- **Priority:** High
|
||||
|
||||
### FR-004: Responsive Application Layout
|
||||
- **Description:** The system shall provide a default, responsive application layout.
|
||||
- **Acceptance Criteria:**
|
||||
- The boilerplate shall include a main application shell with a header, a collapsible sidebar for navigation, and a main content area.
|
||||
- The layout shall adapt correctly to various screen sizes, including desktop, tablet, and mobile.
|
||||
- **Priority:** High
|
||||
|
||||
### FR-005: Routing and Navigation
|
||||
- **Description:** The system shall include a pre-configured routing system for navigating between different views.
|
||||
- **Acceptance Criteria:**
|
||||
- The project shall have a main `AppRoutingModule`.
|
||||
- The boilerplate shall provide an example of a lazy-loaded feature route.
|
||||
- Navigation links in the sidebar shall correctly navigate to their corresponding routes.
|
||||
- **Priority:** Medium
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
### NFR-001: Performance (Developer Experience)
|
||||
- **Description:** The boilerplate should be optimized for a fast and efficient development workflow.
|
||||
- **Acceptance Criteria:**
|
||||
- The initial `ng serve` compilation time shall be reasonably fast.
|
||||
- Live-reloading times during development shall be minimal.
|
||||
- The production build (`ng build --prod`) shall be optimized, with tree-shaking and minification enabled.
|
||||
- **Priority:** Medium
|
||||
|
||||
### NFR-002: Usability (Developer Experience)
|
||||
- **Description:** The codebase should be intuitive and easy for an Angular developer to understand and extend.
|
||||
- **Acceptance Criteria:**
|
||||
- The project structure shall be logical and follow established Angular best practices.
|
||||
- The code shall be clean, well-formatted, and include comments for complex or non-obvious sections.
|
||||
- A comprehensive `README.txt` file shall guide developers on setup, architecture, and usage.
|
||||
- **Priority:** High
|
||||
|
||||
### NFR-003: Maintainability
|
||||
- **Description:** The codebase should be structured to allow for easy updates, modifications, and extensions.
|
||||
- **Acceptance Criteria:**
|
||||
- The modular architecture shall allow for independent development and testing of features.
|
||||
- Dependencies shall be clearly defined in `package.json` and easy to update.
|
||||
- The separation of concerns between modules should be strictly enforced.
|
||||
- **Priority:** High
|
||||
|
||||
## Data Requirements (Client-Side)
|
||||
|
||||
### Entity Modeling:
|
||||
- **Description:** The boilerplate will not have predefined data models but will require developers to define them using TypeScript.
|
||||
- **Attributes:**
|
||||
- Data models shall be defined as **TypeScript interfaces or classes**.
|
||||
- These models will represent the structure of data consumed from and sent to a backend API.
|
||||
|
||||
## Interface Requirements
|
||||
|
||||
### UI/UX Requirements (Frontend Boilerplate):
|
||||
- **Layout:** A clean, professional single-page application layout based on the Clarity Design System.
|
||||
- **Header:** A top header bar, typically containing the application title/logo and user-related actions (e.g., profile, logout).
|
||||
- **Sidebar:** A collapsible vertical navigation sidebar containing links to different feature areas of the application.
|
||||
- **Content Area:** A main content area where the components for the currently active route are displayed.
|
||||
- **Styling:** Adherence to the styles and design tokens provided by the Clarity Design System.
|
||||
|
||||
### API Requirements (Backend Interaction):
|
||||
- **Backend Agnostic:** The boilerplate is a frontend application and makes no assumptions about the backend technology stack.
|
||||
- **Communication Protocol:** The boilerplate shall use Angular's `HttpClient` module to communicate with a backend over HTTP/HTTPS.
|
||||
- **API Endpoint Configuration:** The base URL for the backend API shall be configurable via the `environments` files (e.g., `environment.ts`, `environment.prod.ts`).
|
||||
- **Data Format:** The boilerplate is designed to work with APIs that transact data in **JSON** format.
|
||||
- **Error Handling:** The architecture shall support a centralized way to handle API errors, typically through an `HttpInterceptor` provided in the `CoreModule`.
|
||||
81
frontend/angular-clarity-master/.sureai/sprint_plan.md
Normal file
81
frontend/angular-clarity-master/.sureai/sprint_plan.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Angular Boilerplate Project - Sprint Plan (Sprint 1)
|
||||
|
||||
## Sprint Goal
|
||||
|
||||
To establish the foundational architecture of the Angular Clarity Boilerplate, including setting up the core project structure, integrating the Clarity Design System, implementing the main responsive layout, and creating a clear, documented starting point for developers.
|
||||
|
||||
## Sprint Duration
|
||||
|
||||
[Assumed: A focused 1-week sprint to deliver the core boilerplate MVP.]
|
||||
|
||||
## Team Capacity
|
||||
|
||||
[Assumed: Full developer availability for the sprint duration.]
|
||||
|
||||
## Product Backlog Items (Developer Stories) for Sprint 1
|
||||
|
||||
1. **User Story: Quick Project Initialization**
|
||||
* **As a developer, I want to clone the repository and run `npm install` and `ng serve` to get a live development server running, so that I can bypass manual setup and start building features immediately.**
|
||||
* **Acceptance Criteria:**
|
||||
* The project is initialized using the latest stable Angular CLI.
|
||||
* All necessary dependencies are defined in `package.json`.
|
||||
* The application compiles successfully without errors.
|
||||
|
||||
2. **User Story: Scalable Architecture Foundation**
|
||||
* **As a developer, I want a well-defined modular structure (`Core`, `Shared`), so that I can build a scalable and maintainable application.**
|
||||
* **Acceptance Criteria:**
|
||||
* A `CoreModule` is created for singleton services and one-time imports.
|
||||
* A `SharedModule` is created for reusable components, directives, and pipes.
|
||||
* The `AppModule` is cleanly organized and imports the necessary foundational modules.
|
||||
|
||||
3. **User Story: Clarity Design System Integration**
|
||||
* **As a developer, I want a responsive application layout built with the Clarity Design System, so that I have a professional and consistent UI foundation.**
|
||||
* **Acceptance Criteria:**
|
||||
* Clarity dependencies are added and correctly configured.
|
||||
* The main `AppComponent` uses Clarity components for the header, sidebar navigation, and main content area.
|
||||
* The layout is responsive and functions correctly on desktop, tablet, and mobile screen sizes.
|
||||
|
||||
## Sprint Tasks (Derived from User Stories)
|
||||
|
||||
### Architecture & Setup Tasks:
|
||||
- **Task:** Initialize a new Angular project using the Angular CLI.
|
||||
- **Task:** Clean up default boilerplate files and structure the project directories.
|
||||
- **Task:** Create the `CoreModule` and ensure it is imported only once in the `AppModule`.
|
||||
- **Task:** Create the `SharedModule` with common exports (`CommonModule`, `FormsModule`, etc.).
|
||||
- **Task:** Set up the main `AppRoutingModule` with a default route.
|
||||
- **Task:** Configure environment files (`environment.ts`, `environment.prod.ts`) with a placeholder for an API base URL.
|
||||
|
||||
### Clarity Integration Tasks:
|
||||
- **Task:** Install `@clr/angular`, `@clr/ui`, and `@cds/core` npm packages.
|
||||
- **Task:** Configure `angular.json` to include Clarity's global CSS files and assets.
|
||||
- **Task:** Implement the main application layout in `app.component.html` using `<clr-main-container>`, `<clr-header>`, and `<clr-vertical-nav>`.
|
||||
- **Task:** Add placeholder navigation links in the vertical navigation sidebar.
|
||||
- **Task:** Ensure the Clarity icons are properly loaded and can be used within the application.
|
||||
|
||||
### Documentation & General Tasks:
|
||||
- **Task:** Create the initial `README.txt` file with project setup instructions.
|
||||
- **Task:** Write inline comments for the `CoreModule` and `SharedModule` explaining their purpose.
|
||||
- **Task:** Set up basic linting rules in `.eslintrc.json` to enforce code quality.
|
||||
- **Task:** Configure the `.gitignore` file to exclude unnecessary files from version control.
|
||||
|
||||
## Definition of Done (DoD) for Sprint 1
|
||||
|
||||
- All selected user stories are implemented and meet their acceptance criteria.
|
||||
- The boilerplate can be successfully set up and run by another developer following the `README.txt`.
|
||||
- The core architecture (`CoreModule`, `SharedModule`) is in place.
|
||||
- The main application layout using Clarity is implemented and responsive.
|
||||
- All code is reviewed, formatted, and merged into the main branch.
|
||||
- No known critical bugs or console errors in the initial boilerplate.
|
||||
|
||||
## Potential Impediments
|
||||
|
||||
- Issues with Clarity dependency versions or peer dependencies.
|
||||
- Unexpected complexities in configuring Clarity's global styles with the Angular CLI.
|
||||
- Difficulties in achieving the desired responsive behavior with the Clarity layout components.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Daily stand-ups to track progress and identify any blockers.
|
||||
- Prepare for Sprint 2, which will focus on adding example feature modules, advanced routing (lazy loading), and more complex Clarity component examples.
|
||||
- Sprint Review at the end of the sprint to demonstrate the working boilerplate.
|
||||
- Sprint Retrospective to refine the development process.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Technology Stack Document
|
||||
Generated: Tuesday, September 16, 2025
|
||||
|
||||
## Frontend Technologies
|
||||
|
||||
* **Framework:** **Angular**. The boilerplate is built on the latest stable version of the Angular framework, chosen for its robustness, component-based architecture, and suitability for large-scale, enterprise applications.
|
||||
* **Language:** **TypeScript**. As a superset of JavaScript, TypeScript is used for its strong typing, which improves code quality, maintainability, and developer productivity.
|
||||
* **Styling:** **SCSS**. SCSS is used for its advanced features over standard CSS, such as variables, nesting, and mixins, allowing for more organized and maintainable stylesheets.
|
||||
* **UI Framework:** **VMware Clarity Design System**. This comprehensive design system provides a set of accessible, high-quality UI components and a consistent visual language, which accelerates UI development.
|
||||
* **Core Libraries:**
|
||||
* **RxJS:** Used extensively throughout Angular for reactive programming and managing asynchronous operations.
|
||||
* **Zone.js:** A signaling mechanism that enables Angular's automatic change detection.
|
||||
|
||||
## Backend Technologies
|
||||
|
||||
* **Backend Agnostic:** This is a frontend-only boilerplate and is not tied to any specific backend technology. It is designed to communicate with any backend that exposes a RESTful or GraphQL API.
|
||||
|
||||
## Database Technologies
|
||||
|
||||
* **Not Applicable:** As a frontend project, the boilerplate does not include a database.
|
||||
|
||||
## Infrastructure & Deployment
|
||||
|
||||
* **Web Server:** The built application consists of static files that can be served by any modern web server (e.g., **Nginx**, **Apache**, **Caddy**).
|
||||
* **Hosting:** The project can be deployed to any static site hosting provider, such as **Firebase Hosting**, **Netlify**, **Vercel**, **AWS S3**, or **GitHub Pages**.
|
||||
* **Containerization (Optional):** The application can be easily containerized using **Docker** for consistent deployment environments.
|
||||
|
||||
## Development & Build Tools
|
||||
|
||||
* **Build Tool:** **Angular CLI**. The command-line interface for Angular is used for creating, building, testing, and deploying the application.
|
||||
* **Package Manager:** **npm**. The Node Package Manager is used for managing all project dependencies.
|
||||
* **Version Control:** **Git**. Git is the standard for version control and source code management.
|
||||
* **Testing:**
|
||||
* **Unit Testing:** **Jasmine** (framework) and **Karma** (test runner) are the default tools for unit testing in Angular.
|
||||
* **End-to-End (E2E) Testing:** The project can be configured to use **Protractor** or more modern alternatives like **Cypress** or **Playwright**.
|
||||
* **Code Formatting/Linting:**
|
||||
* **ESLint:** Used for identifying and reporting on patterns in ECMAScript/JavaScript code.
|
||||
* **Prettier:** An opinionated code formatter that enforces a consistent style.
|
||||
* **EditorConfig:** Helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.
|
||||
@@ -1,86 +0,0 @@
|
||||
# BasicP1 UI Enhancement Implementation
|
||||
|
||||
This document explains the UI enhancement implementation for the BasicP1 component using reusable field components.
|
||||
|
||||
## Overview
|
||||
|
||||
The BasicP1 component has been enhanced to use reusable field components for different data types:
|
||||
- Text fields
|
||||
- Number fields
|
||||
- Phone number fields
|
||||
- Paragraph fields
|
||||
- Password fields
|
||||
- Textarea fields
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### 1. Component Structure
|
||||
|
||||
The component now uses a modern UI pattern with:
|
||||
- Hero section with gradient background
|
||||
- Consistent button styling using ThemeService
|
||||
- Responsive grid layout
|
||||
- Enhanced modals with better styling
|
||||
- Reusable field components for all form inputs
|
||||
|
||||
### 2. Reusable Field Components
|
||||
|
||||
Each field type now uses a dedicated component:
|
||||
- `<app-text-field>` for text inputs
|
||||
- `<app-number-field>` for number inputs
|
||||
- `<app-phone-field>` for phone number inputs
|
||||
- `<app-paragraph-field>` for paragraph inputs
|
||||
- `<app-password-field>` for password inputs
|
||||
- `<app-textarea-field>` for textarea inputs
|
||||
|
||||
### 3. Field Configuration
|
||||
|
||||
Each field component is configured using a FieldConfig object:
|
||||
```typescript
|
||||
{
|
||||
name: string; // Field name
|
||||
label: string; // Display label
|
||||
type: string; // Field type
|
||||
required?: boolean; // Is required?
|
||||
placeholder?: string; // Placeholder text
|
||||
// Type-specific properties
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Data Binding
|
||||
|
||||
Field components use two-way data binding:
|
||||
```html
|
||||
<app-text-field
|
||||
[field]="{ name: 'username', label: 'Username', type: 'text' }"
|
||||
[value]="formData.username"
|
||||
(valueChange)="formData.username = $event">
|
||||
</app-text-field>
|
||||
```
|
||||
|
||||
### 5. Benefits
|
||||
|
||||
1. **Consistency**: All fields follow the same styling and behavior patterns
|
||||
2. **Maintainability**: Changes to one field type automatically apply everywhere
|
||||
3. **Reusability**: Components can be used across different forms and modules
|
||||
4. **Theme Support**: All components use ThemeService for consistent theming
|
||||
5. **Validation**: Built-in validation support for each field type
|
||||
6. **Accessibility**: Proper labeling and ARIA attributes
|
||||
|
||||
## Styling
|
||||
|
||||
The component uses the modern styling patterns established in the UI enhancement rules:
|
||||
- Gradient hero sections
|
||||
- Consistent button styling with ThemeService
|
||||
- Responsive design
|
||||
- Proper spacing and typography
|
||||
- Card-based layouts where appropriate
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
To further improve the component:
|
||||
1. Implement the DynamicFormComponent for even easier form creation
|
||||
2. Add more field types as needed
|
||||
3. Implement form validation at the component level
|
||||
4. Add more business logic specific to each field type
|
||||
5. Enhance accessibility features
|
||||
202
frontend/angular-clarity-master/README.txt
Normal file
202
frontend/angular-clarity-master/README.txt
Normal file
@@ -0,0 +1,202 @@
|
||||
# Angular Clarity Boilerplate
|
||||
|
||||
This project is an Angular boilerplate application that uses the [Clarity Design System](https://clarity.design/) by VMware. It serves as a starter template for building modern, responsive, and feature-rich web applications.
|
||||
|
||||
This boilerplate is pre-configured with a standard project structure and includes essential modules and components to kickstart your development process.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
* **Angular:** The latest version of the Angular framework.
|
||||
* **Clarity Design System:** A comprehensive set of UX guidelines, HTML/CSS components, and Angular components.
|
||||
* **Responsive Layout:** A responsive navigation and layout structure.
|
||||
* **Scalable Architecture:** A well-organized and scalable project structure.
|
||||
* **Theming:** Easily customizable themes (light and dark).
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Getting Started
|
||||
|
||||
Follow these instructions to get a copy of the project up and running on your local machine for development and testing purposes.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Make sure you have [Node.js](https://nodejs.org/) and the [Angular CLI](https://angular.io/cli) installed on your system.
|
||||
|
||||
```bash
|
||||
npm install -g @angular/cli
|
||||
|
||||
## Installation
|
||||
|
||||
Install the dependencies:
|
||||
npm install
|
||||
|
||||
Running the Application
|
||||
Run the following command to start the development server:
|
||||
ng serve
|
||||
|
||||
The app will automatically reload if you change any of the source files.
|
||||
|
||||
|
||||
## DEPENDENCIES
|
||||
|
||||
This project includes the following main dependencies:
|
||||
|
||||
@angular/animations: The Angular animations library.
|
||||
@angular/common: Commonly needed services, pipes, and directives.
|
||||
@angular/compiler: The Angular template compiler.
|
||||
@angular/core: Core Angular framework.
|
||||
@angular/forms: Angular's form validation and handling library.
|
||||
@angular/platform-browser: Everything needed to run Angular in a web browser.
|
||||
@angular/router: The Angular router for navigation.
|
||||
@cds/core: Clarity Design System core components.
|
||||
@clr/angular: Angular components for Clarity.
|
||||
@clr/ui: HTML/CSS components for Clarity.
|
||||
rxjs: Reactive extensions for JavaScript.
|
||||
zone.js: A signaling mechanism for Angular that allows it to detect when to run change detection.
|
||||
|
||||
|
||||
📂 Project Structure
|
||||
/
|
||||
├── .vscode/ # VSCode settings
|
||||
├── node_modules/ # Node.js modules
|
||||
├── src/ # Application source code
|
||||
│ ├── app/ # Application components and modules
|
||||
│ │ ├── core/ # Core module (singleton services, guards, etc.)
|
||||
│ │ ├── shared/ # Shared module (common components, pipes, etc.)
|
||||
│ │ ├── app-routing.module.ts
|
||||
│ │ ├── app.component.html
|
||||
│ │ ├── app.component.scss
|
||||
│ │ └── app.module.ts
|
||||
│ ├── assets/ # Static assets (images, icons, etc.)
|
||||
│ ├── environments/ # Environment-specific configuration
|
||||
│ ├── index.html # Main HTML file
|
||||
│ ├── main.ts # Main entry point
|
||||
│ └── styles.scss # Global styles
|
||||
├── .editorconfig # Editor configuration
|
||||
├── .gitignore # Git ignore file
|
||||
├── angular.json # Angular CLI configuration
|
||||
├── package.json # Project dependencies and scripts
|
||||
├── README.md # This README file
|
||||
└── tsconfig.json # TypeScript configuration
|
||||
|
||||
|
||||
---
|
||||
|
||||
## ✅ What’s already built in this codebase (with file locations)
|
||||
|
||||
### Authentication & Login
|
||||
- Login page (UI + logic):
|
||||
- src/app/modules/login/login-page/login-page.component.html
|
||||
- src/app/modules/login/login-page/login-page.component.ts
|
||||
- src/app/modules/login/login-page/login-page.component.spec.ts
|
||||
- Login routing + module:
|
||||
- src/app/modules/login/login-routing.module.ts
|
||||
- src/app/modules/login/login.module.ts
|
||||
- Auth services:
|
||||
- src/app/services/api/login.service.ts
|
||||
- src/app/services/auth_guard.service.ts
|
||||
- src/app/services/jwt.interceptor.ts
|
||||
- Account flows:
|
||||
- Forgot/reset password: src/app/modules/login/forgotresetpassword/forgotresetpassword.component.html
|
||||
- Forgot/reset password (alt): src/app/modules/login/forgotresetpassword1/forgotresetpassword1.component.html
|
||||
- Email verification: src/app/modules/login/emailverification/emailverification.component.{ts,html}
|
||||
- Add guest: src/app/modules/login/addguest/addguest.component.html
|
||||
- About work: src/app/modules/login/about-work/about-work.component.{ts,html}
|
||||
|
||||
### Shell, Layout, Navigation (Menus/Sidebar/Topbar)
|
||||
- Application shell and layout (includes navbar/sidebar containers):
|
||||
- src/app/modules/main/layout/layout.component.{ts,html,scss}
|
||||
- Main module + routing:
|
||||
- src/app/modules/main/main.module.ts
|
||||
- src/app/modules/main/main-routing.module.ts
|
||||
- Menu models and admin menu management:
|
||||
- Models: src/app/models/builder/Rn_Main_Menu.ts, src/app/models/builder/Rn_Sub_Menu.ts, src/app/models/builder/Rn_Fb_Header.ts
|
||||
- Services: src/app/services/admin/menu-register.service.ts, src/app/services/admin/menu-group.service.ts, src/app/services/admin/menumaintance.service.ts
|
||||
- Components (CRUD):
|
||||
- src/app/modules/main/admin/menu-register/* (add/edit/all/readonly)
|
||||
- src/app/modules/main/admin/menu-group/* (all/edit/read-only)
|
||||
- src/app/modules/main/admin/menumaintance/menumaintance.component.{ts,html}
|
||||
- src/app/modules/main/admin/submenu/submenu.component.{ts,html}
|
||||
- src/app/services/api/realnet-menu.service.ts
|
||||
|
||||
### User & Access Management
|
||||
- User management (list/add/edit/profile/settings, groups):
|
||||
- src/app/modules/main/admin/user/user.component.{ts,html}
|
||||
- src/app/modules/main/admin/usermaintance/usermaintance.component.{ts,html}
|
||||
- src/app/modules/main/admin/usermaintanceadd/usermaintanceadd.component.{ts,html}
|
||||
- src/app/modules/main/admin/usermaintanceedit/usermaintanceedit.component.{ts,html}
|
||||
- src/app/modules/main/admin/usergrpmaintenance/usergrpmaintenance.component.ts
|
||||
- src/app/modules/main/admin/profile-setting/profile-setting.component.html
|
||||
- Services: src/app/services/admin/usermaintance.service.ts, src/app/services/admin/usergrpmaintaince.service.ts, src/app/services/admin/user-profile.service.ts, src/app/services/admin/user-registration.service.ts
|
||||
- Access types / permissions:
|
||||
- src/app/modules/main/admin/accesstype/accesstype.component.{ts,html}
|
||||
- src/app/services/admin/accesstype.service.ts
|
||||
- Guard: src/app/services/auth_guard.service.ts
|
||||
|
||||
### System Administration & Configuration
|
||||
- System parameters, health, logs, connectors, webhooks:
|
||||
- System parameters: src/app/modules/main/admin/systemparameters/systemparameters.component.html; service: src/app/services/admin/sysparameter.service.ts
|
||||
- Health checkup: src/app/services/admin/health-checkup.service.ts
|
||||
- Session logger UI: src/app/modules/main/admin/sessionlogger/sessionlogger.component.html; service: src/app/services/admin/sessionlogger.service.ts
|
||||
- Connectors & mapping: src/app/services/admin/sure-connector.service.ts, src/app/services/admin/connector-mapping.service.ts
|
||||
- Outgoing webhooks: src/app/services/admin/outgoingwebhook.service.ts
|
||||
- Audit reporting: src/app/services/admin/auditreport.service.ts; API: src/app/services/api/audittrail.service.ts
|
||||
- Deployment profile: src/app/services/admin/deploymentprofile.service.ts
|
||||
|
||||
### Foundation (FND) and Data Management
|
||||
- Token registry:
|
||||
- src/app/modules/main/fnd/Token_registery/Token_registery.component.{ts,html}
|
||||
- src/app/modules/main/fnd/Token_registery/Token_registery.service.ts
|
||||
- API registry (CRUD + lines):
|
||||
- src/app/modules/main/fnd/apiregistery/apiregistery.component.{ts,html}
|
||||
- src/app/modules/main/fnd/apiregistery/allapiregistery/allapiregistery.component.{ts,html}
|
||||
- src/app/modules/main/fnd/apiregistery/Apiregisteryline/Apiregisteryline.component.{ts,html}
|
||||
- Sequence generator:
|
||||
- src/app/modules/main/fnd/sequencegenarator/sequencegenarator.component.{ts,html}
|
||||
- Extensions:
|
||||
- src/app/modules/main/fnd/extension/* (add/edit/all/components)
|
||||
- Document master:
|
||||
- src/app/modules/main/admin/documentmaster/documentmaster.component.{ts,html}
|
||||
- Data management (bulk import, mapping rules):
|
||||
- Bulk import: src/app/modules/main/datamanagement/bulkimport/**/*.{ts,html}
|
||||
- Mapping rules: src/app/modules/main/datamanagement/mappingrule/**/*.{ts,html}
|
||||
- Services: src/app/services/fnd/bulkimport.service.ts, src/app/services/fnd/datamanagement.service.ts
|
||||
|
||||
### Reporting & Dashboards
|
||||
- Report builder and runner (multiple generations):
|
||||
- Builder: src/app/modules/main/builder/report-build/**/*.{ts,html}
|
||||
- Builder v2: src/app/modules/main/builder/report-build2/**/*.{ts,html}
|
||||
- Runner: src/app/modules/main/builder/report-runner/**/*.{ts,html}
|
||||
- Dashboard (new + runner): src/app/modules/main/builder/dashboardnew/**/*, src/app/modules/main/builder/dashboardrunner/**/*
|
||||
- Services: src/app/services/api/report-builder.service.ts, src/app/services/builder/*.ts
|
||||
|
||||
### Query (Super Admin)
|
||||
- Query management:
|
||||
- src/app/modules/main/superadmin/query/**/*.{ts,html}
|
||||
- src/app/modules/main/superadmin/queryadd/queryadd.component.ts
|
||||
- src/app/modules/main/superadmin/queryedit/queryedit.component.ts
|
||||
- API: src/app/services/api/query-runner.service.ts
|
||||
|
||||
### Shared Utilities
|
||||
- Pipes:
|
||||
- src/app/pipes/*.ts (e.g., search-filter.pipe.ts, thai-date*.pipe.ts, time-pipe.pipe.ts, sanitize.pipe.ts)
|
||||
- Notifications/Alerts services:
|
||||
- src/app/services/notification.service.ts, src/app/services/alerts.service.ts, src/app/services/fnd/alerts.service.ts
|
||||
- CSV/Excel helpers:
|
||||
- src/app/services/csv.service.ts, src/app/services/excel.service.ts
|
||||
- i18n assets:
|
||||
- src/assets/i18n/en.json, src/assets/i18n/hi.json
|
||||
- App-level routing + module:
|
||||
- src/app/app-routing.module.ts
|
||||
- src/app/app.module.ts
|
||||
|
||||
---
|
||||
|
||||
## Quick Start (recap)
|
||||
1. npm install -g @angular/cli
|
||||
2. npm install
|
||||
3. ng serve
|
||||
|
||||
This project already includes: authentication flow, guarded routes, admin menus and access, user and group management, system configuration screens, FND (token/api registry, sequences, extensions), data management (bulk import, mapping rules), reporting and dashboards, super-admin queries, shared utilities (pipes, alerts, CSV/Excel), i18n scaffolding, and a Clarity-based layout and navigation.
|
||||
@@ -1,155 +0,0 @@
|
||||
# Reusable Field Components
|
||||
|
||||
This document explains how to use the reusable field components created for consistent UI across different data types.
|
||||
|
||||
## Overview
|
||||
|
||||
We've created a set of reusable Angular components for different field types:
|
||||
- Text Field
|
||||
- Number Field
|
||||
- Phone Number Field
|
||||
- Paragraph Field
|
||||
- Password Field
|
||||
- Textarea Field
|
||||
|
||||
Each component follows the same pattern and uses ThemeService for consistent styling.
|
||||
|
||||
## Field Configuration
|
||||
|
||||
All field components use a common `FieldConfig` interface:
|
||||
|
||||
```typescript
|
||||
interface FieldConfig {
|
||||
name: string; // Unique field name
|
||||
label: string; // Display label
|
||||
type: string; // Field type (text, number, phone, etc.)
|
||||
required?: boolean; // Is field required?
|
||||
placeholder?: string; // Placeholder text
|
||||
description?: string; // Helper text
|
||||
// Additional type-specific properties
|
||||
}
|
||||
```
|
||||
|
||||
## Component Usage
|
||||
|
||||
### 1. Text Field
|
||||
```html
|
||||
<app-text-field
|
||||
[field]="{ name: 'username', label: 'Username', type: 'text', required: true }"
|
||||
[value]="formData.username"
|
||||
(valueChange)="formData.username = $event">
|
||||
</app-text-field>
|
||||
```
|
||||
|
||||
### 2. Number Field
|
||||
```html
|
||||
<app-number-field
|
||||
[field]="{ name: 'age', label: 'Age', type: 'number', min: 0, max: 120 }"
|
||||
[value]="formData.age"
|
||||
(valueChange)="formData.age = $event">
|
||||
</app-number-field>
|
||||
```
|
||||
|
||||
### 3. Phone Field
|
||||
```html
|
||||
<app-phone-field
|
||||
[field]="{ name: 'phone', label: 'Phone Number', type: 'phone', pattern: '^\\+?[1-9]\\d{1,14}$' }"
|
||||
[value]="formData.phone"
|
||||
(valueChange)="formData.phone = $event">
|
||||
</app-phone-field>
|
||||
```
|
||||
|
||||
### 4. Paragraph Field
|
||||
```html
|
||||
<app-paragraph-field
|
||||
[field]="{ name: 'description', label: 'Description', type: 'paragraph', rows: 6, showCharacterCount: true }"
|
||||
[value]="formData.description"
|
||||
(valueChange)="formData.description = $event">
|
||||
</app-paragraph-field>
|
||||
```
|
||||
|
||||
### 5. Password Field
|
||||
```html
|
||||
<app-password-field
|
||||
[field]="{ name: 'password', label: 'Password', type: 'password', showStrengthIndicator: true }"
|
||||
[value]="formData.password"
|
||||
(valueChange)="formData.password = $event">
|
||||
</app-password-field>
|
||||
```
|
||||
|
||||
### 6. Textarea Field
|
||||
```html
|
||||
<app-textarea-field
|
||||
[field]="{ name: 'comments', label: 'Comments', type: 'textarea', rows: 4 }"
|
||||
[value]="formData.comments"
|
||||
(valueChange)="formData.comments = $event">
|
||||
</app-textarea-field>
|
||||
```
|
||||
|
||||
## Dynamic Form Component
|
||||
|
||||
For easier usage, we've created a `DynamicFormComponent` that can render multiple fields based on configuration:
|
||||
|
||||
```html
|
||||
<app-dynamic-form
|
||||
[fields]="formFields"
|
||||
[formData]="formData"
|
||||
(formSubmit)="onSubmit($event)"
|
||||
(formCancel)="onCancel()">
|
||||
</app-dynamic-form>
|
||||
```
|
||||
|
||||
In your component:
|
||||
```typescript
|
||||
formFields = [
|
||||
{ name: 'name', label: 'Name', type: 'text', required: true },
|
||||
{ name: 'email', label: 'Email', type: 'text', required: true },
|
||||
{ name: 'age', label: 'Age', type: 'number', min: 0 },
|
||||
{ name: 'phone', label: 'Phone', type: 'phone' },
|
||||
{ name: 'bio', label: 'Bio', type: 'paragraph' }
|
||||
];
|
||||
|
||||
formData = {};
|
||||
|
||||
onSubmit(data) {
|
||||
console.log('Form submitted:', data);
|
||||
// Handle form submission
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
console.log('Form cancelled');
|
||||
// Handle form cancellation
|
||||
}
|
||||
```
|
||||
|
||||
## Benefits of This Approach
|
||||
|
||||
1. **Consistency**: All fields follow the same styling and behavior patterns
|
||||
2. **Maintainability**: Changes to one field type automatically apply everywhere
|
||||
3. **Reusability**: Components can be used across different forms and modules
|
||||
4. **Extensibility**: Easy to add new field types following the same pattern
|
||||
5. **Theme Support**: All components use ThemeService for consistent theming
|
||||
6. **Validation**: Built-in validation support for each field type
|
||||
7. **Accessibility**: Proper labeling and ARIA attributes
|
||||
|
||||
## Adding New Field Types
|
||||
|
||||
To add a new field type:
|
||||
|
||||
1. Create a new component that extends `BaseFieldComponent`
|
||||
2. Implement the template and logic specific to that field type
|
||||
3. Add the component to the `FieldTypesModule`
|
||||
4. Register it in the `FieldFactoryService`
|
||||
5. Update the documentation
|
||||
|
||||
## Styling
|
||||
|
||||
All field components use the shared SCSS file which provides:
|
||||
- Consistent spacing and typography
|
||||
- ThemeService integration for colors
|
||||
- Responsive design patterns
|
||||
- Proper focus states and hover effects
|
||||
- Error state styling
|
||||
- Accessibility considerations
|
||||
|
||||
The styling follows the same patterns used in the UI enhancement rules we established earlier.
|
||||
@@ -1,338 +0,0 @@
|
||||
# ð¨ Theme Customization System - Complete Implementation
|
||||
|
||||
## Overview
|
||||
Successfully implemented a comprehensive dynamic theme customization system for the Angular Clarity project. Users can now customize colors, fonts, and appearance in real-time with immediate visual feedback.
|
||||
|
||||
## â
Completed Features
|
||||
|
||||
### 1. Theme Service (`src/app/services/theme.service.ts`)
|
||||
- **Dynamic Theme Management**: Complete theme switching and customization
|
||||
- **Predefined Themes**: 6 built-in themes (Default Blue, Purple Magic, Nature Green, Dark Mode, Sunset Orange, Minimal Gray)
|
||||
- **Custom Theme Creation**: Users can create and save custom themes
|
||||
- **Theme Persistence**: Themes are saved in localStorage
|
||||
- **Import/Export**: Theme sharing and backup functionality
|
||||
- **Real-time Application**: Instant theme changes across the application
|
||||
|
||||
### 2. Theme Customization Component (`src/app/modules/main/theme-customization/`)
|
||||
- **Modern UI**: Beautiful, intuitive customization interface
|
||||
- **Color Customization**:
|
||||
- Primary, Secondary, Accent colors
|
||||
- Background and Surface colors
|
||||
- Text colors with live preview
|
||||
- Color picker with preset options
|
||||
- **Typography Customization**:
|
||||
- Primary, Secondary, and Monospace fonts
|
||||
- Live font preview
|
||||
- 8 popular font options
|
||||
- **Advanced Settings**:
|
||||
- Border radius adjustment
|
||||
- Shadow intensity control
|
||||
- **Theme Management**:
|
||||
- Predefined theme selection
|
||||
- Custom theme creation
|
||||
- Import/Export functionality
|
||||
- Reset to default
|
||||
|
||||
### 3. Dynamic CSS Variables (`src/styles/_theme-variables.scss`)
|
||||
- **CSS Custom Properties**: Real-time theme switching via CSS variables
|
||||
- **Theme-aware Components**: All components automatically adapt to theme changes
|
||||
- **Gradient Support**: Dynamic gradients based on theme colors
|
||||
- **Glassmorphism Effects**: Theme-aware glass effects
|
||||
- **Utility Classes**: Helper classes for theme-aware styling
|
||||
|
||||
### 4. Dashboard Integration
|
||||
- **Theme Button**: Added "Customize Theme" button in welcome section
|
||||
- **Quick Action**: Theme customization in quick actions grid
|
||||
- **Navigation**: Easy access from main dashboard
|
||||
|
||||
### 5. Routing & Module Integration
|
||||
- **Route**: `/cns-portal/theme-customization`
|
||||
- **Module**: Added to MainModule declarations
|
||||
- **Navigation**: Integrated with existing routing system
|
||||
|
||||
## ð¯ Key Features
|
||||
|
||||
### Real-time Theme Switching
|
||||
- **Instant Updates**: Changes apply immediately without page refresh
|
||||
- **CSS Variables**: Efficient theme switching using CSS custom properties
|
||||
- **Component Integration**: All components automatically adapt to theme changes
|
||||
|
||||
### Comprehensive Customization
|
||||
- **Colors**: 6 color categories with live preview
|
||||
- **Fonts**: 3 font types with 8 options each
|
||||
- **Visual Effects**: Border radius, shadows, and glassmorphism
|
||||
- **Presets**: Quick color selection with predefined options
|
||||
|
||||
### User Experience
|
||||
- **Intuitive Interface**: Clean, modern customization panel
|
||||
- **Live Preview**: See changes as you make them
|
||||
- **Theme Gallery**: Visual theme selection with previews
|
||||
- **Export/Import**: Share themes and backup customizations
|
||||
|
||||
### Technical Implementation
|
||||
- **Service-based**: Centralized theme management
|
||||
- **Reactive**: RxJS observables for theme changes
|
||||
- **Persistent**: localStorage for theme persistence
|
||||
- **Scalable**: Easy to add new themes and customization options
|
||||
|
||||
## ð File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
âââ app/
|
||||
â âââ services/
|
||||
â â âââ theme.service.ts # Theme management service
|
||||
â âââ modules/
|
||||
â âââ main/
|
||||
â âââ theme-customization/
|
||||
â â âââ theme-customization.component.ts
|
||||
â â âââ theme-customization.component.html
|
||||
â â âââ theme-customization.component.scss
|
||||
â âââ main-page/
|
||||
â â âââ main-page.component.html # Updated with theme buttons
|
||||
â âââ layout/
|
||||
â â âââ layout.component.ts # Theme service integration
|
||||
â âââ main.module.ts # Component registration
|
||||
â âââ main-routing.module.ts # Route configuration
|
||||
âââ styles/
|
||||
âââ _theme-variables.scss # Dynamic theme variables
|
||||
âââ styles.scss # Updated imports
|
||||
```
|
||||
|
||||
## ð¨ Predefined Themes
|
||||
|
||||
### 1. Default Blue
|
||||
- **Primary**: #0ea5e9 (Sky Blue)
|
||||
- **Style**: Clean, professional
|
||||
- **Use Case**: Default enterprise theme
|
||||
|
||||
### 2. Purple Magic
|
||||
- **Primary**: #8b5cf6 (Purple)
|
||||
- **Style**: Creative, modern
|
||||
- **Use Case**: Creative applications
|
||||
|
||||
### 3. Nature Green
|
||||
- **Primary**: #10b981 (Emerald)
|
||||
- **Style**: Fresh, natural
|
||||
- **Use Case**: Environmental, health apps
|
||||
|
||||
### 4. Dark Mode
|
||||
- **Primary**: #3b82f6 (Blue)
|
||||
- **Style**: Dark, modern
|
||||
- **Use Case**: Night mode, developer tools
|
||||
|
||||
### 5. Sunset Orange
|
||||
- **Primary**: #f59e0b (Orange)
|
||||
- **Style**: Warm, energetic
|
||||
- **Use Case**: Creative, entertainment
|
||||
|
||||
### 6. Minimal Gray
|
||||
- **Primary**: #6b7280 (Gray)
|
||||
- **Style**: Minimal, clean
|
||||
- **Use Case**: Professional, documentation
|
||||
|
||||
## ð§ Technical Details
|
||||
|
||||
### Theme Service API
|
||||
```typescript
|
||||
// Get available themes
|
||||
getThemes(): ThemeConfig[]
|
||||
|
||||
// Get current theme
|
||||
getCurrentTheme(): ThemeConfig
|
||||
|
||||
// Set theme
|
||||
setTheme(themeId: string): void
|
||||
|
||||
// Create custom theme
|
||||
createCustomTheme(customTheme: Partial<ThemeConfig>): void
|
||||
|
||||
// Export theme
|
||||
exportTheme(): string
|
||||
|
||||
// Import theme
|
||||
importTheme(themeJson: string): boolean
|
||||
|
||||
// Reset to default
|
||||
resetToDefault(): void
|
||||
```
|
||||
|
||||
### CSS Variables
|
||||
```css
|
||||
:root {
|
||||
--theme-primary: #0ea5e9;
|
||||
--theme-secondary: #64748b;
|
||||
--theme-accent: #8b5cf6;
|
||||
--theme-background: #f8fafc;
|
||||
--theme-surface: #ffffff;
|
||||
--theme-text: #111827;
|
||||
--theme-text-secondary: #6b7280;
|
||||
--theme-font-primary: 'Inter', sans-serif;
|
||||
--theme-font-secondary: 'Poppins', sans-serif;
|
||||
--theme-font-mono: 'JetBrains Mono', monospace;
|
||||
--theme-border-radius: 0.75rem;
|
||||
--theme-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
```
|
||||
|
||||
### Component Integration
|
||||
All components automatically use theme variables:
|
||||
- **Cards**: `background: var(--theme-surface)`
|
||||
- **Buttons**: `background: var(--theme-gradient-primary)`
|
||||
- **Text**: `color: var(--theme-text)`
|
||||
- **Borders**: `border-color: var(--theme-primary)`
|
||||
|
||||
## ð Usage Instructions
|
||||
|
||||
### For Users
|
||||
1. **Access Theme Customization**:
|
||||
- Click "Customize Theme" button on dashboard
|
||||
- Or go to Quick Actions â Theme Customization
|
||||
|
||||
2. **Select Predefined Theme**:
|
||||
- Choose from 6 built-in themes
|
||||
- Click on theme card to apply
|
||||
|
||||
3. **Create Custom Theme**:
|
||||
- Click "Customize Theme" button
|
||||
- Adjust colors using color pickers
|
||||
- Select fonts from dropdowns
|
||||
- Modify border radius and shadows
|
||||
- Click "Apply Theme" to save
|
||||
|
||||
4. **Export/Import Themes**:
|
||||
- Use Export button to download theme
|
||||
- Use Import to load saved themes
|
||||
|
||||
### For Developers
|
||||
1. **Add New Predefined Theme**:
|
||||
```typescript
|
||||
// In theme.service.ts
|
||||
private themes: ThemeConfig[] = [
|
||||
// ... existing themes
|
||||
{
|
||||
id: 'new-theme',
|
||||
name: 'New Theme',
|
||||
colors: { /* theme colors */ },
|
||||
fonts: { /* theme fonts */ },
|
||||
borderRadius: '1rem',
|
||||
shadows: '0 4px 6px rgba(0, 0, 0, 0.1)'
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
2. **Use Theme Variables in Components**:
|
||||
```scss
|
||||
.my-component {
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
border: 1px solid var(--theme-primary);
|
||||
}
|
||||
```
|
||||
|
||||
3. **Subscribe to Theme Changes**:
|
||||
```typescript
|
||||
constructor(private themeService: ThemeService) {
|
||||
this.themeService.currentTheme$.subscribe(theme => {
|
||||
// Handle theme changes
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## ð± Responsive Design
|
||||
|
||||
### Mobile Optimization
|
||||
- **Touch-friendly**: Large touch targets for mobile
|
||||
- **Responsive Grid**: Adaptive layout for all screen sizes
|
||||
- **Simplified Interface**: Streamlined mobile experience
|
||||
|
||||
### Breakpoints
|
||||
- **Mobile**: < 768px
|
||||
- **Tablet**: 768px - 1024px
|
||||
- **Desktop**: > 1024px
|
||||
|
||||
## â¿ Accessibility Features
|
||||
|
||||
### WCAG 2.1 AA Compliance
|
||||
- **Color Contrast**: All themes meet contrast requirements
|
||||
- **Keyboard Navigation**: Full keyboard support
|
||||
- **Screen Readers**: Proper ARIA labels and semantic HTML
|
||||
- **Focus Indicators**: Clear focus states
|
||||
|
||||
### Accessibility Features
|
||||
- **High Contrast**: Dark theme for better visibility
|
||||
- **Font Size**: Readable font sizes across all themes
|
||||
- **Color Independence**: Information not conveyed by color alone
|
||||
|
||||
## ð Theme Persistence
|
||||
|
||||
### Storage
|
||||
- **localStorage**: Themes saved locally
|
||||
- **Automatic Loading**: Themes restored on page reload
|
||||
- **Fallback**: Default theme if no saved theme
|
||||
|
||||
### Data Structure
|
||||
```json
|
||||
{
|
||||
"id": "custom",
|
||||
"name": "Custom Theme",
|
||||
"colors": {
|
||||
"primary": "#0ea5e9",
|
||||
"secondary": "#64748b",
|
||||
"accent": "#8b5cf6",
|
||||
"background": "#f8fafc",
|
||||
"surface": "#ffffff",
|
||||
"text": "#111827",
|
||||
"textSecondary": "#6b7280"
|
||||
},
|
||||
"fonts": {
|
||||
"primary": "Inter",
|
||||
"secondary": "Poppins",
|
||||
"mono": "JetBrains Mono"
|
||||
},
|
||||
"borderRadius": "0.75rem",
|
||||
"shadows": "0 10px 15px -3px rgba(0, 0, 0, 0.1)"
|
||||
}
|
||||
```
|
||||
|
||||
## ð¯ Performance Optimizations
|
||||
|
||||
### CSS Variables
|
||||
- **Efficient**: No JavaScript manipulation of DOM
|
||||
- **Fast**: Browser-optimized CSS variable updates
|
||||
- **Smooth**: 60fps theme transitions
|
||||
|
||||
### Lazy Loading
|
||||
- **Component**: Theme customization loads on demand
|
||||
- **Fonts**: Google Fonts loaded as needed
|
||||
- **Assets**: Optimized image and icon loading
|
||||
|
||||
## ð® Future Enhancements
|
||||
|
||||
### Potential Features
|
||||
1. **Theme Presets**: Industry-specific theme collections
|
||||
2. **Advanced Customization**: More granular control options
|
||||
3. **Theme Sharing**: Community theme marketplace
|
||||
4. **Auto-save**: Automatic theme saving
|
||||
5. **Theme Scheduling**: Time-based theme switching
|
||||
6. **Accessibility Themes**: High contrast, large text options
|
||||
|
||||
### Technical Improvements
|
||||
1. **Theme Validation**: Color contrast validation
|
||||
2. **Performance Monitoring**: Theme switching performance
|
||||
3. **A/B Testing**: Theme effectiveness testing
|
||||
4. **Analytics**: Theme usage tracking
|
||||
|
||||
## ⨠Summary
|
||||
|
||||
The theme customization system provides:
|
||||
|
||||
- **ð¨ Complete Visual Control**: Colors, fonts, and styling
|
||||
- **â¡ Real-time Updates**: Instant theme changes
|
||||
- **ð¾ Persistent Storage**: Themes saved and restored
|
||||
- **ð± Responsive Design**: Works on all devices
|
||||
- **â¿ Accessible**: WCAG 2.1 AA compliant
|
||||
- **ð§ Developer Friendly**: Easy to extend and customize
|
||||
- **ð Production Ready**: Enterprise-grade implementation
|
||||
|
||||
Users can now fully customize their application experience with a beautiful, intuitive interface that provides immediate visual feedback and persistent theme storage.
|
||||
@@ -1,184 +0,0 @@
|
||||
# UI Enhancement Rules
|
||||
|
||||
This document outlines the standard UI enhancement patterns to be followed across all components in the application.
|
||||
|
||||
## 1. ThemeService Integration
|
||||
|
||||
All styling must use ThemeService variables instead of hardcoded colors or values:
|
||||
- Use `var(--theme-primary)`, `var(--theme-accent)`, etc. for colors
|
||||
- Use `var(--theme-font-primary)`, `var(--theme-font-secondary)` for fonts
|
||||
- Use `var(--theme-surface)`, `var(--theme-background)` for backgrounds
|
||||
- Use `var(--theme-text)`, `var(--theme-text-secondary)` for text colors
|
||||
|
||||
## 2. Modern Component Layout
|
||||
|
||||
### Hero Section
|
||||
- Implement a hero section with gradient background:
|
||||
```scss
|
||||
.component-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
```
|
||||
|
||||
### Container Styling
|
||||
- Use consistent container styling with rounded corners and shadows:
|
||||
```scss
|
||||
.component-container {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Button Styling
|
||||
|
||||
Use the standardized button classes with ThemeService integration:
|
||||
|
||||
### Base Button Class
|
||||
```scss
|
||||
.sq-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: var(--theme-font-primary);
|
||||
z-index: 1;
|
||||
}
|
||||
```
|
||||
|
||||
### Button Variants
|
||||
- Primary: `.sq-btn.sq-btn-primary` (gradient background)
|
||||
- Outline: `.sq-btn.sq-btn-outline` (transparent background with border)
|
||||
- Error: `.sq-btn.sq-btn-error` (error color styling)
|
||||
- Ghost: `.sq-btn.sq-btn-ghost` (minimal styling)
|
||||
|
||||
### Button Sizes
|
||||
- Small: `.sq-btn.sq-btn-sm`
|
||||
- Medium: `.sq-btn.sq-btn-md`
|
||||
- Large: `.sq-btn.sq-btn-lg`
|
||||
|
||||
## 4. Form Enhancement
|
||||
|
||||
### Form Labels
|
||||
```scss
|
||||
.sq-form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
```
|
||||
|
||||
### Form Inputs
|
||||
```scss
|
||||
.sq-form-input {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
transition: all 200ms ease-out;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Card-Based Design
|
||||
|
||||
Implement responsive card layouts for data display:
|
||||
```scss
|
||||
.sq-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.sq-card-item {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
transition: all 200ms ease-out;
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Modal Enhancement
|
||||
|
||||
Enhance modals with consistent styling:
|
||||
- Gradient headers
|
||||
- Proper padding
|
||||
- Consistent footer styling
|
||||
- ThemeService integration for all elements
|
||||
|
||||
## 7. Data Grid Enhancement
|
||||
|
||||
Improve data grids with:
|
||||
- Custom column styling
|
||||
- Enhanced row hover effects
|
||||
- Better pagination styling
|
||||
- Consistent action overflow menus
|
||||
|
||||
## 8. Responsive Design
|
||||
|
||||
Ensure all components are responsive:
|
||||
- Mobile-first approach
|
||||
- Flexible grid layouts
|
||||
- Appropriate breakpoints
|
||||
- Touch-friendly elements
|
||||
|
||||
## 9. Typography
|
||||
|
||||
Use consistent typography with ThemeService:
|
||||
- Primary font for general text: `var(--theme-font-primary)`
|
||||
- Secondary font for headings: `var(--theme-font-secondary)`
|
||||
- Proper font weights and sizes
|
||||
- Consistent text colors
|
||||
|
||||
## 10. Spacing and Layout
|
||||
|
||||
Follow consistent spacing rules:
|
||||
- 8px baseline grid
|
||||
- Consistent padding and margins
|
||||
- Proper visual hierarchy
|
||||
- Balanced whitespace
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
When enhancing any component, ensure:
|
||||
- [ ] ThemeService is used for all colors and fonts
|
||||
- [ ] Hero section is implemented with gradient background
|
||||
- [ ] All buttons use sq-btn classes with appropriate variants
|
||||
- [ ] Forms are properly styled with consistent labels and inputs
|
||||
- [ ] Card view is implemented for data display where appropriate
|
||||
- [ ] Modals are enhanced with modern styling
|
||||
- [ ] Data grids are customized with improved styling
|
||||
- [ ] Component is fully responsive
|
||||
- [ ] Typography follows ThemeService guidelines
|
||||
- [ ] Spacing and layout follow the 8px grid system
|
||||
@@ -1,387 +0,0 @@
|
||||
# User Group Maintenance UI Enhancement Summary
|
||||
|
||||
## Overview
|
||||
This document summarizes the enhancements made to the User Group Maintenance module to create a modern, production-ready, and beautiful UI following the UI Enhancement Rules.
|
||||
|
||||
## Key Enhancements
|
||||
|
||||
### 1. Modern Design System Implementation
|
||||
- Applied the design system tokens from `UI_ENHANCEMENT_RULES.md`
|
||||
- Used ThemeService for all color, font, and styling customizations
|
||||
- Implemented glassmorphism effects and modern gradients
|
||||
- Added proper spacing, typography, and responsive design
|
||||
|
||||
### 2. Component Enhancements
|
||||
|
||||
#### Hero Section
|
||||
- Created a gradient hero section with icon and title
|
||||
- Added glassmorphism effect with backdrop blur
|
||||
- Implemented responsive layout for all screen sizes
|
||||
|
||||
#### Toolbar
|
||||
- Modern search input with integrated icon
|
||||
- View toggle buttons with proper styling
|
||||
- Consistent spacing and shadow effects
|
||||
|
||||
#### Data Grid (Table View)
|
||||
- Enhanced table styling with modern borders and shadows
|
||||
- Added status badges with color coding (green for enabled, red for disabled)
|
||||
- Improved row hover effects and spacing
|
||||
- Modern pagination controls
|
||||
|
||||
#### Card View
|
||||
- Created responsive card layout with grid system
|
||||
- Added glassmorphism cards with proper shadows and borders
|
||||
- Implemented key-value display for user group information
|
||||
- Added status badges with consistent styling
|
||||
|
||||
#### Modals
|
||||
- Enhanced modal dialogs with gradient headers
|
||||
- Improved form layouts with proper spacing and labels
|
||||
- Added validation error styling
|
||||
- Implemented modern buttons with consistent styling
|
||||
|
||||
### 3. ThemeService Integration
|
||||
- Properly subscribed to theme changes in the component
|
||||
- Used CSS custom properties for dynamic theme support
|
||||
- Ensured all colors, fonts, and styling use theme variables
|
||||
- Added OnDestroy lifecycle hook to unsubscribe from theme changes
|
||||
|
||||
### 4. Responsive Design
|
||||
- Implemented responsive layouts for all screen sizes
|
||||
- Added mobile-friendly adjustments for toolbar and hero section
|
||||
- Ensured card grid adapts to different screen widths
|
||||
- Improved touch targets for mobile devices
|
||||
|
||||
### 5. Accessibility Improvements
|
||||
- Added proper focus states for interactive elements
|
||||
- Ensured sufficient color contrast for text
|
||||
- Implemented semantic HTML structure
|
||||
- Added ARIA attributes where appropriate
|
||||
|
||||
### 6. Performance Optimizations
|
||||
- Added loading states with modern spinners
|
||||
- Implemented skeleton loading for better perceived performance
|
||||
- Optimized animations with CSS transitions
|
||||
- Reduced unnecessary DOM elements
|
||||
|
||||
### 7. User Experience Enhancements
|
||||
- Added confirmation dialogs for destructive actions
|
||||
- Improved form validation with clear error messages
|
||||
- Added success and error notifications
|
||||
- Implemented smooth animations and transitions
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. `src/app/modules/main/admin/usergrpmaintenance/usergrpmaintenance.component.scss` - Complete SCSS rewrite with modern styles
|
||||
2. `src/app/modules/main/admin/usergrpmaintenance/usergrpmaintenance.component.html` - Enhanced HTML with modern components
|
||||
3. `src/app/modules/main/admin/usergrpmaintenance/usergrpmaintenance.component.ts` - Added ThemeService integration and improved data handling
|
||||
4. `src/styles.scss` - Added global component extensions
|
||||
|
||||
## Design System Compliance
|
||||
|
||||
All enhancements follow the UI Enhancement Rules:
|
||||
- ✅ Modern & Clean design
|
||||
- ✅ AI-Inspired gradients and glassmorphism
|
||||
- ✅ Production-Ready appearance
|
||||
- ✅ Responsive design
|
||||
- ✅ Accessibility compliance
|
||||
- ✅ ThemeService usage for all styling
|
||||
- ✅ Design token implementation
|
||||
- ✅ Consistent component styling
|
||||
|
||||
## Color Palette Usage
|
||||
|
||||
- Primary colors from the design system
|
||||
- Semantic colors for status indicators
|
||||
- Dynamic theme support through ThemeService
|
||||
- Proper contrast ratios for accessibility
|
||||
|
||||
## Typography
|
||||
|
||||
- Inter font for primary text
|
||||
- Poppins font for headings
|
||||
- Proper font sizing and hierarchy
|
||||
- Responsive font adjustments
|
||||
|
||||
## Spacing System
|
||||
|
||||
- Consistent spacing using design tokens
|
||||
- Proper padding and margins for all components
|
||||
- Responsive spacing adjustments
|
||||
|
||||
## Component Guidelines
|
||||
|
||||
- Cards with glassmorphism effects
|
||||
- Modern buttons with gradient backgrounds
|
||||
- Enhanced form elements with proper validation
|
||||
- Data tables with improved styling
|
||||
- Modals with gradient headers
|
||||
- Badges with color coding
|
||||
|
||||
## Testing
|
||||
|
||||
The enhanced UI has been tested for:
|
||||
- ✅ Responsive behavior on different screen sizes
|
||||
- ✅ Theme switching functionality
|
||||
- ✅ Form validation
|
||||
- ✅ Data loading and error states
|
||||
- ✅ Accessibility compliance
|
||||
- ✅ Performance optimization
|
||||
|
||||
## Future Improvements
|
||||
|
||||
1. Add dark mode support
|
||||
2. Implement more advanced filtering options
|
||||
3. Add export customization features
|
||||
4. Enhance mobile experience further
|
||||
5. Add keyboard navigation improvements
|
||||
|
||||
## ð¨ UI Enhancement Summary - CloudnSure Enterprise Platform
|
||||
|
||||
## Overview
|
||||
Successfully transformed the Angular Clarity project into a modern, AI-inspired, production-ready application with a comprehensive design system. All enhancements focus on UI/UX improvements without touching any business logic.
|
||||
|
||||
## â
Completed Enhancements
|
||||
|
||||
### 1. Design System Foundation
|
||||
- **Created comprehensive design tokens** (`src/styles/_design-tokens.scss`)
|
||||
- Modern color palette with primary, secondary, accent, and neutral colors
|
||||
- Typography system with Inter, Poppins, and JetBrains Mono fonts
|
||||
- Spacing scale, border radius, shadows, and animation tokens
|
||||
- Responsive breakpoints and z-index scale
|
||||
|
||||
- **Base styles and utilities** (`src/styles/_base.scss`)
|
||||
- CSS reset and modern typography
|
||||
- Utility classes for spacing, display, flexbox, and text
|
||||
- Responsive utilities and accessibility features
|
||||
- Smooth scrollbar styling
|
||||
|
||||
- **Component library** (`src/styles/_components.scss`)
|
||||
- Modern card components with glassmorphism effects
|
||||
- Enhanced button variants with hover states
|
||||
- Form components with floating labels and validation states
|
||||
- Data tables, badges, alerts, and modal components
|
||||
- Loading states and skeleton components
|
||||
|
||||
- **Animation system** (`src/styles/_animations.scss`)
|
||||
- Fade, scale, slide, and rotation animations
|
||||
- Hover effects and micro-interactions
|
||||
- Staggered animations for lists
|
||||
- Reduced motion support for accessibility
|
||||
|
||||
### 2. Layout Component Enhancement
|
||||
- **Modern Header Design**
|
||||
- Glassmorphism header with backdrop blur
|
||||
- Enhanced logo with glow effects and hover animations
|
||||
- Modern navigation icons with tooltips
|
||||
- Redesigned user dropdown with profile information
|
||||
- Multi-language support with flag icons
|
||||
|
||||
- **Enhanced Sidebar Navigation**
|
||||
- Clean navigation groups with smooth animations
|
||||
- Modern link styling with active states
|
||||
- Hover effects and micro-interactions
|
||||
- Responsive collapse behavior
|
||||
|
||||
- **Content Area Improvements**
|
||||
- Modern content wrapper with proper spacing
|
||||
- Responsive design for all screen sizes
|
||||
- Smooth transitions and animations
|
||||
|
||||
### 3. Dashboard Component Transformation
|
||||
- **Welcome Section**
|
||||
- Hero section with gradient background
|
||||
- Animated floating cards
|
||||
- Call-to-action buttons with modern styling
|
||||
- Responsive layout for mobile devices
|
||||
|
||||
- **Statistics Cards**
|
||||
- Modern stat cards with trend indicators
|
||||
- Color-coded icons and values
|
||||
- Hover effects and smooth animations
|
||||
- Responsive grid layout
|
||||
|
||||
- **Quick Actions Grid**
|
||||
- Interactive action cards with hover effects
|
||||
- Clear visual hierarchy
|
||||
- Smooth transitions and micro-interactions
|
||||
- Responsive design
|
||||
|
||||
- **Activity Feed**
|
||||
- Clean activity list with status indicators
|
||||
- Color-coded activity types
|
||||
- Hover effects and smooth transitions
|
||||
|
||||
### 4. Design System Rules
|
||||
- **Comprehensive guidelines** (`UI_ENHANCEMENT_RULES.md`)
|
||||
- Color palette and usage guidelines
|
||||
- Typography scale and font families
|
||||
- Spacing system and component guidelines
|
||||
- Animation principles and timing
|
||||
- Accessibility standards (WCAG 2.1 AA)
|
||||
- Implementation rules and quality checklist
|
||||
|
||||
## ð¯ Key Features
|
||||
|
||||
### Modern Design Elements
|
||||
- **Glassmorphism Effects**: Backdrop blur and translucent elements
|
||||
- **Gradient Backgrounds**: Modern gradient combinations
|
||||
- **Smooth Animations**: 200ms-300ms transitions with easing functions
|
||||
- **Micro-interactions**: Hover states, focus indicators, and loading states
|
||||
- **Responsive Design**: Mobile-first approach with breakpoint system
|
||||
|
||||
### AI-Inspired UI Components
|
||||
- **Floating Elements**: Animated cards and visual elements
|
||||
- **Gradient Overlays**: Modern color combinations
|
||||
- **Smooth Transitions**: Eased animations and state changes
|
||||
- **Modern Typography**: Clean, readable font combinations
|
||||
- **Card-based Layout**: Clean, organized content structure
|
||||
|
||||
### Production-Ready Features
|
||||
- **Accessibility**: WCAG 2.1 AA compliance
|
||||
- **Performance**: Optimized animations and transitions
|
||||
- **Responsive**: Works on all device sizes
|
||||
- **Maintainable**: Well-organized SCSS with design tokens
|
||||
- **Scalable**: Component-based architecture
|
||||
|
||||
## ð File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
âââ styles/
|
||||
â âââ _design-tokens.scss # Design system variables
|
||||
â âââ _base.scss # Base styles and utilities
|
||||
â âââ _components.scss # Component styles
|
||||
â âââ _animations.scss # Animation definitions
|
||||
âââ app/
|
||||
â âââ modules/
|
||||
â âââ main/
|
||||
â âââ layout/
|
||||
â â âââ layout.component.html # Enhanced layout
|
||||
â â âââ layout.component.scss # Modern styling
|
||||
â âââ main-page/
|
||||
â âââ main-page.component.html # Dashboard UI
|
||||
â âââ main-page.component.scss # Dashboard styling
|
||||
âââ UI_ENHANCEMENT_RULES.md # Design guidelines
|
||||
```
|
||||
|
||||
## ð Implementation Highlights
|
||||
|
||||
### No Logic Changes
|
||||
- All enhancements are purely visual/UI focused
|
||||
- No TypeScript business logic modifications
|
||||
- Preserved all existing functionality
|
||||
- Maintained component interfaces and APIs
|
||||
|
||||
### Modern CSS Architecture
|
||||
- SCSS with design tokens for consistency
|
||||
- Component-based styling approach
|
||||
- Responsive design with mobile-first approach
|
||||
- Accessibility-first implementation
|
||||
|
||||
### Performance Optimizations
|
||||
- Efficient CSS selectors
|
||||
- Optimized animations with `transform` and `opacity`
|
||||
- Reduced motion support for accessibility
|
||||
- Minimal bundle size impact
|
||||
|
||||
## ð¨ Visual Improvements
|
||||
|
||||
### Before vs After
|
||||
- **Header**: Basic Clarity header â Modern glassmorphism design
|
||||
- **Sidebar**: Simple navigation â Rich, animated navigation with tooltips
|
||||
- **Dashboard**: Basic breadcrumb â Comprehensive dashboard with stats and actions
|
||||
- **Typography**: Default fonts â Modern Inter/Poppins typography
|
||||
- **Colors**: Basic Clarity colors â Rich, modern color palette
|
||||
- **Animations**: None â Smooth, purposeful animations throughout
|
||||
|
||||
### Design Consistency
|
||||
- Unified color palette across all components
|
||||
- Consistent spacing and typography scale
|
||||
- Standardized component patterns
|
||||
- Cohesive visual language
|
||||
|
||||
## ð± Responsive Design
|
||||
|
||||
### Breakpoints
|
||||
- **Mobile**: < 640px
|
||||
- **Tablet**: 640px - 1024px
|
||||
- **Desktop**: 1024px - 1280px
|
||||
- **Large Desktop**: > 1280px
|
||||
|
||||
### Mobile Optimizations
|
||||
- Collapsible sidebar on mobile
|
||||
- Touch-friendly button sizes (44px minimum)
|
||||
- Optimized typography scale
|
||||
- Simplified navigation patterns
|
||||
|
||||
## â¿ Accessibility Features
|
||||
|
||||
### WCAG 2.1 AA Compliance
|
||||
- Color contrast ratios meet standards
|
||||
- Focus indicators for keyboard navigation
|
||||
- Screen reader friendly markup
|
||||
- Reduced motion support
|
||||
- Touch target sizes meet guidelines
|
||||
|
||||
### Keyboard Navigation
|
||||
- Tab order follows logical flow
|
||||
- Focus states clearly visible
|
||||
- Skip links for main content
|
||||
- Keyboard shortcuts support
|
||||
|
||||
## ð§ Technical Implementation
|
||||
|
||||
### CSS Architecture
|
||||
- **Design Tokens**: Centralized variables for consistency
|
||||
- **Component Styles**: Modular, reusable component styles
|
||||
- **Utility Classes**: Helper classes for common patterns
|
||||
- **Animation System**: Centralized animation definitions
|
||||
|
||||
### Browser Support
|
||||
- Modern browsers with CSS Grid and Flexbox support
|
||||
- Graceful degradation for older browsers
|
||||
- Progressive enhancement approach
|
||||
|
||||
## ð Performance Impact
|
||||
|
||||
### Bundle Size
|
||||
- Minimal impact on bundle size
|
||||
- Only CSS/SCSS additions
|
||||
- No additional JavaScript dependencies
|
||||
- Optimized font loading
|
||||
|
||||
### Runtime Performance
|
||||
- Efficient CSS selectors
|
||||
- Hardware-accelerated animations
|
||||
- Optimized repaints and reflows
|
||||
- Smooth 60fps animations
|
||||
|
||||
## ð¯ Next Steps (Optional)
|
||||
|
||||
### Potential Future Enhancements
|
||||
1. **Dark Mode**: Add dark theme support
|
||||
2. **Custom Themes**: Allow users to customize colors
|
||||
3. **Advanced Animations**: Add more sophisticated micro-interactions
|
||||
4. **Component Library**: Extract reusable components
|
||||
5. **Storybook Integration**: Document component library
|
||||
|
||||
### Maintenance
|
||||
1. **Design Token Updates**: Centralized color/typography changes
|
||||
2. **Component Consistency**: Regular audits for design consistency
|
||||
3. **Performance Monitoring**: Track animation performance
|
||||
4. **Accessibility Testing**: Regular accessibility audits
|
||||
|
||||
## ⨠Summary
|
||||
|
||||
The Angular Clarity project has been successfully transformed into a modern, AI-inspired, production-ready application with:
|
||||
|
||||
- **ð¨ Modern Design**: Glassmorphism, gradients, and smooth animations
|
||||
- **ð± Responsive**: Works perfectly on all device sizes
|
||||
- **â¿ Accessible**: WCAG 2.1 AA compliant
|
||||
- **ð Performance**: Optimized for smooth user experience
|
||||
- **ð§ Maintainable**: Well-organized, scalable codebase
|
||||
- **ð¯ Production-Ready**: Professional appearance suitable for enterprise use
|
||||
|
||||
All enhancements maintain backward compatibility while providing a significantly improved user experience that rivals modern AI-built applications.
|
||||
@@ -66,7 +66,7 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "5mb",
|
||||
"maximumWarning": "10mb",
|
||||
"maximumError": "10mb"
|
||||
},
|
||||
{
|
||||
|
||||
44493
frontend/angular-clarity-master/package-lock.json
generated
44493
frontend/angular-clarity-master/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,155 +1,39 @@
|
||||
<!-- Modern AI-Inspired Login Page -->
|
||||
<div class="modern-login-container" *ngIf="showLogin2">
|
||||
<!-- Background Elements -->
|
||||
<div class="login-background">
|
||||
<div class="gradient-overlay"></div>
|
||||
<div class="floating-shapes">
|
||||
<div class="shape shape-1"></div>
|
||||
<div class="shape shape-2"></div>
|
||||
<div class="shape shape-3"></div>
|
||||
<div class="shape shape-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <router-outlet></router-outlet> -->
|
||||
|
||||
<!-- Main Login Content -->
|
||||
<div class="login-content">
|
||||
<!-- Left Side - Branding -->
|
||||
<div class="login-branding">
|
||||
<div class="brand-content">
|
||||
<div class="logo-section">
|
||||
<div class="logo-container">
|
||||
<img class="logo-img" src="assets/images/icon/micrologo.png" alt="CloudnSure Logo">
|
||||
<div class="logo-glow"></div>
|
||||
</div>
|
||||
<h1 class="brand-title">
|
||||
<ng-container *ngIf="loginEnvironment?.companyName; else defaultTitle">
|
||||
<!-- <div class="login-wrapper" *ngIf="showLogin2 && loginEnvironment.templateNo == 'Template 1'" [style.backgroundImage]="'url(' + loginEnvironment.imagePath + ')'">
|
||||
<form class="login">
|
||||
<section class="title">
|
||||
<h3 class="welcome">Welcome to</h3>
|
||||
{{ loginEnvironment.companyName }}
|
||||
</ng-container>
|
||||
<ng-template #defaultTitle>
|
||||
CloudnSure
|
||||
</ng-template>
|
||||
</h1>
|
||||
<p class="brand-subtitle">Enterprise Platform</p>
|
||||
<h5 class="hint">Use your ID to sign in OR <a [routerLink]="['/email-verification']" class="signup">create one now </a> </h5>
|
||||
</section>
|
||||
<div class="login-group">
|
||||
<clr-input-container>
|
||||
<label class="clr-sr-only">Username</label>
|
||||
<input type="text" name="username" clrInput autocomplete="off" [(ngModel)]="model.email"
|
||||
placeholder="Username (sysadmin)"/>
|
||||
</clr-input-container>
|
||||
<clr-password-container>
|
||||
<label class="clr-sr-only">Password</label>
|
||||
<input type="password" name="password" clrPassword id="login_password" autocomplete="off" [(ngModel)]="model.password"
|
||||
placeholder="Password (test3)"/>
|
||||
</clr-password-container>
|
||||
<clr-checkbox-wrapper>
|
||||
<input clrCheckbox type="checkbox" id="rememberme">
|
||||
<label for="rememberme"> Remember me </label>
|
||||
</clr-checkbox-wrapper>
|
||||
|
||||
<div class="error active" *ngIf="isError">
|
||||
Invalid user name or password
|
||||
</div>
|
||||
|
||||
<div class="brand-features">
|
||||
<div class="feature-item">
|
||||
<clr-icon shape="shield" class="feature-icon"></clr-icon>
|
||||
<span>Secure & Reliable</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<clr-icon shape="analytics" class="feature-icon"></clr-icon>
|
||||
<span>Advanced Analytics</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<clr-icon shape="cog" class="feature-icon"></clr-icon>
|
||||
<span>Customizable</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Side - Login Form -->
|
||||
<div class="login-form-section">
|
||||
<div class="form-container">
|
||||
<div class="form-header">
|
||||
<h2 class="form-title">Welcome Back</h2>
|
||||
<p class="form-subtitle">Sign in to your account to continue</p>
|
||||
</div>
|
||||
|
||||
<form class="modern-login-form" (ngSubmit)="onLogin()">
|
||||
<!-- Username Field -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">Username</label>
|
||||
<div class="input-container">
|
||||
<clr-icon shape="user" class="input-icon"></clr-icon>
|
||||
<input type="text" name="username" class="modern-input" autocomplete="username" [(ngModel)]="model.email"
|
||||
(input)="clearError()" placeholder="Enter your username" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password Field -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">Password</label>
|
||||
<div class="input-container">
|
||||
<clr-icon shape="lock" class="input-icon"></clr-icon>
|
||||
<input [type]="showPassword ? 'text' : 'password'" name="password" class="modern-input"
|
||||
autocomplete="current-password" [(ngModel)]="model.password" (input)="clearError()"
|
||||
placeholder="Enter your password" required>
|
||||
<button type="button" class="password-toggle" (click)="togglePasswordVisibility()"
|
||||
[attr.aria-label]="showPassword ? 'Hide password' : 'Show password'">
|
||||
<span class="toggle-text">{{ showPassword ? 'Hide' : 'Show' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Remember Me & Forgot Password -->
|
||||
<div class="form-options">
|
||||
<label class="checkbox-container">
|
||||
<input type="checkbox" id="rememberme" class="modern-checkbox">
|
||||
<span class="checkmark"></span>
|
||||
<span class="checkbox-label">Remember me</span>
|
||||
</label>
|
||||
<a href="javascript://" class="forgot-link" (click)="goforgotpass()">
|
||||
Forgot password?
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div class="error-message" *ngIf="isError">
|
||||
<clr-icon shape="exclamation-triangle"></clr-icon>
|
||||
<span>{{ errMsg || 'Invalid username or password' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Login Button -->
|
||||
<button type="submit" class="modern-login-btn" [disabled]="isLoading" [class.loading]="isLoading">
|
||||
<span class="btn-content" *ngIf="!isLoading">
|
||||
<clr-icon shape="login"></clr-icon>
|
||||
Sign In
|
||||
</span>
|
||||
<span class="btn-loading" *ngIf="isLoading">
|
||||
<div class="spinner"></div>
|
||||
Signing In...
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<!-- Sign Up Link -->
|
||||
<div class="signup-section" *ngIf="loginEnvironment?.isSignup === 'true'">
|
||||
<p class="signup-text">
|
||||
Don't have an account?
|
||||
<a [routerLink]="['/email-verification']" class="signup-link">
|
||||
Create one now
|
||||
</a>
|
||||
</p>
|
||||
<button [disabled]="!model.email || !model.password" type="submit" class="btn btn-primary"
|
||||
(click)="onLogin()">Login</button>
|
||||
<a (click)="goforgotpass()" class="signup">{{ loginEnvironment.forgotpassword }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div> -->
|
||||
|
||||
<!-- Social Login (Optional) -->
|
||||
<div class="social-login">
|
||||
<div class="divider">
|
||||
<span>Or continue with</span>
|
||||
</div>
|
||||
<div class="social-buttons">
|
||||
<button class="social-btn google-btn" type="button">
|
||||
<clr-icon shape="world"></clr-icon>
|
||||
<span>Google</span>
|
||||
</button>
|
||||
<button class="social-btn microsoft-btn" type="button">
|
||||
<clr-icon shape="world"></clr-icon>
|
||||
<span>Microsoft</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
<div [class]="getWrapperClass()" *ngIf="showLogin2 && loginEnvironment.templateNo == '<templateNo>'" [style.backgroundImage]="'url(' + ('../../../../assets/images/new.png') + ')'">
|
||||
<form class="login">
|
||||
<section class="title">
|
||||
@@ -224,7 +108,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- <div class="login-wrapper"> -->
|
||||
<div [class]="getWrapperClass()" *ngIf="showLogin2 && loginEnvironment.templateNo == 'Template 2'" [style.backgroundImage]="'url(' + (loginEnvironment.loginImageURL !== 'null' || null ? loginEnvironment.loginImageURL : '../../../../assets/images/new.png') + ')'">
|
||||
<form class="login">
|
||||
<section class="title">
|
||||
@@ -259,4 +143,4 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
-->
|
||||
|
||||
@@ -1,642 +1,12 @@
|
||||
// ========================================
|
||||
// MODERN AI-INSPIRED LOGIN PAGE STYLES
|
||||
// ========================================
|
||||
|
||||
@import '../../../../styles/design-tokens';
|
||||
|
||||
// Modern Login Container
|
||||
.modern-login-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, $primary-50 0%, $primary-100 50%, $secondary-50 100%);
|
||||
}
|
||||
|
||||
// Background Elements
|
||||
.login-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.gradient-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg,
|
||||
rgba($primary-600, 0.1) 0%,
|
||||
rgba($primary-400, 0.05) 50%,
|
||||
rgba($accent-purple, 0.1) 100%);
|
||||
}
|
||||
|
||||
.floating-shapes {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
.shape {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(45deg, rgba($primary-400, 0.1), rgba($accent-purple, 0.1));
|
||||
animation: float 6s ease-in-out infinite;
|
||||
|
||||
&.shape-1 {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
&.shape-2 {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
top: 60%;
|
||||
right: 15%;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
&.shape-3 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
bottom: 20%;
|
||||
left: 20%;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
&.shape-4 {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
top: 30%;
|
||||
right: 30%;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main Content
|
||||
.login-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: $space-8;
|
||||
gap: $space-12;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Left Side - Branding
|
||||
.login-branding {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $space-8;
|
||||
|
||||
.brand-content {
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.logo-section {
|
||||
margin-bottom: $space-8;
|
||||
|
||||
.logo-container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-bottom: $space-6;
|
||||
|
||||
.logo-img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 8px 16px rgba($primary-600, 0.3));
|
||||
transition: transform $duration-300 $ease-out;
|
||||
}
|
||||
|
||||
.logo-glow {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: -10px;
|
||||
right: -10px;
|
||||
bottom: -10px;
|
||||
background: linear-gradient(45deg, $primary-400, $accent-purple);
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
filter: blur(20px);
|
||||
transition: opacity $duration-300 $ease-out;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.logo-img {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.logo-glow {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.brand-title {
|
||||
font-size: $text-4xl;
|
||||
font-weight: $font-bold;
|
||||
color: $gray-900;
|
||||
margin-bottom: $space-2;
|
||||
background: linear-gradient(135deg, $primary-600, $accent-purple);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.brand-subtitle {
|
||||
font-size: $text-lg;
|
||||
color: $gray-600;
|
||||
font-weight: $font-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-features {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $space-4;
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
padding: $space-3;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border-radius: $radius-lg;
|
||||
backdrop-filter: $backdrop-blur-sm;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
transform: translateX(8px);
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
color: $primary-600;
|
||||
font-size: $text-lg;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: $gray-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Right Side - Login Form
|
||||
.login-form-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $space-8;
|
||||
|
||||
.form-container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: $backdrop-blur-md;
|
||||
border-radius: $radius-2xl;
|
||||
padding: $space-8;
|
||||
box-shadow: $shadow-xl;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.form-header {
|
||||
text-align: center;
|
||||
margin-bottom: $space-8;
|
||||
|
||||
.form-title {
|
||||
font-size: $text-2xl;
|
||||
font-weight: $font-bold;
|
||||
color: $gray-900;
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
|
||||
.form-subtitle {
|
||||
font-size: $text-sm;
|
||||
color: $gray-600;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-login-form {
|
||||
.form-group {
|
||||
margin-bottom: $space-6;
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
color: $gray-700;
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.input-icon {
|
||||
position: absolute;
|
||||
left: $space-3;
|
||||
color: $gray-400;
|
||||
font-size: $text-base;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.modern-input {
|
||||
width: 100%;
|
||||
padding: $space-3 $space-3 $space-3 $space-10;
|
||||
border: 2px solid $gray-200;
|
||||
border-radius: $radius-lg;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: $gray-900;
|
||||
background: $white;
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&::placeholder {
|
||||
color: $gray-400;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: $primary-500;
|
||||
box-shadow: 0 0 0 3px rgba($primary-500, 0.1);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $gray-300;
|
||||
}
|
||||
}
|
||||
|
||||
// Password field with toggle button
|
||||
&:has(.password-toggle) .modern-input {
|
||||
padding-right: $space-10;
|
||||
}
|
||||
|
||||
.password-toggle {
|
||||
position: absolute;
|
||||
right: $space-3;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
color: $gray-400;
|
||||
cursor: pointer;
|
||||
padding: $space-1;
|
||||
border-radius: $radius-sm;
|
||||
transition: all $duration-200 $ease-out;
|
||||
z-index: 2;
|
||||
|
||||
&:hover {
|
||||
color: $gray-600;
|
||||
background: rgba($gray-100, 0.5);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
color: $primary-600;
|
||||
background: rgba($primary-50, 0.5);
|
||||
}
|
||||
|
||||
clr-icon {
|
||||
font-size: $text-base;
|
||||
}
|
||||
|
||||
.toggle-text {
|
||||
font-size: $text-xs;
|
||||
font-weight: $font-semibold;
|
||||
color: inherit;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: $space-6;
|
||||
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-2;
|
||||
cursor: pointer;
|
||||
|
||||
.modern-checkbox {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
accent-color: $primary-600;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
font-size: $text-sm;
|
||||
color: $gray-600;
|
||||
font-weight: $font-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.forgot-link {
|
||||
font-size: $text-sm;
|
||||
color: $primary-600;
|
||||
text-decoration: none;
|
||||
font-weight: $font-medium;
|
||||
transition: color $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
color: $primary-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-2;
|
||||
padding: $space-3;
|
||||
background: rgba($accent-red, 0.1);
|
||||
border: 1px solid rgba($accent-red, 0.2);
|
||||
border-radius: $radius-lg;
|
||||
margin-bottom: $space-6;
|
||||
color: $accent-red;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
|
||||
clr-icon {
|
||||
font-size: $text-base;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-login-btn {
|
||||
width: 100%;
|
||||
padding: $space-4;
|
||||
background: linear-gradient(135deg, $primary-600, $primary-700);
|
||||
color: $white;
|
||||
border: none;
|
||||
border-radius: $radius-lg;
|
||||
font-size: $text-base;
|
||||
font-weight: $font-semibold;
|
||||
cursor: pointer;
|
||||
transition: all $duration-200 $ease-out;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: $shadow-lg;
|
||||
background: linear-gradient(135deg, $primary-700, $primary-800);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
.btn-content {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.btn-loading {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $space-2;
|
||||
transition: opacity $duration-200 $ease-out;
|
||||
}
|
||||
|
||||
.btn-loading {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-2;
|
||||
opacity: 0;
|
||||
transition: opacity $duration-200 $ease-out;
|
||||
|
||||
.spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-top: 2px solid $white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.signup-section {
|
||||
text-align: center;
|
||||
margin-top: $space-6;
|
||||
|
||||
.signup-text {
|
||||
font-size: $text-sm;
|
||||
color: $gray-600;
|
||||
|
||||
.signup-link {
|
||||
color: $primary-600;
|
||||
text-decoration: none;
|
||||
font-weight: $font-semibold;
|
||||
transition: color $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
color: $primary-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.social-login {
|
||||
margin-top: $space-8;
|
||||
|
||||
.divider {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin-bottom: $space-6;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
background: $gray-200;
|
||||
}
|
||||
|
||||
span {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 0 $space-4;
|
||||
font-size: $text-xs;
|
||||
color: $gray-500;
|
||||
font-weight: $font-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.social-buttons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: $space-3;
|
||||
|
||||
.social-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $space-2;
|
||||
padding: $space-3;
|
||||
border: 2px solid $gray-200;
|
||||
border-radius: $radius-lg;
|
||||
background: $white;
|
||||
color: $gray-700;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
cursor: pointer;
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
border-color: $gray-300;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
&.google-btn:hover {
|
||||
border-color: #db4437;
|
||||
color: #db4437;
|
||||
}
|
||||
|
||||
&.microsoft-btn:hover {
|
||||
border-color: #0078d4;
|
||||
color: #0078d4;
|
||||
}
|
||||
|
||||
clr-icon {
|
||||
font-size: $text-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Animations
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0px) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20px) rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// Responsive Design
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
.login-content {
|
||||
grid-template-columns: 1fr;
|
||||
gap: $space-8;
|
||||
padding: $space-6;
|
||||
}
|
||||
|
||||
.login-branding {
|
||||
order: 2;
|
||||
padding: $space-4;
|
||||
|
||||
.brand-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.logo-section .brand-title {
|
||||
font-size: $text-3xl;
|
||||
}
|
||||
|
||||
.brand-features {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form-section {
|
||||
order: 1;
|
||||
padding: $space-4;
|
||||
|
||||
.form-container {
|
||||
padding: $space-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
.modern-login-container {
|
||||
padding: $space-4;
|
||||
}
|
||||
|
||||
.login-content {
|
||||
padding: $space-4;
|
||||
}
|
||||
|
||||
.login-branding {
|
||||
.brand-features {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form-section .form-container {
|
||||
padding: $space-4;
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy styles (preserved for compatibility)
|
||||
.tamplate1 {
|
||||
.tamplate1 {
|
||||
background-image: url(../../../../assets/images/new.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 60%;
|
||||
background-position: right center;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
}
|
||||
|
||||
.tamplate2 {
|
||||
.tamplate2 {
|
||||
background-image: url(../../../../assets/images/new.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 60%;
|
||||
@@ -645,9 +15,9 @@
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.signup {
|
||||
}
|
||||
.signup {
|
||||
cursor: pointer;
|
||||
}
|
||||
// color:#80b0ff;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@ export class LoginPageComponent implements OnInit {
|
||||
email = '';
|
||||
password = '';
|
||||
isError = false;
|
||||
isLoading = false;
|
||||
showPassword = false;
|
||||
|
||||
model: any = {};
|
||||
errMsg: string = '';
|
||||
@@ -73,80 +71,32 @@ export class LoginPageComponent implements OnInit {
|
||||
}
|
||||
|
||||
onLogin() {
|
||||
console.log('onLogin called');
|
||||
console.log('Form data:', { email: this.model.email, password: this.model.password });
|
||||
|
||||
// Reset error state
|
||||
this.isError = false;
|
||||
this.errMsg = '';
|
||||
|
||||
// Validate inputs
|
||||
if (!this.model.email || !this.model.password) {
|
||||
this.isError = true;
|
||||
this.errMsg = 'Please enter both email and password';
|
||||
console.log('Validation failed - missing email or password');
|
||||
return;
|
||||
}
|
||||
|
||||
// Set loading state
|
||||
this.isLoading = true;
|
||||
console.log('Loading state set to true, making API call...');
|
||||
|
||||
// tslint:disable-next-line:max-line-length
|
||||
this.loginService.getToken(this.model.email, this.model.password)
|
||||
.subscribe(
|
||||
resp => {
|
||||
console.log('API Response received:', resp);
|
||||
this.isLoading = false;
|
||||
|
||||
// Handle different response formats
|
||||
if (resp.operationStatus === 'ERROR') {
|
||||
this.isError = true;
|
||||
this.errMsg = resp.operationMessage || 'Login failed';
|
||||
return;
|
||||
}
|
||||
// Handle different response formats
|
||||
if (resp.success === 'false') {
|
||||
this.isError = true;
|
||||
this.errMsg = resp.message || 'Login failed';
|
||||
return;
|
||||
}
|
||||
.subscribe(resp => {
|
||||
if (resp.user === undefined || resp.user.token === undefined || resp.user.token === "INVALID") {
|
||||
this.isError = true;
|
||||
this.errMsg = 'Invalid email or password';
|
||||
this.errMsg = 'Checking Email or password';
|
||||
return;
|
||||
}
|
||||
|
||||
// Success - navigate to landing page
|
||||
console.log('Login successful, navigating to:', resp.landingPage);
|
||||
this.router.navigate([resp.landingPage]);
|
||||
this.router.navigate([resp.landingPage]);// add , {skipLocationChange: true}
|
||||
},
|
||||
(errResponse: HttpErrorResponse) => {
|
||||
console.log('API Error received:', errResponse);
|
||||
this.isLoading = false;
|
||||
this.isError = true;
|
||||
|
||||
switch (errResponse.status) {
|
||||
case 401:
|
||||
this.errMsg = 'Email or password is incorrect';
|
||||
break;
|
||||
case 404:
|
||||
this.errMsg = 'Service not found';
|
||||
break;
|
||||
case 408:
|
||||
this.errMsg = 'Request timeout';
|
||||
break;
|
||||
this.errMsg = 'Request Timedout';
|
||||
case 500:
|
||||
this.errMsg = 'Internal server error';
|
||||
break;
|
||||
case 0:
|
||||
this.errMsg = 'Network error - please check your connection';
|
||||
break;
|
||||
this.errMsg = 'Internal Server Error';
|
||||
default:
|
||||
this.errMsg = 'An error occurred. Please try again.';
|
||||
this.errMsg = 'Server Error';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
goaccount(){
|
||||
}
|
||||
@@ -154,17 +104,5 @@ export class LoginPageComponent implements OnInit {
|
||||
this.router.navigate(["../forgotpass"], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
// Clear error when user starts typing
|
||||
clearError() {
|
||||
if (this.isError) {
|
||||
this.isError = false;
|
||||
this.errMsg = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle password visibility
|
||||
togglePasswordVisibility() {
|
||||
this.showPassword = !this.showPassword;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -234,8 +240,7 @@ export class Stepper_workflowComponent implements OnInit {
|
||||
|
||||
rsModaldescription = false;
|
||||
goToReplaceStringdescription(row) {
|
||||
this.rowSelected = row;
|
||||
this.rsModaldescription = true;
|
||||
this.rowSelected = row; this.rsModaldescription = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,39 +253,6 @@ export class Stepper_workflowComponent implements OnInit {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
this.router.navigate(["../demostepper/", id], { relativeTo: this.route });
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// updateaction
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"sources":["demostepper.component.scss","demostepper.component.css"],"names":[],"mappings":"AAAA;EACE,UAAA;EACA,YAAA;ACCF;;ADCA;EACE,UAAA;EACA,aAAA;ACEF;;ADAA;EACE,UAAA;EACA,aAAA;ACGF;;ADDA;EACE,UAAA;EACA,aAAA;ACIF;;ADDA;EACE,WAAA;EACA,aAAA;ACIF;;ADDA;EACE,WAAA;EACA,kBAAA;EACA,aAAA;EACA,qBAAA;EACA,sBAAA;EACA,kBAAA;EACA,sBAAA;ACIF;;ADFA;EACE,UAAA;ACKF;;ADHA;EACE,kBAAA;ACMF;;ADHA;EACE,WAAA;ACMF;;ADJA;EACA;IACA,WAAA;ECOE;AACF","file":"demostepper.component.css"}
|
||||
@@ -1,328 +0,0 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/']">Home</a></li>
|
||||
<li><a href="javascript://">stepper</a></li>
|
||||
</ol>
|
||||
|
||||
<div class="button-bar">
|
||||
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-sm btn-primary" (click)="reset()">Reset</button>
|
||||
|
||||
<button class="btn btn-sm btn-primary" (click)="changeToHorizonTal()"
|
||||
*ngIf="layout.direction === 'vertical'">HorizonTal Layout</button>
|
||||
<button class="btn btn-sm btn-primary" (click)="changeToVertical()" *ngIf="layout.direction === 'horizontal'">Vertical
|
||||
Layout</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clr-row">
|
||||
<div [class]="layout.block1">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 style="text-align: center;"> Workflow</h3>
|
||||
</div>
|
||||
|
||||
<div class=" card-block container">
|
||||
|
||||
<clr-timeline [clrLayout]="layout.direction">
|
||||
<clr-timeline-step [clrState]="timelineStyle.step0.state">
|
||||
<clr-timeline-step-header>step 0</clr-timeline-step-header>
|
||||
<clr-timeline-step-title> <span *ngIf="!appToUpdate">Application</span><span *ngIf="appToUpdate"> Update
|
||||
Datagrid</span> </clr-timeline-step-title>
|
||||
<clr-timeline-step-description> <span>Create/registration<br> Information Of
|
||||
Customer</span></clr-timeline-step-description>
|
||||
</clr-timeline-step>
|
||||
|
||||
<clr-timeline-step [clrState]="timelineStyle.step1.state">
|
||||
<clr-timeline-step-header>Step 2</clr-timeline-step-header>
|
||||
<clr-timeline-step-title>Review And <br>Confirmation</clr-timeline-step-title>
|
||||
<clr-timeline-step-description>
|
||||
Finish .
|
||||
</clr-timeline-step-description>
|
||||
</clr-timeline-step></clr-timeline>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div [class]="layout.block2">
|
||||
<!--STEP 0-->
|
||||
<div class="card" *ngIf="timelineStyle.step0.open">
|
||||
<div class="card-header">
|
||||
<h3 style="text-align: center;" *ngIf="!appToUpdate">registration</h3>
|
||||
<h3 style="text-align: center;" *ngIf="appToUpdate"> Update {{Test11entryForm.name}}</h3>
|
||||
<div class="container">
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
<form [formGroup]="Test11entryForm">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-sm-12">
|
||||
<label> Name</label>
|
||||
<input class="clr-input" type="text" formControlName="name" />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<h6> List of picupload</h6>
|
||||
|
||||
<div class="clr-row" style="margin-top: 10px;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th> File</th>
|
||||
<th>File Name</th>
|
||||
<th>Preview</th>
|
||||
<th>Cancel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let attach of FileDatapicupload; let i=index">
|
||||
<td style="width: 70px;"><input type="text" class="clr-input" value={{i+1}} [readonly]="true">
|
||||
</td>
|
||||
<td><input type="file" (change)="onFileChangedpicupload($event, i)"
|
||||
accept="image/*" /><!--accept=".pdf,.doc,.docx,.jpg,.msg"-->
|
||||
</td>
|
||||
<td>{{attach.uploadedfile_name}}</td>
|
||||
<td> <img [src]="attach.filePreview" alt="File Preview" [ngModelOptions]="{standalone: true}"
|
||||
name="filePreview" width="100px" height="100px"></td>
|
||||
<td>
|
||||
<a (click)="deleteRowpicupload(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" style="margin-left: 20px;"
|
||||
(click)="onAddLinespicupload()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h6> List of fileupload_field</h6>
|
||||
|
||||
<div class="clr-row" style="margin-top: 10px;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th> File</th>
|
||||
<th>File Name</th>
|
||||
<th>Preview</th>
|
||||
<th>Cancel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let attach of FileDatafileupload_field; let i=index">
|
||||
<td style="width: 70px;"><input type="text" class="clr-input" value={{i+1}} [readonly]="true">
|
||||
</td>
|
||||
<td><input type="file" (change)="onFileChangedfileupload_field($event, i)"
|
||||
accept="application/pdf,.csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" /><!--accept=".pdf,.doc,.docx,.jpg,.msg"-->
|
||||
</td>
|
||||
<td>{{attach.uploadedfile_name}}</td>
|
||||
<td> <img [src]="attach.filePreview" alt="File Preview" [ngModelOptions]="{standalone: true}"
|
||||
name="filePreview" width="100px" height="100px"></td>
|
||||
<td>
|
||||
<a (click)="deleteRowfileupload_field(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" style="margin-left: 20px;"
|
||||
(click)="onAddLinesfileupload_field()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h6> List of audio_field</h6>
|
||||
|
||||
<div class="clr-row" style="margin-top: 10px;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th> File</th>
|
||||
<th>File Name</th>
|
||||
<th>Preview</th>
|
||||
<th>Cancel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let attach of FileDataaudio_field; let i=index">
|
||||
<td style="width: 70px;"><input type="text" class="clr-input" value={{i+1}} [readonly]="true">
|
||||
</td>
|
||||
<td><input type="file" (change)="onFileChangedaudio_field($event, i)"
|
||||
accept="audio/*" /><!--accept="audio file"-->
|
||||
</td>
|
||||
<td>{{attach.uploadedfile_name}}</td>
|
||||
<td> <audio *ngIf="attach.filePreview" [src]="attach.filePreview" controls></audio></td>
|
||||
<td>
|
||||
<a (click)="deleteRowaudio_field(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" style="margin-left: 20px;"
|
||||
(click)="onAddLinesaudio_field()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h6> List of video_field</h6>
|
||||
|
||||
<div class="clr-row" style="margin-top: 10px;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th> File</th>
|
||||
<th>File Name</th>
|
||||
<th>Preview</th>
|
||||
<th>Cancel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let attach of FileDatavideo_field; let i=index">
|
||||
<td style="width: 70px;"><input type="text" class="clr-input" value={{i+1}} [readonly]="true">
|
||||
</td>
|
||||
<td><input type="file" (change)="onFileChangedvideo_field($event, i)"
|
||||
accept="video/*" /><!--accept=".mp4,.mpeg4"-->
|
||||
</td>
|
||||
<td>{{attach.uploadedfile_name}}</td>
|
||||
<td> <video *ngIf="attach.filePreview" [src]="attach.filePreview" width="100px" height="100px"
|
||||
controls></video></td>
|
||||
<td>
|
||||
<a (click)="deleteRowvideo_field(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" style="margin-left: 20px;"
|
||||
(click)="onAddLinesvideo_field()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="clr-row">
|
||||
|
||||
</div>
|
||||
<!-- end row -->
|
||||
<br>
|
||||
<div class="button">
|
||||
<button type="submit" class="btn btn-primary" (click)="onregistrationSave()">Submit</button>
|
||||
<button type="button" class="btn btn-primary" (click)="this.timelineStyle.step0 = { state: 'success', open: false };
|
||||
this.timelineStyle.step1 = { state: 'current', open: true }; this.current()">Complete</button>
|
||||
<button type="button" class="btn btn-primary" (click)="this.timelineStyle.step0 = { state: 'current', open: false };
|
||||
this.timelineStyle.step1 = { state: 'not-started', open: true }">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--STEP 1-->
|
||||
<div class="card" *ngIf="timelineStyle.step1.open">
|
||||
<div class="card-header">
|
||||
<h3 style="text-align: center;" *ngIf="!appToUpdate"> Review And Confirmation</h3>
|
||||
<div class="container">
|
||||
|
||||
<!-- Info -->
|
||||
<div class="clr-row mb-3">
|
||||
<div class="clr-col-12">
|
||||
<h5>Registration Summary:</h5>
|
||||
<p><strong>Name : </strong> {{ Test11entryForm.get('name')?.value | json}}</p>
|
||||
|
||||
<div>
|
||||
<p><strong>Uploaded Images Preview:</strong></p>
|
||||
<div class="clr-row" *ngIf="FileDatapicupload.length > 0">
|
||||
<div class="clr-col" *ngFor="let img of FileDatapicupload">
|
||||
<img [src]="img.filePreview" width="100" height="100" style="margin: 10px; border: 1px solid #ccc;"
|
||||
*ngIf="img.filePreview" />
|
||||
<p style="font-size: 12px;">{{ img.uploadedfile_name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p><strong>Uploaded Files Preview:</strong></p>
|
||||
<div class="clr-row" *ngIf="FileDatafileupload_field.length > 0">
|
||||
<div class="clr-col" *ngFor="let file of FileDatafileupload_field">
|
||||
<a *ngIf="file.filePreview" [href]="file.filePreview" target="_blank">
|
||||
<img src="assets/icons/file-icon.png" width="40" height="40" style="margin: 10px;" />
|
||||
</a>
|
||||
<p style="font-size: 12px;">{{ file.uploadedfile_name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<p><strong>Uploaded Audios Preview:</strong></p>
|
||||
<div class="clr-row" *ngIf="FileDataaudio_field.length > 0">
|
||||
<div class="clr-col" *ngFor="let audio of FileDataaudio_field">
|
||||
<audio *ngIf="audio.filePreview" [src]="audio.filePreview" controls style="margin: 10px;"></audio>
|
||||
<p style="font-size: 12px;">{{ audio.uploadedfile_name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<p><strong>Uploaded Videos Preview:</strong></p>
|
||||
<div class="clr-row" *ngIf="FileDatavideo_field.length > 0">
|
||||
<div class="clr-col" *ngFor="let video of FileDatavideo_field">
|
||||
<video *ngIf="video.filePreview" [src]="video.filePreview" width="120" height="90" controls
|
||||
style="margin: 10px;"></video>
|
||||
<p style="font-size: 12px;">{{ video.uploadedfile_name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="button">
|
||||
<button class="btn btn-primary-outline" (click)="this.timelineStyle.step0 = { state: 'current', open: true };
|
||||
this.timelineStyle.step1 = { state: 'not-started', open: false }">Back</button>
|
||||
<button class="btn btn-primary" (click)="timelineStyle.step1 = { state: 'success', open: false }; current();
|
||||
alert('Process Finished Successfully!')">Finish</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,46 +0,0 @@
|
||||
.horizontal{
|
||||
width: 25%;
|
||||
padding: 5px;
|
||||
}
|
||||
.horizontal1{
|
||||
width: 50%;
|
||||
padding: 10px;
|
||||
}
|
||||
.middle{
|
||||
width: 33%;
|
||||
padding: 10px;
|
||||
}
|
||||
.middle1{
|
||||
width: 75%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.full{
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
input[type=text],[type=date], select {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.required-field{
|
||||
color: red;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
.center{
|
||||
color: blue;
|
||||
}
|
||||
@media (max-width: 600px){
|
||||
.horizontal,.middle,.horizontal1,.middle1 {
|
||||
width: 100%;
|
||||
}}
|
||||
|
||||
@@ -1,525 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { College } from 'src/app/models/fnd/play';
|
||||
import { student } from 'src/app/models/fnd/Studentadd';
|
||||
import { AbstractControl,FormArray, FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ValidationError } from 'src/app/models/fnd/ValidationError';
|
||||
import { demostepperservice } from './demostepper.service';
|
||||
declare var JsBarcode: any;
|
||||
@Component({
|
||||
selector: 'app-editstepper',
|
||||
templateUrl: './demostepper.component.html',
|
||||
styleUrls: ['./demostepper.component.scss']
|
||||
})
|
||||
export class demostepperComponent implements OnInit {
|
||||
updated = false;
|
||||
stringJson: any;
|
||||
customerId: string = '';
|
||||
selectedFile!: File;
|
||||
fileName = '';
|
||||
|
||||
id: number;
|
||||
errorFields: ValidationError[] = [];
|
||||
appToUpdate: College = null;
|
||||
trained = false;
|
||||
|
||||
json: string = "";
|
||||
luisApp =
|
||||
{
|
||||
name: '',
|
||||
created: 1,
|
||||
trained: 1,
|
||||
tested: 1,
|
||||
updated: 1,
|
||||
published: 1,
|
||||
|
||||
};
|
||||
// Layout direction changing
|
||||
layout = {
|
||||
direction: "vertical",
|
||||
block1: "clr-col-lg-3 clr-col-12 ",
|
||||
block2: "clr-col-lg-9 clr-col-12 ",
|
||||
};
|
||||
|
||||
timelineStyle = {
|
||||
step0: { state: "current", open: true, failed: false },
|
||||
step1: { state: "not-started", open: false, failed: false },
|
||||
};
|
||||
public Test11entryForm: FormGroup;
|
||||
submitted = false;
|
||||
rowSelected: any = {};
|
||||
modalcomplete = false;
|
||||
|
||||
constructor(
|
||||
private mainService: demostepperservice,
|
||||
|
||||
private Test11_fb: FormBuilder,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private toastr: ToastrService,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.id = this.route.snapshot.params["id"];
|
||||
console.log("update with id = ", this.id);
|
||||
|
||||
|
||||
this.Test11entryForm = this.Test11_fb.group({
|
||||
name : [null],
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const stepId = this.id; // or from route/query/etc
|
||||
|
||||
this.getResolvedDataFromStepper(stepId).subscribe(res => {
|
||||
console.log('response get ', res);
|
||||
|
||||
if (res === null) {
|
||||
this.showEmptyForm();
|
||||
} else {
|
||||
if (res['Test11']) {
|
||||
|
||||
this.prefillregistrationForm(res['Test11']);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
showEmptyForm(): void {
|
||||
console.log('No config found. Showing empty form.');
|
||||
// You can choose to show one or both based on some logic
|
||||
|
||||
this.Test11entryForm.reset();
|
||||
}
|
||||
prefillregistrationForm(data: any): void {
|
||||
|
||||
console.log(' registration data ', data)
|
||||
this.Test11entryForm.patchValue({
|
||||
id: data.id || '',
|
||||
name: data.name || '',
|
||||
|
||||
picupload: data.picupload || '',
|
||||
|
||||
fileupload_field: data.fileupload_field || '',
|
||||
|
||||
audio_field: data.audio_field || '',
|
||||
|
||||
video_field: data.video_field || '',
|
||||
|
||||
});
|
||||
}
|
||||
getResolvedDataFromStepper(id: number): Observable<any> {
|
||||
console.log('get step config');
|
||||
|
||||
return new Observable(observer => {
|
||||
this.mainService.gettabledata(id).subscribe(configList => {
|
||||
if (!configList || configList.length === 0) {
|
||||
console.log('empty config');
|
||||
observer.next(null);
|
||||
observer.complete();
|
||||
return;
|
||||
}
|
||||
|
||||
const results: { [key: string]: any } = {};
|
||||
let processed = 0;
|
||||
|
||||
configList.forEach(config => {
|
||||
const { table_name, table_id } = config;
|
||||
|
||||
this.getByTableNameAndId(table_name, table_id).subscribe(data => {
|
||||
|
||||
console.log(table_name, ' data is ', data);
|
||||
results[table_name] = data;
|
||||
|
||||
processed++;
|
||||
if (processed === configList.length) {
|
||||
observer.next(results); // emit combined data
|
||||
observer.complete();
|
||||
}
|
||||
|
||||
}, error => {
|
||||
console.error(`Error loading data for table ${table_name}`, error);
|
||||
processed++;
|
||||
if (processed === configList.length) {
|
||||
observer.next(results); // continue with what we have
|
||||
observer.complete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}, error => {
|
||||
console.error("Error loading stepper config", error);
|
||||
observer.error(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
getByTableNameAndId(tableName: string, id: number): Observable<any> {
|
||||
|
||||
switch (tableName) {
|
||||
|
||||
case 'Test11':
|
||||
return this.mainService.getTest11ById(id);// aur bhi cases agar naye table add ho to
|
||||
default:
|
||||
throw new Error(`Unknown table name: ${tableName}`);
|
||||
}
|
||||
}
|
||||
// Change to Horizontal Layout
|
||||
changeToHorizonTal() {
|
||||
this.layout = {
|
||||
direction: "horizontal",
|
||||
block1: "clr-col-lg-12 clr-col-12 height container",
|
||||
block2: "clr-col-lg-12 clr-col-12 container",
|
||||
}
|
||||
}
|
||||
// Change to Vertical Layout
|
||||
changeToVertical() {
|
||||
this.layout = {
|
||||
direction: "vertical",
|
||||
block1: "clr-col-lg-3 clr-col-12 ",
|
||||
block2: "clr-col-lg-9 clr-col-12 ",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
onregistrationSave() {
|
||||
console.log('Form Submitted:', this.Test11entryForm.value);
|
||||
this.submitted = true;
|
||||
if (this.Test11entryForm.invalid) {
|
||||
|
||||
console.log('invalid form ..');
|
||||
// Log all form errors
|
||||
Object.keys(this.Test11entryForm.controls).forEach(field => {
|
||||
const control = this.Test11entryForm.get(field);
|
||||
if (control && control.invalid) {
|
||||
console.log(`Error in field: ${field}`, control.errors);
|
||||
}
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.onregistrationCreate();
|
||||
}
|
||||
|
||||
onregistrationCreate() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
this.mainService.createTest11(this.Test11entryForm.value).subscribe(
|
||||
(data) => {
|
||||
console.log('adding data ', data);
|
||||
this.customerId = data.id;
|
||||
|
||||
console.log('id is ', this.customerId);
|
||||
|
||||
|
||||
const tableId = data.id;
|
||||
const tableName = 'Test11';
|
||||
const stepperId = this.id;
|
||||
|
||||
// Save stepper config
|
||||
this.mainService.saveStepperConfig(stepperId, tableId, tableName).subscribe(() => {
|
||||
this.toastr.success("Stepper Config Saved");
|
||||
}); if (data || data.status >= 200 && data.status <= 299) {
|
||||
this.toastr.success("Added Successfully");
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.ngOnInit();
|
||||
}, 500);
|
||||
|
||||
|
||||
for (let i = 0; i < this.selectedpicupload.length; i++){
|
||||
|
||||
this.mainService.uploadPicupload(data.id,tableName,this.selectedpicupload[i]).subscribe(uploaddata =>{
|
||||
console.log(uploaddata);
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.selectedfileupload_field.length; i++){
|
||||
|
||||
this.mainService.uploadfilefileupload_field(data.id,tableName,this.selectedfileupload_field[i]).subscribe(uploaddata =>{
|
||||
console.log(uploaddata);
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.selectedaudio_field.length; i++){
|
||||
|
||||
this.mainService.uploadAudio_field(data.id,tableName,this.selectedaudio_field[i]).subscribe(uploaddata =>{
|
||||
console.log(uploaddata);
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.selectedvideo_field.length; i++){
|
||||
|
||||
this.mainService.uploadVideo_field(data.id,tableName,this.selectedvideo_field[i]).subscribe(uploaddata =>{
|
||||
console.log(uploaddata);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
if (error.status >= 200 && error.status <= 299) {
|
||||
// this.toastr.success("Added Succesfully");
|
||||
}
|
||||
if (error.status >= 400 && error.status <= 499) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
if (error.status >= 500 && error.status <= 599) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
});
|
||||
this.rowSelected = this.Test11entryForm.value;
|
||||
|
||||
setTimeout(() => {
|
||||
this.ngOnInit();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
onnext() {
|
||||
this.router.navigate(["../../main/workflow"], { relativeTo: this.route });
|
||||
}
|
||||
reset() {
|
||||
this.json = "";
|
||||
this.luisApp =
|
||||
{
|
||||
name: '',
|
||||
trained: 1,
|
||||
tested: 1,
|
||||
updated: 1,
|
||||
published: 1,
|
||||
created: 1,
|
||||
|
||||
};
|
||||
|
||||
this.timelineStyle = {
|
||||
step0: { state: "current", open: true, failed: false },
|
||||
step1: { state: "not-started", open: false, failed: false },
|
||||
};
|
||||
}
|
||||
current() {
|
||||
console.log(this.timelineStyle)
|
||||
this.stringJson = JSON.stringify(this.timelineStyle);
|
||||
console.log("String json object :", this.stringJson);
|
||||
|
||||
}
|
||||
|
||||
|
||||
filePreviewpicupload: string | ArrayBuffer | null = null;
|
||||
FileDatapicupload: {uploadedfile_name?:any, filePreview: string | ArrayBuffer | null }[] = []; // Initialize the array
|
||||
selectedpicupload: File[]=[];
|
||||
public onFileChangedpicupload(event, index) {
|
||||
const files = event.target.files;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
this.FileDatapicupload[index].uploadedfile_name = files[i].name;
|
||||
this.selectedpicupload.push(files[i]);
|
||||
if (file.type.startsWith('image/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
// Set the file preview source
|
||||
const filePreview = e.target?.result as string;
|
||||
this.FileDatapicupload[index] = {
|
||||
...this.FileDatapicupload[index], // Preserve existing properties
|
||||
filePreview: filePreview // Update only the filePreview property
|
||||
};
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
onAddLinespicupload(){
|
||||
this.FileDatapicupload.push({
|
||||
uploadedfile_name: "",
|
||||
filePreview: "",
|
||||
// f3: "",
|
||||
});
|
||||
}
|
||||
deleteRowpicupload(index,id) {
|
||||
this.FileDatapicupload.splice(index, 1);
|
||||
|
||||
if(id){
|
||||
this.mainService.uploadPicuploaddelete(id).subscribe(data =>{
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
filePreviewfileupload_field: string | ArrayBuffer | null = null;
|
||||
FileDatafileupload_field: {uploadedfile_name?:any, filePreview: string | ArrayBuffer | null }[] = []; // Initialize the array
|
||||
selectedfileupload_field: File[]=[];
|
||||
public onFileChangedfileupload_field(event, index) {
|
||||
const files = event.target.files;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
this.FileDatafileupload_field[index].uploadedfile_name = files[i].name;
|
||||
this.selectedfileupload_field.push(files[i]);
|
||||
if (file.type.startsWith('file/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
// Set the file preview source
|
||||
const filePreview = e.target?.result as string;
|
||||
this.FileDatafileupload_field[index] = {
|
||||
...this.FileDatafileupload_field[index], // Preserve existing properties
|
||||
filePreview: filePreview // Update only the filePreview property
|
||||
};
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
onAddLinesfileupload_field(){
|
||||
this.FileDatafileupload_field.push({
|
||||
uploadedfile_name: "",
|
||||
filePreview: "",
|
||||
// f3: "",
|
||||
});
|
||||
}
|
||||
deleteRowfileupload_field(index,id) {
|
||||
this.FileDatafileupload_field.splice(index, 1);
|
||||
|
||||
if(id){
|
||||
this.mainService.uploadfiledeletefileupload_field(id).subscribe(data =>{
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
filePreviewaudio_field: string | ArrayBuffer | null = null;
|
||||
FileDataaudio_field: {uploadedfile_name?:any, filePreview: string | ArrayBuffer | null }[] = []; // Initialize the array
|
||||
selectedaudio_field: File[]=[];
|
||||
public onFileChangedaudio_field(event, index) {
|
||||
const files = event.target.files;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
this.FileDataaudio_field[index].uploadedfile_name = files[i].name;
|
||||
this.selectedaudio_field.push(files[i]);
|
||||
if (file.type.startsWith('audio/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
// Set the file preview source
|
||||
const filePreview = e.target?.result as string;
|
||||
this.FileDataaudio_field[index] = {
|
||||
...this.FileDataaudio_field[index], // Preserve existing properties
|
||||
filePreview: filePreview // Update only the filePreview property
|
||||
};
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
onAddLinesaudio_field(){
|
||||
this.FileDataaudio_field.push({
|
||||
uploadedfile_name: "",
|
||||
filePreview: "",
|
||||
// f3: "",
|
||||
});
|
||||
}
|
||||
deleteRowaudio_field(index,id) {
|
||||
this.FileDataaudio_field.splice(index, 1);
|
||||
|
||||
if(id){
|
||||
this.mainService.uploadAudio_fielddelete(id).subscribe(data =>{
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
filePreviewvideo_field: string | ArrayBuffer | null = null;
|
||||
FileDatavideo_field: {uploadedfile_name?:any, filePreview: string | ArrayBuffer | null }[] = []; // Initialize the array
|
||||
selectedvideo_field: File[]=[];
|
||||
public onFileChangedvideo_field(event, index) {
|
||||
const files = event.target.files;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
this.FileDatavideo_field[index].uploadedfile_name = files[i].name;
|
||||
this.selectedvideo_field.push(files[i]);
|
||||
if (file.type.startsWith('video/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
// Set the file preview source
|
||||
const filePreview = e.target?.result as string;
|
||||
this.FileDatavideo_field[index] = {
|
||||
...this.FileDatavideo_field[index], // Preserve existing properties
|
||||
filePreview: filePreview // Update only the filePreview property
|
||||
};
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
onAddLinesvideo_field(){
|
||||
this.FileDatavideo_field.push({
|
||||
uploadedfile_name: "",
|
||||
filePreview: "",
|
||||
// f3: "",
|
||||
});
|
||||
}
|
||||
deleteRowvideo_field(index,id) {
|
||||
this.FileDatavideo_field.splice(index, 1);
|
||||
|
||||
if(id){
|
||||
this.mainService.uploadVideo_fielddelete(id).subscribe(data =>{
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
FileDataPicupload: any[];
|
||||
selectedPicupload: any[];
|
||||
|
||||
|
||||
|
||||
FileDataAudio_field: any[];
|
||||
selectedAudio_field: any[];
|
||||
|
||||
FileDataVideo_field: any[];
|
||||
selectedVideo_field: any[];
|
||||
|
||||
|
||||
// updateaction
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from "rxjs";
|
||||
import { HttpClient, HttpHeaders, HttpParams, } from "@angular/common/http";
|
||||
import { ApiRequestService } from "src/app/services/api/api-request.service";
|
||||
import { environment } from 'src/environments/environment';
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class demostepperservice{
|
||||
private StepperURL = "Stepper_table_config/Stepper_table_config";
|
||||
private Test11URL = "Test11/Test11" ; constructor(
|
||||
private http: HttpClient,
|
||||
private apiRequest: ApiRequestService,
|
||||
) { }
|
||||
gettabledata(id: number): Observable<any> {
|
||||
const _http = this.StepperURL + "/stepId/" + id;
|
||||
return this.apiRequest.get(_http);
|
||||
}
|
||||
|
||||
saveStepperConfig(stepperId: number, tableId: number, tableName: string): Observable<any> {
|
||||
const params = new HttpParams()
|
||||
.set('stepperId', stepperId.toString())
|
||||
.set('tableId', tableId.toString())
|
||||
.set('tableName', tableName);
|
||||
|
||||
return this.apiRequest.post(this.StepperURL, null, params); // null body, params used
|
||||
} getAllTest11(page?: number, size?: number): Observable<any> {
|
||||
return this.apiRequest.get(this.Test11URL);
|
||||
}
|
||||
getTest11ById(id: number): Observable<any> {
|
||||
const _http = this.Test11URL + "/" + id;
|
||||
return this.apiRequest.get(_http);
|
||||
}
|
||||
createTest11(data: any): Observable<any> {
|
||||
return this.apiRequest.post(this.Test11URL, data);
|
||||
}
|
||||
updateTest11(id: number, data: any): Observable<any> {
|
||||
const _http = this.Test11URL + "/" + id;
|
||||
return this.apiRequest.put(_http, data);
|
||||
}
|
||||
deleteTest11(id: number): Observable<any> {
|
||||
const _http = this.Test11URL + "/" + id;
|
||||
return this.apiRequest.delete(_http);
|
||||
}
|
||||
|
||||
|
||||
uploadPicupload(ref:any, Test11:any, file:any): Observable<any>{
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return this.apiRequest.postFormData(`FileUpload/Uploadeddocs/${ref}/${Test11}`, formData);
|
||||
}
|
||||
|
||||
uploadPicuploadgetById(ref:any, Test11:any,): Observable<any> {
|
||||
return this.apiRequest.get(`FileUpload/Uploadeddocs/${ref}/${Test11}`);
|
||||
}
|
||||
|
||||
|
||||
uploadPicuploaddelete(id: number): Observable<any> {
|
||||
return this.apiRequest.delete(`FileUpload/Uploadeddocs/${id}`);
|
||||
}
|
||||
|
||||
uploadfilefileupload_field(ref:any, Test11:any, file:any): Observable<any>{
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return this.apiRequest.postFormData(`FileUpload/Uploadeddocs/${ref}/${Test11}`, formData);
|
||||
}
|
||||
|
||||
uploadfilegetByIdfileupload_field(ref:any, Test11:any,): Observable<any> {
|
||||
return this.apiRequest.get(`FileUpload/Uploadeddocs/${ref}/${Test11}`);
|
||||
}
|
||||
|
||||
|
||||
uploadfiledeletefileupload_field(id: number): Observable<any> {
|
||||
return this.apiRequest.delete(`FileUpload/Uploadeddocs/${id}`);
|
||||
}
|
||||
|
||||
uploadAudio_field(ref:any, Test11:any, file:any): Observable<any>{
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return this.apiRequest.postFormData(`FileUpload/Uploadeddocs/${ref}/${Test11}`, formData);
|
||||
}
|
||||
|
||||
uploadAudio_fieldgetById(ref:any, Test11:any,): Observable<any> {
|
||||
return this.apiRequest.get(`FileUpload/Uploadeddocs/${ref}/${Test11}`);
|
||||
}
|
||||
|
||||
|
||||
uploadAudio_fielddelete(id: number): Observable<any> {
|
||||
return this.apiRequest.delete(`FileUpload/Uploadeddocs/${id}`);
|
||||
}
|
||||
|
||||
uploadVideo_field(ref:any, Test11:any, file:any): Observable<any>{
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return this.apiRequest.postFormData(`FileUpload/Uploadeddocs/${ref}/${Test11}`, formData);
|
||||
}
|
||||
|
||||
uploadVideo_fieldgetById(ref:any, Test11:any,): Observable<any> {
|
||||
return this.apiRequest.get(`FileUpload/Uploadeddocs/${ref}/${Test11}`);
|
||||
}
|
||||
|
||||
|
||||
uploadVideo_fielddelete(id: number): Observable<any> {
|
||||
return this.apiRequest.delete(`FileUpload/Uploadeddocs/${id}`);
|
||||
}
|
||||
|
||||
// updateaction
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"sources":["steptest1.component.scss","steptest1.component.css"],"names":[],"mappings":"AAAA;EACE,UAAA;EACA,YAAA;ACCF;;ADCA;EACE,UAAA;EACA,aAAA;ACEF;;ADAA;EACE,UAAA;EACA,aAAA;ACGF;;ADDA;EACE,UAAA;EACA,aAAA;ACIF;;ADDA;EACE,WAAA;EACA,aAAA;ACIF;;ADDA;EACE,WAAA;EACA,kBAAA;EACA,aAAA;EACA,qBAAA;EACA,sBAAA;EACA,kBAAA;EACA,sBAAA;ACIF;;ADFA;EACE,UAAA;ACKF;;ADHA;EACE,kBAAA;ACMF;;ADHA;EACE,WAAA;ACMF;;ADJA;EACA;IACA,WAAA;ECOE;AACF","file":"steptest1.component.css"}
|
||||
@@ -1,232 +0,0 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/']">Home</a></li>
|
||||
<li><a href="javascript://">stepper</a></li>
|
||||
</ol>
|
||||
|
||||
<div class="button-bar">
|
||||
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-sm btn-primary" (click)="reset()">Reset</button>
|
||||
|
||||
<button class="btn btn-sm btn-primary" (click)="changeToHorizonTal()"
|
||||
*ngIf="layout.direction === 'vertical'">HorizonTal Layout</button>
|
||||
<button class="btn btn-sm btn-primary" (click)="changeToVertical()" *ngIf="layout.direction === 'horizontal'">Vertical
|
||||
Layout</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clr-row">
|
||||
<div [class]="layout.block1">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 style="text-align: center;"> Workflow</h3>
|
||||
</div>
|
||||
|
||||
<div class=" card-block container">
|
||||
|
||||
<clr-timeline [clrLayout]="layout.direction">
|
||||
<clr-timeline-step [clrState]="timelineStyle.step0.state">
|
||||
<clr-timeline-step-header>step 0</clr-timeline-step-header>
|
||||
<clr-timeline-step-title> <span *ngIf="!appToUpdate">Application</span><span *ngIf="appToUpdate"> Update
|
||||
Datagrid</span> </clr-timeline-step-title>
|
||||
<clr-timeline-step-description> <span>Create/registration<br> Information Of
|
||||
Customer</span></clr-timeline-step-description>
|
||||
</clr-timeline-step>
|
||||
|
||||
<clr-timeline-step [clrState]="timelineStyle.step1.state">
|
||||
<clr-timeline-step-header>step 1</clr-timeline-step-header>
|
||||
<clr-timeline-step-title> <span *ngIf="!appToUpdate">Application</span><span *ngIf="appToUpdate"> Update
|
||||
Datagrid</span> </clr-timeline-step-title>
|
||||
<clr-timeline-step-description> <span>Create/File_upload<br> Information Of
|
||||
Customer</span></clr-timeline-step-description>
|
||||
</clr-timeline-step>
|
||||
|
||||
<clr-timeline-step [clrState]="timelineStyle.step2.state">
|
||||
<clr-timeline-step-header>Step 2</clr-timeline-step-header>
|
||||
<clr-timeline-step-title>Review And <br>Confirmation</clr-timeline-step-title>
|
||||
<clr-timeline-step-description>
|
||||
Finish .
|
||||
</clr-timeline-step-description>
|
||||
</clr-timeline-step></clr-timeline>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div [class]="layout.block2">
|
||||
<!--STEP 0-->
|
||||
<div class="card" *ngIf="timelineStyle.step0.open">
|
||||
<div class="card-header">
|
||||
<h3 style="text-align: center;" *ngIf="!appToUpdate">registration</h3>
|
||||
<h3 style="text-align: center;" *ngIf="appToUpdate"> Update {{Test11entryForm.name}}</h3>
|
||||
<div class="container">
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
<form [formGroup]="Test11entryForm">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-sm-12">
|
||||
<label> Name</label>
|
||||
<input class="clr-input" type="text" formControlName="name" />
|
||||
</div>
|
||||
|
||||
<div class="clr-col-sm-12">
|
||||
<label> Description</label>
|
||||
<textarea cols="10" rows="2" formControlName="description" placeholder="Textarea"> </textarea>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-sm-12">
|
||||
<label> Active</label>
|
||||
<input type="checkbox" formControlName="active" clrToggle />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="clr-row">
|
||||
|
||||
</div>
|
||||
<!-- end row -->
|
||||
<br>
|
||||
<div class="button">
|
||||
<button type="submit" class="btn btn-primary" (click)="onregistrationSave()">Submit</button>
|
||||
<button type="button" class="btn btn-primary" (click)="this.timelineStyle.step0 = { state: 'success', open: false };
|
||||
this.timelineStyle.step1 = { state: 'current', open: true }; this.current()">Complete</button>
|
||||
<button type="button" class="btn btn-primary" (click)="this.timelineStyle.step0 = { state: 'current', open: false };
|
||||
this.timelineStyle.step1 = { state: 'not-started', open: true }">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--STEP 1-->
|
||||
<div class="card" *ngIf="timelineStyle.step1.open">
|
||||
<div class="card-header">
|
||||
<h3 style="text-align: center;" *ngIf="!appToUpdate">File_upload</h3>
|
||||
<h3 style="text-align: center;" *ngIf="appToUpdate"> Update {{Test22entryForm.name}}</h3>
|
||||
<div class="container">
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
<form [formGroup]="Test22entryForm">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-sm-12">
|
||||
<label> Name</label>
|
||||
<input class="clr-input" type="text" formControlName="name" />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<h6> List of fileupload_field</h6>
|
||||
|
||||
<div class="clr-row" style="margin-top: 10px;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th> File</th>
|
||||
<th>File Name</th>
|
||||
<th>Preview</th>
|
||||
<th>Cancel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let attach of FileDatafileupload_field; let i=index">
|
||||
<td style="width: 70px;"><input type="text" class="clr-input" value={{i+1}} [readonly]="true">
|
||||
</td>
|
||||
<td><input type="file" (change)="onFileChangedfileupload_field($event, i)"
|
||||
accept="application/pdf,.csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" /><!--accept=".pdf,.doc,.docx,.jpg,.msg"-->
|
||||
</td>
|
||||
<td>{{attach.uploadedfile_name}}</td>
|
||||
<td> <img [src]="attach.filePreview" alt="File Preview" [ngModelOptions]="{standalone: true}"
|
||||
name="filePreview" width="100px" height="100px"></td>
|
||||
<td>
|
||||
<a (click)="deleteRowfileupload_field(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" style="margin-left: 20px;"
|
||||
(click)="onAddLinesfileupload_field()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="clr-row">
|
||||
|
||||
</div>
|
||||
<!-- end row -->
|
||||
<br>
|
||||
<div class="button">
|
||||
<button type="submit" class="btn btn-success" (click)="onFile_uploadSave()">File upload</button>
|
||||
<button type="button" class="btn btn-primary" (click)="timelineStyle.step1 = { state: 'success', open: false };
|
||||
timelineStyle.step2 = { state: 'current', open: true }">Complete</button>
|
||||
<button class="btn btn-primary-outline" (click)="timelineStyle.step0 = { state: 'current', open: true };
|
||||
timelineStyle.step1 = { state: 'not-started', open: false }">Back</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--STEP 2-->
|
||||
<div class="card" *ngIf="timelineStyle.step2.open">
|
||||
<div class="card-header">
|
||||
<h3 style="text-align: center;" *ngIf="!appToUpdate"> Review And Confirmation</h3>
|
||||
<div class="container">
|
||||
|
||||
<!-- Info -->
|
||||
<div class="clr-row mb-3">
|
||||
<div class="clr-col-12">
|
||||
<h5>registration Summary:</h5>
|
||||
<p><strong>Name : </strong> {{ Test11entryForm.get('name')?.value }}</p>
|
||||
|
||||
<p><strong>Description : </strong> {{ Test11entryForm.get('description')?.value }}</p>
|
||||
|
||||
<p><strong>Active : </strong> {{ Test11entryForm.get('active')?.value }}</p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-row mb-3">
|
||||
<div class="clr-col-12">
|
||||
<h5>File_upload Summary:</h5>
|
||||
<p><strong>Name : </strong> {{ Test22entryForm.get('name')?.value }}</p>
|
||||
|
||||
<p><strong>Fileupload Field : </strong> {{ Test22entryForm.get('fileupload_field')?.value }}</p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="button">
|
||||
<button class="btn btn-primary-outline" (click)="this.timelineStyle.step1 = { state: 'current', open: true };
|
||||
this.timelineStyle.step2 = { state: 'not-started', open: false }">Back</button>
|
||||
<button class="btn btn-primary" (click)="timelineStyle.step2 = { state: 'success', open: false }; current();
|
||||
alert('Process Finished Successfully!')">Finish</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,46 +0,0 @@
|
||||
.horizontal{
|
||||
width: 25%;
|
||||
padding: 5px;
|
||||
}
|
||||
.horizontal1{
|
||||
width: 50%;
|
||||
padding: 10px;
|
||||
}
|
||||
.middle{
|
||||
width: 33%;
|
||||
padding: 10px;
|
||||
}
|
||||
.middle1{
|
||||
width: 75%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.full{
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
input[type=text],[type=date], select {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.required-field{
|
||||
color: red;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
.center{
|
||||
color: blue;
|
||||
}
|
||||
@media (max-width: 600px){
|
||||
.horizontal,.middle,.horizontal1,.middle1 {
|
||||
width: 100%;
|
||||
}}
|
||||
|
||||
@@ -1,476 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { College } from 'src/app/models/fnd/play';
|
||||
import { student } from 'src/app/models/fnd/Studentadd';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ValidationError } from 'src/app/models/fnd/ValidationError';
|
||||
import { steptest1service } from './steptest1.service';
|
||||
@Component({
|
||||
selector: 'app-editstepper',
|
||||
templateUrl: './steptest1.component.html',
|
||||
styleUrls: ['./steptest1.component.scss']
|
||||
})
|
||||
export class steptest1Component implements OnInit {
|
||||
updated = false;
|
||||
stringJson: any;
|
||||
customerId: string = '';
|
||||
selectedFile!: File;
|
||||
fileName = '';
|
||||
|
||||
id: number;
|
||||
errorFields: ValidationError[] = [];
|
||||
appToUpdate: College = null;
|
||||
trained = false;
|
||||
|
||||
json: string = "";
|
||||
luisApp =
|
||||
{
|
||||
name: '',
|
||||
created: 1,
|
||||
trained: 1,
|
||||
tested: 1,
|
||||
updated: 1,
|
||||
published: 1,
|
||||
|
||||
};
|
||||
// Layout direction changing
|
||||
layout = {
|
||||
direction: "vertical",
|
||||
block1: "clr-col-lg-3 clr-col-12 ",
|
||||
block2: "clr-col-lg-9 clr-col-12 ",
|
||||
};
|
||||
|
||||
timelineStyle = {
|
||||
step0: { state: "current", open: true, failed: false },
|
||||
step1: { state: "not-started", open: false, failed: false },
|
||||
step2: { state: "not-started", open: false, failed: false },
|
||||
};
|
||||
public Test11entryForm: FormGroup;
|
||||
public Test22entryForm: FormGroup;
|
||||
submitted = false;
|
||||
rowSelected: any = {};
|
||||
modalcomplete = false;
|
||||
|
||||
constructor(
|
||||
private mainService: steptest1service,
|
||||
|
||||
private registration_fb: FormBuilder,
|
||||
private File_upload_fb: FormBuilder,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private toastr: ToastrService,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.id = this.route.snapshot.params["id"];
|
||||
console.log("update with id = ", this.id);
|
||||
|
||||
|
||||
this.Test11entryForm = this.registration_fb.group({
|
||||
name : [null],
|
||||
|
||||
description : [null],
|
||||
|
||||
active : [true],
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
this.Test22entryForm = this.File_upload_fb.group({
|
||||
name : [null],
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const stepId = this.id; // or from route/query/etc
|
||||
|
||||
this.getResolvedDataFromStepper(stepId).subscribe(res => {
|
||||
console.log('response get ', res);
|
||||
|
||||
if (res === null) {
|
||||
this.showEmptyForm();
|
||||
} else {
|
||||
if (res['Test11']) {
|
||||
|
||||
this.prefillregistrationForm(res['Test11']);
|
||||
}
|
||||
|
||||
if (res['Test22']) {
|
||||
|
||||
this.prefillFile_uploadForm(res['Test22']);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
showEmptyForm(): void {
|
||||
console.log('No config found. Showing empty form.');
|
||||
// You can choose to show one or both based on some logic
|
||||
|
||||
this.Test11entryForm.reset();
|
||||
|
||||
this.Test22entryForm.reset();
|
||||
} prefillregistrationForm(data: any): void {
|
||||
|
||||
console.log(' registration data ', data)
|
||||
this.Test11entryForm.patchValue({
|
||||
id: data.id || '',
|
||||
name: data.name || '',
|
||||
|
||||
description: data.description || '',
|
||||
|
||||
active: data.active || '',
|
||||
|
||||
});
|
||||
} prefillFile_uploadForm(data: any): void {
|
||||
|
||||
console.log(' File_upload data ', data)
|
||||
this.Test22entryForm.patchValue({
|
||||
id: data.id || '',
|
||||
name: data.name || '',
|
||||
|
||||
fileupload_field: data.fileupload_field || '',
|
||||
|
||||
});
|
||||
}
|
||||
getResolvedDataFromStepper(id: number): Observable<any> {
|
||||
console.log('get step config');
|
||||
|
||||
return new Observable(observer => {
|
||||
this.mainService.gettabledata(id).subscribe(configList => {
|
||||
if (!configList || configList.length === 0) {
|
||||
console.log('empty config');
|
||||
observer.next(null);
|
||||
observer.complete();
|
||||
return;
|
||||
}
|
||||
|
||||
const results: { [key: string]: any } = {};
|
||||
let processed = 0;
|
||||
|
||||
configList.forEach(config => {
|
||||
const { table_name, table_id } = config;
|
||||
|
||||
this.getByTableNameAndId(table_name, table_id).subscribe(data => {
|
||||
|
||||
console.log('data is ', data);
|
||||
results[table_name] = data;
|
||||
|
||||
processed++;
|
||||
if (processed === configList.length) {
|
||||
observer.next(results); // emit combined data
|
||||
observer.complete();
|
||||
}
|
||||
|
||||
}, error => {
|
||||
console.error(`Error loading data for table ${table_name}`, error);
|
||||
processed++;
|
||||
if (processed === configList.length) {
|
||||
observer.next(results); // continue with what we have
|
||||
observer.complete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}, error => {
|
||||
console.error("Error loading stepper config", error);
|
||||
observer.error(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
getByTableNameAndId(tableName: string, id: number): Observable<any> {
|
||||
|
||||
switch (tableName) {
|
||||
case 'Test11':
|
||||
return this.mainService.getTest11ById(id); case 'Test22':
|
||||
return this.mainService.getTest22ById(id);// aur bhi cases agar naye table add ho to
|
||||
default:
|
||||
throw new Error(`Unknown table name: ${tableName}`);
|
||||
}
|
||||
}
|
||||
// Change to Horizontal Layout
|
||||
changeToHorizonTal() {
|
||||
this.layout = {
|
||||
direction: "horizontal",
|
||||
block1: "clr-col-lg-12 clr-col-12 height container",
|
||||
block2: "clr-col-lg-12 clr-col-12 container",
|
||||
}
|
||||
}
|
||||
// Change to Vertical Layout
|
||||
changeToVertical() {
|
||||
this.layout = {
|
||||
direction: "vertical",
|
||||
block1: "clr-col-lg-3 clr-col-12 ",
|
||||
block2: "clr-col-lg-9 clr-col-12 ",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
onregistrationSave() {
|
||||
console.log('Form Submitted:', this.Test11entryForm.value);
|
||||
this.submitted = true;
|
||||
if (this.Test11entryForm.invalid) {
|
||||
|
||||
console.log('invalid form ..');
|
||||
// Log all form errors
|
||||
Object.keys(this.Test11entryForm.controls).forEach(field => {
|
||||
const control = this.Test11entryForm.get(field);
|
||||
if (control && control.invalid) {
|
||||
console.log(`Error in field: ${field}`, control.errors);
|
||||
}
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.onregistrationCreate();
|
||||
}
|
||||
|
||||
onregistrationCreate() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
this.mainService.createTest11(this.Test11entryForm.value).subscribe(
|
||||
(data) => {
|
||||
console.log('adding data ', data);
|
||||
this.customerId = data.id;
|
||||
|
||||
console.log('id is ', this.customerId);
|
||||
|
||||
|
||||
const tableId = data.id;
|
||||
const tableName = 'Test11';
|
||||
const stepperId = this.id;
|
||||
|
||||
// Save stepper config
|
||||
this.mainService.saveStepperConfig(stepperId, tableId, tableName).subscribe(() => {
|
||||
this.toastr.success("Stepper Config Saved");
|
||||
}); if (data || data.status >= 200 && data.status <= 299) {
|
||||
this.toastr.success("Added Successfully");
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.ngOnInit();
|
||||
}, 500);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
if (error.status >= 200 && error.status <= 299) {
|
||||
// this.toastr.success("Added Succesfully");
|
||||
}
|
||||
if (error.status >= 400 && error.status <= 499) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
if (error.status >= 500 && error.status <= 599) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
});
|
||||
this.rowSelected = this.Test11entryForm.value;
|
||||
|
||||
setTimeout(() => {
|
||||
this.ngOnInit();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
onFile_uploadSave() {
|
||||
console.log('Form Submitted:', this.Test22entryForm.value);
|
||||
this.submitted = true;
|
||||
if (this.Test22entryForm.invalid) {
|
||||
|
||||
console.log('invalid form ..');
|
||||
// Log all form errors
|
||||
Object.keys(this.Test22entryForm.controls).forEach(field => {
|
||||
const control = this.Test22entryForm.get(field);
|
||||
if (control && control.invalid) {
|
||||
console.log(`Error in field: ${field}`, control.errors);
|
||||
}
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.onFile_uploadCreate();
|
||||
}
|
||||
|
||||
onFile_uploadCreate() {
|
||||
|
||||
|
||||
|
||||
|
||||
this.mainService.createTest22(this.Test22entryForm.value).subscribe(
|
||||
(data) => {
|
||||
console.log('adding data ', data);
|
||||
this.customerId = data.id;
|
||||
|
||||
console.log('id is ', this.customerId);
|
||||
|
||||
|
||||
const tableId = data.id;
|
||||
const tableName = 'Test22';
|
||||
const stepperId = this.id;
|
||||
|
||||
// Save stepper config
|
||||
this.mainService.saveStepperConfig(stepperId, tableId, tableName).subscribe(() => {
|
||||
this.toastr.success("Stepper Config Saved");
|
||||
}); if (data || data.status >= 200 && data.status <= 299) {
|
||||
this.toastr.success("Added Successfully");
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.ngOnInit();
|
||||
}, 500);
|
||||
|
||||
|
||||
for (let i = 0; i < this.selectedfileupload_field.length; i++){
|
||||
|
||||
this.mainService.uploadfilefileupload_field(data.id,tableName,this.selectedfileupload_field[i]).subscribe(uploaddata =>{
|
||||
console.log(uploaddata);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
if (error.status >= 200 && error.status <= 299) {
|
||||
// this.toastr.success("Added Succesfully");
|
||||
}
|
||||
if (error.status >= 400 && error.status <= 499) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
if (error.status >= 500 && error.status <= 599) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
});
|
||||
this.rowSelected = this.Test22entryForm.value;
|
||||
|
||||
setTimeout(() => {
|
||||
this.ngOnInit();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
onnext() {
|
||||
this.router.navigate(["../../main/workflow"], { relativeTo: this.route });
|
||||
}
|
||||
reset() {
|
||||
this.json = "";
|
||||
this.luisApp =
|
||||
{
|
||||
name: '',
|
||||
trained: 1,
|
||||
tested: 1,
|
||||
updated: 1,
|
||||
published: 1,
|
||||
created: 1,
|
||||
|
||||
};
|
||||
|
||||
this.timelineStyle = {
|
||||
step0: { state: "current", open: true, failed: false },
|
||||
step1: { state: "not-started", open: false, failed: false },
|
||||
step2: { state: "not-started", open: false, failed: false },
|
||||
};
|
||||
}
|
||||
current() {
|
||||
console.log(this.timelineStyle)
|
||||
this.stringJson = JSON.stringify(this.timelineStyle);
|
||||
console.log("String json object :", this.stringJson);
|
||||
|
||||
}
|
||||
|
||||
|
||||
filePreviewfileupload_field: string | ArrayBuffer | null = null;
|
||||
FileDatafileupload_field: {uploadedfile_name?:any, filePreview: string | ArrayBuffer | null }[] = []; // Initialize the array
|
||||
selectedfileupload_field: File[]=[];
|
||||
public onFileChangedfileupload_field(event, index) {
|
||||
const files = event.target.files;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
this.FileDatafileupload_field[index].uploadedfile_name = files[i].name;
|
||||
this.selectedfileupload_field.push(files[i]);
|
||||
if (file.type.startsWith('file/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
// Set the file preview source
|
||||
const filePreview = e.target?.result as string;
|
||||
this.FileDatafileupload_field[index] = {
|
||||
...this.FileDatafileupload_field[index], // Preserve existing properties
|
||||
filePreview: filePreview // Update only the filePreview property
|
||||
};
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
onAddLinesfileupload_field(){
|
||||
this.FileDatafileupload_field.push({
|
||||
uploadedfile_name: "",
|
||||
filePreview: "",
|
||||
// f3: "",
|
||||
});
|
||||
}
|
||||
deleteRowfileupload_field(index,id) {
|
||||
this.FileDatafileupload_field.splice(index, 1);
|
||||
|
||||
if(id){
|
||||
this.mainService.uploadfiledeletefileupload_field(id).subscribe(data =>{
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// updateaction
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from "rxjs";
|
||||
import { HttpClient, HttpHeaders, HttpParams, } from "@angular/common/http";
|
||||
import { ApiRequestService } from "src/app/services/api/api-request.service";
|
||||
import { environment } from 'src/environments/environment';
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class steptest1service{
|
||||
private StepperURL = "Stepper_table_config/Stepper_table_config";
|
||||
private Test11URL = "Test11/Test11" ; private Test22URL = "Test22/Test22" ; constructor(
|
||||
private http: HttpClient,
|
||||
private apiRequest: ApiRequestService,
|
||||
) { }
|
||||
gettabledata(id: number): Observable<any> {
|
||||
const _http = this.StepperURL + "/stepId/" + id;
|
||||
return this.apiRequest.get(_http);
|
||||
}
|
||||
|
||||
saveStepperConfig(stepperId: number, tableId: number, tableName: string): Observable<any> {
|
||||
const params = new HttpParams()
|
||||
.set('stepperId', stepperId.toString())
|
||||
.set('tableId', tableId.toString())
|
||||
.set('tableName', tableName);
|
||||
|
||||
return this.apiRequest.post(this.StepperURL, null, params); // null body, params used
|
||||
} getAllTest11(page?: number, size?: number): Observable<any> {
|
||||
return this.apiRequest.get(this.Test11URL);
|
||||
}
|
||||
getTest11ById(id: number): Observable<any> {
|
||||
const _http = this.Test11URL + "/" + id;
|
||||
return this.apiRequest.get(_http);
|
||||
}
|
||||
createTest11(data: any): Observable<any> {
|
||||
return this.apiRequest.post(this.Test11URL, data);
|
||||
}
|
||||
updateTest11(id: number, data: any): Observable<any> {
|
||||
const _http = this.Test11URL + "/" + id;
|
||||
return this.apiRequest.put(_http, data);
|
||||
}
|
||||
deleteTest11(id: number): Observable<any> {
|
||||
const _http = this.Test11URL + "/" + id;
|
||||
return this.apiRequest.delete(_http);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
getAllTest22(page?: number, size?: number): Observable<any> {
|
||||
return this.apiRequest.get(this.Test22URL);
|
||||
}
|
||||
getTest22ById(id: number): Observable<any> {
|
||||
const _http = this.Test22URL + "/" + id;
|
||||
return this.apiRequest.get(_http);
|
||||
}
|
||||
createTest22(data: any): Observable<any> {
|
||||
return this.apiRequest.post(this.Test22URL, data);
|
||||
}
|
||||
updateTest22(id: number, data: any): Observable<any> {
|
||||
const _http = this.Test22URL + "/" + id;
|
||||
return this.apiRequest.put(_http, data);
|
||||
}
|
||||
deleteTest22(id: number): Observable<any> {
|
||||
const _http = this.Test22URL + "/" + id;
|
||||
return this.apiRequest.delete(_http);
|
||||
}
|
||||
|
||||
|
||||
uploadfilefileupload_field(ref:any, Test22:any, file:any): Observable<any>{
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return this.apiRequest.postFormData(`FileUpload/Uploadeddocs/${ref}/${Test22}`, formData);
|
||||
}
|
||||
|
||||
uploadfilegetByIdfileupload_field(ref:any, Test22:any,): Observable<any> {
|
||||
return this.apiRequest.get(`FileUpload/Uploadeddocs/${ref}/${Test22}`);
|
||||
}
|
||||
|
||||
|
||||
uploadfiledeletefileupload_field(id: number): Observable<any> {
|
||||
return this.apiRequest.delete(`FileUpload/Uploadeddocs/${id}`);
|
||||
}
|
||||
|
||||
// updateaction
|
||||
}
|
||||
@@ -1,465 +1,279 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon> {{'SECURITY' | translate}}</a></li>
|
||||
<li><a href="javascript://">{{'MENU_ACCESS_CONTROL' | translate}}</a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon>{{'SECURITY' | translate}}</a></li>
|
||||
<li><a href="javascript://">{{ 'MENU_ACCESS_CONTROL' | translate }}</a></li>
|
||||
</ol>
|
||||
|
||||
<section class="mac-hero">
|
||||
<div class="mac-hero__content">
|
||||
<div class="mac-hero__icon">
|
||||
<clr-icon shape="shield-check"></clr-icon>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-6" style="display:flex ;">
|
||||
<div style="margin-right: 25px;">
|
||||
<h4 style="font-weight:300;">{{ 'MENU_ACCESS_CONTROL' | translate }} </h4>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="mac-hero__title">{{'MENU_ACCESS_CONTROL' | translate}}</h2>
|
||||
<p class="mac-hero__subtitle">{{'SECURITY' | translate}}</p>
|
||||
<div style="margin-top:27px ; position: relative;">
|
||||
<span class="label label-light-blue" style="display: inline;">{{ 'EDIT_MODE' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mac-hero__actions">
|
||||
<span class="mac-chip">{{'EDIT_MODE' | translate}}</span>
|
||||
<div class="mac-sep"></div>
|
||||
<label class="mac-label">{{'FOR' | translate}}</label>
|
||||
<select class="mac-select" (change)="idofselected($event.target.value)">
|
||||
<div class="clr-col-6" style="text-align: right;">
|
||||
{{ 'FOR' | translate }} <select id="" style="height: 30px;" (change)="idofselected($event.target.value)">
|
||||
<option *ngFor="let sub of givendata" [value]="sub.usrGrp" [selected]="sub.usrGrp== 40">{{sub.groupName}}</option>
|
||||
</select>
|
||||
<button id="add" class="mac-btn mac-btn-primary" (click)="getbyuseriddata()">
|
||||
<clr-icon shape="refresh"></clr-icon>
|
||||
<span class="mac-btn-text">{{'RELOAD' | translate}}</span>
|
||||
</button>
|
||||
<div class="mac-toggle">
|
||||
<span class="mac-toggle__label" *ngIf="!toggle">{{'SHOW_ALL' | translate}}</span>
|
||||
<span class="mac-toggle__label" *ngIf="toggle">{{'ONLY_MAIN_MENU' | translate}}</span>
|
||||
<button id="add" class="btn btn-primary" style="margin-left: 20px;" (click)="getbyuseriddata()"> {{ 'RELOAD' |
|
||||
translate }} </button>
|
||||
<span *ngIf="!toggle">{{ 'SHOW_ALL' | translate }} </span><span *ngIf="toggle">{{ 'ONLY_MAIN_MENU' | translate
|
||||
}}</span>
|
||||
<label class="switch">
|
||||
<input type="checkbox" ([ngModel])="toggle" checked (click)="toggleCheckbox()">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="mac-container">
|
||||
<div class="dg-wrapper">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-12 mac-actions">
|
||||
<button id="add" class="mac-btn mac-btn-primary" (click)="modaladd()" [disabled]="!toggle">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
<span>{{'ADD' | translate}}</span>
|
||||
</button>
|
||||
<div *ngIf="!toggle" class="error-message mac-hint">
|
||||
{{'CLOSE_TOGGLE_TO_ACTIVATE_ADD_BUTTON' | translate}}
|
||||
|
||||
<div class="clr-col-12" style="text-align: right;">
|
||||
|
||||
<button id="add" class="btn btn-primary" style="margin-left: 20px;" (click)="modaladd()" [disabled]="!toggle">
|
||||
<clr-icon shape="plus"></clr-icon>{{ 'ADD' | translate }} </button>
|
||||
<div *ngIf="!toggle" class="error-message" style="color: red; font-size: 14px; margin-top: 5px;">
|
||||
{{ ' Close toggle to activate Add button. ' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mac-toolbar">
|
||||
<div class="mac-toolbar__left">
|
||||
<div class="mac-search">
|
||||
<clr-icon shape="search"></clr-icon>
|
||||
<input class="mac-search__input" type="text" placeholder="{{'SEARCH' | translate}}" [(ngModel)]="filterText" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mac-toolbar__right mac-stats">
|
||||
<div class="mac-stat">
|
||||
<div class="mac-stat__value">{{ totalItems }}</div>
|
||||
<div class="mac-stat__label">{{'TOTAL_ITEMS' | translate}}</div>
|
||||
</div>
|
||||
<div class="mac-stat">
|
||||
<div class="mac-stat__value">{{ mainMenuCount }}</div>
|
||||
<div class="mac-stat__label">{{'MAIN_MENUS' | translate}}</div>
|
||||
</div>
|
||||
<div class="mac-stat">
|
||||
<div class="mac-stat__value">{{ subMenuCount }}</div>
|
||||
<div class="mac-stat__label">{{'SUB_MENUS' | translate}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-datagrid class="mac-grid" [clrDgLoading]="loading" *ngIf="!toggle">
|
||||
<clr-datagrid [clrDgLoading]="loading" *ngIf="!toggle">
|
||||
<clr-dg-placeholder>
|
||||
<ng-template #loadingSpinner>
|
||||
<clr-spinner>{{'LOADING' | translate}} ... </clr-spinner>
|
||||
</ng-template>
|
||||
<div *ngIf="alldata?.length === 0;else loadingSpinner">{{'NO_DATA_AVAILABLE' | translate}}</div>
|
||||
<ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
||||
<div *ngIf="alldata?.length === 0;else loadingSpinner">{{ 'NO_DATA_AVAILABLE' | translate }}</div>
|
||||
</clr-dg-placeholder>
|
||||
|
||||
<clr-dg-column [clrDgField]="'no'" class="mac-col mac-col--no">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="hashtag"></clr-icon> {{'NO' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'menuname'" class="mac-col mac-col--name">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="tag"></clr-icon> {{'MENU_ITEM_NAME' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mvisible'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="eye"></clr-icon> {{'VIEW' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mcreate'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="plus"></clr-icon> {{'CREATE' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'medit'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="edit"></clr-icon> {{'EDIT' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mdelete'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="trash"></clr-icon> {{'DELETE' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mquery'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="search"></clr-icon> {{'QUERY' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mexport'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="export"></clr-icon> {{'EXPORT' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'no'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'NO' | translate }}
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'menuname'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'MENU_ITEM_NAME' | translate }}
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mvisible'"><ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'VIEW' | translate }}
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mcreate'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'CREATE' | translate }}
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'medit'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'EDIT' | translate }}
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mdelete'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'DELETE' | translate }}
|
||||
<!-- <input type="checkbox" clrCheckbox name="mdelete" [checked]="colvalue" (change)="changedelete($event.target.checked)"> -->
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mquery'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'QUERY' | translate }}
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mexport'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'EXPORT' | translate }}
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-row *ngFor="let all of filteredAllData;let i=index">
|
||||
<clr-dg-row *ngFor="let all of alldata;let i=index">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell *ngIf="all.menuId==0">
|
||||
<b>{{all.menuItemDesc}}</b>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell *ngIf="all.menuId==0"><b>{{all.menuItemDesc}}</b></clr-dg-cell>
|
||||
<clr-dg-cell *ngIf="all.menuId!==0"> {{all.menuItemDesc}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mvisible">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mcreate">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.medit">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mdelete">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mquery">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mexport">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mvisible"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mcreate"></clr-dg-cell>
|
||||
<clr-dg-cell> <input type="checkbox" [checked]="selected ===all.medit"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mdelete"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mquery"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mexport"></clr-dg-cell>
|
||||
|
||||
<clr-dg-action-overflow>
|
||||
<button class="mac-action-item" (click)="modalEdit(all)">
|
||||
{{'EDIT' | translate}}
|
||||
<clr-icon shape="edit" class="is-error"></clr-icon>
|
||||
</button>
|
||||
<button class="mac-action-item" *ngIf="all.menuId!==0" (click)="modalDelete(all)">
|
||||
{{'DELETE' | translate}}
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</button>
|
||||
<button class="mac-action-item" *ngIf="all.menuId==0" (click)="modaldeletemainmenu(all)">
|
||||
{{'DELETE_MENU_SUBMENU' | translate}}
|
||||
<clr-icon shape="edit" class="is-error"></clr-icon>
|
||||
</button>
|
||||
<button class="action-item" (click)="modalEdit(all)">{{ 'EDIT' | translate }} <clr-icon shape="edit"
|
||||
class="is-error"></clr-icon></button>
|
||||
<button class="action-item" *ngIf="all.menuId!==0" (click)="modalDelete(all)">{{ 'DELETE' | translate }}
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon></button>
|
||||
<button class="action-item" *ngIf="all.menuId==0" (click)="modaldeletemainmenu(all)">{{ 'DELETE_MENU_SUBMENU' |
|
||||
translate }}
|
||||
<clr-icon shape="edit" class="is-error"></clr-icon></button>
|
||||
|
||||
</clr-dg-action-overflow>
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">{{'MENUNAME' | translate}}</td>
|
||||
<td class="td-title">Menuname</td>
|
||||
<td class="td-content"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
</clr-dg-row-detail>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer class="mac-grid-footer">
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">{{'RECORDS_PER_PAGE' | translate}}</clr-dg-page-size>
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
{{'OF' | translate}} {{pagination.totalItems}} {{'RECORDS' | translate}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
||||
<clr-datagrid class="mac-grid" [clrDgLoading]="loading" *ngIf="toggle">
|
||||
<clr-datagrid [clrDgLoading]="loading" *ngIf="toggle">
|
||||
<clr-dg-placeholder>
|
||||
<ng-template #loadingSpinner>
|
||||
<clr-spinner>{{'LOADING' | translate}} ... </clr-spinner>
|
||||
</ng-template>
|
||||
<div *ngIf="alldata?.length === 0;else loadingSpinner">{{'NO_DATA_AVAILABLE' | translate}}</div>
|
||||
<ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
||||
<div *ngIf="alldata?.length === 0;else loadingSpinner">No data available</div>
|
||||
</clr-dg-placeholder>
|
||||
|
||||
<clr-dg-column [clrDgField]="'no'" class="mac-col mac-col--no">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="hashtag"></clr-icon> {{'NO' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'menuname'" class="mac-col mac-col--name">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="tag"></clr-icon> {{'MENU_ITEM_NAME' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mvisible'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="eye"></clr-icon> {{'VIEW' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mcreate'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="plus"></clr-icon> {{'CREATE' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'medit'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="edit"></clr-icon> {{'EDIT' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mdelete'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="trash"></clr-icon> {{'DELETE' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mquery'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="search"></clr-icon> {{'QUERY' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mexport'" class="mac-col mac-col--perm">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mac-col-title">
|
||||
<clr-icon shape="export"></clr-icon> {{'EXPORT' | translate}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<ng-container *ngFor="let all of filteredAllData;let i=index">
|
||||
<clr-dg-column [clrDgField]="'no'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
NO
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'menuname'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Menu Item Name
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mvisible'"><ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
View
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mcreate'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Create
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'medit'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Edit
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mdelete'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Delete
|
||||
<!-- <input type="checkbox" clrCheckbox name="mdelete" [checked]="colvalue" (change)="changedelete($event.target.checked)"> -->
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mquery'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Query
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'mexport'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Export
|
||||
</ng-container></clr-dg-column>
|
||||
<ng-container *ngFor="let all of alldata;let i=index">
|
||||
<clr-dg-row *ngIf="all.menuId==0">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<b>{{all.menuItemDesc}}</b>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mvisible">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mcreate">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.medit">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mdelete">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mquery">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<input type="checkbox" [checked]="selected ===all.mexport">
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell><b>{{all.menuItemDesc}}</b></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mvisible"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mcreate"></clr-dg-cell>
|
||||
<clr-dg-cell> <input type="checkbox" [checked]="selected ===all.medit"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mdelete"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mquery"></clr-dg-cell>
|
||||
<clr-dg-cell><input type="checkbox" [checked]="selected ===all.mexport"></clr-dg-cell>
|
||||
<clr-dg-action-overflow>
|
||||
<button class="mac-action-item" (click)="Sync(all.menuItemId?.menuItemId,all)">
|
||||
{{'SYNC' | translate}}
|
||||
<clr-icon shape="shrink" class="is-error"></clr-icon>
|
||||
</button>
|
||||
<button class="action-item" (click)="Sync(all.menuItemId?.menuItemId,all)">Sync <clr-icon shape="shrink"
|
||||
class="is-error"></clr-icon> </button>
|
||||
</clr-dg-action-overflow>
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">{{'MENUNAME' | translate}}</td>
|
||||
<td class="td-title">Menuname</td>
|
||||
<td class="td-content"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</clr-dg-row-detail>
|
||||
</clr-dg-row>
|
||||
</ng-container>
|
||||
<clr-dg-footer class="mac-grid-footer">
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">{{'RECORDS_PER_PAGE' | translate}}</clr-dg-page-size>
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
{{'OF' | translate}} {{pagination.totalItems}} {{'RECORDS' | translate}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
||||
<clr-modal class="mac-modal" [(clrModalOpen)]="modalAdd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title mac-modal-title">
|
||||
<clr-icon shape="plus"></clr-icon> {{'ADD_MENU_ACCESS_CONTROL' | translate}}
|
||||
</h3>
|
||||
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Add Menu Access Control</h3>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-sm-12 mac-form-group">
|
||||
<label class="mac-form-label" for="name">{{'MENU_NAME' | translate}}
|
||||
<span class="required-field">*</span>
|
||||
</label>
|
||||
<select name="" id="" class="mac-form-select w-100" (change)="idselected($event.target.value)">
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Menu Name<span class="required-field">*</span></label>
|
||||
<select name="" id="" style="width: 100%;padding: 5px 5px;border: 1px solid #ccc;border-radius: 4px;"
|
||||
(change)="idselected($event.target.value)">
|
||||
<option *ngFor="let sub of menus" [value]="sub.menuItemId">{{sub.menuItemDesc}}</option>
|
||||
</select>
|
||||
<div class="mac-form-help">{{'CHOOSE_MAIN_MENU_FOR_ACCESS' | translate}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="mac-btn mac-btn-outline" (click)="modalAdd = false">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{'CANCEL' | translate}}</span>
|
||||
</button>
|
||||
<button type="submit" class="mac-btn mac-btn-primary">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
<span>{{'ADD' | translate}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline" (click)="modalAdd = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">ADD</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal class="mac-modal" [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title mac-modal-title">
|
||||
<clr-icon shape="edit"></clr-icon> {{'UPDATE_MENU_ACCESS_CONTROL' | translate}}
|
||||
</h3>
|
||||
<clr-modal [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Update Menu Access Control</h3>
|
||||
<div class="modal-body" *ngIf="rowSelected.menuItemId">
|
||||
<div class="mac-form-help">{{'MENU_ID' | translate}}:
|
||||
<code class="clr-code">{{rowSelected.menuItemId.menuItemId}}</code>
|
||||
</div>
|
||||
<h2 class="heading">{{rowSelected.menuItemId.menuItemId}}</h2>
|
||||
<form (ngSubmit)="onUpdate(rowSelected.menuItemId.menuItemId,rowSelected.usrGrp.usrGrp)">
|
||||
<div class="mac-perms">
|
||||
<label class="mac-perm">
|
||||
<input type="checkbox" clrCheckbox name="mvisible" [(ngModel)]="selected ===rowSelected.mvisible" (change)="rowSelected.mvisible === $event.target.checked ? 'y' : 'n'">
|
||||
<span class="mac-perm__icon">
|
||||
<clr-icon shape="eye"></clr-icon>
|
||||
</span>
|
||||
<span class="mac-perm__label">{{'VIEW' | translate}}</span>
|
||||
</label>
|
||||
<label class="mac-perm">
|
||||
<input type="checkbox" clrCheckbox name="mcreate" [(ngModel)]="selected ===rowSelected.mcreate" (change)="rowSelected.mcreate === $event.target.checked ? 'y' : 'n'">
|
||||
<span class="mac-perm__icon">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</span>
|
||||
<span class="mac-perm__label">{{'CREATE' | translate}}</span>
|
||||
</label>
|
||||
<label class="mac-perm">
|
||||
<input type="checkbox" clrCheckbox name="medit" [(ngModel)]="selected ===rowSelected.medit" (change)="rowSelected.medit === $event.target.checked ? 'y' : 'n'">
|
||||
<span class="mac-perm__icon">
|
||||
<clr-icon shape="edit"></clr-icon>
|
||||
</span>
|
||||
<span class="mac-perm__label">{{'EDIT' | translate}}</span>
|
||||
</label>
|
||||
<label class="mac-perm">
|
||||
<input type="checkbox" clrCheckbox name="mdelete" [(ngModel)]="selected ===rowSelected.mdelete" (change)="rowSelected.mdelete === $event.target.checked ? 'y' : 'n'">
|
||||
<span class="mac-perm__icon">
|
||||
<clr-icon shape="trash"></clr-icon>
|
||||
</span>
|
||||
<span class="mac-perm__label">{{'DELETE' | translate}}</span>
|
||||
</label>
|
||||
<label class="mac-perm">
|
||||
<input type="checkbox" clrCheckbox name="mquery" [(ngModel)]="selected ===rowSelected.mquery" (change)="rowSelected.mquery === $event.target.checked ? 'y' : 'n'">
|
||||
<span class="mac-perm__icon">
|
||||
<clr-icon shape="search"></clr-icon>
|
||||
</span>
|
||||
<span class="mac-perm__label">{{'QUERY' | translate}}</span>
|
||||
</label>
|
||||
<label class="mac-perm">
|
||||
<input type="checkbox" clrCheckbox name="mexport" [(ngModel)]="selected ===rowSelected.mexport" (change)="rowSelected.mexport === $event.target.checked ? 'y' : 'n'">
|
||||
<span class="mac-perm__icon">
|
||||
<clr-icon shape="export"></clr-icon>
|
||||
</span>
|
||||
<span class="mac-perm__label">{{'EXPORT' | translate}}</span>
|
||||
</label>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="tags">View</label>
|
||||
<input type="checkbox" clrCheckbox name="mvisible" [(ngModel)]="selected ===rowSelected.mvisible"
|
||||
(change)="rowSelected.mvisible === $event.target.checked ? 'y' : 'n'">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Create</label>
|
||||
<input type="checkbox" clrCheckbox name="mcreate" name="mcreate"
|
||||
[(ngModel)]="selected ===rowSelected.mcreate"
|
||||
(change)="rowSelected.mcreate === $event.target.checked ? 'y' : 'n'">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="tags">Edit</label>
|
||||
<input type="checkbox" clrCheckbox name="medit" [(ngModel)]="selected ===rowSelected.medit"
|
||||
(change)="rowSelected.medit === $event.target.checked ? 'y' : 'n'">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="tags">Delete</label>
|
||||
<input type="checkbox" clrCheckbox name="mdelete" [(ngModel)]="selected ===rowSelected.mdelete"
|
||||
(change)="rowSelected.mdelete === $event.target.checked ? 'y' : 'n'">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="tags">Query</label>
|
||||
<input type="checkbox" clrCheckbox name="mquery" [(ngModel)]="selected ===rowSelected.mquery"
|
||||
(change)="rowSelected.mquery === $event.target.checked ? 'y' : 'n'">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="tags">Export</label>
|
||||
<input type="checkbox" clrCheckbox name="mexport" [(ngModel)]="selected ===rowSelected.mexport"
|
||||
(change)="rowSelected.mexport === $event.target.checked ? 'y' : 'n'">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="mac-btn mac-btn-outline" (click)="modaledit = false">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{'CANCEL' | translate}}</span>
|
||||
</button>
|
||||
<button type="submit" class="mac-btn mac-btn-primary">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
<span>{{'UPDATE' | translate}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline" (click)="modaledit = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">UPDATE</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal class="mac-modal" [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<div class="modal-body">
|
||||
<div class="mac-delete-header">
|
||||
<div class="mac-delete-icon">
|
||||
<clr-icon shape="exclamation-triangle" size="48"></clr-icon>
|
||||
</div>
|
||||
<h1 class="mac-delete-title">{{'ARE_YOU_SURE_WANT_TO_DELETE' | translate}}?</h1>
|
||||
<p class="mac-delete-subtitle">{{'THIS_ACTION_CANNOT_BE_UNDONE' | translate}}</p>
|
||||
</div>
|
||||
<div class="mac-delete-details" *ngIf="rowSelected.menuItemId">
|
||||
<div class="mac-delete-detail-item">
|
||||
<span class="mac-delete-detail-label">{{'MENU_ITEM_ID' | translate}}:</span>
|
||||
<span class="mac-delete-detail-value">{{rowSelected.menuItemId.menuItemId}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="mac-btn mac-btn-outline" (click)="modaldelete = false">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{'CANCEL' | translate}}</span>
|
||||
</button>
|
||||
<button type="submit" (click)="delete(rowSelected.menuItemId.menuItemId,rowSelected.usrGrp.usrGrp)" class="mac-btn mac-btn-error">
|
||||
<clr-icon shape="trash"></clr-icon>
|
||||
<span>{{'DELETE' | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
|
||||
<clr-modal class="mac-modal" [(clrModalOpen)]="modaldelete1" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<div class="modal-body">
|
||||
<div class="mac-delete-header">
|
||||
<div class="mac-delete-icon">
|
||||
<clr-icon shape="exclamation-triangle" size="48"></clr-icon>
|
||||
</div>
|
||||
<h1 class="mac-delete-title">{{'ARE_YOU_SURE_WANT_TO_DELETE_MAIN_MENU_WITH_SUBMENU' | translate}}?</h1>
|
||||
<p class="mac-delete-subtitle">{{'THIS_ACTION_CANNOT_BE_UNDONE' | translate}}</p>
|
||||
</div>
|
||||
<div class="mac-delete-details" *ngIf="rowSelected.menuItemId">
|
||||
<div class="mac-delete-detail-item">
|
||||
<span class="mac-delete-detail-label">{{'MENU_ITEM_ID' | translate}}:</span>
|
||||
<span class="mac-delete-detail-value">{{rowSelected.menuItemId.menuItemId}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body" *ngIf="rowSelected.menuItemId">
|
||||
<h1 class="delete">Are You Sure Want to delete?</h1>
|
||||
<h2 class="heading">{{rowSelected.menuItemId.menuItemId}}</h2>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="mac-btn mac-btn-outline" (click)="modaldelete1 = false">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{'CANCEL' | translate}}</span>
|
||||
</button>
|
||||
<button type="submit" (click)="delete1(rowSelected.menuItemId.menuItemId,rowSelected.usrGrp.usrGrp)" class="mac-btn mac-btn-error">
|
||||
<clr-icon shape="trash"></clr-icon>
|
||||
<span>{{'DELETE' | translate}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
|
||||
<button type="submit" (click)="delete(rowSelected.menuItemId.menuItemId,rowSelected.usrGrp.usrGrp)"
|
||||
class="btn btn-primary">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
<clr-modal [(clrModalOpen)]="modaldelete1" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
|
||||
<div class="modal-body" *ngIf="rowSelected.menuItemId">
|
||||
<h1 class="delete">Are You Sure Want to delete Main menu with submenu?</h1>
|
||||
<h2 class="heading">{{rowSelected.menuItemId.menuItemId}}</h2>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaldelete1 = false">Cancel</button>
|
||||
<button type="submit" (click)="delete1(rowSelected.menuItemId.menuItemId,rowSelected.usrGrp.usrGrp)"
|
||||
class="btn btn-primary">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
</div>
|
||||
@@ -1,160 +1,43 @@
|
||||
@import '../../../../../styles/_design-tokens.scss';
|
||||
|
||||
// Import base styles
|
||||
input[type=text],
|
||||
[type=date],
|
||||
[type=password],
|
||||
[type=checkbox] {
|
||||
input[type=text],[type=date],[type=password],[type=checkbox] {
|
||||
width: 100%;
|
||||
padding: 15px 20px;
|
||||
background-color: var(--theme-surface);
|
||||
// margin: 3px 0;
|
||||
background-color:rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
font-family: var(--theme-font-primary);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
.required-field{
|
||||
color: red;
|
||||
font-size: 18px;
|
||||
|
||||
input[type=text]:focus,
|
||||
[type=date]:focus,
|
||||
[type=password]:focus,
|
||||
[type=checkbox]:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: var(--theme-error, #ef4444);
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
// select{
|
||||
// width: 100%;
|
||||
// padding: 5px 5px;
|
||||
// border: 1px solid #ccc;
|
||||
// border-radius: 4px;
|
||||
// }
|
||||
.td-title {
|
||||
text-align: center;
|
||||
width: 150px;
|
||||
color: white;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
background-color: var(--theme-primary);
|
||||
background-color: rgba(63, 122, 231, 0.863);
|
||||
//color: rgb(24, 13, 13);
|
||||
}
|
||||
|
||||
th {
|
||||
th{
|
||||
//background-color:rgb(170, 169, 169);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.td-content {
|
||||
.td-content{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
// Modern Button Styles using ThemeService
|
||||
.mac-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: var(--theme-font-primary);
|
||||
z-index: 1;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--theme-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.mac-btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.mac-btn-md {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&.mac-btn-lg {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
// Variants
|
||||
&.mac-btn-primary {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, var(--theme-primary, #0284c7) 0%, var(--theme-accent, #7c3aed) 100%);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
&.mac-btn-outline {
|
||||
background: transparent;
|
||||
color: var(--theme-secondary);
|
||||
border-color: var(--theme-secondary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 116, 139, 0.1);
|
||||
border-color: var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.mac-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: white;
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
border-color: var(--theme-error-dark, #dc2626);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3), 0 4px 6px -2px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&.mac-btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--theme-text-secondary);
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
.delete,.heading{
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
|
||||
//toggle button
|
||||
.switch {
|
||||
position: relative;
|
||||
@@ -193,585 +76,24 @@ th {
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked+.slider {
|
||||
background-color: var(--theme-primary);
|
||||
input:checked + .slider {
|
||||
background-color: #0072a3;
|
||||
}
|
||||
|
||||
input:focus+.slider {
|
||||
box-shadow: 0 0 1px var(--theme-primary);
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #0072a3;
|
||||
}
|
||||
|
||||
input:checked+.slider:before {
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
.slider.round {
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
// Modern themed enhancements (ThemeService variables)
|
||||
.mm-breadcrumb {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.mac-header-left {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.mac-title h4 {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.mac-edit-chip {
|
||||
margin-top: 27px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mac-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6px 12px;
|
||||
background-color: var(--theme-background);
|
||||
color: var(--theme-text);
|
||||
border-radius: var(--theme-border-radius);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.mac-header-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mac-select {
|
||||
height: 40px;
|
||||
padding: 8px 12px;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mac-btn-primary {
|
||||
margin-left: 20px;
|
||||
box-shadow: var(--theme-shadow);
|
||||
}
|
||||
|
||||
.mac-actions {
|
||||
text-align: right;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.mac-hint {
|
||||
color: var(--theme-error, #ef4444);
|
||||
font-size: 14px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.mac-grid {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
|
||||
::ng-deep .datagrid {
|
||||
.datagrid-head {
|
||||
background: var(--theme-background);
|
||||
|
||||
.datagrid-column {
|
||||
padding: 16px 24px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-row {
|
||||
transition: background-color 150ms ease-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.datagrid-cell {
|
||||
padding: 16px 24px;
|
||||
font-size: 14px;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mac-grid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.mac-modal .modal-title {
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
// Hero and actions
|
||||
.mac-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
clr-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: var(--theme-font-secondary);
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.mac-sep {
|
||||
width: 1px;
|
||||
height: 22px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.mac-label {
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mac-toggle__label {
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
// Grid columns
|
||||
.mac-col-title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.mac-col--perm .mac-col-title clr-icon {
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
// Toolbar, search and stats
|
||||
.mac-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&__left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__right {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.mac-search {
|
||||
position: relative;
|
||||
max-width: 400px;
|
||||
|
||||
clr-icon {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #9ca3af;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__input {
|
||||
width: 100%;
|
||||
padding: 12px 12px 12px 40px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: all 200ms ease-out;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mac-stats {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.mac-stat {
|
||||
min-width: 110px;
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
border-radius: var(--theme-border-radius);
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
box-shadow: var(--theme-shadow);
|
||||
|
||||
&__value {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--theme-primary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 12px;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
}
|
||||
|
||||
// Enhanced modals
|
||||
.mac-modal-title clr-icon {
|
||||
margin-right: 6px;
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
.mac-form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mac-form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
.mac-form-select {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
transition: all 200ms ease-out;
|
||||
margin-bottom: 0;
|
||||
font-family: var(--theme-font-primary);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
|
||||
background-position: right 12px center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 12px;
|
||||
padding-right: 40px;
|
||||
appearance: none;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text-secondary);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.mac-form-help {
|
||||
color: var(--theme-text-secondary);
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
.mac-perms {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.mac-perm {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: var(--theme-border-radius);
|
||||
box-shadow: var(--theme-shadow);
|
||||
transition: all 200ms ease-out;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mac-perm__icon clr-icon {
|
||||
color: var(--theme-primary);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.mac-perm__label {
|
||||
color: var(--theme-text);
|
||||
font-weight: 500;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
// Datagrid action overflow buttons
|
||||
.mac-action-item {
|
||||
@extend .mac-btn;
|
||||
@extend .mac-btn-ghost;
|
||||
@extend .mac-btn-sm;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 4px;
|
||||
text-align: left;
|
||||
|
||||
clr-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&.mac-btn-error {
|
||||
color: var(--theme-error, #ef4444);
|
||||
|
||||
&:hover {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Modal Styles
|
||||
.mac-delete-header {
|
||||
text-align: center;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.mac-delete-icon {
|
||||
color: var(--theme-error, #ef4444);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mac-delete-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--theme-text);
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.mac-delete-subtitle {
|
||||
font-size: 16px;
|
||||
color: var(--theme-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mac-delete-details {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.mac-delete-detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mac-delete-detail-label {
|
||||
font-weight: 500;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.mac-delete-detail-value {
|
||||
font-weight: 600;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
.delete,
|
||||
.heading {
|
||||
text-align: center;
|
||||
color: var(--theme-error, #ef4444);
|
||||
}
|
||||
|
||||
// Modal Header
|
||||
::ng-deep .modal-header {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px 16px 0 0 !important;
|
||||
padding: 20px 24px !important;
|
||||
|
||||
.modal-title {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Body
|
||||
::ng-deep .modal-body {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
// Modal Footer
|
||||
::ng-deep .modal-footer {
|
||||
padding: 20px 24px !important;
|
||||
background: var(--theme-background);
|
||||
border-radius: 0 0 16px 16px !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@media (max-width: 768px) {
|
||||
.mac-hero {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
|
||||
&__content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.mac-toolbar {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.mac-search {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.mac-stats {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mac-perms {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.mac-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mac-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,6 @@ import { MenuGroupService } from 'src/app/services/admin/menu-group.service';
|
||||
import { MenumaintanceService } from 'src/app/services/admin/menumaintance.service';
|
||||
import { UsergrpmaintainceService } from 'src/app/services/admin/usergrpmaintaince.service';
|
||||
import { UsermaintanceService } from '../../../../services/admin/usermaintance.service';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-menuaccesscontrol',
|
||||
templateUrl: './menuaccesscontrol.component.html',
|
||||
@@ -38,26 +36,15 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
toggle: boolean = false;
|
||||
maindata;
|
||||
showdata;
|
||||
// UI enhancements (no API changes)
|
||||
filterText: string = '';
|
||||
|
||||
constructor(
|
||||
private mainservice: UsermaintanceService,
|
||||
constructor(private mainservice: UsermaintanceService,
|
||||
private _fb: FormBuilder,
|
||||
private toastr: ToastrService,
|
||||
private route: ActivatedRoute,
|
||||
private usergrpservice: UsergrpmaintainceService,
|
||||
private menuGroupService: MenuGroupService,
|
||||
private menuservice: MenumaintanceService,
|
||||
private themeService: ThemeService
|
||||
) { }
|
||||
private menuservice: MenumaintanceService,) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// Ensure theme variables are applied to the view
|
||||
this.themeService.currentTheme$.subscribe(() => {
|
||||
// CSS variables are updated globally; no extra handling needed here
|
||||
});
|
||||
|
||||
this.showdata = this.menuGroupService.getdata();
|
||||
console.log(this.showdata);
|
||||
this.mcreate = this.showdata.mcreate;
|
||||
@@ -74,64 +61,35 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
grpid: this.usergrpid,
|
||||
gmenuid: this.menuselectid,
|
||||
});
|
||||
}
|
||||
|
||||
// Stats & filtering helpers for UI only
|
||||
get totalItems(): number {
|
||||
const list: any[] = (this.alldata as unknown as any[]) || [];
|
||||
return list.length;
|
||||
}
|
||||
|
||||
get mainMenuCount(): number {
|
||||
const list: any[] = (this.alldata as unknown as any[]) || [];
|
||||
return list.filter(it => it && it.menuId === 0).length;
|
||||
}
|
||||
|
||||
get subMenuCount(): number {
|
||||
const list: any[] = (this.alldata as unknown as any[]) || [];
|
||||
return list.filter(it => it && it.menuId !== 0).length;
|
||||
}
|
||||
|
||||
get filteredAllData(): any[] {
|
||||
const items: any[] = (this.alldata as unknown as any[]) || [];
|
||||
const text = (this.filterText || '').toLowerCase();
|
||||
if (!text) { return items; }
|
||||
return items.filter(m => (
|
||||
(m?.menuItemDesc || '').toLowerCase().includes(text)
|
||||
));
|
||||
}
|
||||
|
||||
dropddowngetdata() {
|
||||
this.usergrpservice.getAll().subscribe((data) => {
|
||||
console.log(data);
|
||||
this.givendata = data;
|
||||
});
|
||||
}
|
||||
|
||||
getdata() {
|
||||
this.menuservice.getByCurrentUserMenuGroupId1().subscribe(resp => {
|
||||
this.menus = resp;
|
||||
console.log('menus: ', this.menus);
|
||||
})
|
||||
}
|
||||
|
||||
getall() {
|
||||
this.usergrpservice.getall().subscribe((data) => {
|
||||
this.secmenuaccessdata = data
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
|
||||
idofselected(val) {
|
||||
console.log(val);
|
||||
this.usergrpid = val;
|
||||
}
|
||||
|
||||
}
|
||||
idselected(val) {
|
||||
console.log(val)
|
||||
this.menuselectid = val;
|
||||
}
|
||||
|
||||
getbyuseriddata() {
|
||||
this.usergrpservice.getbyusergrpid(this.usergrpid).subscribe((data) => {
|
||||
this.alldata = data;
|
||||
@@ -153,12 +111,10 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
modaladd() {
|
||||
this.modalAdd = true;
|
||||
this.getdata();
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.modalAdd = false;
|
||||
this.entryForm.value.grpid = this.usergrpid;
|
||||
@@ -182,20 +138,18 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
}
|
||||
this.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
modalEdit(row) {
|
||||
this.rowSelected = row;
|
||||
console.log(this.rowSelected);
|
||||
this.modaledit = true;
|
||||
}
|
||||
|
||||
modalDelete(row) {
|
||||
this.rowSelected = row;
|
||||
console.log(this.rowSelected)
|
||||
this.modaldelete = true;
|
||||
}
|
||||
|
||||
delete(id, usrgrp) {
|
||||
this.modaldelete = false;
|
||||
this.usergrpservice.delete(id, usrgrp).subscribe((data) => {
|
||||
@@ -212,13 +166,11 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
this.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
||||
modaldeletemainmenu(row) {
|
||||
this.rowSelected = row;
|
||||
console.log(this.rowSelected)
|
||||
this.modaldelete1 = true;
|
||||
}
|
||||
|
||||
delete1(id, usrgrp) {
|
||||
this.modaldelete1 = false;
|
||||
this.usergrpservice.deletemain(id, usrgrp).subscribe((data) => {
|
||||
@@ -235,7 +187,6 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
this.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
||||
onUpdate(id: any, usrgrp: any) {
|
||||
this.modaledit = false;
|
||||
console.log(id, usrgrp);
|
||||
@@ -253,7 +204,6 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
this.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
||||
onChecked(value) {
|
||||
if (value == "y") {
|
||||
this.selected = "y"
|
||||
@@ -263,13 +213,11 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
this.selected = "n"// make a call for unchecked
|
||||
}
|
||||
}
|
||||
|
||||
changedelete(val) {
|
||||
console.log(val);
|
||||
val = this.colvalue = val;
|
||||
console.log(val);
|
||||
}
|
||||
|
||||
data: {};
|
||||
Sync(id: any, row) {
|
||||
this.rowSelected = row;
|
||||
@@ -291,7 +239,6 @@ export class MenuaccesscontrolComponent implements OnInit {
|
||||
this.ngOnInit();
|
||||
})
|
||||
}
|
||||
|
||||
toggleCheckbox() {
|
||||
this.toggle = !this.toggle;
|
||||
//this.dataService.setDivToggler(this.toggler);
|
||||
|
||||
@@ -1,39 +1,11 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon>{{ 'SECURITY' | translate }}</a></li>
|
||||
<li><a href="javascript://">{{ 'MENU_MAINTENANCE' | translate }}</a></li>
|
||||
</ol>
|
||||
|
||||
<div class="mm-container">
|
||||
<section class="mm-hero">
|
||||
<div class="mm-hero__content">
|
||||
<div class="mm-hero__icon">
|
||||
<clr-icon shape="organization"></clr-icon>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="mm-hero__title">{{ 'MENU_MAINTENANCE' | translate }}</h2>
|
||||
<p class="mm-hero__subtitle">{{ 'MAIN_MENU' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mm-hero__actions">
|
||||
<button class="btn btn-outline mm-btn-outline" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon>
|
||||
<span class="mm-btn-text">{{ 'EXPORT_XLSX' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary mm-btn-primary" (click)="csvImport()">
|
||||
<clr-icon shape="import"></clr-icon>
|
||||
<span class="mm-btn-text">{{ 'IMPORT' | translate }}</span>
|
||||
</button>
|
||||
<button id="add" class="btn btn-primary mm-btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
<span class="mm-btn-text">{{ 'ADD' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn mm-btn-secondary" (click)="downloadFiles()">
|
||||
<clr-icon shape="download"></clr-icon>
|
||||
<span class="mm-btn-text">{{ 'DOWNLOAD_TEMPLATE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- <div class="clr-row">
|
||||
<div class="clr-col-12" style="text-align: right;">
|
||||
<button id="add" *ngIf="mcreate == 'true'" class="btn btn-primary" (click)="goToAdd()">
|
||||
@@ -41,44 +13,29 @@
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="mm-stats">
|
||||
<div class="mm-stat">
|
||||
<div class="mm-stat__value">{{ totalMenus }}</div>
|
||||
<div class="mm-stat__label">{{ 'TOTAL_MENUS' | translate }}</div>
|
||||
</div>
|
||||
<div class="mm-stat">
|
||||
<div class="mm-stat__value">{{ enabledMenusCount }}</div>
|
||||
<div class="mm-stat__label">{{ 'ENABLED' | translate }}</div>
|
||||
</div>
|
||||
<div class="mm-stat">
|
||||
<div class="mm-stat__value">{{ disabledMenusCount }}</div>
|
||||
<div class="mm-stat__label">{{ 'DISABLED' | translate }}</div>
|
||||
</div>
|
||||
<div class="clr-row" style="margin-top: 15px;">
|
||||
<div class="clr-col">
|
||||
<h3 style="font-weight: 300;display: inline;">{{ 'MENU_MAINTENANCE' | translate }} </h3>
|
||||
<span class="label label-light-blue" style="display: inline;margin-left: 30px;">{{ 'MAIN_MENU' | translate }}</span><br>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mm-toolbar">
|
||||
<div class="mm-toolbar__left">
|
||||
<div class="mm-search">
|
||||
<clr-icon shape="search"></clr-icon>
|
||||
<input class="mm-search__input" type="text" [placeholder]="'SEARCH' | translate" [(ngModel)]="filterText" />
|
||||
<div class="clr-col" style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<button class="btn text-dark" (click)="downloadFiles()"><b>{{ 'DOWNLOAD_TEMPLATE' | translate }}</b></button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="mm-toolbar__right">
|
||||
<select class="mm-select" [(ngModel)]="statusFilter">
|
||||
<option value="All">{{ 'ALL' | translate }}</option>
|
||||
<option value="Enable">{{ 'ENABLED' | translate }}</option>
|
||||
<option value="Disable">{{ 'DISABLED' | translate }}</option>
|
||||
</select>
|
||||
<div class="mm-view-toggle">
|
||||
<button class="btn btn-sm" [class.btn-primary]="viewMode==='cards'" (click)="setViewMode('cards')">
|
||||
<clr-icon shape="view-cards"></clr-icon>
|
||||
|
||||
<button class="btn btn-primary" (click)="csvImport()">{{ 'IMPORT' | translate }}</button>
|
||||
|
||||
<button class="btn btn-outline" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon> {{ 'EXPORT_XLSX' | translate }}
|
||||
</button>
|
||||
<button class="btn btn-sm" [class.btn-primary]="viewMode==='table'" (click)="setViewMode('table')">
|
||||
<clr-icon shape="table"></clr-icon>
|
||||
<button id="add" class="btn btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon> {{ 'ADD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -187,81 +144,62 @@
|
||||
|
||||
</tbody>
|
||||
</table> -->
|
||||
|
||||
<div class="mm-skeleton-list" *ngIf="loading">
|
||||
<div class="mm-skeleton-item" *ngFor="let i of [1,2,3,4,5,6]">
|
||||
<div class="mm-skel mm-skel--icon"></div>
|
||||
<div class="mm-skel mm-skel--title"></div>
|
||||
<div class="mm-skel mm-skel--meta"></div>
|
||||
<div class="mm-skel mm-skel--chip"></div>
|
||||
<div class="mm-skel mm-skel--link"></div>
|
||||
<div class="mm-skel mm-skel--badge"></div>
|
||||
<div class="mm-skel mm-skel--actions"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mm-card" *ngIf="viewMode==='table'">
|
||||
<clr-datagrid class="mm-grid mm-grid--modern" [clrDgLoading]="loading" [(clrDgSelected)]="selected">
|
||||
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>{{'LOADING'|translate}} ...
|
||||
</clr-spinner></ng-template>
|
||||
<div class="mm-empty" *ngIf="error;else loadingSpinner">
|
||||
<clr-icon shape="warning-standard"></clr-icon>
|
||||
<div class="mm-empty__title">{{ 'NO_DATA' | translate }}</div>
|
||||
<div class="mm-empty__subtitle">{{ error }}</div>
|
||||
</div>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="''" class="mm-col mm-col--icon">
|
||||
<clr-datagrid [clrDgLoading]="loading" [(clrDgSelected)]="selected">
|
||||
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>{{'LOADING'|translate}} ... </clr-spinner></ng-template>
|
||||
<div *ngIf="error;else loadingSpinner">{{error}}</div></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="''" style="max-width: 40px;">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}"></ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--no">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mm-col-title"><clr-icon shape="hashtag"></clr-icon> {{'NO' | translate}}</span>
|
||||
{{'NO' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--name">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mm-col-title"><clr-icon shape="tag"></clr-icon> {{'MENU_ITEM_NAME' | translate}}</span>
|
||||
{{'MENU_ITEM_NAME' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--id">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mm-col-title"><clr-icon shape="id-badge"></clr-icon> {{'ID' | translate}}</span>
|
||||
{{'ID' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--seq">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mm-col-title"><clr-icon shape="number-list"></clr-icon> {{'SEQUENCE' | translate}}</span>
|
||||
{{'SEQUENCE' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--module">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mm-col-title"><clr-icon shape="application"></clr-icon> {{'MODULE_NAME' | translate}}</span>
|
||||
{{'MODULE_NAME' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--link">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mm-col-title"><clr-icon shape="link"></clr-icon> {{'MENU_ACTION_LINK' | translate}}</span>
|
||||
{{'MENU_ACTION_LINK' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--status">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="mm-col-title"><clr-icon shape="shield-check"></clr-icon> {{'STATUS' | translate}}</span>
|
||||
{{'STATUS' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--submenu">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{'SUB_MENU' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column class="mm-col mm-col--action">
|
||||
<clr-dg-column>
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<clr-icon shape="bars"></clr-icon>
|
||||
{{'ACTION' | translate}}
|
||||
@@ -269,49 +207,22 @@
|
||||
</clr-dg-column>
|
||||
|
||||
|
||||
<clr-dg-row class="mm-row" *clrDgItems="let user of filteredMenus;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell class="mm-cell mm-cell--icon">
|
||||
<span class="mm-icon-action"><clr-icon shape="edit" (click)="goToEdit(user)"
|
||||
class="is-error mm-icon-edit"></clr-icon></span>
|
||||
<clr-dg-row *clrDgItems="let user of menus;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell style="max-width: 40px;">
|
||||
<span style="cursor: pointer;"><clr-icon shape="edit" (click)="goToEdit(user)" class="red is-error" style="color:red;"></clr-icon></span>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--no">{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--name">
|
||||
<div class="mm-item">
|
||||
<div class="mm-item__avatar"><clr-icon shape="bookmark"></clr-icon></div>
|
||||
<div class="mm-item__text">
|
||||
<div class="mm-item__title">{{user.menuItemDesc}}</div>
|
||||
<div class="mm-item__meta">ID: {{user.menuId}} ⢠Seq: {{user.itemSeq}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--id">{{user.menuId}}</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--seq">{{user.itemSeq}}</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--module">
|
||||
<div class="mm-chip mm-chip--module">
|
||||
<clr-icon shape="application"></clr-icon>
|
||||
<span>{{user.moduleName}}</span>
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--link">
|
||||
<div class="mm-link">
|
||||
<clr-icon shape="link"></clr-icon>
|
||||
<span>{{user.main_menu_action_name}}</span>
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--status">
|
||||
<span class="mm-badge" [class.mm-badge--success]="user.status==='Enable'"
|
||||
[class.mm-badge--muted]="user.status!=='Enable'">{{user.status}}</span>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--submenu"><clr-icon shape="bullet-list" (click)="submenu(user.menuItemId)"
|
||||
class="mm-icon-link"></clr-icon> </clr-dg-cell>
|
||||
<clr-dg-cell class="mm-cell mm-cell--action">
|
||||
<div class="mm-actions-inline">
|
||||
<button class="btn btn-sm btn-outline" (click)="goToEdit(user)"><clr-icon shape="edit"></clr-icon></button>
|
||||
<button class="btn btn-sm btn-outline" (click)="onDelete(user)"><clr-icon shape="trash"></clr-icon></button>
|
||||
</div>
|
||||
<clr-dg-cell >{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.menuItemDesc}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.menuId}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.itemSeq}}</clr-dg-cell>
|
||||
<clr-dg-cell > {{user.moduleName}} </clr-dg-cell>
|
||||
<clr-dg-cell > {{user.main_menu_action_name}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.status}} </clr-dg-cell>
|
||||
<clr-dg-cell ><clr-icon shape="bullet-list" (click)="submenu(user.menuItemId)" style="color: rgb(108, 108, 194);"></clr-icon> </clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<span style="cursor: pointer;padding: 10px; "><clr-icon shape="trash" (click)="onDelete(user)" class="red is-error" style="color: red;"></clr-icon></span>
|
||||
<clr-signpost>
|
||||
<span class="mm-icon-action" clrSignpostTrigger><clr-icon shape="help"
|
||||
class="mm-icon-help"></clr-icon></span>
|
||||
<span style="cursor: pointer;" clrSignpostTrigger><clr-icon shape="help" class="success" style="color: rgb(0, 130, 236);"></clr-icon></span>
|
||||
<clr-signpost-content [clrPosition]="'left-middle'" *clrIfOpen>
|
||||
<h5 style="margin-top: 0">{{'WHO_COLUMN'|translate}} </h5>
|
||||
<div>{{'ACCOUNT_ID'|translate}} <code class="clr-code">{{user.accountId}}</code></div>
|
||||
@@ -327,16 +238,17 @@
|
||||
<button class="action-item" *ngIf="mdelete == 'true'" (click)="onDelete(user)">Delete<clr-icon shape="trash" class="is-error"></clr-icon></button>
|
||||
</clr-dg-action-overflow> -->
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<div class="mm-detail">
|
||||
<div class="mm-detail__row"><span>Menu Name</span><strong>{{user.menuItemDesc}}</strong></div>
|
||||
<div class="mm-detail__row"><span>Action Link</span><strong>{{user.main_menu_action_name}}</strong></div>
|
||||
<div class="mm-detail__row"><span>Module</span><strong>{{user.moduleName}}</strong></div>
|
||||
</div>
|
||||
<clr-dg-row-detail *clrIfExpanded >
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">Menu Name: </td>
|
||||
<td class="td-content">{{user.menuItemDesc}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</clr-dg-row-detail>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer class="mm-grid-footer">
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Users per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
@@ -344,37 +256,8 @@
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
|
||||
<div *ngIf="viewMode==='cards'">
|
||||
<div class="mm-cards">
|
||||
<div class="mm-card-item" *ngFor="let user of filteredMenus; let i = index">
|
||||
<div class="mm-card-item__header">
|
||||
<!-- <div class="mm-card-item__icon"><clr-icon [shape]="getIconShape(user)"></clr-icon></div> -->
|
||||
<div class="mm-card-item__title">{{user.menuItemDesc}}</div>
|
||||
<div class="mm-card-item__badge" [class.mm-badge--success]="user.status==='Enable'"
|
||||
[class.mm-badge--muted]="user.status!=='Enable'">{{user.status}}</div>
|
||||
</div>
|
||||
<div class="mm-card-item__body">
|
||||
<div class="mm-kv"><span>ID</span><strong>{{user.menuId}}</strong></div>
|
||||
<div class="mm-kv"><span>Sequence</span><strong>{{user.itemSeq}}</strong></div>
|
||||
<div class="mm-kv"><span>Module</span><strong>{{user.moduleName}}</strong></div>
|
||||
<div class="mm-kv mm-link"><clr-icon shape="link"></clr-icon><strong>{{user.main_menu_action_name}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mm-card-item__footer">
|
||||
<button class="btn btn-sm btn-outline" (click)="goToEdit(user)"><clr-icon shape="edit"></clr-icon>
|
||||
Edit</button>
|
||||
<button class="btn btn-sm btn-outline" (click)="onDelete(user)"><clr-icon shape="trash"></clr-icon>
|
||||
Delete</button>
|
||||
<button class="btn btn-sm" (click)="submenu(user.menuItemId)"><clr-icon shape="bullet-list"></clr-icon>
|
||||
Submenu</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-modal class="mm-modal" [(clrModalOpen)]="modalAdd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Add Menu Maintenance</h3>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
|
||||
@@ -391,28 +274,24 @@
|
||||
<label for="name">Menu Item Name<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" formControlName="menuItemDesc">
|
||||
<div *ngIf="submitted && entryForm.controls.menuItemDesc.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.menuItemDesc.errors.required" class="error_mess">*This field
|
||||
is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.menuItemDesc.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Sequence</label>
|
||||
<input type="text" class="clr-input" formControlName="itemSeq">
|
||||
<div *ngIf="submitted && entryForm.controls.itemSeq.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.itemSeq.errors.required" class="error_mess">*This field is
|
||||
Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.itemSeq.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
<div *ngIf="submitted && entryForm.controls.itemSeq.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.itemSeq.errors.pattern" class="error_mess">*Required Only
|
||||
Number</div>
|
||||
<div *ngIf="submitted && entryForm.controls.itemSeq.errors.pattern" class="error_mess">*Required Only Number</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Module Name</label>
|
||||
<input type="text" class="clr-input" formControlName="moduleName">
|
||||
<div *ngIf="submitted && entryForm.controls.moduleName.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.moduleName.errors.required" class="error_mess">*This field is
|
||||
Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.moduleName.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
@@ -422,16 +301,14 @@
|
||||
<option value="Disable">Disable</option>
|
||||
</select>
|
||||
<div *ngIf="submitted && entryForm.controls.status.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.status.errors.required" class="error_mess">*This field is
|
||||
Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.status.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Menu Action Link</label>
|
||||
<input type="text" class="clr-input" formControlName="main_menu_action_name">
|
||||
<div *ngIf="submitted && entryForm.controls.main_menu_action_name.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.main_menu_action_name.errors.required" class="error_mess">
|
||||
*This field is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.main_menu_action_name.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
<!-- <select NAME="menu_id" >
|
||||
<option SELECTED >Home Menu
|
||||
@@ -476,35 +353,34 @@
|
||||
<label for="tags">Menu Icon Name</label>
|
||||
<input type="text" class="clr-input" formControlName="main_menu_icon_name">
|
||||
<div *ngIf="submitted && entryForm.controls.main_menu_icon_name.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.main_menu_icon_name.errors.required" class="error_mess">*This
|
||||
field is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.main_menu_icon_name.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modalAdd = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">ADD</button>
|
||||
<button type="submit" class="btn btn-primary" >ADD</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal class="mm-modal" [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
|
||||
<div class="modal-body" *ngIf="rowSelected.menuItemId">
|
||||
<h1 class="delete">Are You Sure Want to delete?</h1>
|
||||
<h2 class="heading">{{rowSelected.menuItemId}}</h2>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
|
||||
<button type="submit" (click)="delete(rowSelected.menuItemId)" class="btn btn-primary">Delete</button>
|
||||
<button type="submit" (click)="delete(rowSelected.menuItemId)" class="btn btn-primary" >Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
|
||||
<clr-modal class="mm-modal" [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<clr-modal [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Update Menu Maintenance</h3>
|
||||
<div class="modal-body" *ngIf="rowSelected.menuItemId">
|
||||
<h2 class="heading">{{rowSelected.menuItemId}}</h2>
|
||||
@@ -536,19 +412,17 @@
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Menu Action Link</label>
|
||||
<input type="text" class="clr-input" name="main_menu_action_name"
|
||||
[(ngModel)]="rowSelected.main_menu_action_name">
|
||||
<input type="text" class="clr-input" name="main_menu_action_name" [(ngModel)]="rowSelected.main_menu_action_name">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Menu Icon Name </label>
|
||||
<input type="text" class="clr-input" name="main_menu_icon_name"
|
||||
[(ngModel)]="rowSelected.main_menu_icon_name">
|
||||
<input type="text" class="clr-input" name="main_menu_icon_name" [(ngModel)]="rowSelected.main_menu_icon_name">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaledit = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
<button type="submit" class="btn btn-primary" >Update</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -556,14 +430,12 @@
|
||||
</clr-modal>
|
||||
|
||||
|
||||
<clr-modal class="mm-modal" [(clrModalOpen)]="modalCsv" [clrModalSize]="'sm'" [clrModalStaticBackdrop]="false">
|
||||
<clr-modal [(clrModalOpen)]="modalCsv" [clrModalSize]="'sm'" [clrModalStaticBackdrop]="false">
|
||||
<h3 class="modal-title">Import File</h3>
|
||||
<div class="modal-body">
|
||||
<input type="file" name="file" class="file" (change)="selectFile($event)"
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
|
||||
<input type="file" name="file" class="file" (change)="selectFile($event)" accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" type="button" [disabled]="!selectedFiles" (click)="saveCsv()">Import</button>
|
||||
</div>
|
||||
</clr-modal>
|
||||
</div>
|
||||
@@ -60,591 +60,3 @@ select{
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Modern theme-aware enhancements */
|
||||
.mm-container {
|
||||
background: var(--theme-surface);
|
||||
border-radius: var(--theme-border-radius);
|
||||
box-shadow: var(--theme-shadow);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.mm-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: var(--theme-glass-bg);
|
||||
backdrop-filter: blur(12px);
|
||||
border: 1px solid var(--theme-glass-border);
|
||||
border-radius: calc(var(--theme-border-radius) + 4px);
|
||||
padding: 1rem 1.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
box-shadow: var(--theme-glass-shadow);
|
||||
}
|
||||
|
||||
.mm-hero__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.mm-hero__icon clr-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: var(--theme-primary);
|
||||
filter: drop-shadow(0 4px 10px rgba(0,0,0,0.15));
|
||||
}
|
||||
|
||||
.mm-hero__title {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.2;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mm-hero__subtitle {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.mm-hero__actions .btn + .btn {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.mm-breadcrumb {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.mm-header-row {
|
||||
align-items: center;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.mm-title-wrap {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.mm-title {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
.mm-subtitle {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mm-actions {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mm-btn-group {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mm-btn-primary {
|
||||
border-radius: var(--theme-border-radius);
|
||||
background: var(--theme-primary);
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
|
||||
transition: transform 120ms var(--ease-out, cubic-bezier(0, 0, 0.2, 1)), box-shadow 150ms ease;
|
||||
}
|
||||
|
||||
.mm-btn-primary:hover { box-shadow: 0 4px 10px rgba(0,0,0,0.12); transform: translateY(-1px); }
|
||||
.mm-btn-primary:active { transform: translateY(0); }
|
||||
|
||||
.mm-btn-outline {
|
||||
border-radius: var(--theme-border-radius);
|
||||
border: 1px solid var(--theme-primary);
|
||||
color: var(--theme-primary);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.mm-btn-outline:hover { background: var(--theme-primary-100); }
|
||||
|
||||
.mm-btn-secondary {
|
||||
border-radius: var(--theme-border-radius);
|
||||
background: var(--theme-secondary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.mm-btn-text {
|
||||
margin-left: 0.35rem;
|
||||
}
|
||||
|
||||
.mm-grid {
|
||||
background: var(--theme-surface);
|
||||
border-radius: var(--theme-border-radius);
|
||||
box-shadow: var(--theme-shadow);
|
||||
}
|
||||
.mm-grid--modern .datagrid-header {
|
||||
background: linear-gradient(135deg, var(--theme-primary-50), transparent);
|
||||
}
|
||||
|
||||
.mm-col-title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mm-col--icon { width: 44px; }
|
||||
.mm-col--no { width: 70px; }
|
||||
.mm-col--name { min-width: 220px; }
|
||||
.mm-col--id { width: 120px; }
|
||||
.mm-col--seq { width: 120px; }
|
||||
.mm-col--module { min-width: 160px; }
|
||||
.mm-col--link { min-width: 220px; }
|
||||
.mm-col--status { width: 140px; }
|
||||
.mm-col--submenu { width: 100px; }
|
||||
.mm-col--action { width: 140px; }
|
||||
|
||||
.mm-card {
|
||||
background: var(--theme-glass-bg);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid var(--theme-glass-border);
|
||||
border-radius: var(--theme-border-radius);
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.mm-grid-footer {
|
||||
border-top: 1px solid rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
.mm-col--icon,
|
||||
.mm-cell--icon {
|
||||
max-width: 40px;
|
||||
}
|
||||
|
||||
.mm-row:hover {
|
||||
background: var(--theme-primary-50);
|
||||
}
|
||||
|
||||
.mm-icon-action {
|
||||
cursor: pointer;
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
transition: background 150ms ease-out, transform 150ms ease-out;
|
||||
}
|
||||
|
||||
.mm-icon-action:hover {
|
||||
background: var(--theme-primary-100);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.mm-icon-edit {
|
||||
color: var(--theme-accent);
|
||||
}
|
||||
|
||||
.mm-icon-link {
|
||||
color: var(--theme-secondary);
|
||||
}
|
||||
|
||||
.mm-icon-help {
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
.mm-icon-delete {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.mm-danger:hover {
|
||||
background: rgba(239, 68, 68, 0.12);
|
||||
}
|
||||
|
||||
.mm-modal .modal-body {
|
||||
background: var(--theme-surface);
|
||||
}
|
||||
|
||||
.mm-modal .modal-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Modernize Add/Edit modals */
|
||||
.mm-modal .modal-body form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mm-modal .modal-body .clr-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.mm-modal .modal-body .clr-row { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.mm-modal label {
|
||||
display: inline-block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
.mm-modal input.clr-input,
|
||||
.mm-modal select {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(0,0,0,0.12);
|
||||
background: var(--theme-background);
|
||||
transition: border-color 150ms ease, box-shadow 150ms ease;
|
||||
}
|
||||
|
||||
.mm-modal input.clr-input:focus,
|
||||
.mm-modal select:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px var(--theme-primary-100);
|
||||
}
|
||||
|
||||
.mm-modal .modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.mm-modal .modal-footer .btn.btn-primary {
|
||||
background: var(--theme-primary);
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.mm-modal .modal-footer .btn.btn-outline {
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
}
|
||||
|
||||
.mm-modal .error_mess { color: #ef4444; font-size: 12px; margin-top: 4px; }
|
||||
|
||||
.mm-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.mm-item__avatar clr-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: var(--theme-accent);
|
||||
}
|
||||
|
||||
.mm-item__title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mm-item__meta {
|
||||
font-size: 0.75rem;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.mm-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(0,0,0,0.06);
|
||||
background: var(--theme-primary-50);
|
||||
}
|
||||
|
||||
.mm-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.mm-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--theme-secondary);
|
||||
color: white;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.mm-badge--success {
|
||||
background: var(--theme-primary);
|
||||
}
|
||||
|
||||
.mm-badge--muted {
|
||||
background: var(--theme-primary-200);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
.mm-actions-inline .btn {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.mm-detail {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.mm-detail__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* Skeleton loader */
|
||||
.mm-skeleton-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
margin: 8px 0 12px;
|
||||
}
|
||||
|
||||
.mm-skeleton-item {
|
||||
display: grid;
|
||||
grid-template-columns: 44px 1.2fr 0.8fr 0.6fr 1fr 120px 140px;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
background: var(--theme-surface);
|
||||
border-radius: var(--theme-border-radius);
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.mm-skel {
|
||||
height: 12px;
|
||||
border-radius: 6px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(0,0,0,0.05) 25%,
|
||||
rgba(0,0,0,0.08) 37%,
|
||||
rgba(0,0,0,0.05) 63%
|
||||
);
|
||||
background-size: 400% 100%;
|
||||
animation: mm-shimmer 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.mm-skel--icon { width: 24px; height: 24px; border-radius: 50%; }
|
||||
.mm-skel--title { width: 60%; height: 14px; }
|
||||
.mm-skel--meta { width: 40%; }
|
||||
.mm-skel--chip { width: 80px; }
|
||||
.mm-skel--link { width: 60%; }
|
||||
.mm-skel--badge { width: 70px; }
|
||||
.mm-skel--actions { width: 60px; }
|
||||
|
||||
@keyframes mm-shimmer {
|
||||
0% { background-position: 100% 0; }
|
||||
100% { background-position: 0 0; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.mm-skel { animation: none; }
|
||||
}
|
||||
|
||||
/* Row mount animation */
|
||||
.mm-row { transition: transform 220ms var(--ease-out, cubic-bezier(0, 0, 0.2, 1)), background 200ms ease; }
|
||||
.mm-row.ng-enter { transform: translateY(8px); opacity: 0.001; }
|
||||
.mm-row.ng-enter-active { transform: translateY(0); opacity: 1; }
|
||||
|
||||
/* Responsive layouts */
|
||||
@media (max-width: 1024px) {
|
||||
.mm-col--id, .mm-col--seq, .mm-col--submenu { display: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.mm-col--link { display: none; }
|
||||
.mm-item__meta { display: none; }
|
||||
.mm-actions-inline .btn { padding: 0 6px; }
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.mm-col--action { width: 100px; }
|
||||
.mm-col--status { width: 110px; }
|
||||
.mm-hero { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
|
||||
.mm-hero__actions { width: 100%; display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 6px; }
|
||||
}
|
||||
|
||||
/* Sticky toolbar */
|
||||
.mm-toolbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 8px;
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
border-radius: var(--theme-border-radius);
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.mm-search {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border: 1px solid rgba(0,0,0,0.08);
|
||||
padding: 6px 8px;
|
||||
border-radius: 999px;
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
.mm-search__input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.mm-select {
|
||||
border-radius: 999px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid rgba(0,0,0,0.08);
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.mm-search__input { min-width: 140px; }
|
||||
}
|
||||
|
||||
.mm-view-toggle .btn { margin-left: 6px; border-radius: 999px; }
|
||||
|
||||
/* Card view */
|
||||
.mm-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) { .mm-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
||||
@media (max-width: 640px) { .mm-cards { grid-template-columns: 1fr; } }
|
||||
|
||||
.mm-card-item {
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0,0,0,0.06);
|
||||
border-radius: var(--theme-border-radius);
|
||||
box-shadow: var(--theme-shadow);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mm-card-item__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
background: linear-gradient(135deg, var(--theme-primary-50), transparent);
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.mm-card-item__icon clr-icon { color: var(--theme-primary); width: 18px; height: 18px; }
|
||||
.mm-card-item__title { font-weight: 700; flex: 1 1 auto; }
|
||||
.mm-card-item__badge { margin-left: auto; }
|
||||
|
||||
/* Prevent overlaps and long text issues */
|
||||
.mm-ellipsis {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mm-card-item__title {
|
||||
max-width: 60%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.mm-card-item__title { max-width: 54%; }
|
||||
}
|
||||
|
||||
.mm-card-item__body {
|
||||
padding: 10px 12px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0,1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) { .mm-card-item__body { grid-template-columns: 1fr; } }
|
||||
|
||||
.mm-kv { display: flex; justify-content: space-between; }
|
||||
.mm-kv span { color: var(--theme-text-secondary); }
|
||||
|
||||
.mm-card-item__footer {
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
border-top: 1px solid rgba(0,0,0,0.06);
|
||||
}
|
||||
|
||||
/* Theme the card footer buttons */
|
||||
.mm-card-item__footer .btn {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.mm-card-item__footer .btn.btn-outline {
|
||||
border: 1px solid var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.mm-card-item__footer .btn.btn-outline:hover { background: rgba(0,0,0,0.04); }
|
||||
|
||||
.mm-card-item__footer .btn:not(.btn-outline) {
|
||||
background: var(--theme-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.mm-card-item__footer .btn:not(.btn-outline):hover {
|
||||
filter: brightness(0.98);
|
||||
}
|
||||
|
||||
/* View toggle buttons */
|
||||
.mm-view-toggle .btn.btn-primary { background: var(--theme-primary); color: #fff; }
|
||||
.mm-view-toggle .btn:not(.btn-primary) { background: var(--theme-primary-100); color: var(--theme-text); }
|
||||
|
||||
.mm-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin: 0.75rem 0 1rem;
|
||||
}
|
||||
|
||||
.mm-stat {
|
||||
background: var(--theme-surface);
|
||||
border-radius: var(--theme-border-radius);
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.mm-stat__value {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
.mm-stat__label {
|
||||
font-size: 0.75rem;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.mm-empty {
|
||||
text-align: center;
|
||||
padding: 1.5rem 0.5rem;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.mm-empty clr-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: var(--theme-secondary);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.mm-empty__title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import { CsvService } from 'src/app/services/csv.service';
|
||||
import { ExcelService } from 'src/app/services/excel.service';
|
||||
import * as moment from 'moment';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
@Component({
|
||||
selector: 'app-menumaintance',
|
||||
templateUrl: './menumaintance.component.html',
|
||||
@@ -32,10 +31,6 @@ export class MenumaintanceComponent implements OnInit {
|
||||
showdata;
|
||||
error;
|
||||
submitted = false;
|
||||
// Quick filter UI state (no API/logic changes)
|
||||
filterText = '';
|
||||
statusFilter: 'All' | 'Enable' | 'Disable' | '' = 'All';
|
||||
viewMode: 'cards' | 'table' = 'cards';
|
||||
constructor(private menuservice: MenumaintanceService,
|
||||
private toastr: ToastrService,
|
||||
private excel: ExcelService,
|
||||
@@ -44,14 +39,9 @@ export class MenumaintanceComponent implements OnInit {
|
||||
private menuGroupService: MenuGroupService,
|
||||
private csvService: CsvService,
|
||||
private translate: TranslateService,
|
||||
private router: Router,
|
||||
private themeService: ThemeService) { }
|
||||
private router: Router,) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// Ensure theme variables are applied; subscription keeps this view reactive to theme changes
|
||||
this.themeService.currentTheme$.subscribe(() => {
|
||||
// Theme applied globally via CSS variables; no additional handling needed here
|
||||
});
|
||||
this.showdata = this.menuGroupService.getdata();
|
||||
console.log(this.showdata);
|
||||
this.mcreate = this.showdata.mcreate;
|
||||
@@ -79,71 +69,6 @@ export class MenumaintanceComponent implements OnInit {
|
||||
this.getdata();
|
||||
}
|
||||
|
||||
// Stats for UI (template-safe, no inline arrow functions)
|
||||
get totalMenus(): number {
|
||||
return this.menus ? this.menus.length : 0;
|
||||
}
|
||||
|
||||
get enabledMenusCount(): number {
|
||||
const list: any[] = (this.menus as unknown as any[]) || [];
|
||||
return list.filter(menu => menu && menu.status === 'Enable').length;
|
||||
}
|
||||
|
||||
get disabledMenusCount(): number {
|
||||
const list: any[] = (this.menus as unknown as any[]) || [];
|
||||
return list.filter(menu => menu && menu.status === 'Disable').length;
|
||||
}
|
||||
|
||||
// Filtered list for view
|
||||
get filteredMenus(): Rn_Main_Menu[] {
|
||||
const items: any[] = (this.menus as unknown as any[]) || [];
|
||||
const text = (this.filterText || '').toLowerCase();
|
||||
const status = this.statusFilter;
|
||||
return items.filter(m => {
|
||||
const matchText = !text || (
|
||||
(m.menuItemDesc || '').toLowerCase().includes(text) ||
|
||||
(m.moduleName || '').toLowerCase().includes(text) ||
|
||||
(m.main_menu_action_name || '').toLowerCase().includes(text)
|
||||
);
|
||||
const matchStatus = !status || status === 'All' || m.status === status;
|
||||
return matchText && matchStatus;
|
||||
});
|
||||
}
|
||||
|
||||
setViewMode(mode: 'cards' | 'table') {
|
||||
this.viewMode = mode;
|
||||
}
|
||||
|
||||
// Resolve a safe Clarity icon shape for a menu item
|
||||
getIconShape(menu: any): string {
|
||||
const raw = (menu?.main_menu_icon_name ?? menu?.mainMenuIconName ?? '').toString().trim();
|
||||
const name = raw.toLowerCase();
|
||||
const invalid = !name || name === 'undefined' || name === 'null' || name === '-' || name === 'na' || name === 'n/a';
|
||||
if (invalid) {
|
||||
return 'file'; // universal fallback icon
|
||||
}
|
||||
// Optional alias normalization
|
||||
const aliasMap: Record<string, string> = {
|
||||
'home': 'home',
|
||||
'dashboard': 'dashboard',
|
||||
'menu': 'list',
|
||||
'list': 'list',
|
||||
'link': 'link',
|
||||
'application': 'application',
|
||||
'applications': 'applications',
|
||||
'module': 'application',
|
||||
'settings': 'cog',
|
||||
'config': 'cog',
|
||||
'user': 'user',
|
||||
'users': 'users',
|
||||
'folder': 'folder',
|
||||
'file': 'file',
|
||||
'tag': 'tag',
|
||||
'bookmark': 'bookmark'
|
||||
};
|
||||
return aliasMap[name] ?? name;
|
||||
}
|
||||
|
||||
switchLanguage(language: string) {
|
||||
this.translate.use(language);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon>Security</a></li>
|
||||
<li><a href="javascript://">Menu Maintenance</a></li>
|
||||
@@ -9,50 +9,22 @@
|
||||
<span class="label label-light-blue" style="display: inline;margin-left: 30px;">Sub Menu</span><br> -->
|
||||
|
||||
|
||||
<section class="mm-hero">
|
||||
<div class="mm-hero__content">
|
||||
<div class="mm-hero__icon"><clr-icon shape="organization"></clr-icon></div>
|
||||
<div>
|
||||
<h2 class="mm-hero__title">Sub-Menu Maintenance</h2>
|
||||
<p class="mm-hero__subtitle">Sub Menu</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mm-hero__actions">
|
||||
<button id="add" class="btn btn-primary mm-btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
<span class="mm-btn-text">Add</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<div class="clr-row" style="margin-top: 15px;">
|
||||
<div class="clr-col-8">
|
||||
<h3 style="font-weight: 300;display: inline;">Sub-Menu Maintenance </h3>
|
||||
<span class="label label-light-blue" style="display: inline;margin-left: 30px;">Sub Menu</span><br>
|
||||
|
||||
<div class="mm-toolbar">
|
||||
<div class="mm-toolbar__left">
|
||||
<div class="mm-search">
|
||||
<clr-icon shape="search"></clr-icon>
|
||||
<input class="mm-search__input" type="text" placeholder="Search" [(ngModel)]="filterText" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mm-toolbar__right">
|
||||
<select class="mm-select" [(ngModel)]="statusFilter">
|
||||
<option value="All">All</option>
|
||||
<option value="Enable">Enabled</option>
|
||||
<option value="Disable">Disabled</option>
|
||||
</select>
|
||||
<div class="mm-view-toggle">
|
||||
<button class="btn btn-sm" [class.btn-primary]="viewMode==='cards'" (click)="setViewMode('cards')">
|
||||
<clr-icon shape="view-cards"></clr-icon>
|
||||
</div>
|
||||
<div class="clr-col-4" style="text-align: right;">
|
||||
<button id="add" class="btn btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon>ADD New
|
||||
</button>
|
||||
<button class="btn btn-sm" [class.btn-primary]="viewMode==='table'" (click)="setViewMode('table')">
|
||||
<clr-icon shape="table"></clr-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="mm-card" *ngIf="viewMode==='table'">
|
||||
<clr-datagrid class="mm-grid mm-grid--modern" [clrDgLoading]="loading">
|
||||
<clr-datagrid [clrDgLoading]="loading" >
|
||||
<clr-dg-placeholder><clr-spinner [clrMedium]="true">Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
|
||||
<clr-dg-column > <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
@@ -77,29 +49,19 @@
|
||||
Status
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-row class="mm-row" *clrDgItems="let user of filteredSubMenus;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-row *clrDgItems="let user of sub;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell >{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<div class="mm-item">
|
||||
<!-- <div class="mm-item__avatar"><clr-icon [shape]="getIconShape(user)"></clr-icon></div> -->
|
||||
<div class="mm-item__text">
|
||||
<div class="mm-item__title">{{user.menuItemDesc}}</div>
|
||||
<div class="mm-item__meta">ID: {{ user.menuId || 'â' }} | Seq: {{ (user.itemSeq === 0 || user.itemSeq) ? user.itemSeq : 'â' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.menuItemDesc}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.menuId}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.itemSeq}}</clr-dg-cell>
|
||||
<clr-dg-cell > {{user.moduleName}} </clr-dg-cell>
|
||||
<clr-dg-cell > {{user.main_menu_action_name}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.status}} </clr-dg-cell>
|
||||
|
||||
<clr-dg-cell class="mm-cell mm-cell--action">
|
||||
<div class="mm-actions-inline">
|
||||
<button class="btn btn-sm btn-outline mm-btn-edit" (click)="goToEdit(user)"><clr-icon shape="edit"></clr-icon></button>
|
||||
<button class="btn btn-sm btn-outline mm-btn-delete" (click)="onDelete(user)"><clr-icon shape="trash"></clr-icon></button>
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-action-overflow>
|
||||
<button class="action-item" (click)="goToEdit(user)">Edit <clr-icon shape="edit" class="is-error"></clr-icon></button>
|
||||
<button class="action-item" (click)="onDelete(user)">Delete<clr-icon shape="trash" class="is-error"></clr-icon></button>
|
||||
</clr-dg-action-overflow>
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded >
|
||||
<table class="table">
|
||||
@@ -111,7 +73,7 @@
|
||||
</clr-dg-row-detail>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer class="mm-grid-footer">
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Users per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
@@ -119,31 +81,8 @@
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
|
||||
<div *ngIf="viewMode==='cards'">
|
||||
<div class="mm-cards">
|
||||
<div class="mm-card-item" *ngFor="let user of filteredSubMenus; let i = index">
|
||||
<div class="mm-card-item__header">
|
||||
<!-- <div class="mm-card-item__icon"><clr-icon [shape]="getIconShape(user)"></clr-icon></div> -->
|
||||
<div class="mm-card-item__title">{{user.menuItemDesc}}</div>
|
||||
<div class="mm-card-item__badge" [class.mm-badge--success]="user.status==='Enable'" [class.mm-badge--muted]="user.status!=='Enable'">{{user.status}}</div>
|
||||
</div>
|
||||
<div class="mm-card-item__body">
|
||||
<div class="mm-kv"><span>ID</span><strong>{{ user.menuId || 'â' }}</strong></div>
|
||||
<div class="mm-kv"><span>Sequence</span><strong>{{ (user.itemSeq === 0 || user.itemSeq) ? user.itemSeq : 'â' }}</strong></div>
|
||||
<div class="mm-kv"><span>Module</span><strong class="mm-ellipsis">{{ user.moduleName || 'â' }}</strong></div>
|
||||
<div class="mm-kv mm-link"><clr-icon shape="link"></clr-icon><strong class="mm-ellipsis">{{ user.main_menu_action_name || 'â' }}</strong></div>
|
||||
</div>
|
||||
<div class="mm-card-item__footer">
|
||||
<button class="btn btn-sm btn-outline mm-btn-edit" (click)="goToEdit(user)"><clr-icon shape="edit"></clr-icon> Edit</button>
|
||||
<button class="btn btn-sm btn-outline mm-btn-delete" (click)="onDelete(user)"><clr-icon shape="trash"></clr-icon> Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-modal class="mm-modal" [(clrModalOpen)]="modalAdd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Add Sub Menu Maintenance</h3>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
|
||||
@@ -242,7 +181,7 @@
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modalAdd = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">ADD</button>
|
||||
<button type="submit" class="btn btn-primary" >ADD</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -262,7 +201,7 @@
|
||||
</clr-modal>
|
||||
|
||||
|
||||
<clr-modal class="mm-modal" [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<clr-modal [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Update Sub Menu Maintenance</h3>
|
||||
<div class="modal-body" *ngIf="rowSelected.menuItemId">
|
||||
<h2 class="heading">{{rowSelected.menuItemId}}</h2>
|
||||
@@ -301,7 +240,7 @@
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaledit = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
<button type="submit" class="btn btn-primary" >Update</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,88 +1,3 @@
|
||||
@import '../../../../../styles/design-tokens';
|
||||
|
||||
.mm-breadcrumb { margin-bottom: 0.75rem; }
|
||||
.mm-modal .modal-body { background: var(--theme-surface); }
|
||||
.mm-modal .modal-title { font-weight: 600; }
|
||||
.mm-modal .modal-body .clr-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; }
|
||||
@media (max-width: 640px) { .mm-modal .modal-body .clr-row { grid-template-columns: 1fr; } }
|
||||
.mm-modal label { display: inline-block; margin-bottom: 6px; font-weight: 600; color: var(--theme-text); }
|
||||
.mm-modal input.clr-input, .mm-modal select { width: 100%; padding: 10px 12px; border-radius: 10px; border: 1px solid rgba(0,0,0,0.12); background: var(--theme-background); transition: border-color 150ms ease, box-shadow 150ms ease; }
|
||||
.mm-modal input.clr-input:focus, .mm-modal select:focus { outline: none; border-color: var(--theme-primary); box-shadow: 0 0 0 3px var(--theme-primary-100); }
|
||||
.mm-modal .modal-footer { display: flex; justify-content: flex-end; gap: 10px; }
|
||||
.mm-modal .modal-footer .btn.btn-primary { background: var(--theme-primary); color: #fff; border-radius: 10px; }
|
||||
.mm-modal .modal-footer .btn.btn-outline { border-radius: 10px; border: 1px solid var(--theme-secondary); color: var(--theme-secondary); }
|
||||
.mm-modal .error_mess { color: #ef4444; font-size: 12px; margin-top: 4px; }
|
||||
|
||||
.mm-hero {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
background: var(--theme-glass-bg); backdrop-filter: blur(12px);
|
||||
border: 1px solid var(--theme-glass-border);
|
||||
border-radius: calc(var(--theme-border-radius) + 4px);
|
||||
padding: 1rem 1.25rem; margin-bottom: 0.75rem; box-shadow: var(--theme-glass-shadow);
|
||||
}
|
||||
.mm-hero__content { display: flex; align-items: center; gap: 0.75rem; }
|
||||
.mm-hero__icon clr-icon { width: 28px; height: 28px; color: var(--theme-primary); }
|
||||
.mm-hero__title { font-size: 1.25rem; margin: 0; }
|
||||
.mm-hero__subtitle { margin: 0; font-size: 0.875rem; color: var(--theme-text-secondary); }
|
||||
.mm-hero__actions .btn + .btn { margin-left: 0.5rem; }
|
||||
|
||||
.mm-btn-primary { border-radius: var(--theme-border-radius); background: var(--theme-primary); color: #fff; }
|
||||
.mm-btn-text { margin-left: 0.35rem; }
|
||||
|
||||
.mm-toolbar { position: sticky; top: 0; z-index: 10; display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 8px 10px; margin-bottom: 8px; background: var(--theme-surface); border: 1px solid rgba(0,0,0,0.05); border-radius: var(--theme-border-radius); box-shadow: 0 1px 0 rgba(0,0,0,0.03); }
|
||||
.mm-search { display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(0,0,0,0.08); padding: 6px 8px; border-radius: 999px; background: var(--theme-background); }
|
||||
.mm-search__input { border: none; outline: none; background: transparent; min-width: 220px; }
|
||||
.mm-select { border-radius: 999px; padding: 6px 10px; border: 1px solid rgba(0,0,0,0.08); background: var(--theme-background); }
|
||||
.mm-view-toggle .btn { margin-left: 6px; border-radius: 999px; }
|
||||
|
||||
.mm-card { background: var(--theme-glass-bg); backdrop-filter: blur(10px); border: 1px solid var(--theme-glass-border); border-radius: var(--theme-border-radius); padding: 0.25rem; }
|
||||
.mm-grid { background: var(--theme-surface); border-radius: var(--theme-border-radius); box-shadow: var(--theme-shadow); }
|
||||
.mm-grid--modern .datagrid-header { background: linear-gradient(135deg, var(--theme-primary-50), transparent); }
|
||||
.mm-grid-footer { border-top: 1px solid rgba(0,0,0,0.06); }
|
||||
.mm-row:hover { background: var(--theme-primary-50); }
|
||||
.mm-item { display: flex; align-items: center; gap: 0.75rem; }
|
||||
.mm-item__avatar clr-icon { width: 18px; height: 18px; color: var(--theme-accent); }
|
||||
.mm-item__title { font-weight: 600; }
|
||||
.mm-item__meta { font-size: 0.75rem; color: var(--theme-text-secondary); }
|
||||
.mm-actions-inline .btn { margin-right: 6px; }
|
||||
.mm-actions-inline .mm-btn-edit { border: 1px solid var(--theme-accent); color: var(--theme-accent); }
|
||||
.mm-actions-inline .mm-btn-edit:hover { background: rgba(139, 92, 246, 0.12); }
|
||||
.mm-actions-inline .mm-btn-delete { border: 1px solid #ef4444; color: #ef4444; }
|
||||
.mm-actions-inline .mm-btn-delete:hover { background: rgba(239, 68, 68, 0.12); }
|
||||
|
||||
.mm-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
|
||||
@media (max-width: 1024px) { .mm-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
||||
@media (max-width: 640px) { .mm-cards { grid-template-columns: 1fr; } .mm-search__input { min-width: 140px; } }
|
||||
.mm-card-item { background: var(--theme-surface); border: 1px solid rgba(0,0,0,0.06); border-radius: var(--theme-border-radius); box-shadow: var(--theme-shadow); overflow: hidden; display: flex; flex-direction: column; }
|
||||
.mm-card-item__header { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: linear-gradient(135deg, var(--theme-primary-50), transparent); }
|
||||
.mm-card-item__icon clr-icon { color: var(--theme-primary); width: 18px; height: 18px; }
|
||||
.mm-card-item__title { font-weight: 700; flex: 1 1 auto; max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.mm-card-item__badge { margin-left: auto; }
|
||||
.mm-card-item__body { padding: 10px 12px; display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 8px; }
|
||||
@media (max-width: 640px) { .mm-card-item__body { grid-template-columns: 1fr; } }
|
||||
.mm-kv { display: flex; justify-content: space-between; }
|
||||
.mm-kv span { color: var(--theme-text-secondary); }
|
||||
.mm-card-item__footer { padding: 10px 12px; display: flex; gap: 8px; border-top: 1px solid rgba(0,0,0,0.06); }
|
||||
.mm-card-item__footer .mm-btn-edit { border: 1px solid var(--theme-accent); color: var(--theme-accent); }
|
||||
.mm-card-item__footer .mm-btn-edit:hover { background: rgba(139, 92, 246, 0.12); }
|
||||
.mm-card-item__footer .mm-btn-delete { border: 1px solid #ef4444; color: #ef4444; }
|
||||
.mm-card-item__footer .mm-btn-delete:hover { background: rgba(239, 68, 68, 0.12); }
|
||||
.mm-badge { display: inline-block; padding: 2px 10px; border-radius: 999px; background: var(--theme-secondary); color: #fff; font-size: 0.75rem; }
|
||||
.mm-badge--success { background: var(--theme-primary); }
|
||||
.mm-badge--muted { background: var(--theme-primary-200); color: var(--theme-text); }
|
||||
|
||||
/* Modals */
|
||||
.mm-modal .modal-body { background: var(--theme-surface); }
|
||||
.mm-modal .modal-title { font-weight: 600; }
|
||||
.mm-modal .modal-body .clr-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; }
|
||||
@media (max-width: 640px) { .mm-modal .modal-body .clr-row { grid-template-columns: 1fr; } }
|
||||
.mm-modal label { display: inline-block; margin-bottom: 6px; font-weight: 600; color: var(--theme-text); }
|
||||
.mm-modal input.clr-input, .mm-modal select { width: 100%; padding: 10px 12px; border-radius: 10px; border: 1px solid rgba(0,0,0,0.12); background: var(--theme-background); transition: border-color 150ms ease, box-shadow 150ms ease; }
|
||||
.mm-modal input.clr-input:focus, .mm-modal select:focus { outline: none; border-color: var(--theme-primary); box-shadow: 0 0 0 3px var(--theme-primary-100); }
|
||||
.mm-modal .modal-footer { display: flex; justify-content: flex-end; gap: 10px; }
|
||||
.mm-modal .modal-footer .btn.btn-primary { background: var(--theme-primary); color: #fff; border-radius: 10px; }
|
||||
.mm-modal .modal-footer .btn.btn-outline { border-radius: 10px; border: 1px solid var(--theme-secondary); color: var(--theme-secondary); }
|
||||
.mm-modal .error_mess { color: #ef4444; font-size: 12px; margin-top: 4px; }
|
||||
input[type=text],[type=date],[type=password],[type=number] {
|
||||
width: 100%;
|
||||
padding: 15px 20px;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
import { MenumaintanceService } from '../../../../services/admin/menumaintance.service';
|
||||
import { Rn_Main_Menu } from '../../../../models/builder/Rn_Main_Menu';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
@@ -31,22 +30,13 @@ export class SubmenuComponent implements OnInit {
|
||||
mainid;
|
||||
submitted = false;
|
||||
public entryForm: FormGroup;
|
||||
// UI filter/view state
|
||||
filterText = '';
|
||||
statusFilter: 'All' | 'Enable' | 'Disable' | '' = 'All';
|
||||
viewMode: 'cards' | 'table' = 'cards';
|
||||
|
||||
constructor(private menuservice: MenumaintanceService,
|
||||
private toastr: ToastrService,
|
||||
private _fb: FormBuilder,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private themeService: ThemeService) { }
|
||||
private router: Router,) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.themeService.currentTheme$.subscribe(() => {
|
||||
// Theme CSS variables applied globally
|
||||
});
|
||||
this.id = this.route.snapshot.params["id"];
|
||||
console.log("project mainmenu with id = ", this.id);
|
||||
this.getById(this.id);
|
||||
@@ -65,34 +55,6 @@ export class SubmenuComponent implements OnInit {
|
||||
|
||||
// this.getdata();
|
||||
}
|
||||
|
||||
// Derived/filtered list for view
|
||||
get filteredSubMenus(): any[] {
|
||||
const items: any[] = (this.sub as unknown as any[]) || [];
|
||||
const text = (this.filterText || '').toLowerCase();
|
||||
const status = this.statusFilter;
|
||||
return items.filter(m => {
|
||||
const matchText = !text || (
|
||||
(m.menuItemDesc || '').toLowerCase().includes(text) ||
|
||||
(m.moduleName || '').toLowerCase().includes(text) ||
|
||||
(m.main_menu_action_name || '').toLowerCase().includes(text)
|
||||
);
|
||||
const matchStatus = !status || status === 'All' || m.status === status;
|
||||
return matchText && matchStatus;
|
||||
});
|
||||
}
|
||||
|
||||
setViewMode(mode: 'cards' | 'table') { this.viewMode = mode; }
|
||||
|
||||
// Resolve a safe icon
|
||||
getIconShape(menu: any): string {
|
||||
const raw = (menu?.main_menu_icon_name ?? menu?.mainMenuIconName ?? '').toString().trim();
|
||||
const name = raw.toLowerCase();
|
||||
const invalid = !name || name === 'undefined' || name === 'null' || name === '-' || name === 'na' || name === 'n/a';
|
||||
if (invalid) return 'file';
|
||||
const alias: Record<string, string> = { application:'application', applications:'applications', settings:'cog', config:'cog', user:'user', users:'users', folder:'folder', file:'file', tag:'tag', bookmark:'bookmark', home:'home', dashboard:'dashboard', menu:'list', list:'list', link:'link', module:'application' };
|
||||
return alias[name] ?? name;
|
||||
}
|
||||
getById(id: any) {
|
||||
this.menuservice.getbyid(id).subscribe((data) => {
|
||||
this.sub = data;
|
||||
|
||||
@@ -1,71 +1,47 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon>{{ 'SECURITY' | translate }}</a></li>
|
||||
<li><a href="javascript://">{{'USER_GROUP_MAINTENANCE' | translate}}</a></li>
|
||||
|
||||
</ol>
|
||||
|
||||
<section class="ug-hero">
|
||||
<div class="ug-hero__content">
|
||||
<div class="ug-hero__icon"><clr-icon shape="users"></clr-icon></div>
|
||||
<div>
|
||||
<h2 class="ug-hero__title">{{'USER_GROUP_MAINTENANCE' | translate}}</h2>
|
||||
<p class="ug-hero__subtitle">{{ 'SECURITY' | translate }}</p>
|
||||
|
||||
<div class="dg-wrapper">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col">
|
||||
<h3>{{'USER_GROUP_MAINTENANCE' | translate}}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ug-hero__actions">
|
||||
<button class="ug-btn ug-btn-secondary" (click)="downloadFiles()">
|
||||
<clr-icon shape="download"></clr-icon>
|
||||
<span class="ug-btn-text">{{ 'DOWNLOAD_TEMPLATE' | translate }}</span>
|
||||
</button>
|
||||
<button class="ug-btn ug-btn-secondary" (click)="csvImport()">
|
||||
<clr-icon shape="import"></clr-icon>
|
||||
<span class="ug-btn-text">{{ 'IMPORT' | translate }}</span>
|
||||
</button>
|
||||
<button class="ug-btn ug-btn-secondary" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon>
|
||||
<span class="ug-btn-text">{{ 'EXPORT_XLSX' | translate }}</span>
|
||||
</button>
|
||||
<button id="add" class="ug-btn ug-btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
<span class="ug-btn-text">{{ 'ADD' | translate }}</span>
|
||||
</button>
|
||||
<div class="clr-col" style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<button class="btn text-dark" (click)="downloadFiles()"><b>{{ 'DOWNLOAD_TEMPLATE' | translate }}</b></button>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="ug-toolbar">
|
||||
<div class="ug-toolbar__left">
|
||||
<div class="ug-search">
|
||||
<clr-icon shape="search"></clr-icon>
|
||||
<input class="ug-search__input" type="text" [placeholder]="'SEARCH' | translate" [(ngModel)]="filterText" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ug-toolbar__right">
|
||||
<div class="ug-view-toggle">
|
||||
<button class="ug-btn ug-btn-sm" [class.ug-btn-primary]="viewMode==='cards'" (click)="setViewMode('cards')">
|
||||
<clr-icon shape="view-cards"></clr-icon>
|
||||
<button class="btn btn-primary" (click)="csvImport()">{{ 'IMPORT' | translate }}</button>
|
||||
<button class="btn btn-outline" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon> {{ 'EXPORT_XLSX' | translate }}
|
||||
</button>
|
||||
<button class="ug-btn ug-btn-sm" [class.ug-btn-primary]="viewMode==='table'" (click)="setViewMode('table')">
|
||||
<clr-icon shape="table"></clr-icon>
|
||||
<button id="add" class="btn btn-primary" *ngIf="mcreate == 'true'" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon> {{ 'ADD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-datagrid class="ug-grid" [clrDgLoading]="loading" *ngIf="viewMode==='table'">
|
||||
<clr-dg-placeholder>
|
||||
<ng-template #loadingSpinner>
|
||||
<clr-spinner>{{'LOADING' | translate}} ... </clr-spinner>
|
||||
</ng-template>
|
||||
<div *ngIf="error;else loadingSpinner">{{error}}</div>
|
||||
</clr-dg-placeholder>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder> <ng-template #loadingSpinner><clr-spinner>{{'LOADING' | translate}} ... </clr-spinner></ng-template>
|
||||
<div *ngIf="error;else loadingSpinner">{{error}}</div></clr-dg-placeholder>
|
||||
|
||||
<clr-dg-column [clrDgField]="'usrGrp'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{'USERGROUP_NO' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'groupName'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{'GROUP_NAME' | translate}}
|
||||
@@ -92,32 +68,19 @@
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of filteredGroups;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-row *clrDgItems="let user of givendata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{user.usrGrp}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.groupName}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.groupDesc}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.groupDesc}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.groupLevel}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<span class="ug-status-badge" [class.ug-status-enabled]="user.status === 'E'"
|
||||
[class.ug-status-disabled]="user.status === 'D'">
|
||||
{{user.status === 'E' ? 'Enabled' : 'Disabled'}}
|
||||
</span>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.status}}</clr-dg-cell>
|
||||
<!-- <clr-dg-cell>{{user.usrGrp}}</clr-dg-cell> -->
|
||||
<clr-dg-cell>{{user.updateDateFormated}}</clr-dg-cell>
|
||||
|
||||
<clr-dg-action-overflow>
|
||||
<!-- <button class="ug-action-item" *ngIf="medit == 'true' || medit == true" (click)="goToEdit(user)">
|
||||
<clr-icon shape="edit"></clr-icon>
|
||||
{{'EDIT' | translate}}
|
||||
</button> -->
|
||||
<button class="ug-action-item" (click)="goToEdit(user)">
|
||||
<clr-icon shape="edit"></clr-icon>
|
||||
{{'EDIT' | translate}}
|
||||
</button>
|
||||
<button class="ug-action-item ug-btn-error" (click)="onDelete(user)">
|
||||
<clr-icon shape="trash"></clr-icon>
|
||||
{{'DELETE'|translate}}
|
||||
</button>
|
||||
|
||||
<button class="action-item" *ngIf="medit == 'true'" (click)="goToEdit(user)"> {{'EDIT' | translate}}</button>
|
||||
<button class="action-item" (click)="onDelete(user)">{{'DELETE'|translate}}<clr-icon shape="trash" class="is-error"></clr-icon></button>
|
||||
</clr-dg-action-overflow>
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
@@ -126,195 +89,136 @@
|
||||
<td class="td-title">username</td>
|
||||
<td class="td-content">{{user.groupName}}</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
</clr-dg-row-detail>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer class="ug-grid-footer">
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
||||
<div class="ug-cards" *ngIf="viewMode==='cards'">
|
||||
<div class="ug-card-item" *ngFor="let user of filteredGroups; let i = index">
|
||||
<div class="ug-card-item__header">
|
||||
<div class="ug-card-item__icon"><clr-icon shape="users"></clr-icon></div>
|
||||
|
||||
<div class="ug-card-item__title">{{user.groupName}}</div>
|
||||
<div class="ug-card-item__badge" [class.ug-status-enabled]="user.status === 'E'"
|
||||
[class.ug-status-disabled]="user.status === 'D'">
|
||||
{{user.status === 'E' ? 'Enabled' : 'Disabled'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ug-card-item__body">
|
||||
<div class="ug-kv"><span>ID</span><strong>{{user.usrGrp}}</strong></div>
|
||||
<div class="ug-kv"><span>Desc</span><strong>{{user.groupDesc}}</strong></div>
|
||||
<div class="ug-kv"><span>Level</span><strong>{{user.groupLevel}}</strong></div>
|
||||
<div class="ug-kv"><span>Updated</span><strong>{{user.updateDateFormated}}</strong></div>
|
||||
</div>
|
||||
<div class="ug-card-item__footer">
|
||||
<!-- <button class="ug-btn ug-btn-sm ug-btn-outline" *ngIf="medit == 'true' || medit == true" (click)="goToEdit(user)">
|
||||
<clr-icon shape="edit"></clr-icon> Edit
|
||||
</button> -->
|
||||
<button class="ug-btn ug-btn-sm ug-btn-outline" (click)="goToEdit(user)">
|
||||
<clr-icon shape="edit"></clr-icon> Edit
|
||||
</button>
|
||||
<button class="ug-btn ug-btn-sm ug-btn-error" (click)="onDelete(user)">
|
||||
<clr-icon shape="trash"></clr-icon> Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Add User Group Maintenance</h3>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="groupName" class="ug-form-label">User Group<span class="required-field">*</span></label>
|
||||
<input type="text" id="groupName" class="ug-form-input" formControlName="groupName">
|
||||
<div *ngIf="submitted && entryForm.controls.groupName.errors" class="ug-form-error">
|
||||
<div *ngIf="submitted && entryForm.controls.groupName.errors.required">*This field is Required</div>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">User Group<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" formControlName="groupName">
|
||||
<div *ngIf="submitted && entryForm.controls.groupName.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.groupName.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="groupDesc" class="ug-form-label">Description<span class="required-field">*</span></label>
|
||||
<input type="text" id="groupDesc" class="ug-form-input" formControlName="groupDesc">
|
||||
<div *ngIf="submitted && entryForm.controls.groupDesc.errors" class="ug-form-error">
|
||||
<div *ngIf="submitted && entryForm.controls.groupDesc.errors.required">*This field is Required</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Description<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" formControlName="groupDesc">
|
||||
<div *ngIf="submitted && entryForm.controls.groupDesc.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.groupDesc.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="status" class="ug-form-label">Status<span class="required-field">*</span></label>
|
||||
<select id="status" class="ug-form-select" formControlName="status">
|
||||
<option value="">Select Status</option>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Status<span class="required-field">*</span></label>
|
||||
<select id="" formControlName="status">
|
||||
<option value="E">Enable</option>
|
||||
<option value="D">Disable</option>
|
||||
<option value="D">Disable</option></select>
|
||||
<div *ngIf="submitted && entryForm.controls.status.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.status.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Group Level<span class="required-field">*</span></label>
|
||||
<select id="" formControlName="groupLevel">
|
||||
<option >10</option>
|
||||
<option >20</option>
|
||||
<option >30</option>
|
||||
<option >40</option>
|
||||
<option>50</option>
|
||||
</select>
|
||||
<div *ngIf="submitted && entryForm.controls.status.errors" class="ug-form-error">
|
||||
<div *ngIf="submitted && entryForm.controls.status.errors.required">*This field is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.groupLevel.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.groupLevel.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="groupLevel" class="ug-form-label">Group Level<span class="required-field">*</span></label>
|
||||
<select id="groupLevel" class="ug-form-select" formControlName="groupLevel">
|
||||
<option value="">Select Level</option>
|
||||
<option value="10">10</option>
|
||||
<option value="20">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="40">40</option>
|
||||
<option value="50">50</option>
|
||||
</select>
|
||||
<div *ngIf="submitted && entryForm.controls.groupLevel.errors" class="ug-form-error">
|
||||
<div *ngIf="submitted && entryForm.controls.groupLevel.errors.required">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="ug-btn ug-btn-outline" (click)="modalAdd = false">Cancel</button>
|
||||
<button type="submit" class="ug-btn ug-btn-primary">ADD</button>
|
||||
<button type="button" class="btn btn-outline" (click)="modalAdd = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary" >ADD</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Update User Group Maintenance</h3>
|
||||
|
||||
|
||||
<div class="modal-body" *ngIf="rowSelected.usrGrp">
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="editUsrGrp" class="ug-form-label">User Group ID</label>
|
||||
<input type="text" id="editUsrGrp" class="ug-form-input" [(ngModel)]="rowSelected.usrGrp" name="usrGrp" disabled>
|
||||
<h2 class="heading">{{rowSelected.usrGrp}}</h2>
|
||||
<form (ngSubmit)="onUpdate(rowSelected.usrGrp)">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">User Group<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="rowSelected.groupName" name="groupName">
|
||||
</div>
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="editGroupName" class="ug-form-label">User Group<span class="required-field">*</span></label>
|
||||
<input type="text" id="editGroupName" class="ug-form-input" [(ngModel)]="rowSelected.groupName" name="groupName">
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Description<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="rowSelected.groupDesc" name="groupDesc">
|
||||
</div>
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="editGroupDesc" class="ug-form-label">Description<span class="required-field">*</span></label>
|
||||
<input type="text" id="editGroupDesc" class="ug-form-input" [(ngModel)]="rowSelected.groupDesc" name="groupDesc">
|
||||
</div>
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="editStatus" class="ug-form-label">Status<span class="required-field">*</span></label>
|
||||
<select id="editStatus" class="ug-form-select" [(ngModel)]="rowSelected.status" name="status">
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Status<span class="required-field">*</span></label>
|
||||
<select id="" [(ngModel)]="rowSelected.status" name="status">
|
||||
<option value="E">Enable</option>
|
||||
<option value="D">Disable</option>
|
||||
<option value="D">Disable</option></select>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Group Level<span class="required-field">*</span></label>
|
||||
<select id="" [(ngModel)]="rowSelected.groupLevel" name="groupLevel">
|
||||
<option >10</option>
|
||||
<option >20</option>
|
||||
<option >30</option>
|
||||
<option >40</option>
|
||||
<option>50</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="ug-form-group">
|
||||
<label for="editGroupLevel" class="ug-form-label">Group Level<span class="required-field">*</span></label>
|
||||
<select id="editGroupLevel" class="ug-form-select" [(ngModel)]="rowSelected.groupLevel" name="groupLevel">
|
||||
<option value="10">10</option>
|
||||
<option value="20">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="40">40</option>
|
||||
<option value="50">50</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="ug-btn ug-btn-outline" (click)="modaledit = false">Cancel</button>
|
||||
<button type="submit" (click)="onUpdate(rowSelected.usrGrp)" class="ug-btn ug-btn-primary">Update</button>
|
||||
<button type="button" class="btn btn-outline" (click)="modaledit = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary" >Update</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
</clr-modal>
|
||||
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
|
||||
<div class="modal-body" *ngIf="rowSelected.usrGrp">
|
||||
<div class="ug-delete-header">
|
||||
<div class="ug-delete-icon">
|
||||
<clr-icon shape="exclamation-triangle" size="48"></clr-icon>
|
||||
</div>
|
||||
<h1 class="ug-delete-title">Are You Sure Want to Delete?</h1>
|
||||
<p class="ug-delete-subtitle">This action cannot be undone</p>
|
||||
</div>
|
||||
|
||||
<div class="ug-delete-details">
|
||||
<div class="ug-delete-detail-item">
|
||||
<span class="ug-delete-detail-label">User Group ID:</span>
|
||||
<span class="ug-delete-detail-value">{{rowSelected.usrGrp}}</span>
|
||||
</div>
|
||||
<div class="ug-delete-detail-item">
|
||||
<span class="ug-delete-detail-label">Group Name:</span>
|
||||
<span class="ug-delete-detail-value">{{rowSelected.groupName}}</span>
|
||||
</div>
|
||||
<div class="ug-delete-detail-item">
|
||||
<span class="ug-delete-detail-label">Description:</span>
|
||||
<span class="ug-delete-detail-value">{{rowSelected.groupDesc}}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h1 class="delete">Are You Sure Want to delete?</h1>
|
||||
<h2 class="heading">{{rowSelected.usrGrp}}</h2>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="ug-btn ug-btn-outline" (click)="modaldelete = false">Cancel</button>
|
||||
<button type="submit" (click)="delete(rowSelected.usrGrp)" class="ug-btn ug-btn-error">Delete</button>
|
||||
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
|
||||
<button type="submit" (click)="delete(rowSelected.usrGrp)" class="btn btn-primary" >Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modalCsv" [clrModalSize]="'sm'" [clrModalStaticBackdrop]="false">
|
||||
<h3 class="modal-title">Import File</h3>
|
||||
<div class="modal-body">
|
||||
<div class="ug-form-group">
|
||||
<label class="ug-form-label">Select CSV File</label>
|
||||
<input type="file" name="file" class="ug-file-input" (change)="selectFile($event)"
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
|
||||
</div>
|
||||
<input type="file" name="file" class="file" (change)="selectFile($event)" accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="ug-btn ug-btn-outline" type="button" (click)="modalCsv = false">Cancel</button>
|
||||
<button class="ug-btn ug-btn-primary" type="button" [disabled]="!selectedFiles" (click)="saveCsv()">Import</button>
|
||||
<button class="btn btn-primary" type="button" [disabled]="!selectedFiles" (click)="saveCsv()">Import</button>
|
||||
</div>
|
||||
</clr-modal>
|
||||
@@ -1,748 +1,8 @@
|
||||
@import '../../../../../styles.scss';
|
||||
|
||||
// Import design tokens
|
||||
@import '../../../../../styles/design-tokens';
|
||||
|
||||
// User Group Maintenance Styles
|
||||
.ug-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
clr-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: var(--theme-font-secondary);
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
@import '../../../../../styles1.scss';
|
||||
input.ng-invalid.ng-touched {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.ug-btn-text {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
// Modern Button Styles using ThemeService
|
||||
.ug-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: var(--theme-font-primary);
|
||||
z-index: 1;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--theme-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.ug-btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.ug-btn-md {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&.ug-btn-lg {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
// Variants
|
||||
&.ug-btn-primary {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, var(--theme-primary, #0284c7) 0%, var(--theme-accent, #7c3aed) 100%);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
&.ug-btn-secondary {
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
border-color: rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
border-color: rgba(0, 0, 0, 0.2);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.ug-btn-outline {
|
||||
background: transparent;
|
||||
color: var(--theme-secondary);
|
||||
border-color: var(--theme-secondary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 116, 139, 0.1); // var(--theme-secondary) with 10% opacity
|
||||
border-color: var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.ug-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: white;
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
border-color: var(--theme-error-dark, #dc2626);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3), 0 4px 6px -2px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&.ug-btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--theme-text-secondary);
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ug-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&__left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__right {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.ug-search {
|
||||
position: relative;
|
||||
max-width: 400px;
|
||||
|
||||
clr-icon {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #9ca3af;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__input {
|
||||
width: 100%;
|
||||
padding: 12px 12px 12px 40px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: all 200ms ease-out;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1); // var(--theme-primary) with 10% opacity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ug-view-toggle {
|
||||
display: flex;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
.ug-btn {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text-secondary);
|
||||
|
||||
&:first-child {
|
||||
border-right: 1px solid #d1d5db;
|
||||
}
|
||||
|
||||
&.ug-btn-primary {
|
||||
background: var(--theme-primary);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modern Table Styles
|
||||
.ug-grid {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
|
||||
::ng-deep .datagrid {
|
||||
.datagrid-head {
|
||||
background: var(--theme-background);
|
||||
|
||||
.datagrid-column {
|
||||
padding: 16px 24px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-row {
|
||||
transition: background-color 150ms ease-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.datagrid-cell {
|
||||
padding: 16px 24px;
|
||||
font-size: 14px;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ug-grid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
// Modern Card Styles - More beautiful design
|
||||
.ug-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.ug-card-item {
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: var(--theme-border-radius); // Using theme variable
|
||||
box-shadow: var(--theme-shadow); // Using theme variable
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
border-color: rgba(14, 165, 233, 0.3); // var(--theme-primary) with 30% opacity
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, rgba(14, 165, 233, 0.1), transparent); // var(--theme-primary) with 10% opacity
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
clr-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-weight: 700;
|
||||
flex: 1 1 auto;
|
||||
font-size: 18px;
|
||||
color: var(--theme-text);
|
||||
max-width: 60%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__badge {
|
||||
margin-left: auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
border-radius: 9999px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
||||
background: var(--theme-background);
|
||||
}
|
||||
}
|
||||
|
||||
.ug-kv {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
|
||||
span {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
strong {
|
||||
color: var(--theme-text);
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
max-width: 60%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
// Theme the card footer buttons
|
||||
.ug-card-item__footer .ug-btn {
|
||||
border-radius: 10px;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ug-card-item__footer .ug-btn.ug-btn-outline {
|
||||
border: 1px solid var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
background: transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 116, 139, 0.1); // var(--theme-secondary) with 10% opacity
|
||||
border-color: var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.ug-card-item__footer .ug-btn.ug-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: #fff;
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
border-color: var(--theme-error-dark, #dc2626);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
// Table view action buttons
|
||||
.ug-action-item {
|
||||
@extend .ug-btn;
|
||||
@extend .ug-btn-ghost;
|
||||
@extend .ug-btn-sm;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 4px;
|
||||
text-align: left;
|
||||
|
||||
clr-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&.ug-btn-error {
|
||||
color: var(--theme-error, #ef4444);
|
||||
|
||||
&:hover {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure action overflow is visible
|
||||
::ng-deep .datagrid-action-overflow {
|
||||
button.action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 8px 12px;
|
||||
|
||||
clr-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Status Badges
|
||||
.ug-status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6px 16px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
border-radius: 9999px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.ug-status-enabled {
|
||||
background: linear-gradient(135deg, rgba(16, 185, 129, 0.1) 0%, rgba(16, 185, 129, 0.05) 100%);
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.ug-status-disabled {
|
||||
background: linear-gradient(135deg, rgba(239, 68, 68, 0.1) 0%, rgba(239, 68, 68, 0.05) 100%);
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
// Form Styles
|
||||
.ug-form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ug-form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
.ug-form-input, .ug-form-select {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
transition: all 200ms ease-out;
|
||||
margin-bottom: 0;
|
||||
font-family: var(--theme-font-primary);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1); // var(--theme-primary) with 10% opacity
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text-secondary);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border-color: #ef4444;
|
||||
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.ug-form-select {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
|
||||
background-position: right 12px center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 12px;
|
||||
padding-right: 40px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.ug-form-error {
|
||||
color: #ef4444;
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: #ef4444;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.ug-file-input {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
|
||||
&::file-selector-button {
|
||||
@extend .ug-btn;
|
||||
@extend .ug-btn-secondary;
|
||||
margin-right: 12px;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Modal Styles
|
||||
.ug-delete-header {
|
||||
text-align: center;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.ug-delete-icon {
|
||||
color: #ef4444;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.ug-delete-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--theme-text);
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.ug-delete-subtitle {
|
||||
font-size: 16px;
|
||||
color: var(--theme-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ug-delete-details {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.ug-delete-detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ug-delete-detail-label {
|
||||
font-weight: 500;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.ug-delete-detail-value {
|
||||
font-weight: 600;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
.delete {
|
||||
color: #ef4444;
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
color: var(--theme-text);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// Modal Header
|
||||
::ng-deep .modal-header {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px 16px 0 0 !important;
|
||||
padding: 20px 24px !important;
|
||||
|
||||
.modal-title {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Body
|
||||
::ng-deep .modal-body {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
// Modal Footer
|
||||
::ng-deep .modal-footer {
|
||||
padding: 20px 24px !important;
|
||||
background: var(--theme-background);
|
||||
border-radius: 0 0 16px 16px !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@media (max-width: 768px) {
|
||||
.ug-hero {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
|
||||
&__content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.ug-toolbar {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.ug-search {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.ug-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.ug-card-item {
|
||||
&__header {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
|
||||
&__icon {
|
||||
margin-right: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
.error_mess {
|
||||
color: red;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ExcelService } from '../../../../services/excel.service';
|
||||
@@ -8,15 +8,12 @@ import { ToastrService } from 'ngx-toastr';
|
||||
import { MenuGroupService } from 'src/app/services/admin/menu-group.service';
|
||||
import { CsvService } from 'src/app/services/csv.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-usergrpmaintenance',
|
||||
templateUrl: './usergrpmaintenance.component.html',
|
||||
styleUrls: ['./usergrpmaintenance.component.scss']
|
||||
})
|
||||
export class UsergrpmaintenanceComponent implements OnInit, OnDestroy {
|
||||
export class UsergrpmaintenanceComponent implements OnInit {
|
||||
loading = false;
|
||||
public entryForm: FormGroup;
|
||||
givendata;
|
||||
@@ -26,13 +23,10 @@ export class UsergrpmaintenanceComponent implements OnInit, OnDestroy {
|
||||
modaledit=false;
|
||||
modaldelete=false;
|
||||
rowSelected :any= {};
|
||||
mcreate: string | boolean = false;
|
||||
medit: string | boolean = false;
|
||||
showdata: any;
|
||||
mcreate;
|
||||
medit;
|
||||
showdata;
|
||||
submitted=false;
|
||||
filterText: string = '';
|
||||
viewMode: 'table' | 'cards' = 'cards';
|
||||
private themeSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private excel: ExcelService,
|
||||
@@ -44,32 +38,21 @@ export class UsergrpmaintenanceComponent implements OnInit, OnDestroy {
|
||||
private mainservice:UsergrpmaintainceService,
|
||||
private csvService: CsvService,
|
||||
private translate: TranslateService,
|
||||
private themeService: ThemeService,
|
||||
) { }
|
||||
|
||||
switchLanguage(language: string) {
|
||||
this.translate.use(language);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.themeSubscription = this.themeService.currentTheme$.subscribe(() => {
|
||||
// Theme changes will automatically update CSS variables
|
||||
// This triggers a re-render of themed elements
|
||||
});
|
||||
|
||||
this.showdata = this.menuGroupService.getdata();
|
||||
console.log('Showdata:', this.showdata);
|
||||
if (this.showdata) {
|
||||
// Handle both string and boolean values
|
||||
this.mcreate = this.showdata.mcreate === 'true' || this.showdata.mcreate === true ? true : false;
|
||||
this.medit = this.showdata.medit === 'true' || this.showdata.medit === true ? true : false;
|
||||
console.log('MCREATE:', this.mcreate);
|
||||
console.log('MEDIT:', this.medit);
|
||||
}
|
||||
console.log(this.showdata);
|
||||
this.mcreate=this.showdata.mcreate;
|
||||
console.log(this.mcreate);
|
||||
this.medit=this.showdata.medit
|
||||
console.log(this.medit);
|
||||
|
||||
this.mainservice.getAll().subscribe((data) => {
|
||||
console.log('Data received:', data);
|
||||
this.givendata = data || [];
|
||||
console.log(data);
|
||||
this.givendata = data;
|
||||
if(this.givendata.length==0){
|
||||
this.error="No data Available";
|
||||
console.log(this.error)
|
||||
@@ -89,30 +72,6 @@ export class UsergrpmaintenanceComponent implements OnInit, OnDestroy {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.themeSubscription) {
|
||||
this.themeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
get totalGroups(): number {
|
||||
const list: any[] = (this.givendata as unknown as any[]) || [];
|
||||
return list.length;
|
||||
}
|
||||
|
||||
|
||||
get filteredGroups(): any[] {
|
||||
const items: any[] = (this.givendata as unknown as any[]) || [];
|
||||
const text = (this.filterText || '').toLowerCase();
|
||||
if (!text) { return items; }
|
||||
return items.filter(g => (
|
||||
(g?.groupName || '').toLowerCase().includes(text) ||
|
||||
(g?.groupDesc || '').toLowerCase().includes(text)
|
||||
));
|
||||
}
|
||||
|
||||
setViewMode(mode: 'table' | 'cards') { this.viewMode = mode; }
|
||||
onExport() {
|
||||
this.excel.exportAsExcelFile(this.givendata, 'user_',
|
||||
moment().format('YYYYMMDD_HHmmss'))
|
||||
@@ -122,8 +81,7 @@ export class UsergrpmaintenanceComponent implements OnInit, OnDestroy {
|
||||
//this.router.navigate(["../usermaintanceadd"],{relativeTo:this.route});
|
||||
}
|
||||
goToEdit(row){
|
||||
console.log('Edit clicked for row:', row);
|
||||
this.rowSelected = {...row}; // Create a copy to avoid reference issues
|
||||
this.rowSelected = row;
|
||||
this.modaledit=true;
|
||||
//this.router.navigate(["../usermaintanceedit/"+ id], { relativeTo: this.route });
|
||||
}
|
||||
@@ -177,8 +135,7 @@ export class UsergrpmaintenanceComponent implements OnInit, OnDestroy {
|
||||
// }
|
||||
}
|
||||
onDelete(row) {
|
||||
console.log('Delete clicked for row:', row);
|
||||
this.rowSelected = {...row}; // Create a copy to avoid reference issues
|
||||
this.rowSelected = row;
|
||||
this.modaldelete=true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,108 +1,80 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon>{{ 'SECURITY' | translate }}</a></li>
|
||||
<li><a href="javascript://">{{'USER_MAINTENANCE'| translate}}</a></li>
|
||||
|
||||
</ol>
|
||||
|
||||
<section class="um-hero">
|
||||
<div class="um-hero__content">
|
||||
<div class="um-hero__icon"><clr-icon shape="user"></clr-icon></div>
|
||||
<div>
|
||||
<h2 class="um-hero__title">{{'USER_MAINTENANCE'| translate}}</h2>
|
||||
<p class="um-hero__subtitle">{{ 'SECURITY' | translate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="um-hero__actions">
|
||||
<button class="um-btn um-btn-secondary" (click)="downloadFiles()">
|
||||
<clr-icon shape="download"></clr-icon>
|
||||
<span class="um-btn-text">{{ 'DOWNLOAD_TEMPLATE' | translate }}</span>
|
||||
</button>
|
||||
<button class="um-btn um-btn-secondary" (click)="csvImport()">
|
||||
<clr-icon shape="import"></clr-icon>
|
||||
<span class="um-btn-text">{{ 'IMPORT' | translate }}</span>
|
||||
</button>
|
||||
<button class="um-btn um-btn-secondary" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon>
|
||||
<span class="um-btn-text">{{ 'EXPORT_XLSX' | translate }}</span>
|
||||
</button>
|
||||
<button id="add" class="um-btn um-btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
<span class="um-btn-text">{{ 'ADD' | translate }}</span>
|
||||
</button>
|
||||
<!-- <button id="add" class="um-btn um-btn-primary" *ngIf="mcreate == 'true' || mcreate == true" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
<span class="um-btn-text">{{ 'ADD' | translate }}</span>
|
||||
</button> -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="um-toolbar">
|
||||
<div class="um-toolbar__left">
|
||||
<div class="um-search">
|
||||
<clr-icon shape="search"></clr-icon>
|
||||
<input class="um-search__input" type="text" [placeholder]="'SEARCH' | translate" [(ngModel)]="filterText" />
|
||||
<div class="dg-wrapper">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col">
|
||||
<h3>{{'USER_MAINTENANCE'| translate}} </h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="um-toolbar__right">
|
||||
<div class="um-view-toggle">
|
||||
<button class="um-btn um-btn-sm" [class.um-btn-primary]="viewMode==='cards'" (click)="setViewMode('cards')">
|
||||
<clr-icon shape="view-cards"></clr-icon>
|
||||
</button>
|
||||
<button class="um-btn um-btn-sm" [class.um-btn-primary]="viewMode==='table'" (click)="setViewMode('table')">
|
||||
<clr-icon shape="table"></clr-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col" style="text-align: right;">
|
||||
<div class="btn-group">
|
||||
<button class="btn text-dark" (click)="downloadFiles()"><b>{{ 'DOWNLOAD_TEMPLATE' | translate }}</b></button>
|
||||
|
||||
<clr-datagrid class="um-grid" [clrDgLoading]="loading" *ngIf="viewMode==='table'">
|
||||
<clr-dg-placeholder>
|
||||
<ng-template #loadingSpinner>
|
||||
<clr-spinner>{{'LOADING' | translate}} ... </clr-spinner>
|
||||
</ng-template>
|
||||
</div>
|
||||
<button class="btn btn-primary" (click)="csvImport()">{{ 'IMPORT' | translate }}</button>
|
||||
<button class="btn btn-outline" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon> {{ 'EXPORT_XLSX' | translate }}
|
||||
</button>
|
||||
<button id="add" class="btn btn-primary" *ngIf="mcreate == 'true'" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon> {{ 'ADD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder >
|
||||
<ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
||||
<div *ngIf="error;else loadingSpinner">{{error}}</div>
|
||||
</clr-dg-placeholder>
|
||||
<!-- <clr-dg-placeholder *ngIf="!loading1;" > <clr-spinner>not</clr-spinner></clr-dg-placeholder>
|
||||
<ng-template #other_content style="text-align: center;">Data Not found...</ng-template> -->
|
||||
|
||||
<clr-dg-column [clrDgField]="'userId'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{'USER_ID' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'fullName'" style="width: 200px;">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{'FULL_NAME' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'email'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{'EMAIL' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'usrGrpName'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{'USER_GROUP_NAME' | translate}}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'userId'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
User Id
|
||||
</ng-container></clr-dg-column>
|
||||
<!-- <clr-dg-column [clrDgField]="'username'" style="width: 300px;"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
User Name
|
||||
</ng-container></clr-dg-column> -->
|
||||
<clr-dg-column [clrDgField]="'fullName'" style="width: 200px;"><ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Full Name
|
||||
</ng-container></clr-dg-column >
|
||||
<clr-dg-column [clrDgField]="'email'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Email
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'usrGrpName'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
User Group Name
|
||||
</ng-container></clr-dg-column>
|
||||
<!-- <clr-dg-column [clrDgField]="'customerNumer'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Customer Number
|
||||
</ng-container></clr-dg-column> -->
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of filteredUsers;let i = index" [clrDgItem]="user">
|
||||
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of givendata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{user.userId}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.fullName}}</clr-dg-cell>
|
||||
<!-- <clr-dg-cell>{{user.username}}</clr-dg-cell> -->
|
||||
<clr-dg-cell >{{user.fullName}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.email}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.usrGrpName}}</clr-dg-cell>
|
||||
<!-- <clr-dg-cell>{{user.customerNumer}}</clr-dg-cell> -->
|
||||
|
||||
|
||||
<clr-dg-action-overflow>
|
||||
<!-- <button class="um-action-item" *ngIf="medit == 'true' || medit == true" (click)="goToEdit(user.userId)">
|
||||
<clr-icon shape="edit"></clr-icon>
|
||||
{{'EDIT' | translate}}
|
||||
</button> -->
|
||||
<button class="um-action-item" (click)="goToEdit(user.userId)">
|
||||
<clr-icon shape="edit"></clr-icon>
|
||||
{{'EDIT' | translate}}
|
||||
</button>
|
||||
<button class="um-action-item um-btn-error" (click)="onDelete(user)">
|
||||
<clr-icon shape="trash"></clr-icon>
|
||||
{{'DELETE'|translate}}
|
||||
</button>
|
||||
|
||||
<button class="action-item" *ngIf="medit == 'true'" (click)="goToEdit(user.userId)">Edit</button>
|
||||
<button class="action-item" (click)="onDelete(user)">Delete<cds-icon shape="trash" class="is-error"></cds-icon></button>
|
||||
</clr-dg-action-overflow>
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
@@ -111,92 +83,42 @@
|
||||
<td class="td-title">username</td>
|
||||
<td class="td-content">{{user.username}}</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
</clr-dg-row-detail>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer class="um-grid-footer">
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
||||
<div class="um-cards" *ngIf="viewMode==='cards'">
|
||||
<div class="um-card-item" *ngFor="let user of filteredUsers; let i = index">
|
||||
<div class="um-card-item__header">
|
||||
<div class="um-card-item__icon"><clr-icon shape="user"></clr-icon></div>
|
||||
<div class="um-card-item__title">{{user.fullName}}</div>
|
||||
<div class="um-card-item__badge">ID: {{user.userId}}</div>
|
||||
</div>
|
||||
<div class="um-card-item__body">
|
||||
<div class="um-kv"><span>{{'EMAIL' | translate}}</span><strong>{{user.email}}</strong></div>
|
||||
<div class="um-kv"><span>{{'GROUP' | translate}}</span><strong>{{user.usrGrpName}}</strong></div>
|
||||
</div>
|
||||
<div class="um-card-item__footer">
|
||||
<!-- <button class="um-btn um-btn-sm um-btn-outline" *ngIf="medit == 'true' || medit == true"
|
||||
(click)="goToEdit(user.userId)">
|
||||
<clr-icon shape="edit"></clr-icon> {{'EDIT' | translate}}
|
||||
</button> -->
|
||||
|
||||
<button class="um-btn um-btn-sm um-btn-outline" (click)="goToEdit(user.userId)">
|
||||
<clr-icon shape="edit"></clr-icon> {{'EDIT' | translate}}
|
||||
</button>
|
||||
<button class="um-btn um-btn-sm um-btn-error" (click)="onDelete(user)">
|
||||
<clr-icon shape="trash"></clr-icon> {{'DELETE' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
|
||||
<div class="modal-body" *ngIf="rowSelected.userId">
|
||||
<div class="um-delete-header">
|
||||
<div class="um-delete-icon">
|
||||
<clr-icon shape="exclamation-triangle" size="48"></clr-icon>
|
||||
</div>
|
||||
<h1 class="um-delete-title">{{'ARE_YOU_SURE_WANT_TO_DELETE' | translate}}?</h1>
|
||||
<p class="um-delete-subtitle">{{'THIS_ACTION_CANNOT_BE_UNDONE' | translate}}</p>
|
||||
</div>
|
||||
|
||||
<div class="um-delete-details">
|
||||
<div class="um-delete-detail-item">
|
||||
<span class="um-delete-detail-label">{{'USER_ID' | translate}}:</span>
|
||||
<span class="um-delete-detail-value">{{rowSelected.userId}}</span>
|
||||
</div>
|
||||
<div class="um-delete-detail-item">
|
||||
<span class="um-delete-detail-label">{{'FULL_NAME' | translate}}:</span>
|
||||
<span class="um-delete-detail-value">{{rowSelected.fullName}}</span>
|
||||
</div>
|
||||
<div class="um-delete-detail-item">
|
||||
<span class="um-delete-detail-label">{{'EMAIL' | translate}}:</span>
|
||||
<span class="um-delete-detail-value">{{rowSelected.email}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 class="delete">Are You Sure Want to delete?</h1>
|
||||
<h2 class="heading">{{rowSelected.userId}}</h2>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="um-btn um-btn-outline" (click)="modaldelete = false">{{'CANCEL' |
|
||||
translate}}</button>
|
||||
<button type="submit" (click)="delete(rowSelected.userId)" class="um-btn um-btn-error">{{'DELETE' |
|
||||
translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
|
||||
<button type="submit" (click)="delete(rowSelected.userId)" class="btn btn-primary" >Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modalCsv" [clrModalSize]="'sm'" [clrModalStaticBackdrop]="false">
|
||||
<h3 class="modal-title">{{'IMPORT_FILE' | translate}}</h3>
|
||||
<h3 class="modal-title">Import File</h3>
|
||||
<div class="modal-body">
|
||||
<div class="um-form-group">
|
||||
<label class="um-form-label">{{'SELECT_CSV_FILE' | translate}}</label>
|
||||
<input type="file" name="file" class="um-file-input" (change)="selectFile($event)"
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
|
||||
</div>
|
||||
<input type="file" name="file" class="file" (change)="selectFile($event)" accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="um-btn um-btn-outline" type="button" (click)="modalCsv = false">{{'CANCEL' | translate}}</button>
|
||||
<button class="um-btn um-btn-primary" type="button" [disabled]="!selectedFiles" (click)="saveCsv()">{{'IMPORT' |
|
||||
translate}}</button>
|
||||
<button class="btn btn-primary" type="button" [disabled]="!selectedFiles" (click)="saveCsv()">Import</button>
|
||||
</div>
|
||||
</clr-modal>
|
||||
@@ -1,656 +1,4 @@
|
||||
@import '../../../../../styles.scss';
|
||||
|
||||
// Import design tokens
|
||||
@import '../../../../../styles/design-tokens';
|
||||
|
||||
.delete, .heading {
|
||||
.delete,.heading{
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
|
||||
// Modern User Maintenance Styles
|
||||
.um-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
clr-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: var(--theme-font-secondary);
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.um-btn-text {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
// Modern Button Styles using ThemeService
|
||||
.um-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: var(--theme-font-primary);
|
||||
z-index: 1;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--theme-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.um-btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.um-btn-md {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&.um-btn-lg {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
// Variants
|
||||
&.um-btn-primary {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, var(--theme-primary, #0284c7) 0%, var(--theme-accent, #7c3aed) 100%);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-secondary {
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
border-color: rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
border-color: rgba(0, 0, 0, 0.2);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-outline {
|
||||
background: transparent;
|
||||
color: var(--theme-secondary);
|
||||
border-color: var(--theme-secondary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 116, 139, 0.1); // var(--theme-secondary) with 10% opacity
|
||||
border-color: var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: white;
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
border-color: var(--theme-error-dark, #dc2626);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3), 0 4px 6px -2px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--theme-text-secondary);
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.um-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&__left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__right {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.um-search {
|
||||
position: relative;
|
||||
max-width: 400px;
|
||||
|
||||
clr-icon {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #9ca3af;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__input {
|
||||
width: 100%;
|
||||
padding: 12px 12px 12px 40px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: all 200ms ease-out;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1); // var(--theme-primary) with 10% opacity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.um-view-toggle {
|
||||
display: flex;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
.um-btn {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text-secondary);
|
||||
|
||||
&:first-child {
|
||||
border-right: 1px solid #d1d5db;
|
||||
}
|
||||
|
||||
&.um-btn-primary {
|
||||
background: var(--theme-primary);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modern Table Styles
|
||||
.um-grid {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
|
||||
::ng-deep .datagrid {
|
||||
.datagrid-head {
|
||||
background: var(--theme-background);
|
||||
|
||||
.datagrid-column {
|
||||
padding: 16px 24px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-row {
|
||||
transition: background-color 150ms ease-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.datagrid-cell {
|
||||
padding: 16px 24px;
|
||||
font-size: 14px;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.um-grid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
// Modern Card Styles - More beautiful design
|
||||
.um-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.um-card-item {
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: var(--theme-border-radius); // Using theme variable
|
||||
box-shadow: var(--theme-shadow); // Using theme variable
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
border-color: rgba(14, 165, 233, 0.3); // var(--theme-primary) with 30% opacity
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, rgba(14, 165, 233, 0.1), transparent); // var(--theme-primary) with 10% opacity
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
clr-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-weight: 700;
|
||||
flex: 1 1 auto;
|
||||
font-size: 18px;
|
||||
color: var(--theme-text);
|
||||
max-width: 60%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__badge {
|
||||
margin-left: auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
border-radius: 9999px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
background: linear-gradient(135deg, rgba(100, 116, 139, 0.1) 0%, rgba(100, 116, 139, 0.05) 100%);
|
||||
color: var(--theme-secondary);
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
||||
background: var(--theme-background);
|
||||
}
|
||||
}
|
||||
|
||||
.um-kv {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
|
||||
span {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
strong {
|
||||
color: var(--theme-text);
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
max-width: 60%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
// Theme the card footer buttons
|
||||
.um-card-item__footer .um-btn {
|
||||
border-radius: 10px;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.um-card-item__footer .um-btn.um-btn-outline {
|
||||
border: 1px solid var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.um-card-item__footer .um-btn.um-btn-outline:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.um-card-item__footer .um-btn.um-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.um-card-item__footer .um-btn.um-btn-error:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
}
|
||||
|
||||
// Action items in table
|
||||
.um-action-item {
|
||||
@extend .um-btn;
|
||||
@extend .um-btn-ghost;
|
||||
@extend .um-btn-sm;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 4px;
|
||||
text-align: left;
|
||||
|
||||
clr-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&.um-btn-error {
|
||||
color: var(--theme-error, #ef4444);
|
||||
|
||||
&:hover {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure action overflow is visible
|
||||
::ng-deep .datagrid-action-overflow {
|
||||
button.action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 8px 12px;
|
||||
|
||||
clr-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Modal Styles
|
||||
.um-delete-header {
|
||||
text-align: center;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.um-delete-icon {
|
||||
color: #ef4444;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.um-delete-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--theme-text);
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.um-delete-subtitle {
|
||||
font-size: 16px;
|
||||
color: var(--theme-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.um-delete-details {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.um-delete-detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.um-delete-detail-label {
|
||||
font-weight: 500;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.um-delete-detail-value {
|
||||
font-weight: 600;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
// Form Styles
|
||||
.um-form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.um-form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
.um-file-input {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
|
||||
&::file-selector-button {
|
||||
@extend .um-btn;
|
||||
@extend .um-btn-secondary;
|
||||
margin-right: 12px;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Header
|
||||
::ng-deep .modal-header {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px 16px 0 0 !important;
|
||||
padding: 20px 24px !important;
|
||||
|
||||
.modal-title {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Body
|
||||
::ng-deep .modal-body {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
// Modal Footer
|
||||
::ng-deep .modal-footer {
|
||||
padding: 20px 24px !important;
|
||||
background: var(--theme-background);
|
||||
border-radius: 0 0 16px 16px !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@media (max-width: 768px) {
|
||||
.um-hero {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
|
||||
&__content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.um-toolbar {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.um-search {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.um-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.um-card-item {
|
||||
&__header {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
|
||||
&__icon {
|
||||
margin-right: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ExcelService } from '../../../../services/excel.service';
|
||||
@@ -8,15 +8,12 @@ import { MenuGroupService } from 'src/app/services/admin/menu-group.service';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { CsvService } from 'src/app/services/csv.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-usermaintance',
|
||||
templateUrl: './usermaintance.component.html',
|
||||
styleUrls: ['./usermaintance.component.scss']
|
||||
})
|
||||
export class UsermaintanceComponent implements OnInit, OnDestroy {
|
||||
export class UsermaintanceComponent implements OnInit {
|
||||
loading = false;
|
||||
loading1=false;
|
||||
public entryForm: FormGroup;
|
||||
@@ -24,18 +21,13 @@ export class UsermaintanceComponent implements OnInit, OnDestroy {
|
||||
orders;
|
||||
modalAdd= false;
|
||||
modaledit=false;
|
||||
mcreate: string | boolean = false;
|
||||
medit: string | boolean = false;
|
||||
mdelete;
|
||||
showdata;
|
||||
error;
|
||||
modaldelete=false;
|
||||
rowSelected :any= {};
|
||||
// UI-only state
|
||||
filterText: string = '';
|
||||
viewMode: 'table' | 'cards' = 'cards';
|
||||
private themeSubscription: Subscription;
|
||||
|
||||
mcreate;
|
||||
medit;
|
||||
mdelete;
|
||||
showdata;
|
||||
error;
|
||||
modaldelete=false;
|
||||
rowSelected :any= {};
|
||||
constructor(private excel: ExcelService,
|
||||
private _fb: FormBuilder,
|
||||
private router: Router, private toastr:ToastrService,
|
||||
@@ -44,41 +36,25 @@ export class UsermaintanceComponent implements OnInit, OnDestroy {
|
||||
private mainservice:UsermaintanceService,
|
||||
private csvService: CsvService,
|
||||
private translate: TranslateService,
|
||||
private themeService: ThemeService,
|
||||
) {this.loading1 = true;
|
||||
setTimeout(() => {
|
||||
this.loading1 = false;
|
||||
}, 1000); }
|
||||
|
||||
switchLanguage(language: string) {
|
||||
this.translate.use(language);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.themeSubscription = this.themeService.currentTheme$.subscribe(() => {
|
||||
// Theme changes will automatically update CSS variables
|
||||
// This triggers a re-render of themed elements
|
||||
});
|
||||
|
||||
this.showdata = this.menuGroupService.getdata();
|
||||
console.log(this.showdata);
|
||||
if (this.showdata) {
|
||||
this.mcreate = this.showdata.mcreate === 'true' || this.showdata.mcreate === true ? true : false;
|
||||
this.mcreate=this.showdata.mcreate;
|
||||
console.log(this.mcreate);
|
||||
this.mdelete=this.showdata.mdelete
|
||||
console.log(this.mdelete);
|
||||
this.medit = this.showdata.medit === 'true' || this.showdata.medit === true ? true : false;
|
||||
this.medit=this.showdata.medit
|
||||
console.log(this.medit);
|
||||
}
|
||||
this.getData();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.themeSubscription) {
|
||||
this.themeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
getData(){
|
||||
this.mainservice.getAll().subscribe((data) => {
|
||||
console.log(data);
|
||||
@@ -103,23 +79,6 @@ export class UsermaintanceComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
// UI helpers
|
||||
get totalUsers(): number {
|
||||
const list: any[] = (this.givendata as unknown as any[]) || [];
|
||||
return list.length;
|
||||
}
|
||||
get filteredUsers(): any[] {
|
||||
const items: any[] = (this.givendata as unknown as any[]) || [];
|
||||
const text = (this.filterText || '').toLowerCase();
|
||||
if (!text) { return items; }
|
||||
return items.filter(u => (
|
||||
(u?.fullName || '').toLowerCase().includes(text) ||
|
||||
(u?.email || '').toLowerCase().includes(text) ||
|
||||
(u?.usrGrpName || '').toLowerCase().includes(text)
|
||||
));
|
||||
}
|
||||
setViewMode(mode: 'table' | 'cards') { this.viewMode = mode; }
|
||||
|
||||
|
||||
// csv
|
||||
|
||||
@@ -170,7 +129,7 @@ export class UsermaintanceComponent implements OnInit, OnDestroy {
|
||||
this.router.navigate(["../usermaintancedit/"+ id], { relativeTo: this.route });
|
||||
}
|
||||
onDelete(row) {
|
||||
this.rowSelected = {...row}; // Create a copy to avoid reference issues
|
||||
this.rowSelected = row;
|
||||
this.modaldelete=true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,169 +1,204 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon> Security</a></li>
|
||||
<li><a href="javascript://">User Maintenance</a></li>
|
||||
</ol>
|
||||
|
||||
<section class="um-hero">
|
||||
<div class="um-hero__content">
|
||||
<div class="um-hero__icon"><clr-icon shape="user"></clr-icon></div>
|
||||
<div>
|
||||
<h2 class="um-hero__title">User Maintenance</h2>
|
||||
<p class="um-hero__subtitle">Add New User</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<h4 style="font-weight: 300;display: inline;"> User Maintenance</h4>
|
||||
<span class="label label-light-blue" style="display: inline;margin-left: 30px;">Add Mode</span><br>
|
||||
<hr>
|
||||
<div class="main" >
|
||||
<form [formGroup]="entryForm">
|
||||
|
||||
<div class="um-add-container">
|
||||
<div class="um-form-card">
|
||||
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()" class="um-form">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="first_name" class="um-form-label">First Name<span class="required-field">*</span></label>
|
||||
<input type="text" id="first_name" class="um-form-input" formControlName="first_name">
|
||||
<div *ngIf="submitted && entryForm.controls.first_name.errors" class="um-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.first_name.errors.required">*This field is Required</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name"> First Name</label>
|
||||
<input type="text" class="clr-input" formControlName="first_name">
|
||||
<div *ngIf="submitted && entryForm.controls.first_name.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.first_name.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Last Name</label>
|
||||
<input type="text" class="clr-input" formControlName="last_name">
|
||||
<div *ngIf="submitted && entryForm.controls.last_name.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.last_name.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Mobile Number</label>
|
||||
<input type="text" class="clr-input" formControlName="mob_no" required pattern="((\+)?([1-9]{2}))?[1-9]{1}[0-9]{9}$">
|
||||
<div *ngIf="submitted && entryForm.controls.mob_no.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.mob_no.errors.required" class="error_mess">*This field is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.mob_no.errors.pattern" class="error_mess">* Please Follow your pattern,+91 Enter 10 digit Mobile Number.
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="last_name" class="um-form-label">Last Name<span class="required-field">*</span></label>
|
||||
<input type="text" id="last_name" class="um-form-input" formControlName="last_name">
|
||||
<div *ngIf="submitted && entryForm.controls.last_name.errors" class="um-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.last_name.errors.required">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">New Password<span class="required-field">*</span></label>
|
||||
<input type="password" class="clr-input" formControlName="new_password" minlenght="6">
|
||||
<div *ngIf="submitted && entryForm.controls.new_password.errors" class="error_mess">
|
||||
<div *ngIf="entryForm.controls.new_password.errors.required" class="error_mess">*Password is required</div>
|
||||
<div *ngIf="entryForm.controls.new_password.errors.minlength" class="error_mess">* Password must be at least 6 characters</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="mob_no" class="um-form-label">Mobile Number<span class="required-field">*</span></label>
|
||||
<input type="text" id="mob_no" class="um-form-input" formControlName="mob_no" required pattern="((\+)?([1-9]{2}))?[1-9]{1}[0-9]{9}$">
|
||||
<div *ngIf="submitted && entryForm.controls.mob_no.errors" class="um-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.mob_no.errors.required">*This field is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.mob_no.errors.pattern">* Please Follow your pattern,+91 Enter 10 digit Mobile Number.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Confirm New Password<span class="required-field">*</span></label>
|
||||
<input type="password" class="clr-input" formControlName="confirm_password">
|
||||
<div *ngIf="submitted && entryForm.controls.confirm_password.errors" class="error_mess">
|
||||
<div *ngIf="entryForm.controls.confirm_password.errors.required" class="error_mess">* Confirm Password is required</div>
|
||||
<div *ngIf="entryForm.controls.confirm_password.errors.confirmedValidator" class="error_mess">* Password and Confirm Password must be match.</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="email" class="um-form-label">Email<span class="required-field">*</span></label>
|
||||
<input type="text" id="email" class="um-form-input" formControlName="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$">
|
||||
<div *ngIf="submitted && entryForm.controls.email.errors" class="um-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.email.errors.required">*This field is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.email.errors.pattern">*Email must be a valid email address</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="new_password" class="um-form-label">New Password<span class="required-field">*</span></label>
|
||||
<input type="password" id="new_password" class="um-form-input" formControlName="new_password" minlength="6">
|
||||
<div *ngIf="submitted && entryForm.controls.new_password.errors" class="um-error-message">
|
||||
<div *ngIf="entryForm.controls.new_password.errors.required">*Password is required</div>
|
||||
<div *ngIf="entryForm.controls.new_password.errors.minlength">* Password must be at least 6 characters</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Business Title</label>
|
||||
<input type="text" class="clr-input" formControlName="title">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name"> Short Name</label>
|
||||
<input type="text" class="clr-input" formControlName="shortName">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="confirm_password" class="um-form-label">Confirm New Password<span class="required-field">*</span></label>
|
||||
<input type="password" id="confirm_password" class="um-form-input" formControlName="confirm_password">
|
||||
<div *ngIf="submitted && entryForm.controls.confirm_password.errors" class="um-error-message">
|
||||
<div *ngIf="entryForm.controls.confirm_password.errors.required">* Confirm Password is required</div>
|
||||
<div *ngIf="entryForm.controls.confirm_password.errors.confirmedValidator">* Password and Confirm Password must be match.</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Full Name</label>
|
||||
<input type="text" class="clr-input" formControlName="fullName">
|
||||
</div> -->
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Status</label>
|
||||
<select id="" formControlName="status">
|
||||
<option value="E">Enable</option>
|
||||
<option value="A">Active</option></select>
|
||||
</div> -->
|
||||
<!-- <div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Position Code</label>
|
||||
<input type="text" class="clr-input" formControlName="positionCodeString" [(ngModel)]="userobjpos.positionCode" name="positionCode" >
|
||||
</div>
|
||||
<div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" (click)="gotoposition()">V</button>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="usrGrpId" class="um-form-label">User Group<span class="required-field">*</span></label>
|
||||
<select id="usrGrpId" class="um-form-select" formControlName="usrGrpId">
|
||||
<option value="">Select User Group</option>
|
||||
<option *ngFor="let group of usergrpdata" [value]="group.usrGrp">{{group.groupName}}</option>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Department Code</label>
|
||||
<input type="text" class="clr-input" formControlName="departmentCodeString" [(ngModel)]="userobjdept.departmentCode" name="departmentCode">
|
||||
</div>
|
||||
<div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" (click)="gotodepartmet()">V</button>
|
||||
</div> -->
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">User Group</label>
|
||||
<select id="tags" formControlName="usrGrpId" >
|
||||
<option *ngFor="let sub of usergrpdata" [value]="sub.usrGrp">{{sub.groupName}}</option>
|
||||
</select>
|
||||
<div *ngIf="submitted && entryForm.controls.usrGrpId.errors" class="um-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.usrGrpId.errors.required">*This field is Required</div>
|
||||
<div *ngIf="submitted && entryForm.controls.usrGrpId.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.usrGrpId.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Customer Id</label>
|
||||
<input type="text" class="clr-input" formControlName="customerId" name="customerCode">
|
||||
</div> -->
|
||||
<!-- <div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" >V</button>
|
||||
</div> -->
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Email</label>
|
||||
<input type="text" class="clr-input" formControlName="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$">
|
||||
<div *ngIf="submitted && entryForm.controls.email.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.email.errors.required" class="error_mess">*This field is Required</div>
|
||||
<!-- <div *ngIf="submitted && entryForm.controls.email.errors.email" class="error_mess">*Email must be a valid email address</div> -->
|
||||
<div *ngIf="submitted && entryForm.controls.email.errors.pattern" class="error_mess">*Email must be a valid email address</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="accesstype" class="um-form-label">Access Type<span class="required-field">*</span></label>
|
||||
<select id="accesstype" class="um-form-select" formControlName="accesstype">
|
||||
<option value="">Select Access Type</option>
|
||||
<option *ngFor="let access of accessdata" [value]="access.name">{{access.name}}</option>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Access Type</label>
|
||||
<select name="usrGrpId" formControlName="accesstype">
|
||||
<option *ngFor="let sub of accessdata" [value]="sub.name" [selected]="true">{{sub.name}}</option>
|
||||
</select>
|
||||
<div *ngIf="submitted && entryForm.controls.accesstype.errors" class="um-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.accesstype.errors.required">*This field is Required</div>
|
||||
</div>
|
||||
<div *ngIf="submitted && entryForm.controls.accesstype.errors" class="error_mess">
|
||||
<div *ngIf="submitted && entryForm.controls.accesstype.errors.required" class="error_mess">*This field is Required</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Notification</label>
|
||||
<select id="" formControlName="notification">
|
||||
<option value="N" >NO</option>
|
||||
<option value="Y">YES</option></select>
|
||||
</div> -->
|
||||
|
||||
<div class="um-form-actions">
|
||||
<button type="button" class="um-btn um-btn-outline" (click)="goback()">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
<button type="submit" class="um-btn um-btn-primary">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
<span>Add User</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- <div class="clr-row">
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Created By</label>
|
||||
<input type="text" class="clr-input">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Created On</label>
|
||||
<input type="text" class="clr-input">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Updated By</label>
|
||||
<input type="text" class="clr-input">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Updated On</label>
|
||||
<input type="text" class="clr-input">
|
||||
</div>
|
||||
</div> -->
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Customer Modal -->
|
||||
<clr-modal [(clrModalOpen)]="customer" [clrModalSize]="'lg'">
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="goback()">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" (click)="onSubmit()">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<clr-modal [(clrModalOpen)]="customer" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="um-form-input">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder>
|
||||
<clr-spinner>Loading ...</clr-spinner>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<clr-dg-placeholder><clr-spinner>Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Customer Code
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerCode'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerCode'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Customer Id
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'customerName'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Customer Name
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</clr-dg-column >
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of custdata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getcustID(user.customerId)" class="um-clickable-cell">{{user.customerCode}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.customerId}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getcustID(user.customerId)" style="color: rgb(108, 108, 194);" >{{user.customerCode}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.customerId}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.customerName}}</clr-dg-cell>
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">No</td>
|
||||
<td class="td-title">NO</td>
|
||||
<td class="td-content">{{user.id}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="td-title">Customer Code</td>
|
||||
<td class="td-title"> Customer Code</td>
|
||||
<td class="td-content">{{user.customerCode}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="td-title">Customer Id</td>
|
||||
<td class="td-content">{{user.customerId}}</td>
|
||||
<td class="td-content">{{user.customerId}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="td-title">Customer Name</td>
|
||||
<td class="td-title"> Customer Name<td>
|
||||
<td class="td-content">{{user.customerName}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -179,41 +214,38 @@
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
</clr-modal>
|
||||
|
||||
<!-- Department Modal -->
|
||||
<clr-modal [(clrModalOpen)]="department" [clrModalSize]="'lg'">
|
||||
<clr-modal [(clrModalOpen)]="department" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="um-form-input">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder>
|
||||
<clr-spinner>Loading ...</clr-spinner>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<clr-dg-placeholder><clr-spinner>Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Department Code
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of departmentdata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getdepid(user.departmentCode)" class="um-clickable-cell">{{user.departmentCode}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getdepid(user.departmentCode)" style="color: rgb(108, 108, 194);" >{{user.departmentCode}}</clr-dg-cell>
|
||||
|
||||
|
||||
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">No</td>
|
||||
<td class="td-title">NO</td>
|
||||
<td class="td-content">{{user.id}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -228,42 +260,43 @@
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<!-- Position Modal -->
|
||||
<clr-modal [(clrModalOpen)]="position" [clrModalSize]="'lg'">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="position" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="um-form-input">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder>
|
||||
<clr-spinner>Loading ...</clr-spinner>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<clr-dg-placeholder><clr-spinner>Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Position Code
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of positiondata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getposid(user.positionCode)" class="um-clickable-cell">{{user.positionCode}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getposid(user.positionCode)" style="color: rgb(108, 108, 194);" >{{user.positionCode}}</clr-dg-cell>
|
||||
|
||||
|
||||
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">No</td>
|
||||
<td class="td-title">NO</td>
|
||||
<td class="td-content">{{user.id}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -278,5 +311,9 @@
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</clr-modal>
|
||||
</clr-modal>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
@import '../../../../../styles1.scss';
|
||||
@import '../../../../../styles/_design-tokens.scss';
|
||||
|
||||
input.ng-invalid.ng-touched {
|
||||
border-color: red;
|
||||
}
|
||||
@@ -8,383 +6,3 @@ input.ng-invalid.ng-touched {
|
||||
.error_mess {
|
||||
color: red;
|
||||
}
|
||||
|
||||
// User Maintenance Add Styles
|
||||
.um-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
clr-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: var(--theme-font-secondary);
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.um-add-container {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.um-form-card {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.um-form {
|
||||
.clr-row {
|
||||
margin: 0 -12px;
|
||||
}
|
||||
|
||||
.clr-col-md-6,
|
||||
.clr-col-sm-12 {
|
||||
padding: 0 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.um-form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
.um-form-input,
|
||||
.um-form-select {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
transition: all 200ms ease-out;
|
||||
margin-bottom: 0;
|
||||
font-family: var(--theme-font-primary);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1); // var(--theme-primary) with 10% opacity
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text-secondary);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border-color: #ef4444;
|
||||
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.um-form-select {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
|
||||
background-position: right 12px center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 12px;
|
||||
padding-right: 40px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.um-error-message {
|
||||
color: #ef4444;
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: #ef4444;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.um-form-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
// Modern Button Styles using ThemeService
|
||||
.um-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: var(--theme-font-primary);
|
||||
z-index: 1;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--theme-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.um-btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.um-btn-md {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&.um-btn-lg {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
// Variants
|
||||
&.um-btn-primary {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, var(--theme-primary, #0284c7) 0%, var(--theme-accent, #7c3aed) 100%);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-outline {
|
||||
background: transparent;
|
||||
color: var(--theme-secondary);
|
||||
border-color: var(--theme-secondary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 116, 139, 0.1); // var(--theme-secondary) with 10% opacity
|
||||
border-color: var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: white;
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
border-color: var(--theme-error-dark, #dc2626);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3), 0 4px 6px -2px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--theme-text-secondary);
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.um-clickable-cell {
|
||||
color: var(--theme-primary);
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Styles
|
||||
::ng-deep .modal-header {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px 16px 0 0 !important;
|
||||
padding: 20px 24px !important;
|
||||
|
||||
.modal-title {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .modal-body {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
::ng-deep .modal-footer {
|
||||
padding: 20px 24px !important;
|
||||
background: var(--theme-background);
|
||||
border-radius: 0 0 16px 16px !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
// Data Grid Styles
|
||||
.um-datagrid {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
|
||||
::ng-deep .datagrid {
|
||||
.datagrid-head {
|
||||
background: var(--theme-background);
|
||||
|
||||
.datagrid-column {
|
||||
padding: 16px 24px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-row {
|
||||
transition: background-color 150ms ease-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.datagrid-cell {
|
||||
padding: 16px 24px;
|
||||
font-size: 14px;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@media (max-width: 768px) {
|
||||
.um-hero {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
|
||||
&__content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.um-form-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.um-btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,6 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AccesstypeService } from 'src/app/services/admin/accesstype.service';
|
||||
import { UsergrpmaintainceService } from 'src/app/services/admin/usergrpmaintaince.service';
|
||||
import { UsermaintanceService } from '../../../../services/admin/usermaintance.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-usermaintanceadd',
|
||||
@@ -15,62 +12,50 @@ import { Subscription } from 'rxjs';
|
||||
})
|
||||
export class UsermaintanceaddComponent implements OnInit {
|
||||
public entryForm: FormGroup;
|
||||
customer: boolean = false;
|
||||
department: boolean = false;
|
||||
position: boolean = false;
|
||||
customer:boolean=false;
|
||||
department:boolean=false;
|
||||
position:boolean=false;
|
||||
custdata: any;
|
||||
loading = false;
|
||||
clickedID: number;
|
||||
clickedID:number;
|
||||
custiddata: any;
|
||||
userobjcust = {
|
||||
customerName: '',
|
||||
customerCode: '',
|
||||
userobjcust={
|
||||
customerName:'',
|
||||
customerCode:'',
|
||||
}
|
||||
departmentdata: any;
|
||||
positiondata: any;
|
||||
deptiddata: any;
|
||||
userobjdept = {
|
||||
departmentCode: '',
|
||||
userobjdept={
|
||||
departmentCode:'',
|
||||
}
|
||||
userobjpos = {
|
||||
positionCode: '',
|
||||
userobjpos={
|
||||
positionCode:'',
|
||||
}
|
||||
posiddata: any;
|
||||
usergrpdata;
|
||||
accessdata;
|
||||
error;
|
||||
submitted = false;
|
||||
private themeSubscription: Subscription;
|
||||
submitted=false;
|
||||
|
||||
constructor(private _fb: FormBuilder,
|
||||
private mainservice: UsermaintanceService,
|
||||
private router: Router, private accesstype: AccesstypeService,
|
||||
constructor( private _fb: FormBuilder,
|
||||
private mainservice:UsermaintanceService,
|
||||
private router: Router,private accesstype:AccesstypeService,
|
||||
private route: ActivatedRoute,
|
||||
private usergrpservice: UsergrpmaintainceService,
|
||||
private translate: TranslateService,
|
||||
private themeService: ThemeService,
|
||||
private usergrpservice: UsergrpmaintainceService
|
||||
) { }
|
||||
|
||||
switchLanguage(language: string) {
|
||||
this.translate.use(language);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.themeSubscription = this.themeService.currentTheme$.subscribe(() => {
|
||||
// Theme changes will automatically update CSS variables
|
||||
// This triggers a re-render of themed elements
|
||||
});
|
||||
|
||||
this.entryForm = this._fb.group({
|
||||
first_name: ['', [Validators.required]],
|
||||
last_name: ['', [Validators.required]],
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
mob_no: ['', [Validators.required]],
|
||||
new_password: ['', [Validators.required, Validators.minLength(6)]],
|
||||
confirm_password: ['', [Validators.required]],
|
||||
usrGrpId: ['', [Validators.required]],
|
||||
account_id: 1,
|
||||
accesstype: ['', [Validators.required]],
|
||||
first_name :['',[Validators.required]],
|
||||
last_name:['',[Validators.required]],
|
||||
email:['',[Validators.required,Validators.email]],
|
||||
mob_no:['',[Validators.required]],
|
||||
new_password:['',[Validators.required,Validators.minLength(6)]],
|
||||
confirm_password:['',[Validators.required]],
|
||||
usrGrpId:['',[Validators.required]],
|
||||
account_id:1,
|
||||
accesstype:['',[Validators.required]],
|
||||
// status:[null],
|
||||
// username:[null] ,
|
||||
// userPassw:[null] ,
|
||||
@@ -96,29 +81,22 @@ export class UsermaintanceaddComponent implements OnInit {
|
||||
this.usergrp();
|
||||
this.getdata();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.themeSubscription) {
|
||||
this.themeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
getdata() {
|
||||
getdata(){
|
||||
this.accesstype.getAll().subscribe(resp => {
|
||||
this.accessdata = resp;
|
||||
console.log('accessdata: ', this.accessdata);
|
||||
if (this.accessdata.length == 0) {
|
||||
this.error = "No data Available";
|
||||
if(this.accessdata.length==0){
|
||||
this.error="No data Available";
|
||||
console.log(this.error)
|
||||
}
|
||||
}, (error) => {
|
||||
},(error) => {
|
||||
console.log(error);
|
||||
if (error) {
|
||||
this.error = "Server Error";
|
||||
if(error){
|
||||
this.error="Server Error";
|
||||
}
|
||||
})
|
||||
}
|
||||
usergrp() {
|
||||
usergrp(){
|
||||
this.usergrpservice.getAll().subscribe((data) => {
|
||||
console.log(data);
|
||||
this.usergrpdata = data;
|
||||
@@ -142,8 +120,8 @@ export class UsermaintanceaddComponent implements OnInit {
|
||||
|
||||
// });
|
||||
//}
|
||||
onSubmit() {
|
||||
this.submitted = true
|
||||
onSubmit(){
|
||||
this.submitted=true
|
||||
if (this.entryForm.invalid) {
|
||||
return;
|
||||
}
|
||||
@@ -158,53 +136,53 @@ export class UsermaintanceaddComponent implements OnInit {
|
||||
this.router.navigate(["../usermaintance"], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
goback() {
|
||||
goback(){
|
||||
this.router.navigate(["../usermaintance"], { relativeTo: this.route });
|
||||
}
|
||||
gotodepartmet() {
|
||||
this.department = !this.department;
|
||||
this.mainservice.getalldepartment().subscribe((data) => {
|
||||
}
|
||||
gotodepartmet(){
|
||||
this.department=!this.department;
|
||||
this.mainservice.getalldepartment().subscribe((data)=>{
|
||||
console.log(data);
|
||||
this.departmentdata = data;
|
||||
this.departmentdata=data;
|
||||
});
|
||||
}
|
||||
getdepid(id: number) {
|
||||
this.clickedID = id;
|
||||
console.log("clicked by id" + id);
|
||||
getdepid(id:number){
|
||||
this.clickedID=id;
|
||||
console.log("clicked by id"+ id);
|
||||
this.mainservice.getbydepartmentid(id).subscribe((data) => {
|
||||
console.log(data);
|
||||
this.deptiddata = data;
|
||||
this.deptiddata= data;
|
||||
// this.userObj= this.custiddata;
|
||||
this.userobjdept = this.deptiddata;
|
||||
this.userobjdept =this.deptiddata;
|
||||
|
||||
|
||||
});
|
||||
this.department = false;
|
||||
this.department=false;
|
||||
}
|
||||
gotoposition() {
|
||||
this.position = !this.position;
|
||||
this.mainservice.getallposition().subscribe((data) => {
|
||||
gotoposition(){
|
||||
this.position=!this.position;
|
||||
this.mainservice.getallposition().subscribe((data)=>{
|
||||
console.log(data);
|
||||
this.positiondata = data;
|
||||
this.positiondata=data;
|
||||
})
|
||||
}
|
||||
getposid(id: number) {
|
||||
this.clickedID = id;
|
||||
console.log("clicked by id" + id);
|
||||
getposid(id:number){
|
||||
this.clickedID=id;
|
||||
console.log("clicked by id"+ id);
|
||||
this.mainservice.getbypositionid(id).subscribe((data) => {
|
||||
console.log(data);
|
||||
this.posiddata = data;
|
||||
this.posiddata= data;
|
||||
// this.userObj= this.custiddata;
|
||||
this.userobjpos = this.posiddata;
|
||||
this.userobjpos =this.posiddata;
|
||||
|
||||
|
||||
});
|
||||
this.position = false;
|
||||
this.position=false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
export function ConfirmedValidator(controlName: string, matchingControlName: string) {
|
||||
export function ConfirmedValidator(controlName: string, matchingControlName: string){
|
||||
return (formGroup: FormGroup) => {
|
||||
const control = formGroup.controls[controlName];
|
||||
const matchingControl = formGroup.controls[matchingControlName];
|
||||
|
||||
@@ -1,136 +1,234 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="lock"></clr-icon> Security</a></li>
|
||||
<li><a href="javascript://">User Maintenance</a></li>
|
||||
</ol>
|
||||
|
||||
<section class="um-hero">
|
||||
<div class="um-hero__content">
|
||||
<div class="um-hero__icon"><clr-icon shape="user"></clr-icon></div>
|
||||
<div>
|
||||
<h2 class="um-hero__title">User Maintenance</h2>
|
||||
<p class="um-hero__subtitle">Edit User</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="um-edit-container">
|
||||
<div class="um-form-card">
|
||||
<form *ngIf="data1" (ngSubmit)="update()" class="um-form">
|
||||
<h4 style="font-weight: 300;display: inline;"> User Maintenance</h4>
|
||||
<span class="label label-light-blue" style="display: inline;margin-left: 30px;">Edit Mode</span><br>
|
||||
<hr>
|
||||
<div class="main" >
|
||||
<form *ngIf="data1">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="first_name" class="um-form-label">First Name<span class="required-field">*</span></label>
|
||||
<input type="text" id="first_name" class="um-form-input" name="first_name" [(ngModel)]="data1.fullName">
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name"> First Name</label>
|
||||
<input type="text" class="clr-input" name="first_name" [(ngModel)]="data1.fullName" >
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Last Name</label>
|
||||
<input type="text" class="clr-input" name="last_name" [(ngModel)]="data1.last_name">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Mobile Number</label>
|
||||
<input type="text" class="clr-input" name="mob_no" [(ngModel)]="data1.mob_no">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">New Password<span class="required-field">*</span></label>
|
||||
<input type="password" class="clr-input" name="new_password" [(ngModel)]="data1.userPassw">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="last_name" class="um-form-label">Last Name<span class="required-field">*</span></label>
|
||||
<input type="text" id="last_name" class="um-form-input" name="last_name" [(ngModel)]="data1.last_name">
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Business Title</label>
|
||||
<input type="text" class="clr-input" formControlName="title">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="mob_no" class="um-form-label">Mobile Number<span class="required-field">*</span></label>
|
||||
<input type="text" id="mob_no" class="um-form-input" name="mob_no" [(ngModel)]="data1.mob_no">
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name"> Short Name</label>
|
||||
<input type="text" class="clr-input" formControlName="shortName">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="email" class="um-form-label">Email<span class="required-field">*</span></label>
|
||||
<input type="text" id="email" class="um-form-input" name="email" [(ngModel)]="data1.email">
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Full Name</label>
|
||||
<input type="text" class="clr-input" formControlName="fullName">
|
||||
</div> -->
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Status</label>
|
||||
<select id="" formControlName="status">
|
||||
<option value="E">Enable</option>
|
||||
<option value="A">Active</option></select>
|
||||
</div> -->
|
||||
<!-- <div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Position Code</label>
|
||||
<input type="text" class="clr-input" formControlName="positionCodeString" [(ngModel)]="userobjpos.positionCode" name="positionCode" >
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="new_password" class="um-form-label">New Password<span class="required-field">*</span></label>
|
||||
<input type="password" id="new_password" class="um-form-input" name="new_password" [(ngModel)]="data1.userPassw">
|
||||
<div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" (click)="gotoposition()">V</button>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="usrGrpId" class="um-form-label">User Group<span class="required-field">*</span></label>
|
||||
<select id="usrGrpId" class="um-form-select" [(ngModel)]="data1.usrGrpId" name="usrGrpId">
|
||||
<option value="">Select User Group</option>
|
||||
<option *ngFor="let group of usergrpdata" [value]="group.usrGrp">{{group.groupName}}</option>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Department Code</label>
|
||||
<input type="text" class="clr-input" formControlName="departmentCodeString" [(ngModel)]="userobjdept.departmentCode" name="departmentCode">
|
||||
</div>
|
||||
<div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" (click)="gotodepartmet()">V</button>
|
||||
</div> -->
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">User Group</label>
|
||||
<select [(ngModel)]="data1.usrGrpId" name="usrGrpId">
|
||||
<option *ngFor="let sub of usergrpdata" [value]="sub.usrGrp">{{sub.groupName}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="accesstype" class="um-form-label">Access Type<span class="required-field">*</span></label>
|
||||
<select id="accesstype" class="um-form-select" [(ngModel)]="data1.accesstype" name="accesstype">
|
||||
<option value="">Select Access Type</option>
|
||||
<option *ngFor="let access of accessdata" [value]="access.name">{{access.name}}</option>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Customer Id</label>
|
||||
<input type="text" class="clr-input" formControlName="customerId" name="customerCode">
|
||||
</div> -->
|
||||
<!-- <div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" >V</button>
|
||||
</div> -->
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Email</label>
|
||||
<input type="text" class="clr-input" name="email" [(ngModel)]="data1.email">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Access Type</label>
|
||||
<select [(ngModel)]="data1.accesstype" name="usrGrpId">
|
||||
<option *ngFor="let sub of accessdata" [value]="sub.name">{{sub.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Notification</label>
|
||||
<select id="" formControlName="notification">
|
||||
<option value="N" >NO</option>
|
||||
<option value="Y">YES</option></select>
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
<!-- <div class="clr-row">
|
||||
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name"> User Name</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.username" name="username">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">New Password<span class="required-field">*</span></label>
|
||||
<input type="password" class="clr-input" [(ngModel)]="data1.userPassw" name="userPassw">
|
||||
</div>
|
||||
|
||||
<div class="um-form-actions">
|
||||
<button type="button" class="um-btn um-btn-outline" (click)="goback()">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>Close</span>
|
||||
</button>
|
||||
<button type="submit" class="um-btn um-btn-primary">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
<span>Update User</span>
|
||||
</button>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Business Title</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.title" name="title">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name"> Short Name</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.shortName" name="shortName">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Full Name</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.fullName" name="fullName">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Status</label>
|
||||
<select [(ngModel)]="data1.status" name="status">
|
||||
<option value="E">Enable</option>
|
||||
<option value="A">Active</option></select>
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Position Code</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.positionCodeString" [value]="userobjpos.positionCode" name="positionCodeString">
|
||||
</div>
|
||||
<div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" (click)="gotoposition()">V</button>
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Department Code</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.departmentCodeString" [value]="userobjdept.departmentCode" name="departmentCodeString">
|
||||
</div>
|
||||
<div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" (click)="gotodepartmet()">V</button>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">User Group</label>
|
||||
<select [(ngModel)]="data1.usrGrpId" name="usrGrpId">
|
||||
<option *ngFor="let sub of usergrpdata" [value]="sub.usrGrp">{{sub.groupName}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Customer Id</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.customerId" [value]="userobjcust.customerCode" name="customerId">
|
||||
</div>
|
||||
<div class="clr-col-md-1 clr-col-sm-12" style="margin-top: 25px;">
|
||||
<button style="margin-right: 5px;" (click)="gotocustomerid()">V</button>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="name">Email</label>
|
||||
<input type="text" class="clr-input"[(ngModel)]="data1.email" name="email">
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="tags">Notification</label>
|
||||
<select [(ngModel)]="data1.notification" name="notification">
|
||||
<option value="N" >NO</option>
|
||||
<option value="Y">YES</option></select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Created By</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.createby" name="createby">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Created On</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.createdate" name="createdate">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Updated By</label>
|
||||
<input type="text" class="clr-input" [(ngModel)]="data1.updateby" name="updateby">
|
||||
</div>
|
||||
<div class="clr-col-md-3 clr-col-sm-12">
|
||||
<label for="name">Updated On</label>
|
||||
<input type="text" class="clr-input"[(ngModel)]="data1.updatedate" name="updatedate">
|
||||
</div>
|
||||
</div> -->
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Customer Modal -->
|
||||
<clr-modal [(clrModalOpen)]="customer" [clrModalSize]="'lg'">
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="goback()">Close</button>
|
||||
<button type="button" class="btn btn-primary" (click)="update()">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="customer" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="um-form-input">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder>
|
||||
<clr-spinner>Loading ...</clr-spinner>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<clr-dg-placeholder><clr-spinner>Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Customer Code
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerCode'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerCode'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Customer Id
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'customerName'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Customer Name
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</clr-dg-column >
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of custdata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getcustID(user.customerId)" class="um-clickable-cell">{{user.customerCode}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.customerId}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getcustID(user.customerId)" style="color: rgb(108, 108, 194);" >{{user.customerCode}}</clr-dg-cell>
|
||||
<clr-dg-cell >{{user.customerId}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.customerName}}</clr-dg-cell>
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">No</td>
|
||||
<td class="td-title">NO</td>
|
||||
<td class="td-content">{{user.id}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="td-title">Customer Code</td>
|
||||
<td class="td-title"> Customer Code</td>
|
||||
<td class="td-content">{{user.customerCode}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="td-title">Customer Id</td>
|
||||
<td class="td-content">{{user.customerId}}</td>
|
||||
<td class="td-content">{{user.customerId}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="td-title">Customer Name</td>
|
||||
<td class="td-title"> Customer Name<td>
|
||||
<td class="td-content">{{user.customerName}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -146,41 +244,38 @@
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
</clr-modal>
|
||||
|
||||
<!-- Department Modal -->
|
||||
<clr-modal [(clrModalOpen)]="department" [clrModalSize]="'lg'">
|
||||
<clr-modal [(clrModalOpen)]="department" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="um-form-input">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder>
|
||||
<clr-spinner>Loading ...</clr-spinner>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<clr-dg-placeholder><clr-spinner>Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Department Code
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of departmentdata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getdepid(user.departmentCode)" class="um-clickable-cell">{{user.departmentCode}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getdepid(user.departmentCode)" style="color: rgb(108, 108, 194);" >{{user.departmentCode}}</clr-dg-cell>
|
||||
|
||||
|
||||
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">No</td>
|
||||
<td class="td-title">NO</td>
|
||||
<td class="td-content">{{user.id}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -195,42 +290,42 @@
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<!-- Position Modal -->
|
||||
<clr-modal [(clrModalOpen)]="position" [clrModalSize]="'lg'">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</clr-modal>
|
||||
<clr-modal [(clrModalOpen)]="position" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="um-form-input">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder>
|
||||
<clr-spinner>Loading ...</clr-spinner>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<clr-dg-placeholder><clr-spinner>Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'customerId'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Position Code
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of positiondata;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getposid(user.positionCode)" class="um-clickable-cell">{{user.positionCode}}</clr-dg-cell>
|
||||
<clr-dg-cell (click)="getposid(user.positionCode)" style="color: rgb(108, 108, 194);" >{{user.positionCode}}</clr-dg-cell>
|
||||
|
||||
|
||||
|
||||
|
||||
<clr-dg-row-detail *clrIfExpanded>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="td-title">No</td>
|
||||
<td class="td-title">NO</td>
|
||||
<td class="td-content">{{user.id}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -245,5 +340,9 @@
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</clr-modal>
|
||||
</clr-modal>
|
||||
|
||||
@@ -1,375 +1 @@
|
||||
@import '../../../../../styles1.scss';
|
||||
@import '../../../../../styles/_design-tokens.scss';
|
||||
|
||||
// User Maintenance Edit Styles
|
||||
.um-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
clr-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: var(--theme-font-secondary);
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.um-edit-container {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.um-form-card {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.um-form {
|
||||
.clr-row {
|
||||
margin: 0 -12px;
|
||||
}
|
||||
|
||||
.clr-col-md-6,
|
||||
.clr-col-sm-12 {
|
||||
padding: 0 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.um-form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
.um-form-input,
|
||||
.um-form-select {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
transition: all 200ms ease-out;
|
||||
margin-bottom: 0;
|
||||
font-family: var(--theme-font-primary);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1); // var(--theme-primary) with 10% opacity
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text-secondary);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border-color: #ef4444;
|
||||
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.um-form-select {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
|
||||
background-position: right 12px center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 12px;
|
||||
padding-right: 40px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: #ef4444;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.um-form-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
// Modern Button Styles using ThemeService
|
||||
.um-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: var(--theme-font-primary);
|
||||
z-index: 1;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--theme-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.um-btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.um-btn-md {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&.um-btn-lg {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
// Variants
|
||||
&.um-btn-primary {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, var(--theme-primary, #0284c7) 0%, var(--theme-accent, #7c3aed) 100%);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-outline {
|
||||
background: transparent;
|
||||
color: var(--theme-secondary);
|
||||
border-color: var(--theme-secondary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 116, 139, 0.1); // var(--theme-secondary) with 10% opacity
|
||||
border-color: var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: white;
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
border-color: var(--theme-error-dark, #dc2626);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3), 0 4px 6px -2px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&.um-btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--theme-text-secondary);
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.um-clickable-cell {
|
||||
color: var(--theme-primary);
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Styles
|
||||
::ng-deep .modal-header {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px 16px 0 0 !important;
|
||||
padding: 20px 24px !important;
|
||||
|
||||
.modal-title {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .modal-body {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
::ng-deep .modal-footer {
|
||||
padding: 20px 24px !important;
|
||||
background: var(--theme-background);
|
||||
border-radius: 0 0 16px 16px !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
// Data Grid Styles
|
||||
.um-datagrid {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
|
||||
::ng-deep .datagrid {
|
||||
.datagrid-head {
|
||||
background: var(--theme-background);
|
||||
|
||||
.datagrid-column {
|
||||
padding: 16px 24px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-row {
|
||||
transition: background-color 150ms ease-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.datagrid-cell {
|
||||
padding: 16px 24px;
|
||||
font-size: 14px;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@media (max-width: 768px) {
|
||||
.um-hero {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
|
||||
&__content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.um-form-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.um-btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AccesstypeService } from 'src/app/services/admin/accesstype.service';
|
||||
import { UsergrpmaintainceService } from 'src/app/services/admin/usergrpmaintaince.service';
|
||||
import { UsermaintanceService } from '../../../../services/admin/usermaintance.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
//import { Usermain } from 'src/app/models/usermaintaince';
|
||||
|
||||
@Component({
|
||||
selector: 'app-usermaintanceedit',
|
||||
@@ -13,52 +11,40 @@ import { Subscription } from 'rxjs';
|
||||
styleUrls: ['./usermaintanceedit.component.scss']
|
||||
})
|
||||
export class UsermaintanceeditComponent implements OnInit {
|
||||
id: number;
|
||||
data1: any = {};
|
||||
customer: boolean = false;
|
||||
id:number;
|
||||
data1:any={};
|
||||
customer:boolean=false;
|
||||
custdata: any;
|
||||
clickedID: number;
|
||||
clickedID:number;
|
||||
custiddata: any;
|
||||
loading = false;
|
||||
userobjcust = {
|
||||
customerName: '',
|
||||
customerCode: '',
|
||||
userobjcust={
|
||||
customerName:'',
|
||||
customerCode:'',
|
||||
}
|
||||
accessdata;
|
||||
department: boolean = false;
|
||||
department:boolean=false;
|
||||
departmentdata: any;
|
||||
positiondata: any;
|
||||
deptiddata: any;
|
||||
userobjdept = {
|
||||
departmentCode: '',
|
||||
userobjdept={
|
||||
departmentCode:'',
|
||||
}
|
||||
userobjpos = {
|
||||
positionCode: '',
|
||||
userobjpos={
|
||||
positionCode:'',
|
||||
}
|
||||
posiddata: any;
|
||||
position: boolean = false;
|
||||
position:boolean=false;
|
||||
usergrpdata;
|
||||
error;
|
||||
private themeSubscription: Subscription;
|
||||
constructor(private route:ActivatedRoute,
|
||||
private mainservice:UsermaintanceService,
|
||||
private router: Router,private accesstype:AccesstypeService,
|
||||
private usergrpservice: UsergrpmaintainceService
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private mainservice: UsermaintanceService,
|
||||
private router: Router, private accesstype: AccesstypeService,
|
||||
private usergrpservice: UsergrpmaintainceService,
|
||||
private translate: TranslateService,
|
||||
private themeService: ThemeService,
|
||||
) { }
|
||||
|
||||
switchLanguage(language: string) {
|
||||
this.translate.use(language);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.themeSubscription = this.themeService.currentTheme$.subscribe(() => {
|
||||
// Theme changes will automatically update CSS variables
|
||||
// This triggers a re-render of themed elements
|
||||
});
|
||||
|
||||
this.id = this.route.snapshot.params["id"];
|
||||
console.log("update with id = ", this.id);
|
||||
this.getById(this.id);
|
||||
@@ -66,89 +52,82 @@ export class UsermaintanceeditComponent implements OnInit {
|
||||
this.usergrp();
|
||||
this.getdata();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.themeSubscription) {
|
||||
this.themeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
getdata() {
|
||||
getdata(){
|
||||
this.accesstype.getAll().subscribe(resp => {
|
||||
this.accessdata = resp;
|
||||
console.log('accessdata: ', this.accessdata);
|
||||
if (this.accessdata.length == 0) {
|
||||
this.error = "No data Available";
|
||||
if(this.accessdata.length==0){
|
||||
this.error="No data Available";
|
||||
console.log(this.error)
|
||||
}
|
||||
}, (error) => {
|
||||
},(error) => {
|
||||
console.log(error);
|
||||
if (error) {
|
||||
this.error = "Server Error";
|
||||
if(error){
|
||||
this.error="Server Error";
|
||||
}
|
||||
})
|
||||
}
|
||||
usergrp() {
|
||||
usergrp(){
|
||||
this.usergrpservice.getAll().subscribe((data) => {
|
||||
console.log(data);
|
||||
this.usergrpdata = data;
|
||||
});
|
||||
}
|
||||
getById(id: number) {
|
||||
this.mainservice.getbyid(id).subscribe((data) => {
|
||||
this.data1 = data;
|
||||
getById(id:number){
|
||||
this.mainservice.getbyid(id).subscribe((data)=>{
|
||||
this.data1=data;
|
||||
// this.data1=this.data3;
|
||||
console.log(this.data1);
|
||||
});
|
||||
}
|
||||
update() {
|
||||
});
|
||||
}
|
||||
update(){
|
||||
console.log(this.data1);
|
||||
this.mainservice.updatenew(this.id, this.data1).subscribe((data) => {
|
||||
console.log(data);
|
||||
this.mainservice.updatenew(this.id,this.data1).subscribe((data)=>{
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
}
|
||||
goback() {
|
||||
}
|
||||
goback(){
|
||||
this.router.navigate(["../../usermaintance"], { relativeTo: this.route });
|
||||
}
|
||||
gotodepartmet() {
|
||||
this.department = !this.department;
|
||||
this.mainservice.getalldepartment().subscribe((data) => {
|
||||
}
|
||||
gotodepartmet(){
|
||||
this.department=!this.department;
|
||||
this.mainservice.getalldepartment().subscribe((data)=>{
|
||||
console.log(data);
|
||||
this.departmentdata = data;
|
||||
this.departmentdata=data;
|
||||
});
|
||||
}
|
||||
getdepid(id: number) {
|
||||
this.clickedID = id;
|
||||
console.log("clicked by id" + id);
|
||||
getdepid(id:number){
|
||||
this.clickedID=id;
|
||||
console.log("clicked by id"+ id);
|
||||
this.mainservice.getbydepartmentid(id).subscribe((data) => {
|
||||
console.log(data);
|
||||
this.deptiddata = data;
|
||||
this.deptiddata= data;
|
||||
// this.userObj= this.custiddata;
|
||||
this.userobjdept = this.deptiddata;
|
||||
this.userobjdept =this.deptiddata;
|
||||
|
||||
|
||||
});
|
||||
this.department = false;
|
||||
this.department=false;
|
||||
}
|
||||
gotoposition() {
|
||||
this.position = !this.position;
|
||||
this.mainservice.getallposition().subscribe((data) => {
|
||||
gotoposition(){
|
||||
this.position=!this.position;
|
||||
this.mainservice.getallposition().subscribe((data)=>{
|
||||
console.log(data);
|
||||
this.positiondata = data;
|
||||
this.positiondata=data;
|
||||
})
|
||||
}
|
||||
getposid(id: number) {
|
||||
this.clickedID = id;
|
||||
console.log("clicked by id" + id);
|
||||
getposid(id:number){
|
||||
this.clickedID=id;
|
||||
console.log("clicked by id"+ id);
|
||||
this.mainservice.getbypositionid(id).subscribe((data) => {
|
||||
console.log(data);
|
||||
this.posiddata = data;
|
||||
this.posiddata= data;
|
||||
// this.userObj= this.custiddata;
|
||||
this.userobjpos = this.posiddata;
|
||||
this.userobjpos =this.posiddata;
|
||||
|
||||
|
||||
});
|
||||
this.position = false;
|
||||
this.position=false;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong mm-breadcrumb">
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li>
|
||||
<a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']">
|
||||
<clr-icon shape="home"></clr-icon>
|
||||
@@ -8,400 +8,236 @@
|
||||
<a href="">
|
||||
<clr-icon shape="flag"></clr-icon>{{ 'SEQ_GENERATOR' | translate }}</a>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
|
||||
<section class="sq-hero">
|
||||
<div class="sq-hero__content">
|
||||
<div class="sq-hero__icon"><clr-icon shape="number-list"></clr-icon></div>
|
||||
<div>
|
||||
<h2 class="sq-hero__title">{{ 'SEQ_GENERATOR' | translate }}</h2>
|
||||
<p class="sq-hero__subtitle">{{ 'FND' | translate }}</p>
|
||||
<div class="dg-wrapper">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-8">
|
||||
<h3>{{ 'SEQ_GENERATOR' | translate }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sq-hero__actions">
|
||||
<button class="sq-btn sq-btn-outline" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon> <span class="sq-btn-text">{{ 'EXPORT' | translate }}</span>
|
||||
</button>
|
||||
<button id="add" class="sq-btn sq-btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon><span class="sq-btn-text">{{ 'ADD' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sq-container">
|
||||
<div class="sq-toolbar">
|
||||
<div class="sq-toolbar__left">
|
||||
<div class="sq-search">
|
||||
<clr-icon shape="search"></clr-icon>
|
||||
<input class="sq-search__input" type="text" [placeholder]="'SEARCH_ALL_FIELDS' | translate" [(ngModel)]="filterText" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="sq-toolbar__right sq-stats">
|
||||
<div class="sq-stat">
|
||||
<div class="sq-stat__value">{{ totalSequences }}</div>
|
||||
<div class="sq-stat__label">{{ 'TOTAL_SEQUENCES' | translate }}</div>
|
||||
</div>
|
||||
<div class="sq-view-toggle">
|
||||
<button class="sq-btn sq-btn-sm" [class.sq-btn-primary]="viewMode==='cards'" (click)="setViewMode('cards')">
|
||||
<clr-icon shape="view-cards"></clr-icon>
|
||||
<div class="clr-col-4" style="text-align: right;">
|
||||
<button class="btn btn-outline" (click)="onExport()">
|
||||
<clr-icon shape="export"></clr-icon> {{ 'EXPORT' | translate }}
|
||||
</button>
|
||||
<button class="sq-btn sq-btn-sm" [class.sq-btn-primary]="viewMode==='table'" (click)="setViewMode('table')">
|
||||
<clr-icon shape="table"></clr-icon>
|
||||
<button id="add" class="btn btn-primary" (click)="goToAdd()">
|
||||
<clr-icon shape="plus"></clr-icon>{{ 'ADD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-datagrid class="sq-grid" [clrDgLoading]="loading" *ngIf="viewMode==='table'" [(clrDgSelected)]="selected">
|
||||
<clr-datagrid [clrDgLoading]="loading" [(clrDgSelected)]="selected">
|
||||
<clr-dg-placeholder>
|
||||
<ng-template #loadingSpinner>
|
||||
<clr-spinner>{{ 'LOADING' | translate }} ... </clr-spinner>
|
||||
<clr-spinner>Loading ... </clr-spinner>
|
||||
</ng-template>
|
||||
<div *ngIf="error;else loadingSpinner">{{error}}</div>
|
||||
</clr-dg-placeholder>
|
||||
|
||||
<clr-dg-column [clrDgField]="'current_no'" class="sq-col sq-col--no">
|
||||
<clr-dg-column [clrDgField]="'seq_no'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="hashtag"></clr-icon> {{ 'CURRENT_NO' | translate }}
|
||||
</span>
|
||||
{{ 'CURRENT_NO' | translate }}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'seq_no'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'NAME' | translate }}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'prefix'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
{{ 'PREFIX' | translate }}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'sequence_name'" class="sq-col sq-col--name">
|
||||
<clr-dg-column [clrDgField]="'seperator'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="tag"></clr-icon> {{ 'NAME' | translate }}
|
||||
</span>
|
||||
{{ 'SEPARATOR' | translate }}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'prefix'" class="sq-col sq-col--prefix">
|
||||
<clr-dg-column [clrDgField]="'digit'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="text"></clr-icon> {{ 'PREFIX' | translate }}
|
||||
</span>
|
||||
{{ 'SEQUENCE_SIZE' | translate }}
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'seperator'" class="sq-col sq-col--separator">
|
||||
<!-- <clr-dg-column [clrDgField]="'date_format'">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="split-string"></clr-icon> {{ 'SEPARATOR' | translate }}
|
||||
</span>
|
||||
Date Format
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'sequence_size'" class="sq-col sq-col--size">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="ruler"></clr-icon> {{ 'SEQUENCE_SIZE' | translate }}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'suffix'" class="sq-col sq-col--suffix">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="text"></clr-icon> {{ 'SUFFIX' | translate }}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'starting_no'" class="sq-col sq-col--starting">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="play"></clr-icon> {{ 'STARTING_NO' | translate }}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-column [clrDgField]="'sequence_code'" class="sq-col sq-col--code">
|
||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
<span class="sq-col-title">
|
||||
<clr-icon shape="code"></clr-icon> {{ 'SEQUENCE_CODE' | translate }}
|
||||
</span>
|
||||
</ng-container>
|
||||
</clr-dg-column>
|
||||
|
||||
<clr-dg-row *clrDgItems="let user of filteredSequences" [clrDgItem]="user">
|
||||
</clr-dg-column> -->
|
||||
<clr-dg-row *clrDgItems="let user of alldata" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{user.current_no}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.sequence_name}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.prefix}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.seperator}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.sequence_size}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.suffix}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.starting_no}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.sequence_code}}</clr-dg-cell>
|
||||
<!-- <clr-dg-cell>{{user.date_format}}</clr-dg-cell> -->
|
||||
<clr-dg-action-overflow>
|
||||
<button class="sq-action-item" (click)="goToEdit(user)">
|
||||
{{ 'EDIT' | translate }}
|
||||
<clr-icon shape="edit"></clr-icon>
|
||||
</button>
|
||||
<button class="sq-action-item sq-btn-error" (click)="onDelete(user)">
|
||||
{{ 'DELETE' | translate }}
|
||||
<clr-icon shape="trash"></clr-icon>
|
||||
</button>
|
||||
<button class="action-item" (click)="goToEdit(user)"> {{ 'EDIT' | translate }} <clr-icon shape="edit"
|
||||
class="is-error"></clr-icon></button>
|
||||
<button class="action-item" (click)="onDelete(user)"> {{ 'DELETE' | translate }}<clr-icon shape="trash"
|
||||
class="is-error"></clr-icon></button>
|
||||
</clr-dg-action-overflow>
|
||||
|
||||
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer class="sq-grid-footer">
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">
|
||||
{{ 'RECORDS_PER_PAGE' | translate }}
|
||||
</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
{{ 'OF' | translate }} {{pagination.totalItems}} {{ 'RECORDS' | translate }}
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">{{ 'USERS_PER_PAGE' | translate
|
||||
}}</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} of {{pagination.totalItems}} users
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
|
||||
<div class="sq-cards" *ngIf="viewMode==='cards'">
|
||||
<div class="sq-card-item" *ngFor="let user of filteredSequences">
|
||||
<div class="sq-card-item__header">
|
||||
<div class="sq-card-item__icon"><clr-icon shape="number-list"></clr-icon></div>
|
||||
<div class="sq-card-item__title">{{user.sequence_name}}</div>
|
||||
<div class="sq-card-item__badge">{{user.current_no}}</div>
|
||||
</div>
|
||||
<div class="sq-card-item__body">
|
||||
<div class="sq-kv"><span>{{ 'PREFIX' | translate }}</span><strong>{{user.prefix}}</strong></div>
|
||||
<div class="sq-kv"><span>{{ 'SEPARATOR' | translate }}</span><strong>{{user.seperator}}</strong></div>
|
||||
<div class="sq-kv"><span>{{ 'SEQUENCE_SIZE' | translate }}</span><strong>{{user.sequence_size}}</strong></div>
|
||||
<div class="sq-kv" *ngIf="user.suffix"><span>{{ 'SUFFIX' | translate }}</span><strong>{{user.suffix}}</strong></div>
|
||||
<div class="sq-kv" *ngIf="user.starting_no"><span>{{ 'STARTING_NO' | translate }}</span><strong>{{user.starting_no}}</strong></div>
|
||||
<div class="sq-kv" *ngIf="user.sequence_code"><span>{{ 'SEQUENCE_CODE' | translate }}</span><strong>{{user.sequence_code}}</strong></div>
|
||||
<div class="sq-kv" *ngIf="user.demonstration"><span>{{ 'DEMONSTRATION' | translate }}</span><strong>{{user.demonstration}}</strong></div>
|
||||
</div>
|
||||
<div class="sq-card-item__footer">
|
||||
<button class="sq-btn sq-btn-sm sq-btn-outline" (click)="goToEdit(user)">
|
||||
<clr-icon shape="edit"></clr-icon> {{ 'EDIT' | translate }}
|
||||
</button>
|
||||
<button class="sq-btn sq-btn-sm sq-btn-outline" (click)="onDelete(user)">
|
||||
<clr-icon shape="trash"></clr-icon> {{ 'DELETE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-modal class="sq-modal" [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<div class="modal-body">
|
||||
<div class="sq-delete-header">
|
||||
<div class="sq-delete-icon">
|
||||
<clr-icon shape="exclamation-triangle" size="48"></clr-icon>
|
||||
</div>
|
||||
<h1 class="sq-delete-title">{{ 'ARE_YOU_SURE_WANT_TO_DELETE' | translate }}?</h1>
|
||||
<p class="sq-delete-subtitle">{{ 'THIS_ACTION_CANNOT_BE_UNDONE' | translate }}</p>
|
||||
</div>
|
||||
<div class="sq-delete-details" *ngIf="rowSelected.id">
|
||||
<div class="sq-delete-detail-item">
|
||||
<span class="sq-delete-detail-label">{{ 'SEQUENCE_ID' | translate }}:</span>
|
||||
<span class="sq-delete-detail-value">{{rowSelected.id}}</span>
|
||||
</div>
|
||||
<div class="sq-delete-detail-item">
|
||||
<span class="sq-delete-detail-label">{{ 'SEQUENCE_NAME' | translate }}:</span>
|
||||
<span class="sq-delete-detail-value">{{rowSelected.sequence_name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="sq-btn sq-btn-outline" (click)="modaldelete = false">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{ 'CANCEL' | translate }}</span>
|
||||
</button>
|
||||
<button type="submit" (click)="delete(rowSelected.id)" class="sq-btn sq-btn-error">
|
||||
<clr-icon shape="trash"></clr-icon>
|
||||
<span>{{ 'DELETE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
|
||||
<clr-modal class="sq-modal" [(clrModalOpen)]="modaladd" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title sq-modal-title">
|
||||
<clr-icon shape="plus"></clr-icon> {{ 'ADD_SEQUENCE_GENERATOR' | translate }}
|
||||
</h3>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()" class="sq-form">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="sequence_name" class="sq-form-label">
|
||||
{{ 'NAME' | translate }}<span class="required-field">*</span>
|
||||
</label>
|
||||
<input type="text" id="sequence_name" class="sq-form-input" name="sequence_name" formControlName="sequence_name">
|
||||
<div *ngIf="submitted && entryForm.controls.sequence_name.errors" class="sq-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.sequence_name.errors.required">
|
||||
{{ 'THIS_FIELD_IS_REQUIRED' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="sequence_code" class="sq-form-label">
|
||||
{{ 'SEQUENCE_CODE' | translate }}
|
||||
</label>
|
||||
<input type="text" id="sequence_code" class="sq-form-input" name="sequence_code" formControlName="sequence_code">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="demonstration" class="sq-form-label">
|
||||
{{ 'DEMONSTRATION' | translate }}
|
||||
</label>
|
||||
<input type="text" id="demonstration" class="sq-form-input" formControlName="demonstration">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="prefix" class="sq-form-label">
|
||||
{{ 'PREFIX' | translate }}<span class="required-field">*</span>
|
||||
</label>
|
||||
<input type="text" id="prefix" class="sq-form-input" formControlName="prefix" name="prefix">
|
||||
<div *ngIf="submitted && entryForm.controls.prefix.errors" class="sq-error-message">
|
||||
<div *ngIf="submitted && entryForm.controls.prefix.errors.required">
|
||||
{{ 'THIS_FIELD_IS_REQUIRED' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="suffix" class="sq-form-label">
|
||||
{{ 'SUFFIX' | translate }}
|
||||
</label>
|
||||
<input type="text" id="suffix" class="sq-form-input" name="suffix" formControlName="suffix">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="seperator" class="sq-form-label">
|
||||
{{ 'SEPARATOR' | translate }}
|
||||
</label>
|
||||
<input type="text" id="seperator" class="sq-form-input" name="seperator" formControlName="seperator">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="starting_no" class="sq-form-label">
|
||||
{{ 'STARTING_NO' | translate }}
|
||||
</label>
|
||||
<input type="number" id="starting_no" class="sq-form-input" name="starting_no" formControlName="starting_no">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="current_no" class="sq-form-label">
|
||||
{{ 'CURRENT_NO' | translate }}
|
||||
</label>
|
||||
<input type="number" id="current_no" class="sq-form-input" formControlName="current_no">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="sequence_size" class="sq-form-label">
|
||||
{{ 'SEQUENCE_SIZE' | translate }}
|
||||
</label>
|
||||
<input type="number" id="sequence_size" class="sq-form-input" name="sequence_size" formControlName="sequence_size">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sq-form-actions">
|
||||
<button type="button" class="sq-btn sq-btn-outline" (click)="modaladd = false">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{ 'CANCEL' | translate }}</span>
|
||||
</button>
|
||||
<button type="submit" class="sq-btn sq-btn-primary">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
<span>{{ 'ADD' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal class="sq-modal" [(clrModalOpen)]="modaledit" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title sq-modal-title">
|
||||
<clr-icon shape="edit"></clr-icon> {{ 'UPDATE_SEQUENCE_GENERATOR' | translate }}
|
||||
</h3>
|
||||
<div class="modal-body" *ngIf="rowSelected.id">
|
||||
<div class="sq-form-help">
|
||||
{{ 'SEQUENCE_ID' | translate }}: <code class="clr-code">{{rowSelected.id}}</code>
|
||||
<h1 class="delete">Are You Sure Want to delete?</h1>
|
||||
<h2 class="heading">{{rowSelected.id}}</h2>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
|
||||
<button type="submit" (click)="delete(rowSelected.id)" class="btn btn-primary">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<form (ngSubmit)="onUpdate(rowSelected.id)" class="sq-form">
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modaladd" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Add Sequence Genarator</h3>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="sequence_name" class="sq-form-label">
|
||||
{{ 'NAME' | translate }}<span class="required-field">*</span>
|
||||
</label>
|
||||
<input type="text" id="sequence_name" class="sq-form-input" name="sequence_name" [(ngModel)]="rowSelected.sequence_name">
|
||||
<div class="sq-error-message" *ngIf="!rowSelected.sequence_name">
|
||||
{{ 'THIS_FIELD_IS_REQUIRED' | translate }}
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Name<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" name="sequence_name" formControlName="sequence_name">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Sequence Code</label>
|
||||
<input type="text" class="clr-input" name="sequence_code" formControlName="sequence_code">
|
||||
</div>
|
||||
<!-- <div class="clr-col-sm-12">
|
||||
<label for="name">Implementation</label>
|
||||
<select name="implementation" formControlName="implementation" class="clr-dropdown">
|
||||
<option>standard</option>
|
||||
<option>shared</option>
|
||||
</select>
|
||||
</div> -->
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Demonstration</label>
|
||||
<input type="text" class="clr-input" formControlName="demonstration">
|
||||
</div>
|
||||
<!-- <div class="clr-col-sm-12">
|
||||
<label for="name">Active</label>
|
||||
<input type="checkbox" formControlName="active" name="active" clrCheckbox>
|
||||
</div> -->
|
||||
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Prefix<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" formControlName="prefix" name="prefix">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">suffix</label>
|
||||
<input type="text" class="clr-input" name="suffix" formControlName="suffix">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Separator</label>
|
||||
<input type="text" class="clr-input" name="seperator" formControlName="seperator">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Starting No</label>
|
||||
<input type="number" class="clr-input" name="starting_no" formControlName="starting_no">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Current No</label>
|
||||
<input type="number" class="clr-input" formControlName="current_no">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="sequence_code" class="sq-form-label">
|
||||
{{ 'SEQUENCE_CODE' | translate }}
|
||||
</label>
|
||||
<input type="text" id="sequence_code" class="sq-form-input" name="sequence_code" [(ngModel)]="rowSelected.sequence_code">
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags"> Size</label>
|
||||
<input type="number" class="clr-input" name="sequence_size" formControlName="sequence_size">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="demonstration" class="sq-form-label">
|
||||
{{ 'DEMONSTRATION' | translate }}
|
||||
</label>
|
||||
<input type="text" id="demonstration" class="sq-form-input" name="demonstration" [(ngModel)]="rowSelected.demonstration" readonly>
|
||||
<!-- <div class="clr-col-sm-12">
|
||||
<label for="tags">Date Format</label>
|
||||
<input type="text" class="clr-input" name="date_format" formControlName="date_format">
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="prefix" class="sq-form-label">
|
||||
{{ 'PREFIX' | translate }}<span class="required-field">*</span>
|
||||
</label>
|
||||
<input type="text" id="prefix" class="sq-form-input" name="prefix" [(ngModel)]="rowSelected.prefix">
|
||||
<div class="sq-error-message" *ngIf="!rowSelected.prefix">
|
||||
{{ 'THIS_FIELD_IS_REQUIRED' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="suffix" class="sq-form-label">
|
||||
{{ 'SUFFIX' | translate }}
|
||||
</label>
|
||||
<input type="text" id="suffix" class="sq-form-input" name="suffix" [(ngModel)]="rowSelected.suffix">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="seperator" class="sq-form-label">
|
||||
{{ 'SEPARATOR' | translate }}
|
||||
</label>
|
||||
<input type="text" id="seperator" class="sq-form-input" name="seperator" [(ngModel)]="rowSelected.seperator">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="starting_no" class="sq-form-label">
|
||||
{{ 'STARTING_NO' | translate }}
|
||||
</label>
|
||||
<input type="number" id="starting_no" class="sq-form-input" name="starting_no" [(ngModel)]="rowSelected.starting_no">
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="current_no" class="sq-form-label">
|
||||
{{ 'CURRENT_NO' | translate }}
|
||||
</label>
|
||||
<input type="number" id="current_no" class="sq-form-input" name="current_no" [(ngModel)]="rowSelected.current_no" readonly>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="sequence_size" class="sq-form-label">
|
||||
{{ 'SEQUENCE_SIZE' | translate }}
|
||||
</label>
|
||||
<input type="number" id="sequence_size" class="sq-form-input" name="sequence_size" [(ngModel)]="rowSelected.sequence_size">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sq-form-actions">
|
||||
<button type="button" class="sq-btn sq-btn-outline" (click)="modaledit = false">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{ 'CANCEL' | translate }}</span>
|
||||
</button>
|
||||
<button type="submit" class="sq-btn sq-btn-primary">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
<span>{{ 'UPDATE' | translate }}</span>
|
||||
</button>
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaladd = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">ADD</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modaledit" [clrModalSize]="'md'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title">Update Sequence Genarator</h3>
|
||||
<div class="modal-body" *ngIf="rowSelected.id">
|
||||
<h2 class="heading">{{rowSelected.id}}</h2>
|
||||
<form (ngSubmit)="onUpdate(rowSelected.id)">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Name<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" name="sequence_name" [(ngModel)]="rowSelected.sequence_name">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Sequence Code</label>
|
||||
<input type="text" class="clr-input" name="sequence_code" [(ngModel)]="rowSelected.sequence_code">
|
||||
</div>
|
||||
<!-- <div class="clr-col-sm-12">
|
||||
<label for="name">Implementation</label>
|
||||
<select name="implementation" class="clr-dropdown" [(ngModel)]="rowSelected.implementation">
|
||||
<option>standard</option>
|
||||
<option>shared</option>
|
||||
</select>
|
||||
</div> -->
|
||||
<!-- <div class="clr-col-sm-12">
|
||||
<label for="name">Active</label>
|
||||
<input type="checkbox" name="active" name="menuId" clrCheckbox [(ngModel)]="rowSelected.active">
|
||||
</div> -->
|
||||
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="name">Prefix<span class="required-field">*</span></label>
|
||||
<input type="text" class="clr-input" name="prefix" [(ngModel)]="rowSelected.prefix">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">suffix</label>
|
||||
<input type="text" class="clr-input" name="suffix" [(ngModel)]="rowSelected.suffix">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Separator</label>
|
||||
<input type="text" class="clr-input" name="seperator" [(ngModel)]="rowSelected.seperator">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Starting No</label>
|
||||
<input type="number" class="clr-input" name="starting_no" [(ngModel)]="rowSelected.starting_no">
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Current No</label>
|
||||
<input type="number" class="clr-input" name="current_no" [(ngModel)]="rowSelected.current_no"
|
||||
readonly>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Demonstration</label>
|
||||
<input type="text" class="clr-input" name="demonstration" [(ngModel)]="rowSelected.demonstration"
|
||||
readonly>
|
||||
</div>
|
||||
<div class="clr-col-sm-12">
|
||||
<label for="tags">Sequence Size</label>
|
||||
<input type="number" class="clr-input" name="sequence_size" [(ngModel)]="rowSelected.sequence_size">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaledit = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</clr-modal>
|
||||
@@ -1,694 +1,72 @@
|
||||
@import '../../../../../styles/_design-tokens.scss';
|
||||
|
||||
// Sequence Generator Styles
|
||||
.sq-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
clr-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: var(--theme-font-secondary);
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-container {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
// Toolbar, search and stats
|
||||
.sq-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&__left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-search {
|
||||
position: relative;
|
||||
max-width: 400px;
|
||||
|
||||
clr-icon {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #9ca3af;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__input {
|
||||
input[type=text],[type=number],
|
||||
[type=date],
|
||||
[type=password] {
|
||||
width: 100%;
|
||||
padding: 12px 12px 12px 40px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: all 200ms ease-out;
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
font-family: var(--theme-font-primary);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sq-stats {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.sq-stat {
|
||||
min-width: 110px;
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
border-radius: var(--theme-border-radius);
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
box-shadow: var(--theme-shadow);
|
||||
|
||||
&__value {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--theme-primary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 12px;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-view-toggle {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.sq-btn {
|
||||
min-width: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
// Grid columns
|
||||
.sq-col-title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.sq-col--prefix .sq-col-title clr-icon,
|
||||
.sq-col--separator .sq-col-title clr-icon,
|
||||
.sq-col--size .sq-col-title clr-icon {
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
// Data Grid Styles
|
||||
.sq-grid {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 24px;
|
||||
|
||||
::ng-deep .datagrid {
|
||||
.datagrid-head {
|
||||
background: var(--theme-background);
|
||||
|
||||
.datagrid-column {
|
||||
padding: 16px 24px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-row {
|
||||
transition: background-color 150ms ease-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.datagrid-cell {
|
||||
padding: 16px 24px;
|
||||
font-size: 14px;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
|
||||
.datagrid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sq-grid-footer {
|
||||
background: var(--theme-background);
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
// Card View Styles
|
||||
.sq-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.sq-card-item {
|
||||
background: var(--theme-surface);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
transition: all 200ms ease-out;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
padding: 12px;
|
||||
margin-right: 16px;
|
||||
|
||||
clr-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
flex: 1;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__badge {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 20px;
|
||||
padding: 4px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 0 20px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-kv {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
span {
|
||||
color: var(--theme-text-secondary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: var(--theme-text);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
// Form Styles
|
||||
.sq-form {
|
||||
.clr-row {
|
||||
margin: 0 -12px;
|
||||
}
|
||||
|
||||
.clr-col-md-6,
|
||||
.clr-col-sm-12 {
|
||||
padding: 0 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
}
|
||||
|
||||
.sq-form-input,
|
||||
.sq-form-select {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
transition: all 200ms ease-out;
|
||||
margin-bottom: 0;
|
||||
font-family: var(--theme-font-primary);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text-secondary);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.sq-form-select {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
|
||||
background-position: right 12px center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 12px;
|
||||
padding-right: 40px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.sq-error-message {
|
||||
color: var(--theme-error, #ef4444);
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
font-weight: 500;
|
||||
padding: 15px 20px;
|
||||
// margin: 3px 0;
|
||||
background-color: rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: var(--theme-error, #ef4444);
|
||||
margin-left: 4px;
|
||||
color: red;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.sq-form-help {
|
||||
color: var(--theme-text-secondary);
|
||||
font-size: 12px;
|
||||
margin-bottom: 16px;
|
||||
font-family: var(--theme-font-primary);
|
||||
.green {
|
||||
background-color: rgb(156, 231, 156);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.sq-form-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||
.blue {
|
||||
background-color: #57abcf; //rgb(82, 87, 161);
|
||||
color: black;
|
||||
}
|
||||
|
||||
// Modern Button Styles using ThemeService
|
||||
.sq-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease-out;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: var(--theme-font-primary);
|
||||
z-index: 1;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--theme-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.sq-btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.sq-btn-md {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&.sq-btn-lg {
|
||||
padding: 16px 24px;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
// Variants
|
||||
&.sq-btn-primary {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
.td-title {
|
||||
text-align: center;
|
||||
width: 150px;
|
||||
color: white;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, var(--theme-primary, #0284c7) 0%, var(--theme-accent, #7c3aed) 100%);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
&.sq-btn-outline {
|
||||
background: transparent;
|
||||
color: var(--theme-secondary);
|
||||
border-color: var(--theme-secondary);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: rgba(100, 116, 139, 0.1);
|
||||
border-color: var(--theme-secondary);
|
||||
color: var(--theme-secondary);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
&.sq-btn-error {
|
||||
background: var(--theme-error, #ef4444);
|
||||
color: white;
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-error-dark, #dc2626);
|
||||
border-color: var(--theme-error-dark, #dc2626);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3), 0 4px 6px -2px rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&.sq-btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--theme-text-secondary);
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
}
|
||||
font-weight: bold;
|
||||
background-color: rgba(63, 122, 231, 0.863);
|
||||
//color: rgb(24, 13, 13);
|
||||
}
|
||||
|
||||
// Action items in datagrid
|
||||
.sq-action-item {
|
||||
@extend .sq-btn;
|
||||
@extend .sq-btn-ghost;
|
||||
@extend .sq-btn-sm;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 4px;
|
||||
th {
|
||||
//background-color:rgb(170, 169, 169);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.td-content {
|
||||
text-align: left;
|
||||
|
||||
clr-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&.sq-btn-error {
|
||||
color: var(--theme-error, #ef4444);
|
||||
|
||||
&:hover {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
color: var(--theme-error, #ef4444);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Modal Styles
|
||||
.sq-delete-header {
|
||||
.delete,
|
||||
.heading {
|
||||
text-align: center;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
color: red;
|
||||
}
|
||||
|
||||
.sq-delete-icon {
|
||||
color: var(--theme-error, #ef4444);
|
||||
margin-bottom: 16px;
|
||||
.section p {
|
||||
background-color: rgb(206, 201, 201);
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.sq-delete-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--theme-text);
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.sq-delete-subtitle {
|
||||
font-size: 16px;
|
||||
color: var(--theme-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sq-delete-details {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.sq-delete-detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-delete-detail-label {
|
||||
font-weight: 500;
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
.sq-delete-detail-value {
|
||||
font-weight: 600;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
// Modal Styles
|
||||
.sq-modal-title clr-icon {
|
||||
margin-right: 6px;
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
::ng-deep .modal-header {
|
||||
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-accent) 100%);
|
||||
color: white;
|
||||
border-radius: 16px 16px 0 0 !important;
|
||||
padding: 20px 24px !important;
|
||||
|
||||
.modal-title {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .modal-body {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
::ng-deep .modal-footer {
|
||||
padding: 20px 24px !important;
|
||||
background: var(--theme-background);
|
||||
border-radius: 0 0 16px 16px !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
// Breadcrumb
|
||||
.mm-breadcrumb {
|
||||
color: var(--theme-text-secondary);
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@media (max-width: 768px) {
|
||||
.sq-hero {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
|
||||
&__content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
select {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-toolbar {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.sq-search {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.sq-stats {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sq-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.sq-form-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sq-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sq-card-item__footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
padding: 5px 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
input.ng-invalid.ng-touched {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.error_mess {
|
||||
color: red;
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { SequenceService } from 'src/app/services/api/sequence.service';
|
||||
import { ExcelService } from 'src/app/services/excel.service';
|
||||
import * as moment from 'moment';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sequencegenarator',
|
||||
templateUrl: './sequencegenarator.component.html',
|
||||
@@ -24,70 +22,27 @@ export class SequencegenaratorComponent implements OnInit {
|
||||
modaladd = false;
|
||||
modaledit = false;
|
||||
submitted = false;
|
||||
filterText = '';
|
||||
// Changed default view to cards
|
||||
viewMode: 'table' | 'cards' = 'cards';
|
||||
|
||||
public entryForm: FormGroup;
|
||||
|
||||
constructor(
|
||||
private seqservice: SequenceService,
|
||||
private router: Router,
|
||||
private toastr: ToastrService,
|
||||
private _fb: FormBuilder,
|
||||
private route: ActivatedRoute,
|
||||
private excel: ExcelService,
|
||||
private themeService: ThemeService
|
||||
) { }
|
||||
constructor(private seqservice: SequenceService, private router: Router, private toastr: ToastrService, private _fb: FormBuilder,
|
||||
private route: ActivatedRoute, private excel: ExcelService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// Ensure theme variables are applied to the view
|
||||
this.themeService.currentTheme$.subscribe(() => {
|
||||
// CSS variables are updated globally; no extra handling needed here
|
||||
});
|
||||
|
||||
this.getall();
|
||||
this.entryForm = this._fb.group({
|
||||
prefix: [null, Validators.required],
|
||||
prefix: [null],
|
||||
sequence_size: [null],
|
||||
suffix: [null],
|
||||
starting_no: [null],
|
||||
seperator: [null],
|
||||
sequence_name: [null, Validators.required],
|
||||
|
||||
sequence_name: [null],
|
||||
sequence_code: [null],
|
||||
demonstration: [null],
|
||||
|
||||
current_no: [null]
|
||||
});
|
||||
}
|
||||
|
||||
// Stats & filtering helpers for UI only
|
||||
get totalSequences(): number {
|
||||
return ((this.alldata as unknown as any[]) || []).length;
|
||||
}
|
||||
|
||||
get filteredSequences(): any[] {
|
||||
const items: any[] = (this.alldata as unknown as any[]) || [];
|
||||
const text = (this.filterText || '').toLowerCase();
|
||||
if (!text) { return items; }
|
||||
|
||||
// Search across all relevant fields
|
||||
return items.filter(s => (
|
||||
(s?.sequence_name || '').toLowerCase().includes(text) ||
|
||||
(s?.prefix || '').toLowerCase().includes(text) ||
|
||||
(s?.sequence_code || '').toLowerCase().includes(text) ||
|
||||
(s?.suffix || '').toLowerCase().includes(text) ||
|
||||
(s?.seperator || '').toLowerCase().includes(text) ||
|
||||
(s?.sequence_size?.toString() || '').includes(text) ||
|
||||
(s?.starting_no?.toString() || '').includes(text) ||
|
||||
(s?.current_no?.toString() || '').includes(text) ||
|
||||
(s?.demonstration || '').toLowerCase().includes(text)
|
||||
));
|
||||
}
|
||||
|
||||
setViewMode(mode: 'table' | 'cards') {
|
||||
this.viewMode = mode;
|
||||
}
|
||||
|
||||
getall() {
|
||||
this.seqservice.getAll().subscribe((data) => {
|
||||
console.log(data);
|
||||
@@ -102,8 +57,27 @@ export class SequencegenaratorComponent implements OnInit {
|
||||
if (error) {
|
||||
this.error = "No data Available OR server Error";
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
// onSubmit(){
|
||||
// console.log(this.entryForm.value);
|
||||
// this.seqservice.create(this.entryForm.value).subscribe((data)=>{
|
||||
// console.log(data);
|
||||
// if (data) {
|
||||
// this.toastr.success('Added successfully');
|
||||
// }
|
||||
// },
|
||||
// (error) => {
|
||||
// console.log('Error in adding data...',+error);
|
||||
// if(error){
|
||||
// this.toastr.error('Not added Data');
|
||||
// }
|
||||
|
||||
// });
|
||||
// this.modaladd=false;
|
||||
// }
|
||||
|
||||
|
||||
onSubmit() {
|
||||
console.log(this.entryForm.value);
|
||||
@@ -112,8 +86,10 @@ export class SequencegenaratorComponent implements OnInit {
|
||||
return
|
||||
}
|
||||
this.onCreate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
onCreate() {
|
||||
this.modaladd = false;
|
||||
this.seqservice.create(this.entryForm.value).subscribe(
|
||||
@@ -139,24 +115,22 @@ export class SequencegenaratorComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
goToAdd() {
|
||||
this.modaladd = true;
|
||||
this.submitted = false;
|
||||
// Reset form
|
||||
this.entryForm.reset();
|
||||
|
||||
}
|
||||
|
||||
onExport() {
|
||||
this.excel.exportAsExcelFile(this.alldata, 'sequence_',
|
||||
this.excel.exportAsExcelFile(this.alldata, 'user_',
|
||||
moment().format('YYYYMMDD_HHmmss'))
|
||||
}
|
||||
|
||||
goToEdit(row) {
|
||||
this.rowSelected = { ...row }; // Create a copy to avoid direct binding issues
|
||||
this.rowSelected = row;
|
||||
console.log(row)
|
||||
this.modaledit = true;
|
||||
}
|
||||
|
||||
onDelete(row) {
|
||||
this.rowSelected = row;
|
||||
this.modaldelete = true;
|
||||
@@ -187,8 +161,8 @@ export class SequencegenaratorComponent implements OnInit {
|
||||
this.ngOnInit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
onUpdate(id) {
|
||||
this.modaledit = false;
|
||||
this.seqservice.update(id, this.rowSelected).subscribe((data) => {
|
||||
|
||||
@@ -1,66 +1,38 @@
|
||||
<clr-main-container class="modern-layout">
|
||||
<clr-header class="header-5 modern-header">
|
||||
<div class="branding modern-branding">
|
||||
<a href="javascript://" class="nav-link modern-nav-link">
|
||||
<div class="logo-container">
|
||||
<div class="logo-wrapper">
|
||||
<img class="logo-img" src="assets/images/icon/micrologo.png" alt="Logo" height="40" width="40">
|
||||
<div class="logo-glow"></div>
|
||||
<clr-main-container>
|
||||
<clr-header class="header-5">
|
||||
<div class="branding">
|
||||
<a href="javascript://" class="nav-link">
|
||||
<a href="#" class="logo">
|
||||
<img class="img" src="assets/images/icon/micrologo.png" alt="" height="50" width="50">
|
||||
</a>
|
||||
<div style="width:40px;margin-right:10px;">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="brand-text">
|
||||
<ng-container *ngIf="sysparameter?.company_Display_Name !== null; else OPtitle">
|
||||
<span class="company-title">{{ sysparameter?.company_Display_Name }}</span>
|
||||
<span class="company-subtitle">Enterprise Platform</span>
|
||||
<span class="title">{{ sysparameter?.company_Display_Name }}</span>
|
||||
</ng-container>
|
||||
<ng-template #OPtitle>
|
||||
<span class="company-title">CloudnSure</span>
|
||||
<span class="company-subtitle">Enterprise Platform</span>
|
||||
<span class="title">CloudnSure</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="header-nav modern-header-nav" [clr-nav-level]="1">
|
||||
<a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active"
|
||||
routerLink="/cns-portal/dashboard" (click)="loadMenuByMenuGroup()">
|
||||
<div class="nav-icon-wrapper">
|
||||
<div class="header-nav" [clr-nav-level]="1">
|
||||
<a href="javascript://" id="icon" class=" nav-link nav-icon" routerLinkActive="active" routerLink="/cns-portal/dashboard" (click)="loadMenuByMenuGroup()">
|
||||
<clr-icon shape="home"></clr-icon>
|
||||
<span class="nav-tooltip">Dashboard</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active"
|
||||
routerLink="/cns-portal/dashboardrunner">
|
||||
<div class="nav-icon-wrapper">
|
||||
<a href="javascript://" id="icon" class=" nav-link nav-icon" routerLinkActive="active" routerLink="/cns-portal/dashboardrunner" >
|
||||
<clr-icon shape="grid-view" solid></clr-icon>
|
||||
<span class="nav-tooltip">Reports</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active"
|
||||
routerLink="/cns-portal/rerunner/all" (click)="getName()">
|
||||
<div class="nav-icon-wrapper">
|
||||
<a href="javascript://" id="icon" class=" nav-link nav-icon" routerLinkActive="active" routerLink="/cns-portal/rerunner/all" (click)="getName()">
|
||||
<clr-icon shape="file-group" solid="true"></clr-icon>
|
||||
<span class="nav-tooltip">Files</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active"
|
||||
routerLink="/cns-portal/setupicon" (click)="toggleSetupMenus()">
|
||||
<div class="nav-icon-wrapper">
|
||||
<a href="javascript://" id="icon" class=" nav-link nav-icon" routerLinkActive="active" routerLink="/cns-portal/setupicon" (click)="toggleSetupMenus()">
|
||||
<clr-icon shape="cog" solid="true"></clr-icon>
|
||||
<span class="nav-tooltip">Settings</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active"
|
||||
routerLink="/cns-portal/theme-customization">
|
||||
<div class="nav-icon-wrapper">
|
||||
<clr-icon shape="palette" solid="true"></clr-icon>
|
||||
<span class="nav-tooltip">Theme Customization</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -70,149 +42,94 @@
|
||||
|
||||
|
||||
|
||||
<div class="header-actions modern-header-actions">
|
||||
<clr-dropdown class="modern-user-dropdown">
|
||||
<button class="modern-user-button" clrDropdownTrigger>
|
||||
<div class="user-avatar">
|
||||
<div class="avatar-circle">
|
||||
<clr-icon shape="user"></clr-icon>
|
||||
</div>
|
||||
<div class="user-status-indicator"></div>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<span class="user-name">{{userName}}</span>
|
||||
<span class="user-role">Administrator</span>
|
||||
</div>
|
||||
<clr-icon shape="caret down" class="dropdown-arrow"></clr-icon>
|
||||
<div class="header-actions">
|
||||
<!-- <span (click)="restartTour()" style="display: flex;align-items: center;margin-right: 20px;">
|
||||
<clr-icon shape="play"></clr-icon>
|
||||
</span> -->
|
||||
<clr-dropdown>
|
||||
<button class="nav-text demo-title" clrDropdownTrigger>
|
||||
<clr-icon shape="user"></clr-icon><label style="line-height: 60px; cursor: pointer;"> {{userName}}</label>
|
||||
<clr-icon shape="caret down"></clr-icon>
|
||||
</button>
|
||||
<clr-dropdown-menu *clrIfOpen clrPosition="bottom-right" class="modern-dropdown-menu">
|
||||
<div class="dropdown-header">
|
||||
<div class="user-profile">
|
||||
<div class="profile-avatar">
|
||||
<clr-icon shape="user"></clr-icon>
|
||||
</div>
|
||||
<div class="profile-info">
|
||||
<span class="profile-name">{{userName}}</span>
|
||||
<span class="profile-email">admin@cloudnsure.com</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<clr-dropdown-menu *clrIfOpen clrPosition="bottom-right">
|
||||
<a href="javascript://" clrDropdownItem routerLink="/cns-portal/about">About</a>
|
||||
<a href="javascript://" clrDropdownItem routerLink="profile-settings">Profile Settings</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<a href="javascript://" clrDropdownItem routerLink="/cns-portal/about" class="modern-dropdown-item">
|
||||
<clr-icon shape="info-circle"></clr-icon>
|
||||
<span>About</span>
|
||||
</a>
|
||||
<a href="javascript://" clrDropdownItem routerLink="profile-settings" class="modern-dropdown-item">
|
||||
<clr-icon shape="cog"></clr-icon>
|
||||
<span>Profile Settings</span>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<!-- Language Dropdown Section -->
|
||||
<clr-dropdown class="sub-dropdown modern-language-dropdown">
|
||||
<button clrDropdownTrigger class="modern-language-button">
|
||||
<clr-icon shape="language" class="language-icon"></clr-icon>
|
||||
<span>{{ 'Choose language' | translate }}</span>
|
||||
<clr-icon shape="caret down" class="dropdown-arrow"></clr-icon>
|
||||
<clr-dropdown class="sub-dropdown">
|
||||
<button clrDropdownTrigger style="display: flex; align-items: center; padding: 8px; width: 100%; background: none; border: none; cursor: pointer;">
|
||||
<clr-icon shape="language" class="language-icon" style="margin-right: 5px;"></clr-icon>
|
||||
<label style="margin: 0;">{{ 'Choose language' | translate }}</label>
|
||||
<clr-icon shape="caret down" style="margin-left: auto;"></clr-icon>
|
||||
</button>
|
||||
<clr-dropdown-menu *clrIfOpen clrPosition="right" class="modern-language-menu">
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('en')" class="modern-lang-item">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon>
|
||||
<span>English</span>
|
||||
<div class="lang-flag">ðºð¸</div>
|
||||
<clr-dropdown-menu *clrIfOpen clrPosition="right">
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('en')" class="lang-item" style="display: flex; align-items: center; padding: 8px 12px;">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon> English
|
||||
</a>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('hi')" class="modern-lang-item">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon>
|
||||
<span>हिनà¥à¤¦à¥</span>
|
||||
<div class="lang-flag">ð®ð³</div>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('hi')" class="lang-item" style="display: flex; align-items: center; padding: 8px 12px;">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon> Hindi
|
||||
</a>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('ta')" class="modern-lang-item">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon>
|
||||
<span>தமிழà¯</span>
|
||||
<div class="lang-flag">ð®ð³</div>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('ta')" class="lang-item" style="display: flex; align-items: center; padding: 8px 12px;">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon> Tamil
|
||||
</a>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('pa')" class="modern-lang-item">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon>
|
||||
<span>ਪੰà¨à¨¾à¨¬à©</span>
|
||||
<div class="lang-flag">ð®ð³</div>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('pa')" class="lang-item" style="display: flex; align-items: center; padding: 8px 12px;">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon> Punjabi
|
||||
</a>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('ml')" class="modern-lang-item">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon>
|
||||
<span>മലയാളà´</span>
|
||||
<div class="lang-flag">ð®ð³</div>
|
||||
<a href="javascript://" clrDropdownItem (click)="switchLanguage('ml')" class="lang-item" style="display: flex; align-items: center; padding: 8px 12px;">
|
||||
<clr-icon shape="globe" class="lang-icon"></clr-icon> Malayalam
|
||||
</a>
|
||||
</clr-dropdown-menu>
|
||||
</clr-dropdown>
|
||||
<!-- <a href="javascript://" clrDropdownItem routerLink="myworkspace">My Workspaces</a> -->
|
||||
<a href="javascript://" clrDropdownItem routerLink="/cns-portal/passwordreset">Change Password</a>
|
||||
<a href="javascript://" clrDropdownItem (click)="onLogout()">Log out</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<a href="javascript://" clrDropdownItem routerLink="/cns-portal/passwordreset" class="modern-dropdown-item">
|
||||
<clr-icon shape="key"></clr-icon>
|
||||
<span>Change Password</span>
|
||||
</a>
|
||||
<a href="javascript://" clrDropdownItem (click)="onLogout()" class="modern-dropdown-item logout-item">
|
||||
<clr-icon shape="logout"></clr-icon>
|
||||
<span>Log out</span>
|
||||
</a>
|
||||
</clr-dropdown-menu>
|
||||
</clr-dropdown>
|
||||
</div>
|
||||
</clr-header>
|
||||
|
||||
<div class="content-container modern-content-container">
|
||||
<main class="content-area modern-content-area">
|
||||
<div class="content-wrapper">
|
||||
<div class="content-container">
|
||||
<main class="content-area">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<clr-vertical-nav class="modern-sidebar" [clrVerticalNavCollapsible]="true" [(clrVerticalNavCollapsed)]="collapsed"
|
||||
[clr-nav-level]="2">
|
||||
<clr-vertical-nav [clrVerticalNavCollapsible]="true" [(clrVerticalNavCollapsed)]="collapsed" [clr-nav-level]="2">
|
||||
|
||||
<!-- <clr-vertical-nav-group *ngIf="!showFolderNames && !showSetupMenus && !showDashNames" routerLinkActive="active">
|
||||
|
||||
|
||||
|
||||
</clr-vertical-nav-group> -->
|
||||
<div class="sidebar-content">
|
||||
<div *ngFor="let menu of menus" class="menu-item-wrapper">
|
||||
<div *ngFor="let menu of menus">
|
||||
<!-- NEED MODIFICATION-->
|
||||
<!-- <div *ngIf="menu.sub_menus.length >=1;then content else other_content"></div> -->
|
||||
<div *ngIf="menu.subMenus !== null && menu.subMenus?.length >=1;then content else other_content"></div>
|
||||
<ng-template #content>
|
||||
<!-- if sub menu is present -->
|
||||
<clr-vertical-nav-group routerLinkActive="active" class="modern-nav-group">
|
||||
<div class="nav-group-header">
|
||||
<clr-icon [attr.shape]="menu.main_menu_icon_name" clrVerticalNavIcon class="nav-group-icon"></clr-icon>
|
||||
<span class="nav-group-title">{{ menu.menuItemDesc }}</span>
|
||||
<clr-icon shape="angle" class="nav-group-arrow" [class.rotated]="false"></clr-icon>
|
||||
</div>
|
||||
<!-- if sub munu is present -->
|
||||
<clr-vertical-nav-group routerLinkActive="active"> <!--*ngIf="!showFolderNames && !showSetupMenus && !showDashNames" -->
|
||||
<clr-icon [attr.shape]="menu.main_menu_icon_name" clrVerticalNavIcon></clr-icon>
|
||||
{{ menu.menuItemDesc }}
|
||||
<!-- SUB NAV-->
|
||||
<clr-vertical-nav-group-children class="modern-nav-children">
|
||||
<ng-container *ngFor="let subnav of menu.subMenus">
|
||||
<a clrVerticalNavLink *ngIf="subnav.mvisible == 'true'" routerLinkActive="active"
|
||||
(click)="send(subnav)" class="modern-nav-link">
|
||||
<clr-icon [attr.shape]="subnav.mainMenuIconName || 'circle'" clrVerticalNavIcon
|
||||
class="nav-link-icon"></clr-icon>
|
||||
<span class="nav-link-text">{{ subnav.menuItemDesc }}</span>
|
||||
<clr-vertical-nav-group-children *ngFor="let subnav of menu.subMenus">
|
||||
<a clrVerticalNavLink *ngIf="subnav.mvisible == 'true'" routerLinkActive="active" (click)="send(subnav)">
|
||||
<!-- <clr-icon [attr.shape]="subnav.mainMenuIconName" clrVerticalNavIcon></clr-icon>'./' + subnav.main_menu_action_name (click)="send(subnav) [ngStyle]="subnav.mvisible == 'true' && { 'display': 'none' }"
|
||||
[routerLink]=subnav.mvisible == 'true' ? ['./' + subnav.main_menu_action_name] : []-->
|
||||
{{ subnav.menuItemDesc }}
|
||||
</a>
|
||||
</ng-container>
|
||||
</clr-vertical-nav-group-children>
|
||||
</clr-vertical-nav-group>
|
||||
<!-- </div> -->
|
||||
</ng-template>
|
||||
<ng-template #other_content>
|
||||
<!-- if sub menu is not present -->
|
||||
<a clrVerticalNavLink routerLinkActive="active" [routerLink]="'./'+ menu.main_menu_action_name"
|
||||
class="modern-nav-link-single">
|
||||
<clr-icon [attr.shape]="menu.main_menu_icon_name" clrVerticalNavIcon class="nav-link-icon"></clr-icon>
|
||||
<span class="nav-link-text">{{ menu.menuItemDesc }}</span>
|
||||
<a clrVerticalNavLink routerLinkActive="active" [routerLink]="'./'+ menu.main_menu_action_name">
|
||||
<clr-icon [attr.shape]="menu.main_menu_icon_name" clrVerticalNavIcon></clr-icon>
|
||||
{{ menu.menuItemDesc }}
|
||||
</a>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div *ngFor="let report of reportNames">
|
||||
<clr-vertical-nav-group *ngIf="showFolderNames && !showSetupMenus" routerLinkActive="active" routerLink="/cns-portal/rerunner/all">
|
||||
@@ -245,7 +162,7 @@
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
<!--
|
||||
<clr-vertical-nav-group *ngIf="showSetupMenus && !showDashNames && !showFolderNames" routerLinkActive="active">
|
||||
<clr-icon shape="cog" clrVerticalNavIcon class="project-visit-tour"></clr-icon>
|
||||
Setup
|
||||
@@ -298,7 +215,7 @@
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<div class="clr-col-md-6 clr-col-sm-12" >
|
||||
<label>Name: </label>
|
||||
<input class="clr-input" type="text" name="name" placeholder="Enter name">
|
||||
</div>
|
||||
@@ -306,7 +223,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modalteam = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
<button type="submit" class="btn btn-primary" >Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
// ========================================
|
||||
// MODERN LAYOUT COMPONENT STYLES
|
||||
// ========================================
|
||||
|
||||
@import '../../../../styles/design-tokens';
|
||||
|
||||
// Legacy form styles (preserved for compatibility)
|
||||
input[type=text],[type=date], select,textarea {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
@@ -14,680 +7,6 @@ input[type=text],[type=date], select,textarea {
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
// Modern Layout Styles
|
||||
// ========================================
|
||||
|
||||
.modern-layout {
|
||||
background: linear-gradient(135deg, $gray-50 0%, $gray-100 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
// Header Styles
|
||||
// ========================================
|
||||
|
||||
.modern-header {
|
||||
background: linear-gradient(135deg, $primary-600 0%, $primary-700 100%);
|
||||
backdrop-filter: $backdrop-blur-md;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: $shadow-lg;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: $z-sticky;
|
||||
height: $header-height;
|
||||
padding: 0 $space-6;
|
||||
}
|
||||
|
||||
.modern-branding {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-4;
|
||||
|
||||
.modern-nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-4;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logo-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: $gradient-primary;
|
||||
border-radius: $radius-xl;
|
||||
box-shadow: $shadow-md;
|
||||
transition: all $duration-300 $ease-out;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: $shadow-lg;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
object-fit: contain;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.logo-glow {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
background: $gradient-primary;
|
||||
border-radius: $radius-xl;
|
||||
opacity: 0;
|
||||
filter: blur(8px);
|
||||
transition: opacity $duration-300 $ease-out;
|
||||
}
|
||||
|
||||
&:hover .logo-glow {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.company-title {
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-bold;
|
||||
color: $white;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.company-subtitle {
|
||||
font-size: $text-xs;
|
||||
font-weight: $font-medium;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Header Navigation
|
||||
// ========================================
|
||||
|
||||
.modern-header-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-2;
|
||||
margin-left: $space-8;
|
||||
|
||||
.modern-nav-icon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: $radius-lg;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-decoration: none;
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: $white;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: $white;
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
.nav-icon-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav-tooltip {
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: $gray-900;
|
||||
color: $white;
|
||||
padding: $space-2 $space-3;
|
||||
border-radius: $radius-md;
|
||||
font-size: $text-xs;
|
||||
font-weight: $font-medium;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all $duration-200 $ease-out;
|
||||
z-index: $z-tooltip;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border: 4px solid transparent;
|
||||
border-top-color: $gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .nav-tooltip {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Header Actions
|
||||
// ========================================
|
||||
|
||||
.modern-header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-4;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.modern-user-dropdown {
|
||||
.modern-user-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
padding: $space-2 $space-4;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: $radius-xl;
|
||||
color: $white;
|
||||
text-decoration: none;
|
||||
transition: all $duration-200 $ease-out;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-circle {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $white;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
}
|
||||
|
||||
.user-status-indicator {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: $accent-green;
|
||||
border: 2px solid $white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 2px;
|
||||
|
||||
.user-name {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
color: $white;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
font-size: $text-xs;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
font-size: $text-xs;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
transition: transform $duration-200 $ease-out;
|
||||
}
|
||||
|
||||
&:hover .dropdown-arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dropdown Menu
|
||||
// ========================================
|
||||
|
||||
.modern-dropdown-menu {
|
||||
background: $white;
|
||||
border: 1px solid $gray-200;
|
||||
border-radius: $radius-xl;
|
||||
box-shadow: $shadow-xl;
|
||||
padding: $space-2;
|
||||
min-width: 280px;
|
||||
margin-top: $space-2;
|
||||
|
||||
.dropdown-header {
|
||||
padding: $space-4;
|
||||
border-bottom: 1px solid $gray-200;
|
||||
margin-bottom: $space-2;
|
||||
|
||||
.user-profile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
|
||||
.profile-avatar {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: $gradient-primary;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $white;
|
||||
font-size: $text-lg;
|
||||
font-weight: $font-semibold;
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.profile-name {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
color: $gray-900;
|
||||
}
|
||||
|
||||
.profile-email {
|
||||
font-size: $text-xs;
|
||||
color: $gray-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-divider {
|
||||
height: 1px;
|
||||
background: $gray-200;
|
||||
margin: $space-2 0;
|
||||
}
|
||||
|
||||
.modern-dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
padding: $space-3 $space-4;
|
||||
border-radius: $radius-lg;
|
||||
color: $gray-700;
|
||||
text-decoration: none;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
background: $gray-50;
|
||||
color: $gray-900;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
&.logout-item {
|
||||
color: $accent-red;
|
||||
|
||||
&:hover {
|
||||
background: rgba($accent-red, 0.1);
|
||||
color: $accent-red;
|
||||
}
|
||||
}
|
||||
|
||||
clr-icon {
|
||||
font-size: $text-base;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Language Dropdown
|
||||
// ========================================
|
||||
|
||||
.modern-language-dropdown {
|
||||
.modern-language-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
padding: $space-3 $space-4;
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: $gray-700;
|
||||
text-decoration: none;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
border-radius: $radius-lg;
|
||||
transition: all $duration-200 $ease-out;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: $gray-50;
|
||||
color: $gray-900;
|
||||
}
|
||||
|
||||
.language-icon {
|
||||
font-size: $text-base;
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
margin-left: auto;
|
||||
font-size: $text-xs;
|
||||
color: $gray-400;
|
||||
transition: transform $duration-200 $ease-out;
|
||||
}
|
||||
|
||||
&:hover .dropdown-arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.modern-language-menu {
|
||||
background: $white;
|
||||
border: 1px solid $gray-200;
|
||||
border-radius: $radius-xl;
|
||||
box-shadow: $shadow-lg;
|
||||
padding: $space-2;
|
||||
min-width: 200px;
|
||||
margin-left: $space-2;
|
||||
|
||||
.modern-lang-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
padding: $space-3 $space-4;
|
||||
border-radius: $radius-lg;
|
||||
color: $gray-700;
|
||||
text-decoration: none;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
background: $primary-50;
|
||||
color: $primary-700;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.lang-icon {
|
||||
font-size: $text-base;
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
.lang-flag {
|
||||
margin-left: auto;
|
||||
font-size: $text-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Content Container
|
||||
// ========================================
|
||||
|
||||
.modern-content-container {
|
||||
display: flex;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.modern-content-area {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
|
||||
.content-wrapper {
|
||||
padding: $space-6;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar Styles
|
||||
// ========================================
|
||||
|
||||
.modern-sidebar {
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
backdrop-filter: $backdrop-blur-md;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.05);
|
||||
box-shadow: $shadow-lg;
|
||||
width: $sidebar-width;
|
||||
transition: all $duration-300 $ease-out;
|
||||
|
||||
&.nav-collapsed {
|
||||
width: $sidebar-width-collapsed;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
padding: $space-4 0;
|
||||
}
|
||||
|
||||
.menu-item-wrapper {
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
}
|
||||
|
||||
// Navigation Groups
|
||||
// ========================================
|
||||
|
||||
.modern-nav-group {
|
||||
margin-bottom: $space-2;
|
||||
|
||||
.nav-group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
padding: $space-3 $space-4;
|
||||
color: $gray-700;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
cursor: pointer;
|
||||
border-radius: $radius-lg;
|
||||
margin: 0 $space-2;
|
||||
transition: all $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
background: $gray-50;
|
||||
color: $gray-900;
|
||||
}
|
||||
|
||||
.nav-group-icon {
|
||||
font-size: $text-lg;
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
.nav-group-title {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-group-arrow {
|
||||
font-size: $text-sm;
|
||||
color: $gray-400;
|
||||
transition: transform $duration-200 $ease-out;
|
||||
|
||||
&.rotated {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modern-nav-children {
|
||||
margin-top: $space-1;
|
||||
padding-left: $space-4;
|
||||
}
|
||||
}
|
||||
|
||||
// Navigation Links
|
||||
// ========================================
|
||||
|
||||
.modern-nav-link,
|
||||
.modern-nav-link-single {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
padding: $space-3 $space-4;
|
||||
color: $gray-600;
|
||||
text-decoration: none;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
border-radius: $radius-lg;
|
||||
margin: 0 $space-2;
|
||||
transition: all $duration-200 $ease-out;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background: $primary-50;
|
||||
color: $primary-700;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $primary-100;
|
||||
color: $primary-800;
|
||||
font-weight: $font-semibold;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 3px;
|
||||
height: 20px;
|
||||
background: $primary-600;
|
||||
border-radius: 0 $radius-sm $radius-sm 0;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link-icon {
|
||||
font-size: $text-base;
|
||||
color: $gray-500;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav-link-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&:hover .nav-link-icon {
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
&.active .nav-link-icon {
|
||||
color: $primary-700;
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive Design
|
||||
// ========================================
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
.modern-header {
|
||||
padding: 0 $space-4;
|
||||
}
|
||||
|
||||
.modern-header-nav {
|
||||
margin-left: $space-4;
|
||||
gap: $space-1;
|
||||
|
||||
.modern-nav-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-content-area .content-wrapper {
|
||||
padding: $space-4;
|
||||
}
|
||||
|
||||
.modern-sidebar {
|
||||
width: $sidebar-width-collapsed;
|
||||
|
||||
.nav-group-title,
|
||||
.nav-link-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modern-nav-link,
|
||||
.modern-nav-link-single {
|
||||
justify-content: center;
|
||||
padding: $space-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
.modern-branding .brand-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modern-user-button .user-info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modern-header-nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy styles (preserved for compatibility)
|
||||
// ========================================
|
||||
|
||||
.center-content {
|
||||
//width: 100%;
|
||||
// max-width: 800px;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
import { Component, ViewEncapsulation, OnInit, Input } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Component,ViewEncapsulation, OnInit, Input } from '@angular/core';
|
||||
import { Router,ActivatedRoute } from '@angular/router';
|
||||
import { LoginService } from '../../../services/api/login.service';
|
||||
import { UserInfoService } from '../../../services/user-info.service';
|
||||
import { UserInfoService} from '../../../services/user-info.service';
|
||||
import { RealnetMenuService } from '../../../services/api/realnet-menu.service';
|
||||
import { Rn_Main_Menu } from '../../../models/builder/Rn_Main_Menu';
|
||||
import { MenuGroupService } from '../../../services/admin/menu-group.service';
|
||||
@@ -20,7 +20,6 @@ import { ProjectSetup } from 'src/app/models/builder/Project_setup';
|
||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout',
|
||||
@@ -29,32 +28,31 @@ import { ThemeService } from 'src/app/services/theme.service';
|
||||
})
|
||||
export class LayoutComponent implements OnInit {
|
||||
// baseUrl= environment.chaturl;
|
||||
@Input() data: any;
|
||||
@Input() data:any;
|
||||
|
||||
loading = false;
|
||||
apps: Array<ProjectSetup> = [];
|
||||
projectsetup;
|
||||
|
||||
collapsed = true;
|
||||
public showAppAlert: boolean = false;
|
||||
modalteam = false;
|
||||
public userName: string = "";
|
||||
public showAppAlert:boolean = false;
|
||||
modalteam=false;
|
||||
public userName: string="";
|
||||
|
||||
private formCode: string = 'teacher_form';
|
||||
public key: string = "formCode";
|
||||
public storage: Storage = sessionStorage;
|
||||
private formCode: string ='teacher_form';
|
||||
public key:string="formCode";
|
||||
public storage:Storage = sessionStorage;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private userInfoService: UserInfoService,
|
||||
private userInfoService:UserInfoService,
|
||||
private realnetMenuService: RealnetMenuService,
|
||||
private menuGroupService: MenuGroupService,
|
||||
private sysparaservice: SysparameterService,
|
||||
private sysparaservice:SysparameterService,
|
||||
private reportBuilderService: ReportBuilderService,
|
||||
private dashboardService: Dashboard3Service,
|
||||
private dashboardService : Dashboard3Service,
|
||||
private translate: TranslateService,
|
||||
private themeService: ThemeService,
|
||||
// private guidedTourService: GuidedTourService,
|
||||
// private tourservice: TourService,
|
||||
private toastr: ToastrService,
|
||||
@@ -71,10 +69,10 @@ export class LayoutComponent implements OnInit {
|
||||
switchLanguage(language: string): void {
|
||||
this.translate.use(language); // Switch to the selected language
|
||||
}
|
||||
user_name: any;
|
||||
userrole: any;
|
||||
user_name : any;
|
||||
userrole:any;
|
||||
menus: Rn_Main_Menu[];
|
||||
menu: any;
|
||||
menu:any;
|
||||
tourdata;
|
||||
steps;
|
||||
error;
|
||||
@@ -82,47 +80,47 @@ export class LayoutComponent implements OnInit {
|
||||
this.storage.setItem(this.key, this.formCode);
|
||||
this.user_name = this.userInfoService.getUserName();
|
||||
console.log('user name: ' + this.user_name);
|
||||
this.userrole = this.userInfoService.getRoles();
|
||||
console.log('user_role', this.userrole);
|
||||
this.udata = this.userInfoService.getUserId();
|
||||
console.log('user id', this.udata);
|
||||
this.userrole=this.userInfoService.getRoles();
|
||||
console.log('user_role',this.userrole);
|
||||
this.udata=this.userInfoService.getUserId();
|
||||
console.log('user id',this.udata);
|
||||
this.loadMenuByAccountId();
|
||||
this.loadMenuByMenuGroup();
|
||||
this.getById(1);
|
||||
// this.tourservice.getall().subscribe((data)=>{
|
||||
// this.tourdata=data[1];
|
||||
// //console.log("tour data",data);
|
||||
// console.log(this.tourdata);
|
||||
// //console.log(this.tourdata.tourId);
|
||||
// //console.log(this.tourdata.useOrb);
|
||||
// //this.steps=JSON.stringify(this.tourdata.steps);
|
||||
// // console.log(this.tourdata.steps);
|
||||
// //this.dashboardTour.tourId=this.tourdata.tourId;
|
||||
// //console.log(this.dashboardTour.tourId);
|
||||
// //this.dashboardTour.useOrb=this.tourdata.useOrb;
|
||||
// // this.dashboardTour.steps=this.tourdata.steps;
|
||||
// });
|
||||
}
|
||||
// this.tourservice.getall().subscribe((data)=>{
|
||||
// this.tourdata=data[1];
|
||||
// //console.log("tour data",data);
|
||||
// console.log(this.tourdata);
|
||||
// //console.log(this.tourdata.tourId);
|
||||
// //console.log(this.tourdata.useOrb);
|
||||
// //this.steps=JSON.stringify(this.tourdata.steps);
|
||||
// // console.log(this.tourdata.steps);
|
||||
// //this.dashboardTour.tourId=this.tourdata.tourId;
|
||||
// //console.log(this.dashboardTour.tourId);
|
||||
// //this.dashboardTour.useOrb=this.tourdata.useOrb;
|
||||
// // this.dashboardTour.steps=this.tourdata.steps;
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
showFolderNames: boolean = false; // Variable to control the report names display
|
||||
reportNames: any[] = []; // Store the report names
|
||||
showFolderNames: boolean = false; // Variable to control the report names display
|
||||
reportNames: any[] = []; // Store the report names
|
||||
|
||||
// getName() {
|
||||
// this.reportBuilderService.getrbDetails().pipe(
|
||||
// map((data) => data.map((item) => item.folderName))
|
||||
// ).subscribe((reportName) => {
|
||||
// this.reportNames = reportName;
|
||||
// // this.showReportNames = true; // Toggle on
|
||||
// console.log('Report Names:', this.reportNames);
|
||||
// });
|
||||
// getName() {
|
||||
// this.reportBuilderService.getrbDetails().pipe(
|
||||
// map((data) => data.map((item) => item.folderName))
|
||||
// ).subscribe((reportName) => {
|
||||
// this.reportNames = reportName;
|
||||
// // this.showReportNames = true; // Toggle on
|
||||
// console.log('Report Names:', this.reportNames);
|
||||
// });
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
getName() {
|
||||
getName() {
|
||||
if (this.showFolderNames) {
|
||||
// If in report mode, switch to default mode
|
||||
this.showFolderNames = false;
|
||||
@@ -137,18 +135,18 @@ export class LayoutComponent implements OnInit {
|
||||
this.showFolderNames = true;
|
||||
},);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filteredGridData: any[] = [];
|
||||
gridData: any[] = [];
|
||||
// Function to filter the data based on the selected folder
|
||||
filterGridDataByFolder(folderName: string) {
|
||||
filteredGridData: any[] = [];
|
||||
gridData: any[] = [];
|
||||
// Function to filter the data based on the selected folder
|
||||
filterGridDataByFolder(folderName: string) {
|
||||
this.filteredGridData = this.gridData.filter(item => item.folderName === folderName);
|
||||
}
|
||||
}
|
||||
|
||||
showDashNames: boolean = false;
|
||||
dashNames: any[] = [];
|
||||
getDashName() {
|
||||
showDashNames: boolean = false;
|
||||
dashNames: any[] = [];
|
||||
getDashName() {
|
||||
if (this.showDashNames) {
|
||||
// If in report mode, switch to default mode
|
||||
this.showDashNames = false;
|
||||
@@ -164,7 +162,7 @@ export class LayoutComponent implements OnInit {
|
||||
this.showDashNames = true;
|
||||
},);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -172,11 +170,11 @@ export class LayoutComponent implements OnInit {
|
||||
|
||||
|
||||
|
||||
showSetupMenus: boolean = false;
|
||||
toggleSetupMenus() {
|
||||
showSetupMenus: boolean = false;
|
||||
toggleSetupMenus() {
|
||||
this.showSetupMenus = !this.showSetupMenus;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -185,74 +183,74 @@ export class LayoutComponent implements OnInit {
|
||||
|
||||
|
||||
|
||||
// side nav menu-sub_menu
|
||||
loadMenuByAccountId() {
|
||||
// side nav menu-sub_menu
|
||||
loadMenuByAccountId() {
|
||||
this.realnetMenuService.getByAccountId().subscribe(resp => {
|
||||
this.menus = resp;
|
||||
console.log('menu: ', this.menus);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
loadMenuByMenuGroup() {
|
||||
loadMenuByMenuGroup() {
|
||||
this.menuGroupService.getByCurrentUserMenuGroupId2().subscribe(resp => {
|
||||
this.menus = resp;
|
||||
console.log('menus: ', this.menus);
|
||||
}, (error) => {
|
||||
},(error) => {
|
||||
console.log(error);
|
||||
if (error) {
|
||||
this.error = "No data Available OR server Error";
|
||||
if(error){
|
||||
this.error="No data Available OR server Error";
|
||||
}
|
||||
if (error.status === 401) {
|
||||
// auto logout if 401 response returned from api
|
||||
// this.authenticationService.logout();
|
||||
this.toastr.error("Your Token Is Expire Plz login Again")
|
||||
//location.reload(true);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
sysparameter;
|
||||
getById(id: number) {
|
||||
}
|
||||
sysparameter;
|
||||
getById(id: number) {
|
||||
this.sysparaservice.getById(id).subscribe((data) => {
|
||||
this.sysparameter = data;
|
||||
console.log("getbyiddata", this.sysparameter);
|
||||
console.log("getbyiddata",this.sysparameter);
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* menuGroup: Rn_Menu_Group_Header[];
|
||||
menu_id: number;
|
||||
loadMenuGroupData() {
|
||||
/* menuGroup: Rn_Menu_Group_Header[];
|
||||
menu_id: number;
|
||||
loadMenuGroupData() {
|
||||
this.menuGroupService.getAll().subscribe(resp => {
|
||||
this.menuGroup = resp;
|
||||
this.menu_id = this.menuGroup
|
||||
});
|
||||
} */
|
||||
} */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
navbarSelectionChange(val) {
|
||||
navbarSelectionChange(val){
|
||||
// console.log(val);
|
||||
}
|
||||
}
|
||||
|
||||
closeAppAlert() {
|
||||
this.showAppAlert = false;
|
||||
}
|
||||
closeAppAlert(){
|
||||
this.showAppAlert=false;
|
||||
}
|
||||
|
||||
isDisabled(input: string): boolean {
|
||||
if (input === null) {
|
||||
isDisabled(input: string): boolean{
|
||||
if(input === null) {
|
||||
return true;
|
||||
} else false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onLogout() {
|
||||
this.userInfoService.logout().subscribe((data) => {
|
||||
this.userInfoService.logout().subscribe((data)=>{
|
||||
console.log(data);
|
||||
});
|
||||
sessionStorage.clear();
|
||||
@@ -262,20 +260,20 @@ export class LayoutComponent implements OnInit {
|
||||
menuFlag1 = false;
|
||||
udata;
|
||||
uid;
|
||||
message() {
|
||||
message(){
|
||||
//this.menuFlag = false;
|
||||
// this.menuFlag1 = true;
|
||||
// this.menuGroupService.getuser(this.udata).subscribe((data)=>{
|
||||
// console.log(data);
|
||||
// })
|
||||
// window.open(`${this.baseUrl}`)
|
||||
// this.menuGroupService.getuser(this.udata).subscribe((data)=>{
|
||||
// console.log(data);
|
||||
// })
|
||||
// window.open(`${this.baseUrl}`)
|
||||
//window.location.href = `${this.baseUrl}`;
|
||||
//this.udata=this.userInfoService.getUserInfo();
|
||||
//console.log(this.udata);
|
||||
|
||||
this.menuGroupService.save(this.udata);
|
||||
|
||||
this.uid = this.udata.userid;
|
||||
this.uid=this.udata.userid;
|
||||
localStorage.setItem("id", JSON.stringify(this.udata));
|
||||
//localStorage.setItem('id', this.uid);
|
||||
//window.location.href = (`${this.baseUrl}/` + this.udata), true
|
||||
@@ -287,7 +285,7 @@ export class LayoutComponent implements OnInit {
|
||||
//this.userInfoService.storeUserInfo(JSON.stringify(this.udata.user));
|
||||
}//
|
||||
|
||||
modaladd() {
|
||||
modaladd(){
|
||||
//this.modalteam=true;
|
||||
this.router.navigate(['/cns-portal/myworkspace']);
|
||||
}
|
||||
@@ -295,17 +293,17 @@ export class LayoutComponent implements OnInit {
|
||||
me;
|
||||
md;
|
||||
mv;
|
||||
send(val) {
|
||||
send(val){
|
||||
console.log(val);
|
||||
this.menuGroupService.storeaddeditvalues(val);
|
||||
this.mc = val.mcreate;
|
||||
this.me = val.medit;
|
||||
this.md = val.mdelete;
|
||||
this.mv = val.mvisible;
|
||||
if (this.mv == 'false') {
|
||||
this.mc=val.mcreate;
|
||||
this.me=val.medit;
|
||||
this.md=val.mdelete;
|
||||
this.mv=val.mvisible;
|
||||
if(this.mv == 'false'){
|
||||
this.router.navigate(['/**'])
|
||||
}
|
||||
this.router.navigate(['./' + val.main_menu_action_name], { relativeTo: this.route });
|
||||
}
|
||||
this.router.navigate(['./'+ val.main_menu_action_name] , { relativeTo: this.route});
|
||||
}
|
||||
//skipLocationChange: true, value pass params->,queryParams:{mc:this.mc,me:this.me,md:this.md}
|
||||
}
|
||||
|
||||
@@ -1,240 +1,3 @@
|
||||
<!-- Modern Dashboard Welcome Section -->
|
||||
<div class="modern-dashboard">
|
||||
<!-- Welcome Header -->
|
||||
<div class="welcome-section">
|
||||
<div class="welcome-content">
|
||||
<div class="welcome-text">
|
||||
<h1 class="welcome-title animate-fade-in-up">
|
||||
Welcome to CloudnSure
|
||||
<span class="title-accent">Enterprise Platform</span>
|
||||
</h1>
|
||||
<p class="welcome-subtitle animate-fade-in-up stagger-1">
|
||||
Your comprehensive solution for data management, reporting, and business intelligence
|
||||
</p>
|
||||
<div class="welcome-actions animate-fade-in-up stagger-2">
|
||||
<button class="modern-btn btn-primary btn-lg">
|
||||
<clr-icon shape="play"></clr-icon>
|
||||
Get Started
|
||||
</button>
|
||||
<button class="modern-btn btn-outline btn-lg">
|
||||
<clr-icon shape="book"></clr-icon>
|
||||
View Documentation
|
||||
</button>
|
||||
<button class="modern-btn btn-ghost btn-lg" routerLink="/cns-portal/theme-customization">
|
||||
<clr-icon shape="palette"></clr-icon>
|
||||
Customize Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="welcome-visual animate-fade-in-right">
|
||||
<div class="visual-container">
|
||||
<div class="floating-card card-1">
|
||||
<clr-icon shape="analytics"></clr-icon>
|
||||
<span>Analytics</span>
|
||||
</div>
|
||||
<div class="floating-card card-2">
|
||||
<clr-icon shape="file-group"></clr-icon>
|
||||
<span>Reports</span>
|
||||
</div>
|
||||
<div class="floating-card card-3">
|
||||
<clr-icon shape="cog"></clr-icon>
|
||||
<span>Settings</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Stats Cards -->
|
||||
<div class="stats-section">
|
||||
<div class="stats-grid">
|
||||
<div class="modern-card stats-card animate-fade-in-up stagger-1">
|
||||
<div class="card-header">
|
||||
<div class="stats-icon primary">
|
||||
<clr-icon shape="users"></clr-icon>
|
||||
</div>
|
||||
<div class="stats-trend positive">
|
||||
<clr-icon shape="trending-up"></clr-icon>
|
||||
<span>+12%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="stats-value">1,234</div>
|
||||
<div class="stats-label">Active Users</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modern-card stats-card animate-fade-in-up stagger-2">
|
||||
<div class="card-header">
|
||||
<div class="stats-icon success">
|
||||
<clr-icon shape="file-group"></clr-icon>
|
||||
</div>
|
||||
<div class="stats-trend positive">
|
||||
<clr-icon shape="trending-up"></clr-icon>
|
||||
<span>+8%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="stats-value">567</div>
|
||||
<div class="stats-label">Reports Generated</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modern-card stats-card animate-fade-in-up stagger-3">
|
||||
<div class="card-header">
|
||||
<div class="stats-icon warning">
|
||||
<clr-icon shape="clock"></clr-icon>
|
||||
</div>
|
||||
<div class="stats-trend negative">
|
||||
<clr-icon shape="trending-down"></clr-icon>
|
||||
<span>-3%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="stats-value">2.4s</div>
|
||||
<div class="stats-label">Avg Response Time</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modern-card stats-card animate-fade-in-up stagger-4">
|
||||
<div class="card-header">
|
||||
<div class="stats-icon info">
|
||||
<clr-icon shape="shield"></clr-icon>
|
||||
</div>
|
||||
<div class="stats-trend positive">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
<span>99.9%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="stats-value">99.9%</div>
|
||||
<div class="stats-label">Uptime</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="actions-section">
|
||||
<h2 class="section-title animate-fade-in-up">Quick Actions</h2>
|
||||
<div class="actions-grid">
|
||||
<a href="javascript://" class="modern-card action-card animate-fade-in-up stagger-1 hover-lift">
|
||||
<div class="action-icon">
|
||||
<clr-icon shape="plus-circle"></clr-icon>
|
||||
</div>
|
||||
<div class="action-content">
|
||||
<h3>Create Report</h3>
|
||||
<p>Build custom reports with our intuitive report builder</p>
|
||||
</div>
|
||||
<div class="action-arrow">
|
||||
<clr-icon shape="angle"></clr-icon>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="modern-card action-card animate-fade-in-up stagger-2 hover-lift">
|
||||
<div class="action-icon">
|
||||
<clr-icon shape="upload"></clr-icon>
|
||||
</div>
|
||||
<div class="action-content">
|
||||
<h3>Import Data</h3>
|
||||
<p>Upload and process your data files quickly</p>
|
||||
</div>
|
||||
<div class="action-arrow">
|
||||
<clr-icon shape="angle"></clr-icon>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="modern-card action-card animate-fade-in-up stagger-3 hover-lift">
|
||||
<div class="action-icon">
|
||||
<clr-icon shape="cog"></clr-icon>
|
||||
</div>
|
||||
<div class="action-content">
|
||||
<h3>System Settings</h3>
|
||||
<p>Configure your system preferences and options</p>
|
||||
</div>
|
||||
<div class="action-arrow">
|
||||
<clr-icon shape="angle"></clr-icon>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="modern-card action-card animate-fade-in-up stagger-4 hover-lift">
|
||||
<div class="action-icon">
|
||||
<clr-icon shape="help-info"></clr-icon>
|
||||
</div>
|
||||
<div class="action-content">
|
||||
<h3>Help & Support</h3>
|
||||
<p>Get help and access our knowledge base</p>
|
||||
</div>
|
||||
<div class="action-arrow">
|
||||
<clr-icon shape="angle"></clr-icon>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="javascript://" class="modern-card action-card animate-fade-in-up stagger-5 hover-lift" routerLink="/cns-portal/theme-customization">
|
||||
<div class="action-icon">
|
||||
<clr-icon shape="palette"></clr-icon>
|
||||
</div>
|
||||
<div class="action-content">
|
||||
<h3>Theme Customization</h3>
|
||||
<p>Customize colors, fonts, and appearance</p>
|
||||
</div>
|
||||
<div class="action-arrow">
|
||||
<clr-icon shape="angle"></clr-icon>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity -->
|
||||
<div class="activity-section">
|
||||
<h2 class="section-title animate-fade-in-up">Recent Activity</h2>
|
||||
<div class="modern-card activity-card animate-fade-in-up">
|
||||
<div class="activity-list">
|
||||
<div class="activity-item">
|
||||
<div class="activity-icon success">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
</div>
|
||||
<div class="activity-content">
|
||||
<div class="activity-title">Report generated successfully</div>
|
||||
<div class="activity-time">2 minutes ago</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="activity-item">
|
||||
<div class="activity-icon info">
|
||||
<clr-icon shape="user"></clr-icon>
|
||||
</div>
|
||||
<div class="activity-content">
|
||||
<div class="activity-title">New user registered</div>
|
||||
<div class="activity-time">15 minutes ago</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="activity-item">
|
||||
<div class="activity-icon warning">
|
||||
<clr-icon shape="exclamation-triangle"></clr-icon>
|
||||
</div>
|
||||
<div class="activity-content">
|
||||
<div class="activity-title">System maintenance scheduled</div>
|
||||
<div class="activity-time">1 hour ago</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="activity-item">
|
||||
<div class="activity-icon primary">
|
||||
<clr-icon shape="upload"></clr-icon>
|
||||
</div>
|
||||
<div class="activity-content">
|
||||
<div class="activity-title">Data import completed</div>
|
||||
<div class="activity-time">2 hours ago</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Legacy breadcrumb (hidden but preserved for compatibility) -->
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong" style="display: none;">
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://">Home</a></li>
|
||||
</ol>
|
||||
|
||||
@@ -1,510 +0,0 @@
|
||||
// ========================================
|
||||
// MODERN DASHBOARD COMPONENT STYLES
|
||||
// ========================================
|
||||
|
||||
|
||||
@import '../../../../styles/design-tokens';
|
||||
|
||||
|
||||
// Dashboard Container
|
||||
// ========================================
|
||||
|
||||
.modern-dashboard {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Welcome Section
|
||||
// ========================================
|
||||
|
||||
.welcome-section {
|
||||
background: linear-gradient(135deg, $primary-500 0%, $primary-700 100%);
|
||||
border-radius: $radius-2xl;
|
||||
margin-bottom: $space-8;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grain" width="100" height="100" patternUnits="userSpaceOnUse"><circle cx="25" cy="25" r="1" fill="rgba(255,255,255,0.1)"/><circle cx="75" cy="75" r="1" fill="rgba(255,255,255,0.1)"/><circle cx="50" cy="10" r="0.5" fill="rgba(255,255,255,0.05)"/><circle cx="10" cy="60" r="0.5" fill="rgba(255,255,255,0.05)"/><circle cx="90" cy="40" r="0.5" fill="rgba(255,255,255,0.05)"/></pattern></defs><rect width="100" height="100" fill="url(%23grain)"/></svg>');
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.welcome-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: $space-12 $space-8;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: $space-8;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-text {
|
||||
flex: 1;
|
||||
max-width: 600px;
|
||||
|
||||
.welcome-title {
|
||||
font-size: $text-5xl;
|
||||
font-weight: $font-bold;
|
||||
color: $white;
|
||||
margin-bottom: $space-4;
|
||||
line-height: 1.1;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
font-size: $text-4xl;
|
||||
}
|
||||
|
||||
.title-accent {
|
||||
display: block;
|
||||
font-size: $text-2xl;
|
||||
font-weight: $font-medium;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-top: $space-2;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
font-size: $text-xl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-subtitle {
|
||||
font-size: $text-xl;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
margin-bottom: $space-8;
|
||||
line-height: 1.6;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
font-size: $text-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-actions {
|
||||
display: flex;
|
||||
gap: $space-4;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (max-width: $breakpoint-sm) {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-visual {
|
||||
flex: 0 0 300px;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
flex: none;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.visual-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
|
||||
.floating-card {
|
||||
position: absolute;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: $backdrop-blur-md;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: $radius-xl;
|
||||
padding: $space-4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: $space-2;
|
||||
color: $white;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
|
||||
clr-icon {
|
||||
font-size: $text-2xl;
|
||||
}
|
||||
|
||||
&.card-1 {
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
&.card-2 {
|
||||
top: 60px;
|
||||
right: 40px;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
&.card-3 {
|
||||
bottom: 20px;
|
||||
left: 60px;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stats Section
|
||||
// ========================================
|
||||
|
||||
.stats-section {
|
||||
margin-bottom: $space-8;
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: $space-6;
|
||||
|
||||
@media (max-width: $breakpoint-sm) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: $space-4;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
padding: $space-6;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: $gradient-primary;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: $space-4;
|
||||
|
||||
.stats-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: $radius-xl;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: $text-xl;
|
||||
|
||||
&.primary {
|
||||
background: rgba($primary-500, 0.1);
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
&.success {
|
||||
background: rgba($accent-green, 0.1);
|
||||
color: $accent-green;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: rgba($accent-orange, 0.1);
|
||||
color: $accent-orange;
|
||||
}
|
||||
|
||||
&.info {
|
||||
background: rgba($primary-500, 0.1);
|
||||
color: $primary-600;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-trend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-1;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
|
||||
&.positive {
|
||||
color: $accent-green;
|
||||
}
|
||||
|
||||
&.negative {
|
||||
color: $accent-red;
|
||||
}
|
||||
|
||||
clr-icon {
|
||||
font-size: $text-sm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-body {
|
||||
.stats-value {
|
||||
font-size: $text-3xl;
|
||||
font-weight: $font-bold;
|
||||
color: $gray-900;
|
||||
margin-bottom: $space-1;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.stats-label {
|
||||
font-size: $text-sm;
|
||||
color: $gray-600;
|
||||
font-weight: $font-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions Section
|
||||
// ========================================
|
||||
|
||||
.actions-section {
|
||||
margin-bottom: $space-8;
|
||||
|
||||
.section-title {
|
||||
font-size: $text-2xl;
|
||||
font-weight: $font-bold;
|
||||
color: $gray-900;
|
||||
margin-bottom: $space-6;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.actions-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: $space-6;
|
||||
|
||||
@media (max-width: $breakpoint-sm) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: $space-4;
|
||||
}
|
||||
}
|
||||
|
||||
.action-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-4;
|
||||
padding: $space-6;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
border: 1px solid $gray-200;
|
||||
transition: all $duration-300 $ease-out;
|
||||
|
||||
&:hover {
|
||||
border-color: $primary-300;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: $shadow-xl;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
background: $gradient-primary;
|
||||
border-radius: $radius-xl;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $white;
|
||||
font-size: $text-xl;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.action-content {
|
||||
flex: 1;
|
||||
|
||||
h3 {
|
||||
font-size: $text-lg;
|
||||
font-weight: $font-semibold;
|
||||
color: $gray-900;
|
||||
margin-bottom: $space-1;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $text-sm;
|
||||
color: $gray-600;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.action-arrow {
|
||||
color: $gray-400;
|
||||
font-size: $text-lg;
|
||||
transition: transform $duration-200 $ease-out;
|
||||
}
|
||||
|
||||
&:hover .action-arrow {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Activity Section
|
||||
// ========================================
|
||||
|
||||
.activity-section {
|
||||
.section-title {
|
||||
font-size: $text-2xl;
|
||||
font-weight: $font-bold;
|
||||
color: $gray-900;
|
||||
margin-bottom: $space-6;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.activity-card {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
|
||||
.activity-list {
|
||||
.activity-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-4;
|
||||
padding: $space-4 $space-6;
|
||||
border-bottom: 1px solid $gray-100;
|
||||
transition: background-color $duration-200 $ease-out;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $gray-50;
|
||||
}
|
||||
|
||||
.activity-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: $text-base;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.success {
|
||||
background: rgba($accent-green, 0.1);
|
||||
color: $accent-green;
|
||||
}
|
||||
|
||||
&.info {
|
||||
background: rgba($primary-500, 0.1);
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: rgba($accent-orange, 0.1);
|
||||
color: $accent-orange;
|
||||
}
|
||||
|
||||
&.primary {
|
||||
background: rgba($primary-500, 0.1);
|
||||
color: $primary-600;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-content {
|
||||
flex: 1;
|
||||
|
||||
.activity-title {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: $gray-900;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
font-size: $text-xs;
|
||||
color: $gray-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive Design
|
||||
// ========================================
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
.welcome-section .welcome-content {
|
||||
padding: $space-8 $space-6;
|
||||
}
|
||||
|
||||
.stats-section .stats-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
}
|
||||
|
||||
.actions-section .actions-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
.welcome-section .welcome-content {
|
||||
padding: $space-6 $space-4;
|
||||
}
|
||||
|
||||
.welcome-text .welcome-title {
|
||||
font-size: $text-3xl;
|
||||
}
|
||||
|
||||
.welcome-text .welcome-subtitle {
|
||||
font-size: $text-base;
|
||||
}
|
||||
|
||||
.stats-section .stats-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.actions-section .actions-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-sm) {
|
||||
.modern-dashboard {
|
||||
padding: 0 $space-4;
|
||||
}
|
||||
|
||||
.welcome-section {
|
||||
margin-bottom: $space-6;
|
||||
}
|
||||
|
||||
.stats-section,
|
||||
.actions-section,
|
||||
.activity-section {
|
||||
margin-bottom: $space-6;
|
||||
}
|
||||
|
||||
.welcome-actions {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
// Animation Keyframes
|
||||
// ========================================
|
||||
|
||||
@keyframes float {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ThemeService } from '../../../services/theme.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-main-page',
|
||||
@@ -8,13 +7,9 @@ import { ThemeService } from '../../../services/theme.service';
|
||||
})
|
||||
export class MainPageComponent implements OnInit {
|
||||
|
||||
constructor(private themeService: ThemeService) { }
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
// Initialize theme service
|
||||
this.themeService.currentTheme$.subscribe(theme => {
|
||||
// Theme changes will be automatically applied via CSS variables
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,14 +82,9 @@ import { MappingruleallComponent } from './datamanagement/mappingrule/mappingrul
|
||||
import { MappingruleaddComponent } from './datamanagement/mappingrule/mappingruleadd/mappingruleadd.component';
|
||||
import { MappingruleeditComponent } from './datamanagement/mappingrule/mappingruleedit/mappingruleedit.component';
|
||||
import { Stepper_workflowComponent } from './BuilderComponents/stepperworkflow/Stepper_workflow/Stepper_workflow.component';
|
||||
import { AllapiregisteryComponent } from './fnd/apiregistery/allapiregistery/allapiregistery.component';
|
||||
import { AddapiregisteryComponent } from './fnd/apiregistery/addapiregistery/addapiregistery.component';
|
||||
import { EditapiregisteryComponent } from './fnd/apiregistery/editapiregistery/editapiregistery.component';
|
||||
import { ApiregisterylineComponent } from './fnd/apiregistery/Apiregisteryline/Apiregisteryline.component';
|
||||
|
||||
import { Token_registeryComponent } from './fnd/Token_registery/Token_registery.component';
|
||||
import { MyworkspaceComponent } from './admin/myworkspace/myworkspace.component';
|
||||
import { ThemeCustomizationComponent } from './theme-customization/theme-customization.component';
|
||||
|
||||
// import { QueryComponent } from './superadmin/query/query.component';
|
||||
// import { QueryaddComponent } from './superadmin/queryadd/queryadd.component';
|
||||
// import { QueryeditComponent } from './superadmin/queryedit/queryedit.component';
|
||||
@@ -126,8 +121,6 @@ const routes: Routes = [
|
||||
{ path: 'about', component: AboutComponent },
|
||||
{ path: 'setupicon', component: SetupiconComponent },
|
||||
{ path: 'myworkspace', component: MyworkspaceComponent },
|
||||
{ path: 'theme-customization', component: ThemeCustomizationComponent },
|
||||
|
||||
|
||||
|
||||
{
|
||||
@@ -234,20 +227,8 @@ const routes: Routes = [
|
||||
],
|
||||
},
|
||||
{ path: 'SequenceGenerator', component: SequencegenaratorComponent },
|
||||
{ path: 'apiregistery', component: ApiregisteryComponent },
|
||||
|
||||
// Api registery
|
||||
|
||||
{
|
||||
path: 'apiregistery', component: ApiregisteryComponent,
|
||||
children: [
|
||||
{ path: '', redirectTo: 'all', pathMatch: 'full' },
|
||||
{ path: 'all', component: AllapiregisteryComponent },
|
||||
{ path: 'add', component: AddapiregisteryComponent },
|
||||
{ path: 'edit/:id', component: EditapiregisteryComponent },
|
||||
{ path: 'line/:id', component: ApiregisterylineComponent },
|
||||
|
||||
],
|
||||
},
|
||||
|
||||
// DATA MANAGEMENT
|
||||
|
||||
@@ -280,13 +261,18 @@ const routes: Routes = [
|
||||
|
||||
// buildercomponents
|
||||
|
||||
|
||||
{ path: 'tokenregistery', component: Token_registeryComponent },
|
||||
|
||||
|
||||
{ path: 'Stepper_workflow', component: Stepper_workflowComponent },
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{ path: '**', component: PageNotFoundComponent },
|
||||
|
||||
]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
@@ -107,21 +106,13 @@ import { MappingruleaddComponent } from './datamanagement/mappingrule/mappingrul
|
||||
import { MappingruleallComponent } from './datamanagement/mappingrule/mappingruleall/mappingruleall.component';
|
||||
import { MappingruleeditComponent } from './datamanagement/mappingrule/mappingruleedit/mappingruleedit.component';
|
||||
import { Stepper_workflowComponent } from './BuilderComponents/stepperworkflow/Stepper_workflow/Stepper_workflow.component';
|
||||
import { AllapiregisteryComponent } from './fnd/apiregistery/allapiregistery/allapiregistery.component';
|
||||
import { AddapiregisteryComponent } from './fnd/apiregistery/addapiregistery/addapiregistery.component';
|
||||
import { EditapiregisteryComponent } from './fnd/apiregistery/editapiregistery/editapiregistery.component';
|
||||
import { ApiregisterylineComponent } from './fnd/apiregistery/Apiregisteryline/Apiregisteryline.component';
|
||||
|
||||
import { Token_registeryComponent } from './fnd/Token_registery/Token_registery.component';
|
||||
import { MyworkspaceComponent } from './admin/myworkspace/myworkspace.component';
|
||||
import { ThemeCustomizationComponent } from './theme-customization/theme-customization.component';
|
||||
|
||||
// import { QueryComponent } from './superadmin/query/query.component';
|
||||
// import { QueryaddComponent } from './superadmin/queryadd/queryadd.component';
|
||||
// import { QueryeditComponent } from './superadmin/queryedit/queryedit.component';
|
||||
|
||||
import { FieldTypesModule } from '../../shared/components/field-types/field-types.module';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
MainPageComponent, PageNotFoundComponent, UserComponent, PasswordResetComponent,
|
||||
@@ -137,20 +128,57 @@ import { SharedModule } from '../../shared/shared.module';
|
||||
// QueryComponent, QueryaddComponent, QueryeditComponent,
|
||||
ExtensionComponent,
|
||||
AllextensionComponent,
|
||||
AddextensionComponent, EditextensionComponent, ApiregisteryComponent, AllapiregisteryComponent, AddapiregisteryComponent, EditapiregisteryComponent,
|
||||
|
||||
ApiregisterylineComponent,
|
||||
DatamanagementComponent, DatamananementworkflowComponent, BulkimportComponent, BulkimportallComponent, BulkimportaddComponent, BulkimporteditComponent, BulkimportlineComponent, BulkimporteditlineComponent, MappingruleComponent, MappingruleallComponent,
|
||||
MappingruleaddComponent,
|
||||
MappingruleeditComponent, Stepper_workflowComponent, Customer_informationComponent,
|
||||
ThemeCustomizationComponent,
|
||||
// FileUploadListComponent,
|
||||
AddextensionComponent, EditextensionComponent, ApiregisteryComponent,
|
||||
DatamanagementComponent, DatamananementworkflowComponent, BulkimportComponent, BulkimportallComponent, BulkimportaddComponent, BulkimporteditComponent, BulkimportlineComponent, BulkimporteditlineComponent, MappingruleComponent, MappingruleallComponent, MappingruleaddComponent, MappingruleeditComponent,
|
||||
|
||||
|
||||
// buildercomponents
|
||||
|
||||
|
||||
|
||||
Token_registeryComponent,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Stepper_workflowComponent,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
],
|
||||
imports: [
|
||||
@@ -171,8 +199,6 @@ import { SharedModule } from '../../shared/shared.module';
|
||||
NgChartsModule,
|
||||
NgxChartsModule,
|
||||
DynamicModule,
|
||||
FieldTypesModule,
|
||||
SharedModule,
|
||||
],
|
||||
providers: [
|
||||
CookieService,
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
@import '@swimlane/ngx-datatable/index.css';
|
||||
@import '@swimlane/ngx-datatable/themes/bootstrap.css';
|
||||
@import '@swimlane/ngx-datatable/assets/icons.css';
|
||||
.button1::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.button1:hover::after {
|
||||
content: "ADD ROWS";
|
||||
}
|
||||
|
||||
.delete, .heading {
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.section p {
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.clr-input {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.75rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: red;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
input[type=text], textarea {
|
||||
width: 100%;
|
||||
padding: 15px 15px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
/* make sure we use up the whole viewport */
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
ngx-datatable {
|
||||
font-family: Metropolis, Avenir Next, Helvetica Neue, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
padding: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
ngx-datatable .datatable-header, ngx-datatable .datatable-footer {
|
||||
font-size: 11px;
|
||||
line-height: 18px;
|
||||
font-weight: bold;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
ngx-datatable .datatable-header {
|
||||
box-shadow: 0 2px 4px 0px #ccc;
|
||||
}
|
||||
ngx-datatable .datatable-header .datatable-header-cell {
|
||||
line-height: 22px;
|
||||
padding-left: 10px;
|
||||
height: 22px;
|
||||
}
|
||||
ngx-datatable .datatable-header .datatable-header-cell:not(:first-child) {
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
ngx-datatable .datatable-footer {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
ngx-datatable .datatable-footer .page-count {
|
||||
margin: 10px;
|
||||
}
|
||||
ngx-datatable .datatable-footer .pages a {
|
||||
padding: 8px;
|
||||
color: inherit;
|
||||
}
|
||||
ngx-datatable .datatable-footer .pages.active a {
|
||||
padding: 8px;
|
||||
color: #007cbb;
|
||||
background-color: rgb(221, 221, 221);
|
||||
text-align: center;
|
||||
}
|
||||
ngx-datatable .datatable-header-inner {
|
||||
padding: 12px;
|
||||
}
|
||||
ngx-datatable .datatable-body-cell {
|
||||
padding: 8px 0 10px 20px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
ngx-datatable .pager i {
|
||||
font-size: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.postColumn {
|
||||
border: 1px solid #ccc;
|
||||
width: 78%;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.colName {
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.colfields {
|
||||
border: 1px solid black;
|
||||
margin: 17px;
|
||||
text-align: center;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.fieldWrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 5px 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}/*# sourceMappingURL=query.component.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["query.component.scss","query.component.css"],"names":[],"mappings":"AA8JQ,2CAAA;AACA,sDAAA;AACC,kDAAA;AA9JT;EACE,aAAA;ACEF;;ADAA;EACE,mBAAA;ACGF;;ADAA;EACE,kBAAA;EACA,UAAA;ACGF;;ADAA;EACE,iBAAA;ACGF;;ADCA;EAEE,aAAA;EACA,eAAA;ACCF;;ADEA;EACE,cAAA;EACA,yBAAA;EACA,sBAAA;EACA,wBAAA;EACA,eAAA;EACA,WAAA;EACA,mBAAA;ACCF;;ADWA;EACE,UAAA;EACF,eAAA;ACRA;;ADYA;EACE,WAAA;EACA,kBAAA;EAED,oCAAA;EACC,qBAAA;EACA,sBAAA;EACA,kBAAA;EACA,sBAAA;ACVF;;ADcA;EACI,2CAAA;EACA,WAAA;EACA,iBAAA;ACXJ;;ADaA;EACI,WAAA;EACA,sBAAA;ACVJ;;ADeA;EACE,uEAAA;EACA,eAAA;EACA,sBAAA;EACA,kBAAA;EACA,UAAA;EACA,sBAAA;ACZF;ADaE;EACE,eAAA;EACA,iBAAA;EACA,iBAAA;EACA,yBAAA;ACXJ;ADaE;EAEE,8BAAA;ACZJ;ADaI;EACE,iBAAA;EACA,kBAAA;EACA,YAAA;ACXN;ADcE;EACI,2BAAA;ACZN;ADeE;EACE,0BAAA;ACbJ;ADcI;EACE,YAAA;ACZN;ADcI;EACE,YAAA;EACA,cAAA;ACZN;ADcI;EACE,YAAA;EACA,cAAA;EACA,oCAAA;EACA,kBAAA;ACZN;ADgBE;EACE,aAAA;ACdJ;ADgBE;EACE,wBAAA;EACA,0BAAA;ACdJ;ADgBE;EACE,eAAA;EACA,sBAAA;ACdJ;;ADkBA;EACE,sBAAA;EACA,UAAA;EACA,iBAAA;ACfF;;ADiBA;EACE,kBAAA;EACA,YAAA;ACdF;;ADgBA;EACE,uBAAA;EACA,YAAA;EACA,kBAAA;EACA,YAAA;ACbF;;ADeA;EACE,gBAAA;ACZF;;ADcA;EACE,kBAAA;ACXF;;ADcA;EACE,WAAA;EACA,gBAAA;EACA,sBAAA;EACA,kBAAA;ACXF","file":"query.component.css"}
|
||||
@@ -0,0 +1,637 @@
|
||||
<ol class="breadcrumb breadcrumb-arrow font-trirong">
|
||||
<li><a href="javascript://" [routerLink]="['/cns-portal/dashboard/order']"><clr-icon shape="home"></clr-icon></a></li>
|
||||
<li><a href="javascript://"><clr-icon shape="crown"></clr-icon>Super Admin</a></li>
|
||||
<li><a href="javascript://"> Query</a></li>
|
||||
</ol>
|
||||
|
||||
<!-- <span style="float: right;">
|
||||
<ng-template #n2><button type="submit" class="btn btn-primary" (click)="onBack()"><clr-icon shape="angle-double"></clr-icon></button></ng-template>
|
||||
<button *ngIf="!backQuery " type="submit" class="btn btn-primary" (click)="onBack()"><clr-icon shape="angle" direction="down "></clr-icon></button></span>
|
||||
<div *ngIf="backQuery"> -->
|
||||
<div class="container">
|
||||
|
||||
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-8">
|
||||
<h3>SQL Worksheet-
|
||||
<ng-template #no> <b>connection name</b></ng-template>
|
||||
<b *ngIf="databaseName;else no" style="color:#0072a3 ;">{{databaseName}}</b>
|
||||
<span class="label label-light-green p7" style="margin-top: .4em; display: inline; cursor: pointer;"
|
||||
(click)="opendatabsemo()">switch</span>
|
||||
<span class="label label-light-green p7" style="margin-top: .4em; display: inline; cursor: pointer;"
|
||||
(click)="opencopym()">Add New</span>
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clr-col-4" style="text-align: right;">
|
||||
<button mat-raised-button class="btn btn-primary" (click)="addTab(selectAfterAdding.checked)">
|
||||
<clr-icon shape="plus"></clr-icon> new tab
|
||||
</button>
|
||||
<span #selectAfterAdding> </span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-tabs [selectedIndex]="selected.value" (selectedIndexChange)="selected.setValue($event)">
|
||||
<clr-tab *ngFor="let tab of tabs; let index = index" [label]="tab">
|
||||
<button clrTabLink>{{tab}}{{index+1}}</button>
|
||||
<clr-tab-content *clrIfActive>
|
||||
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-8">
|
||||
<!-- <h5> Contents for {{tab}}{{index+1}} tab </h5> -->
|
||||
<div class="clr-row" style="padding-left: 10px;">
|
||||
<div>
|
||||
<!-- <label for="tags">
|
||||
<span class="label label-light-green p7" style="margin-top: .4em; display: inline; cursor: pointer;" (click)="opentablemod()">Add Table</span>
|
||||
</label> -->
|
||||
<!-- <textarea type="text" id="sql_query" name="sql_query" cols="10" rows="3" placeholder="select table here"
|
||||
name="selectedtable" [(ngModel)]="selectedtable" >
|
||||
</textarea> -->
|
||||
|
||||
<clr-combobox-container>
|
||||
<label>Table List</label>
|
||||
<clr-combobox [(ngModel)]="selectedtable" name="selectedtable" clrMulti="true"
|
||||
required>
|
||||
|
||||
<ng-container *clrOptionSelected="let selected;let i = alias">
|
||||
{{selected}} <b>{{ getAliasedColumn(selected) }}</b>
|
||||
|
||||
<!-- <span *ngFor="let data of TableData">
|
||||
<b *ngIf="data.tables == selected">{{data.alias}}</b></span> -->
|
||||
</ng-container>
|
||||
<clr-options>
|
||||
<clr-option *clrOptionItems="let state of tableList" [clrValue]="state">
|
||||
{{state}}
|
||||
</clr-option>
|
||||
</clr-options>
|
||||
</clr-combobox>
|
||||
</clr-combobox-container>
|
||||
|
||||
<!-- <select [(ngModel)]="selectedtable" name="selectedtable" (change)="opentcolmod($event.target.value)" class="clr-dropdown">
|
||||
<option value="null">Choose Data Store</option>
|
||||
<option *ngFor="let sub of tableList" [value]="sub">{{sub}}</option>
|
||||
</select> -->
|
||||
</div>
|
||||
<div style="padding-top: 12px; padding-bottom: 0px;"><br><button class="btn btn-icon btn-sm btn-primary" style="margin-left: 5px;"
|
||||
(click)="opentcolmod()"><clr-icon shape="step-forward-2"></clr-icon></button></div>
|
||||
<div style="padding-top: 12px; padding-bottom: 0px;"><p *ngIf="msg" style="color: red;">{{msg}} </p></div>
|
||||
|
||||
</div>
|
||||
<div class="clr-row" style="padding-left: 10px;">
|
||||
<div>
|
||||
<!-- <label for="tags" class="req"> <span class="label label-light-green p7" style="margin-top: .4em; display: inline; cursor: pointer;" (click)="opentcolmod()" >Add Select String</span></label> -->
|
||||
|
||||
<!-- <textarea type="text" id="sql_query" name="sql_query" cols="10" rows="3" placeholder="select string here"
|
||||
name="selectedcol" [(ngModel)]="selectedcol" >
|
||||
</textarea> -->
|
||||
<clr-combobox-container>
|
||||
<label>Column List</label>
|
||||
<clr-combobox [(ngModel)]="selectedcol" name="selectedcol" clrMulti="true"
|
||||
required>
|
||||
<ng-container *clrOptionSelected="let selected">
|
||||
<ng-container *ngIf="selected.indexOf('.') !== -1; else noDot">
|
||||
<span class="bold">{{ selected.substr(0, selected.indexOf('.')) }}</span>{{ selected.substr(selected.indexOf('.')) }}
|
||||
</ng-container>
|
||||
<ng-template #noDot>
|
||||
{{selected}}
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<clr-options>
|
||||
<clr-option *clrOptionItems="let state of collist" [clrValue]="state">
|
||||
{{state}}
|
||||
</clr-option>
|
||||
</clr-options>
|
||||
</clr-combobox>
|
||||
</clr-combobox-container>
|
||||
|
||||
<!-- <button class="btn btn-icon btn-sm btn-primary" style="margin-left: 5px;" (click)="opentcolmod1()"><clr-icon shape="step-forward-2"></clr-icon></button> -->
|
||||
</div>
|
||||
<div style="padding-top: 12px; padding-bottom: 0px;"><br><button class="btn btn-icon btn-sm btn-primary" style="margin-left: 5px;" (click)="colname()"><clr-icon shape="step-forward-2"></clr-icon></button></div>
|
||||
<div style="padding-top: 12px; padding-bottom: 0px;"><p *ngIf="msg1" style="color: red;">{{msg1}} </p></div>
|
||||
</div>
|
||||
<div class="clr-row" style="padding-left: 10px;">
|
||||
<div>
|
||||
<!-- <label for="tags" class="req">
|
||||
<span class="label label-light-green p7" style="margin-top: .4em; display: inline; cursor: pointer;" (click)="opentcolmod1()" >Add Condition</span>
|
||||
</label> -->
|
||||
|
||||
<!-- <textarea type="text" id="sql_query" name="sql_query" cols="10" rows="3" placeholder="select string here"
|
||||
name="selectedcol" [(ngModel)]="selectedcol1" >
|
||||
</textarea> -->
|
||||
<clr-combobox-container>
|
||||
<label>Condition List</label>
|
||||
<clr-combobox [(ngModel)]="selectedcol1" name="selectedcol1" clrMulti="true"
|
||||
required>
|
||||
<ng-container *clrOptionSelected="let selected">
|
||||
<span *ngFor="let data of conditionData">
|
||||
<b *ngIf="data.fields_name == selected">{{data.andor}}</b></span>
|
||||
<ng-container *ngIf="selected.indexOf('.') !== -1; else noDot">
|
||||
<span class="bold">{{ selected.substr(0, selected.indexOf('.')) }}</span>{{ selected.substr(selected.indexOf('.')) }}
|
||||
</ng-container>
|
||||
<ng-template #noDot>
|
||||
{{selected}}
|
||||
</ng-template>
|
||||
<span *ngFor="let data of conditionData">
|
||||
<b *ngIf="data.fields_name == selected">{{data.condition}} {{data.value}}</b></span>
|
||||
|
||||
</ng-container>
|
||||
<clr-options>
|
||||
<clr-option *clrOptionItems="let state of collist" [clrValue]="state">
|
||||
{{state}}
|
||||
</clr-option>
|
||||
</clr-options>
|
||||
</clr-combobox>
|
||||
<!-- <clr-control-helper>Helper text</clr-control-helper> -->
|
||||
<!-- <clr-control-error>Select one mandatory</clr-control-error> -->
|
||||
</clr-combobox-container>
|
||||
</div>
|
||||
<div style="padding-top: 12px; padding-bottom: 0px;"><br><button class="btn btn-icon btn-sm btn-primary" style="margin-left: 5px;" (click)="filter(selectedcol1)"><clr-icon shape="filter"></clr-icon></button></div>
|
||||
<!-- <div style="padding-top: 12px; padding-bottom: 0px;"><p *ngIf="msg" style="color: red;">{{msg}} </p></div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clr-col-4" style="text-align: right;">
|
||||
<button mat-raised-button class="btn btn-primary" [disabled]="tabs.length === 1" (click)="removeTab(index)">
|
||||
<clr-icon shape="trash"></clr-icon> {{tab}}{{index+1}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container" style="margin-top: 20px;">
|
||||
<div class="progressform">
|
||||
<div class="clr-row">
|
||||
</div>
|
||||
<form [formGroup]="entryForm">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label for="tags"> <span class="label label-light-green p7"
|
||||
style="margin-top: .4em; display: inline; cursor: pointer;" (click)="openquerymod()">Add
|
||||
Query</span>
|
||||
</label>
|
||||
<textarea type="text" id="sql_query" name="sql_query" formControlName="sql_query" cols="10" rows="3"
|
||||
[(ngModel)]="selectedquery" placeholder="Enter Query here">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<span style="float: right;">
|
||||
<button type="submit" class="btn btn-primary" (click)="savequery()">SAVE QUERY</button>
|
||||
<button type="submit" class="btn btn-primary" (click)="onSubmit()">RUN</button>
|
||||
</span><br>
|
||||
<div>
|
||||
<h4 style="font-weight: 300;display: inline;">Response</h4>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="clr-row" style="padding-top: 10px;">
|
||||
|
||||
<!-- <ngx-datatable
|
||||
style='width:fit-content;'
|
||||
[rows]="rows"
|
||||
[columns]="columns"
|
||||
class="bootstrap"
|
||||
[loadingIndicator]="loadingIndicator"
|
||||
[headerHeight]="40"
|
||||
[summaryRow]="true"
|
||||
[summaryPosition]="'bottom'"
|
||||
[scrollbarV]="true"
|
||||
[limit]="10"
|
||||
[rowHeight]="40"
|
||||
[reorderable]="reorderable" >
|
||||
</ngx-datatable> -->
|
||||
</div>
|
||||
</div>
|
||||
</div><br>
|
||||
</clr-tab-content>
|
||||
</clr-tab>
|
||||
</clr-tabs>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
<div class="container" style=" min-width: 1200px; max-height: 500px !important; overflow: auto;">
|
||||
<table class="table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th *ngFor="let co of getHeaders();let i=index">{{co}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of rows">
|
||||
<td *ngFor="let key of getHeaders()">{{item[key]}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- <clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
||||
<div *ngIf="errorco;else loadingSpinner">{{errorco}}</div></clr-dg-placeholder>
|
||||
<clr-dg-column *ngFor="let co of getHeaders()">
|
||||
{{co}}
|
||||
</clr-dg-column>
|
||||
<clr-dg-row *ngFor="let item of rows">
|
||||
<clr-dg-cell *ngFor="let key of getHeaders()">{{item[key]}}</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="5">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid> -->
|
||||
|
||||
<clr-modal [(clrModalOpen)]="database" [clrModalSize]="'xl'">
|
||||
<h3 class="modal-title"><b>Select Database</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12" style="margin-top: 8px;">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input" name="searchtable"
|
||||
[(ngModel)]="searchdatabase">
|
||||
</div>
|
||||
</div>
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
||||
<div *ngIf="errorco;else loadingSpinner">{{errorco}}</div>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'name'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Database Name
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'description'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Description
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'active'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Active
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'type'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Type
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column> <ng-container *clrDgHideableColumn="{hidden: false}"> <clr-icon shape="bars"></clr-icon>
|
||||
Action
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-row *ngFor="let user of databaselist | filter:searchdatabase;let i = index">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell style="color: rgb(108, 108, 194); cursor: pointer;" (click)="databasename(user)">{{user.name}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.description}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{user.active}}</clr-dg-cell>
|
||||
<clr-dg-cell id="word">{{user.type}}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<span style="cursor: pointer;padding: 10px; "><clr-icon shape="trash" (click)="onDelete(user)" class="red is-error" style="color: red;"></clr-icon></span>
|
||||
<!-- <span style="cursor: pointer;"><clr-icon shape="help" class="success" style="color: rgb(0, 130, 236);;"></clr-icon></span> -->
|
||||
</clr-dg-cell>
|
||||
<clr-dg-action-overflow>
|
||||
|
||||
<button class="action-item" (click)="goToEdit(user.id)">Edit <clr-icon shape="edit" class="is-error"></clr-icon></button>
|
||||
<!-- <button class="action-item" (click)="onDelete(user)">Delete<clr-icon shape="trash" class="is-error"></clr-icon></button> -->
|
||||
</clr-dg-action-overflow>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="table" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From Table List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12" style="margin-top: 8px;">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input" name="searchtable"
|
||||
[(ngModel)]="searchtable">
|
||||
</div>
|
||||
</div>
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
||||
<div *ngIf="errortb;else loadingSpinner">{{errortb}}</div>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'tableList'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Table Name
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-row *ngFor="let user of tableList | filter:searchtable;let i = index" [clrDgItem]="user">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell style="color: rgb(108, 108, 194);" (click)="tablename(user)">{{user}}</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Users per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Record
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="col" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From Tables Columns List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12" style="margin-top: 8px;">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input" name="searchtable"
|
||||
[(ngModel)]="searchcol">
|
||||
</div>
|
||||
</div>
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
||||
<div *ngIf="errorcl;else loadingSpinner">{{errorcl}}</div>
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'tableList'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Column Name
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-row *ngFor="let user of collist | filter:searchcol;let i = index">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell style="color: rgb(108, 108, 194);" (click)="colname(user)">{{user}}</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="col1" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select From Tables Columns List:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12" style="margin-top: 8px;">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input" name="searchtable"
|
||||
[(ngModel)]="searchcol">
|
||||
</div>
|
||||
</div>
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder><clr-spinner [clrMedium]="true">Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'tableList'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Column Name
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-row *ngFor="let user of collist | filter:searchcol;let i = index">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell style="color: rgb(108, 108, 194);" (click)="colname1(user)">{{user}}</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="query" [clrModalSize]="'lg'">
|
||||
<h3 class="modal-title"><b>Select Query:</b></h3>
|
||||
<div class="modal-body">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-12 clr-col-sm-12" style="margin-top: 8px;">
|
||||
<input id="data" type="text" placeholder="Enter search Criteria" class="clr-input" name="searchtable"
|
||||
[(ngModel)]="searchquery">
|
||||
</div>
|
||||
</div>
|
||||
<clr-datagrid [clrDgLoading]="loading">
|
||||
<clr-dg-placeholder><clr-spinner [clrMedium]="true">Loading ...</clr-spinner></clr-dg-placeholder>
|
||||
<clr-dg-column [clrDgField]="'id'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
No
|
||||
</ng-container></clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'query'"> <ng-container *clrDgHideableColumn="{hidden: false}">
|
||||
Query
|
||||
</ng-container></clr-dg-column>
|
||||
|
||||
<clr-dg-row *ngFor="let user of querydata | filter:searchquery;let i = index">
|
||||
<clr-dg-cell>{{i+1}}</clr-dg-cell>
|
||||
<clr-dg-cell style="color: rgb(108, 108, 194);"
|
||||
(click)="selectquery(user.sql_query)">{{user.sql_query}}</clr-dg-cell>
|
||||
|
||||
</clr-dg-row>
|
||||
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Record per page</clr-dg-page-size>
|
||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||
of {{pagination.totalItems}} Records
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="addmodal" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title"> Create New</h3>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="addForm" (ngSubmit)="onCreate()">
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label>Conn_String<span class="required-field">*</span></label>
|
||||
<input type="text" formControlName="conn_string" class="clr-input">
|
||||
</div>
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label>Username<span class="required-field">*</span></label>
|
||||
<input type="text" formControlName="username" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label>Password<span class="required-field">*</span></label>
|
||||
<input type="text" formControlName="password" class="clr-input">
|
||||
</div>
|
||||
<div class="clr-col-md-6 clr-col-sm-12">
|
||||
<label>Driver_class_name<span class="required-field">*</span></label>
|
||||
<input type="text" formControlName="driver_class_name" class="clr-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="addmodal = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</clr-modal>
|
||||
<clr-modal [(clrModalOpen)]="filterModel" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title"> Condition Table</h3>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
|
||||
|
||||
<div class="clr-row fieldWrapper" >
|
||||
<div class="clr-col-12">
|
||||
<table class="table table-striped table-bordered" style="margin-top: 0px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ANDOR</th>
|
||||
<th>FIELD NAME</th>
|
||||
<th>CONDITION</th>
|
||||
<th>VALUE</th>
|
||||
<th class="right" style="width:125px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let data of conditionData; let i = index">
|
||||
<td ><select colspan="2" [(ngModel)]="data.andor" [ngModelOptions]="{standalone: true}" name="andor" class="clr-dropdown">
|
||||
<option [ngValue]="null">Select Values</option>
|
||||
<option *ngFor="let sub of andor" [ngValue]="sub">{{sub}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<!-- <td><input type="text" colspan="2" [(ngModel)]="data.alias" [ngModelOptions]="{standalone: true}" name="alias" class="clr-input"/></td> -->
|
||||
|
||||
<td><select colspan="2" [(ngModel)]="data.fields_name" [ngModelOptions]="{standalone: true}" name="fields_name" class="clr-dropdown">
|
||||
<option [ngValue]="null">Select Field Name</option>
|
||||
<!-- <option *ngFor="let sub of sourceTable" [ngValue]="sub">{{sub}}</option> -->
|
||||
<option *ngFor="let item of collist" [ngValue]="item">{{item}}</option>
|
||||
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select colspan="2" [(ngModel)]="data.condition" [ngModelOptions]="{standalone: true}" name="condition" class="clr-dropdown">
|
||||
<option [ngValue]="null">Select Values</option>
|
||||
<option *ngFor="let sub of condition" [ngValue]="sub">{{sub}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="text" [(ngModel)]="data.value" [ngModelOptions]="{standalone: true}" name="value" class="clr-input"/></td>
|
||||
<td style="width:40px;">
|
||||
<a (click)="deleteRow(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" (click)="onAddLines()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<button type="button" class="btn btn-outline" (click)="filterModel = false">Cancel</button>
|
||||
<button type="submit" form-control class="btn btn-primary" (click)="onSelected()">Select</button>
|
||||
<!-- <button type="button" form-control class="btn btn-primary" (click)="back()">Back</button> -->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="columnModal" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title"> Column Table</h3>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
|
||||
|
||||
<div class="clr-row fieldWrapper" >
|
||||
<div class="clr-col-12">
|
||||
<table class="table table-striped table-bordered" style="margin-top: 0px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Column</th>
|
||||
<th>Alias</th>
|
||||
<th class="right" style="width:125px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let data of columnData; let i = index">
|
||||
<td >
|
||||
<input type="text" [(ngModel)]="data.columns" [ngModelOptions]="{standalone: true}" name="columns" class="clr-input" readonly/>
|
||||
<td><input type="text" [(ngModel)]="data.alias" [ngModelOptions]="{standalone: true}" name="alias" class="clr-input"/></td>
|
||||
<td style="width:40px;">
|
||||
<a (click)="deleteColRow(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" (click)="onAddColLines()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<button type="submit" form-control class="btn btn-primary" (click)="onColSelected()">Select</button>
|
||||
<!-- <button type="button" form-control class="btn btn-primary" (click)="back()">Back</button> -->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<!-- <clr-modal [(clrModalOpen)]="tableModal" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
<h3 class="modal-title"> Condition Table</h3>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
|
||||
|
||||
<div class="clr-row fieldWrapper" >
|
||||
<div class="clr-col-12">
|
||||
<table class="table table-striped table-bordered" style="margin-top: 0px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table Name</th>
|
||||
<th>Alias</th>
|
||||
<th></th>
|
||||
<th class="right" style="width:125px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let data of TableData; let i = index">
|
||||
<td >
|
||||
<input type="text" [(ngModel)]="data.tables" [ngModelOptions]="{standalone: true}" name="columns" class="clr-input" readonly/>
|
||||
<td><input type="text" [(ngModel)]="data.alias" [ngModelOptions]="{standalone: true}" name="alias" class="clr-input"/></td>
|
||||
<td><button type="button" class="btn btn-primary" (click)="onTableSelected(data)">Add</button></td>
|
||||
<td style="width:40px;">
|
||||
<a (click)="deleteTableRow(i)">
|
||||
<clr-icon shape="trash" class="is-error"></clr-icon>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
<button type="button" class="btn btn-primary button1" (click)="onAddTableLines()">
|
||||
<clr-icon shape="plus"></clr-icon>
|
||||
</button>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<button type="submit" form-control class="btn btn-outline" (click)="tableModal = false">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</clr-modal> -->
|
||||
|
||||
|
||||
|
||||
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
|
||||
|
||||
<div class="modal-body" *ngIf="rowSelected.id">
|
||||
<h1 class="delete">Are You Sure Want to delete?</h1>
|
||||
<h2 class="heading">{{rowSelected.id}}</h2>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
|
||||
<button type="submit" (click)="delete(rowSelected.id)" class="btn btn-primary" >Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</clr-modal>
|
||||
@@ -0,0 +1,161 @@
|
||||
$bg-color: #dddddd;
|
||||
|
||||
.button1::after {
|
||||
content: none;
|
||||
}
|
||||
.button1:hover::after {
|
||||
content: "ADD ROWS";
|
||||
}
|
||||
|
||||
.delete,.heading{
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.bold{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.section p {
|
||||
//color: white;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.clr-input {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.75rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
// input[type=text],[type=date],textarea {
|
||||
// width: 60%;
|
||||
// padding: 15px 15px;
|
||||
// // margin: 8px 0;
|
||||
// background-color:rgb(255, 255, 255);
|
||||
// display: inline-block;
|
||||
// border: 1px solid #ccc;
|
||||
// border-radius: 4px;
|
||||
// box-sizing: border-box;
|
||||
// }
|
||||
.required-field{
|
||||
color: red;
|
||||
font-size: 18px;
|
||||
|
||||
}
|
||||
|
||||
input[type=text],textarea {
|
||||
width: 100%;
|
||||
padding: 15px 15px;
|
||||
// margin: 8px 0;
|
||||
background-color:rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
html {
|
||||
/* make sure we use up the whole viewport */
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
body {
|
||||
width: 100%;
|
||||
background-color: gray;
|
||||
//min-height: 100vh; /* this helps with the sticky footer */
|
||||
}
|
||||
|
||||
//Import classes from swimlane datatable
|
||||
ngx-datatable {
|
||||
font-family: Metropolis,Avenir Next,Helvetica Neue,Arial,sans-serif;
|
||||
font-size:13px;
|
||||
border:1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
padding:0;
|
||||
background-color: #fff;
|
||||
.datatable-header, .datatable-footer {
|
||||
font-size:11px;
|
||||
line-height:18px;
|
||||
font-weight:bold;
|
||||
background-color:#fafafa;
|
||||
}
|
||||
.datatable-header{
|
||||
//border-bottom: 2px solid #ccc;
|
||||
box-shadow: 0 2px 4px 0px #ccc;
|
||||
.datatable-header-cell{
|
||||
line-height:22px;
|
||||
padding-left:10px;
|
||||
height:22px;
|
||||
}
|
||||
}
|
||||
.datatable-header .datatable-header-cell:not(:first-child) {
|
||||
border-left:1px solid #ccc;
|
||||
}
|
||||
|
||||
.datatable-footer{
|
||||
border-top: 1px solid #ccc;
|
||||
.page-count{
|
||||
margin: 10px;
|
||||
}
|
||||
.pages a{
|
||||
padding:8px;
|
||||
color:inherit;
|
||||
}
|
||||
.pages.active a{
|
||||
padding:8px;
|
||||
color:#007cbb;
|
||||
background-color:rgb(221, 221, 221);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.datatable-header-inner{
|
||||
padding:12px;
|
||||
}
|
||||
.datatable-body-cell{
|
||||
padding:8px 0 10px 20px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
.pager i {
|
||||
font-size:18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.postColumn{
|
||||
border: 1px solid #ccc;
|
||||
width: 78%;
|
||||
margin-left: 15px;
|
||||
}
|
||||
.colName{
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
}
|
||||
.colfields{
|
||||
border: 1px solid black;
|
||||
margin: 17px;
|
||||
text-align: center;
|
||||
padding: 3px;
|
||||
}
|
||||
.fieldWrapper{
|
||||
margin-top: 20px;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
select{
|
||||
width: 100%;
|
||||
padding: 5px 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
// @import '@swimlane/ngx-datatable/index.css';
|
||||
// @import '@swimlane/ngx-datatable/themes/bootstrap.css';
|
||||
// @import '@swimlane/ngx-datatable/assets/icons.css';
|
||||
@@ -1,20 +1,20 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { steptest1Component } from './steptest1.component';
|
||||
import { QueryComponent } from './query.component';
|
||||
|
||||
describe('steptest1Component', () => {
|
||||
let component: steptest1Component;
|
||||
let fixture: ComponentFixture<steptest1Component>;
|
||||
describe('QueryComponent', () => {
|
||||
let component: QueryComponent;
|
||||
let fixture: ComponentFixture<QueryComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ steptest1Component ]
|
||||
declarations: [ QueryComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(steptest1Component);
|
||||
fixture = TestBed.createComponent(QueryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -0,0 +1,536 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
|
||||
import { ReportBuilderService } from 'src/app/services/api/report-builder.service';
|
||||
import { TableList } from '../../../../models/fnd/table-setup';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
@Component({
|
||||
selector: 'app-query',
|
||||
templateUrl: './query.component.html',
|
||||
styleUrls: ['./query.component.scss']
|
||||
})
|
||||
export class QueryComponent implements OnInit {
|
||||
searchtable: any;
|
||||
searchcol: any;
|
||||
columns: any[];
|
||||
table: boolean = false;
|
||||
database: boolean = false;
|
||||
query: boolean = false;
|
||||
public entryForm: FormGroup;
|
||||
public addForm: FormGroup;
|
||||
addmodal: boolean = false;
|
||||
query2: string;
|
||||
rows: any[];
|
||||
loading = false;
|
||||
tableList: TableList[];
|
||||
databaselist = [];
|
||||
collist;
|
||||
search: any;
|
||||
selectedtable: any[];
|
||||
selectedcol: any[];
|
||||
selectedcol1: any[];
|
||||
selectedtablequery;
|
||||
selectcolquery;
|
||||
selectedquery;
|
||||
backQuery = true;
|
||||
searchquery;
|
||||
col: boolean = false;
|
||||
col1: boolean = false;
|
||||
searchdatabase;
|
||||
selecteddatabase;
|
||||
msg;
|
||||
querydata;
|
||||
errorco;
|
||||
errortb;
|
||||
errorcl;
|
||||
loadingIndicator = true; reorderable = true;
|
||||
filterModel = false;
|
||||
conditionData = [];
|
||||
andor = ['AND', 'OR', 'NOT'];
|
||||
fieldname = ['name1', 'name2'];
|
||||
condition = ['=', '!=', '<', '>', '<=', '>=', 'LIKE', 'BETWEEN', 'IN'];
|
||||
alias = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||
tabs = ['Tab', 'Tab',];
|
||||
selected = new FormControl(0);
|
||||
constructor(private _fb: FormBuilder, private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private reportBuilderService: ReportBuilderService, private toastr: ToastrService,) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.entryForm = this._fb.group({
|
||||
sql_query: [null],
|
||||
});
|
||||
this.addForm = this._fb.group({
|
||||
conn_string: [null],
|
||||
username: [null],
|
||||
password: [null],
|
||||
driver_class_name: [null],
|
||||
})
|
||||
// this.listofTables();
|
||||
|
||||
}
|
||||
|
||||
|
||||
listoddatabase() {
|
||||
this.reportBuilderService.getdatabse().subscribe((data) => {
|
||||
this.databaselist = data;
|
||||
console.log('databse list ', this.databaselist)
|
||||
if (this.databaselist.length == 0) {
|
||||
this.errorco = "No data Available";
|
||||
|
||||
}
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
if (error) {
|
||||
this.errorco = "No data Available";
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
listofTables(val) {
|
||||
this.reportBuilderService.getTableListn(val).subscribe(data => {
|
||||
// console.log("table list "+data);
|
||||
this.tableList = data;
|
||||
console.log('table list ', this.tableList);
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
if (error) {
|
||||
this.errortb = "No data Available";
|
||||
}
|
||||
})
|
||||
}
|
||||
msg1;
|
||||
finalColList: any[] = [];
|
||||
listofcol(val) {
|
||||
console.log(this.selectedtable);
|
||||
console.log(this.selectedcol);
|
||||
console.log(this.selectedcol1);
|
||||
const tableString = JSON.stringify(val);
|
||||
console.log(tableString);
|
||||
const array = Array.of(val); // Using the Array constructor
|
||||
console.log(array);
|
||||
console.log(val);
|
||||
// this.reportBuilderService.getcolListn(this.name[1],val).subscribe((data)=>{
|
||||
// this.reportBuilderService.getColumnList(this.name[1],array).subscribe((data)=>{
|
||||
this.reportBuilderService.getAllColumnsFromAllTables(array).subscribe((data) => {
|
||||
console.log(data);
|
||||
this.collist = data;
|
||||
// this.finalColList.push(data);
|
||||
// this.finalColList.push(this.collist)
|
||||
if (this.selectedtable == null) {
|
||||
this.msg = 'Plz First Select Table'
|
||||
} else {
|
||||
this.msg = "";
|
||||
}
|
||||
|
||||
//console.log(this.collist);
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
if (error) {
|
||||
this.errorcl = "No data Available";
|
||||
}
|
||||
})
|
||||
}
|
||||
listofquery() {
|
||||
this.reportBuilderService.getall().subscribe((data) => {
|
||||
this.querydata = data;
|
||||
console.log(this.querydata)
|
||||
})
|
||||
}
|
||||
rowdata;
|
||||
onSubmit() {
|
||||
this.backQuery = false;
|
||||
|
||||
this.query2 = this.entryForm.value.sql_query;
|
||||
console.log(this.query2);
|
||||
this.reportBuilderService.getMasterData(this.query2).subscribe((data) => {
|
||||
this.rows = data;
|
||||
console.log(this.rows);
|
||||
this.rowdata = [this.rows];
|
||||
console.log(typeof this.rows);
|
||||
if (data) {
|
||||
this.toastr.success("Run Successfully")
|
||||
}
|
||||
var j;
|
||||
var cart = [];
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var columnsIn = data[i];
|
||||
if (i == 1) {
|
||||
for (var key in columnsIn) {
|
||||
j = { prop: key, name: key };
|
||||
cart.push(j)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
this.columns = cart;
|
||||
|
||||
});
|
||||
}
|
||||
getHeaders() {
|
||||
let headers: string[] = [];
|
||||
if (this.rows) {
|
||||
this.rows.forEach((value) => {
|
||||
Object.keys(value).forEach((key) => {
|
||||
if (!headers.find((header) => header == key)) {
|
||||
headers.push(key)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
savequery() {
|
||||
//this.query2=this.entryForm.value.sql_query;
|
||||
console.log(this.entryForm.value);
|
||||
this.reportBuilderService.saveq(this.entryForm.value).subscribe((data) => {
|
||||
console.log(data);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
//tab
|
||||
addTab(selectAfterAdding: boolean) {
|
||||
this.tabs.push('Tab');
|
||||
|
||||
if (selectAfterAdding) {
|
||||
this.selected.setValue(this.tabs.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
removeTab(index: number) {
|
||||
this.tabs.splice(index, 1);
|
||||
}
|
||||
opendatabsemo() {
|
||||
this.database = true;
|
||||
this.listoddatabase();
|
||||
}
|
||||
name;
|
||||
databaseName;
|
||||
databasename(val) {
|
||||
console.log(val);
|
||||
this.databaseName = val.name;
|
||||
this.selecteddatabase = val.conn_string;
|
||||
console.log('selected databse ', this.selecteddatabase);
|
||||
// this.selecteddatabase.substring(0,this.selecteddatabase.indexOf(':3306/'))
|
||||
// console.log(this.selecteddatabase);
|
||||
this.name = this.selecteddatabase.split(":3306/");
|
||||
console.log(this.name[1]);
|
||||
this.database = false;
|
||||
this.listofTables(this.name[1])
|
||||
}
|
||||
opentablemod() {
|
||||
this.table = true;
|
||||
// this.listofTables();
|
||||
}
|
||||
tablename(value) {
|
||||
console.log(value);
|
||||
this.selectedtable = value;
|
||||
this.table = false;
|
||||
}
|
||||
tableModal = false;
|
||||
TableData;
|
||||
opentcolmod() {
|
||||
// this.col=true;
|
||||
|
||||
if (this.selectedtable == null) {
|
||||
this.msg = 'Plz First Select Table'
|
||||
} else {
|
||||
this.msg = "";
|
||||
// this.tableModal = true;
|
||||
}
|
||||
this.listofcol(this.selectedtable)
|
||||
|
||||
if (Array.isArray(this.selectedtable) || this.selectedtable === undefined) {
|
||||
const selectedTables = this.selectedtable.map((table, index) => {
|
||||
const alias = String.fromCharCode(97 + (index % 26)); // Generate aliases starting from 'a'
|
||||
console.log(alias, table);
|
||||
return `${table} ${alias}`;
|
||||
}).join(',');
|
||||
console.log(selectedTables);
|
||||
// const selectedTables = this.TableData.map(({ alias, tables }) => `${tables} ${alias}`).join(',');
|
||||
// console.log(selectedTables);
|
||||
|
||||
this.selectedtablequery = `SELECT * FROM ${selectedTables} WHERE 1=1`;
|
||||
console.log(this.selectedtablequery);
|
||||
// You can perform further actions with the generated SQL query
|
||||
} else {
|
||||
this.selectedtablequery = '';
|
||||
console.log(this.selectedtablequery);
|
||||
// You can perform further actions with the generated SQL query
|
||||
}
|
||||
|
||||
this.selectedquery = this.selectedtablequery;
|
||||
|
||||
// const defaultObject = {
|
||||
// alias: "",
|
||||
// }
|
||||
// const objectArray = this.selectedtable.map(value => ({
|
||||
// ...defaultObject,
|
||||
// tables: value,
|
||||
// }));
|
||||
// console.log(objectArray);
|
||||
// const data = JSON.stringify(objectArray);
|
||||
// try {
|
||||
// this.TableData = JSON.parse(data);
|
||||
// console.log('Received data:', this.TableData );
|
||||
// } catch (e) { console.error('Invalid JSON:', data);}
|
||||
}
|
||||
|
||||
onAddTableLines() {
|
||||
this.TableData.push({
|
||||
tables: "",
|
||||
alias: "",
|
||||
});
|
||||
}
|
||||
deleteTableRow(index) {
|
||||
this.TableData.splice(index, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
opentcolmod1() {
|
||||
// this.col1=true;
|
||||
this.listofcol(this.selectedtable)
|
||||
|
||||
|
||||
}
|
||||
columnModal = false;
|
||||
columnData;
|
||||
colname() {
|
||||
|
||||
this.columnModal = true;
|
||||
|
||||
//column filter
|
||||
const defaultObject = {
|
||||
alias: "",
|
||||
}
|
||||
const objectArray = this.selectedcol.map(value => ({
|
||||
...defaultObject,
|
||||
columns: value,
|
||||
}));
|
||||
console.log(objectArray);
|
||||
const data = JSON.stringify(objectArray);
|
||||
try {
|
||||
this.columnData = JSON.parse(data);
|
||||
console.log('Received data:', this.columnData);
|
||||
} catch (e) { console.error('Invalid JSON:', data); }
|
||||
}
|
||||
|
||||
onAddColLines() {
|
||||
this.columnData.push({
|
||||
columns: "",
|
||||
alias: "",
|
||||
});
|
||||
}
|
||||
deleteColRow(index) {
|
||||
this.columnData.splice(index, 1);
|
||||
}
|
||||
|
||||
onColSelected() {
|
||||
// console.log(col);
|
||||
// this.selectedcol=col;
|
||||
this.col = false;
|
||||
this.columnModal = false;
|
||||
if (Array.isArray(this.columnData)) {
|
||||
// const selectedColumns = this.columnData.join(',');
|
||||
//for column
|
||||
const selectedColumns = this.columnData.map(({ alias, columns }) => `${columns} as ${alias}`).join(',');
|
||||
console.log(selectedColumns);
|
||||
//for table
|
||||
const selectedTables = this.selectedtable.map((table, index) => {
|
||||
const alias = String.fromCharCode(97 + (index % 26)); // Generate aliases starting from 'a'
|
||||
console.log(alias, table);
|
||||
return `${table} ${alias}`;
|
||||
}).join(',');
|
||||
console.log(selectedTables);
|
||||
|
||||
// const selectedTables = this.TableData.map(({ alias, tables }) => `${tables} ${alias}`).join(',');
|
||||
// console.log(selectedTables);
|
||||
|
||||
this.selectcolquery = `SELECT ${selectedColumns} FROM ${selectedTables} WHERE 1=1`;
|
||||
console.log(this.selectcolquery);
|
||||
// You can perform further actions with the generated SQL query
|
||||
} else if (Array.isArray(this.selectedtable)) {
|
||||
//for table
|
||||
const selectedTables = this.selectedtable.map((table, index) => {
|
||||
const alias = String.fromCharCode(97 + (index % 26)); // Generate aliases starting from 'a'
|
||||
console.log(alias, table);
|
||||
return `${table} ${alias}`;
|
||||
}).join(',');
|
||||
console.log(selectedTables);
|
||||
this.selectcolquery = `SELECT * FROM ${selectedTables} WHERE 1=1`;
|
||||
console.log(this.selectcolquery);
|
||||
// You can perform further actions with the generated SQL query
|
||||
} else {
|
||||
// if(this.selectedtable==null){
|
||||
// this.msg1='Plz First Select Table'
|
||||
// }else{
|
||||
// this.msg1="";
|
||||
// }
|
||||
}
|
||||
this.selectedquery = this.selectcolquery;
|
||||
}
|
||||
colname1() {
|
||||
// console.log(col);
|
||||
// this.selectedcol1=col;
|
||||
// this.col1=false;
|
||||
// this.listofquery();
|
||||
}
|
||||
openquerymod() {
|
||||
this.query = true;
|
||||
this.listofquery();
|
||||
}
|
||||
selectquery(val) {
|
||||
console.log(val);
|
||||
this.selectedquery = val;
|
||||
this.query = false;
|
||||
}
|
||||
opencopym() {
|
||||
this.router.navigate(["../queryadd"], { relativeTo: this.route });
|
||||
// this.addmodal=true;
|
||||
}
|
||||
onCreate() {
|
||||
console.log(this.addForm.value);
|
||||
this.reportBuilderService.createdb(this.addForm.value).subscribe((data) => {
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
|
||||
// onSelectedChanged(selected){
|
||||
// this.selectedTableData = this.tableList.filter(item => item.selected);
|
||||
// }
|
||||
conditionVal;
|
||||
filter(val) {
|
||||
|
||||
this.filterModel = true;
|
||||
this.conditionVal = val;
|
||||
|
||||
const defaultObject = {
|
||||
andor: "AND",
|
||||
// alias: "",
|
||||
condition: "=",
|
||||
value: "",
|
||||
}
|
||||
const objectArray = this.conditionVal.map(value => ({
|
||||
...defaultObject,
|
||||
fields_name: value,
|
||||
}));
|
||||
console.log(objectArray);
|
||||
const data = JSON.stringify(objectArray);
|
||||
try {
|
||||
this.conditionData = JSON.parse(data);
|
||||
console.log('Received data:', this.conditionData);
|
||||
} catch (e) { console.error('Invalid JSON:', data); }
|
||||
}
|
||||
|
||||
onAddLines() {
|
||||
this.conditionData.push({
|
||||
andor: "AND",
|
||||
fields_name: "",
|
||||
condition: "=",
|
||||
value: ""
|
||||
});
|
||||
}
|
||||
deleteRow(index) {
|
||||
this.conditionData.splice(index, 1);
|
||||
}
|
||||
filteredConditionData;
|
||||
filterAndor;
|
||||
filtercondlvalue;
|
||||
onSelected() {
|
||||
this.filterModel = false;
|
||||
console.log(this.conditionData);
|
||||
let formattedString = '';
|
||||
for (const condition of this.conditionData) {
|
||||
const { andor, fields_name, condition: cond, value } = condition;
|
||||
formattedString += `${andor} ${fields_name} ${cond} '${value}'`;
|
||||
this.filterAndor = andor;
|
||||
this.filtercondlvalue = cond + ' ' + value;
|
||||
}
|
||||
// this.getConditionBeforeColumn(this.selectedcol1)
|
||||
// this.getConditionAfterColumn(this.selectedcol1);
|
||||
console.log(formattedString);
|
||||
this.filteredConditionData = formattedString
|
||||
if (this.selectcolquery !== undefined) {
|
||||
const mQuery = this.selectcolquery + ' ' + formattedString;
|
||||
console.log(mQuery);
|
||||
this.selectedquery = mQuery;
|
||||
} else {
|
||||
const mQuery = this.selectedtablequery + ' ' + formattedString;
|
||||
console.log(mQuery);
|
||||
this.selectedquery = mQuery;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// getConditionBeforeColumn(selected: any){
|
||||
|
||||
// return this.filterAndor;
|
||||
|
||||
|
||||
// }
|
||||
// getConditionAfterColumn(selected: any){
|
||||
// return this.filtercondlvalue
|
||||
|
||||
|
||||
// }
|
||||
onBack() {
|
||||
// this.backQuery = true;
|
||||
}
|
||||
|
||||
getAliasedColumn(selected: string) {
|
||||
const index = this.selectedtable.findIndex(item => item === selected);
|
||||
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const aliasIndex = index % alphabet.length; // Calculate the index based on the remainder
|
||||
const repeatedAlias = alphabet.charAt(aliasIndex);
|
||||
return repeatedAlias;
|
||||
|
||||
// const index = this.selectedtable.findIndex(item => item === selected);
|
||||
// return this.alias[index];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
goToEdit(id) {
|
||||
this.router.navigate(["../queryedit/" + id], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
rowSelected: any = {};
|
||||
modaldelete = false;
|
||||
onDelete(row) {
|
||||
this.rowSelected = row;
|
||||
this.modaldelete = true;
|
||||
}
|
||||
|
||||
delete(id) {
|
||||
this.modaldelete = false;
|
||||
console.log("in delete " + id);
|
||||
this.reportBuilderService.deleteSqlModel(id).subscribe(
|
||||
(data) => {
|
||||
console.log(data);
|
||||
this.listoddatabase();
|
||||
if (data) {
|
||||
this.toastr.success('Deleted successfully');
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log('Error in adding data...', +error);
|
||||
if (isNaN(error)) {
|
||||
this.toastr.success('Deleted successfully');
|
||||
} else {
|
||||
this.toastr.error('Not Deleted Data Getting Some Error');
|
||||
}
|
||||
this.listoddatabase();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
.s-info-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.s-info-bar button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.entry-pg {
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.button1::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.button1:hover::after {
|
||||
content: "ADD ROWS";
|
||||
}
|
||||
|
||||
.section {
|
||||
background-color: #dddddd;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.section p {
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.clr-input {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.75rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.clr-file {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input[type=text], [type=date], textarea {
|
||||
width: 100%;
|
||||
padding: 15px 15px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: red;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 5px 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}/*# sourceMappingURL=queryadd.component.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["queryadd.component.scss","queryadd.component.css"],"names":[],"mappings":"AACA;EACI,aAAA;EACA,mBAAA;EACA,8BAAA;ACAJ;ADCI;EACE,aAAA;ACCN;;ADGE;EACE,YAAA;ACAJ;;ADGE;EACE,aAAA;ACAJ;;ADEE;EACE,mBAAA;ACCJ;;ADIE;EACE,yBAHS;EAIT,YAAA;ACDJ;;ADIE;EAEE,iBAAA;EACA,aAAA;EACA,eAAA;ACFJ;;ADKE;EACE,cAAA;EACA,yBAAA;EACA,sBAAA;EACA,wBAAA;EACA,eAAA;EACA,WAAA;EACA,mBAAA;ACFJ;;ADKE;EACE,cAAA;EACA,yBAAA;EACA,sBAAA;EAEA,eAAA;EACA,WAAA;EACA,mBAAA;ACHJ;;ADME;EACE,kBAAA;ACHJ;;ADKE;EACE,WAAA;EACA,kBAAA;EAED,oCAAA;EACC,qBAAA;EACA,sBAAA;EACA,kBAAA;EACA,sBAAA;ACHJ;;ADME;EACE,UAAA;ACHJ;;ADME;EACE,WAAA;EACA,gBAAA;EACA,sBAAA;EACA,kBAAA;ACHJ","file":"queryadd.component.css"}
|
||||
@@ -0,0 +1,130 @@
|
||||
<h4 style="font-weight: 300;display: inline;"><b> Add Database</b></h4>
|
||||
<span class="label label-light-blue" style="display: inline;margin-left: 10px;">Add Mode</span><br>
|
||||
<hr>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- entry form-->
|
||||
<form [formGroup]="entryForm"><!-- (ngSubmit)="onSubmit()"-->
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectName">Name</label>
|
||||
<input id="projectName" type="text" formControlName="name" placeholder="Enter Name"
|
||||
class="clr-input" required>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="technologyStack">Type</label>
|
||||
<select formControlName="type" class="clr-dropdown">
|
||||
<option [ngValue]="null">Choose Technology</option>
|
||||
<option *ngFor="let item of type" [ngValue]="item">{{item}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="description">Description (optional)</label>
|
||||
<textarea id="" cols="10" rows="2" name=" remarks" formControlName="description" placeholder="Enter Description">
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="workflow_name">Active</label>
|
||||
<input type="checkbox" formControlName="active" clrToggle value="billable" name="billable" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px;">
|
||||
<h4 style="font-weight: 300;display: inline;"> Configurations</h4>
|
||||
</div>
|
||||
<!-- <div class="clr-row">
|
||||
<div class="clr-col-6">These configurations default to repositories setups.</div>
|
||||
<div class="clr-col-6" style=" display: flex; justify-content: flex-end;"><button (click)="testConnection()" class="btn btn-primary">Test Connection</button></div>
|
||||
</div> -->
|
||||
<hr>
|
||||
|
||||
<div class="clr-row">
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">Driver class Name</label>
|
||||
<input type="text" formControlName="driver_class_name" placeholder="Enter Driver class Name" class="clr-input">
|
||||
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">Connection String</label>
|
||||
<input type="text" formControlName="conn_string" placeholder="Enter connection string" class="clr-input">
|
||||
|
||||
</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="portNumber">Port Number</label>
|
||||
<input colspan="2" type="text" formControlName="portnumber" readonly class="clr-input">
|
||||
|
||||
</div> -->
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">Username</label>
|
||||
<input type="text" formControlName="username" placeholder="Enter Username" class="clr-input">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="dbPassword">Password</label>
|
||||
<input type="text" formControlName="password" placeholder="Enter Password" class="clr-input">
|
||||
|
||||
</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="workflow_name">Connect Through SSH</label>
|
||||
<input type="checkbox" formControlName="connectssh" clrToggle value="billable" name="billable" />
|
||||
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">SSH Host Name</label>
|
||||
<input type="text" formControlName="ssh_host_name" placeholder="Enter Host Name" class="clr-input">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">SSH User Name</label>
|
||||
<input type="text" formControlName="ssh_user_name" placeholder="Enter SSH Username" class="clr-input">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="dbPassword">SSH Password</label>
|
||||
<input type="text" formControlName="ssh_password" placeholder="Enter SSH Password" class="clr-input">
|
||||
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="dbPassword">SSH Key File</label><br>
|
||||
<input type="file" formControlName="ssh_file_key" (change)="onFileChanged($event)" placeholder="Enter Database Password" required>
|
||||
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="center">
|
||||
<div class="btn-group">
|
||||
<div class="checkbox btn">
|
||||
<input type="checkbox" id="btn-demo-check-1" (click)="goback()"/>
|
||||
<label for="btn-demo-check-1">Cancel</label>
|
||||
</div>
|
||||
<!-- <div class="checkbox btn">
|
||||
<input type="checkbox" id="btn-demo-check-2" checked (click)="onSubmit()"/>
|
||||
<label for="btn-demo-check-2">Submit</label>
|
||||
</div> -->
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" [disabled]="!entryForm.valid" (click)="onSubmit()">SUBMIT</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
//@import "../../../../assets/scss/var";
|
||||
.s-info-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
button {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.entry-pg {
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.button1::after {
|
||||
content: none;
|
||||
}
|
||||
.button1:hover::after {
|
||||
content: "ADD ROWS";
|
||||
}
|
||||
|
||||
$bg-color: #dddddd;
|
||||
|
||||
.section {
|
||||
background-color: $bg-color;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.section p {
|
||||
//color: white;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.clr-input {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.75rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.clr-file {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
//padding: 0.6rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
input[type=text],[type=date],textarea {
|
||||
width: 100%;
|
||||
padding: 15px 15px;
|
||||
// margin: 8px 0;
|
||||
background-color:rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.required-field{
|
||||
color: red;
|
||||
|
||||
}
|
||||
select{
|
||||
width: 100%;
|
||||
padding: 5px 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { demostepperComponent } from './demostepper.component';
|
||||
import { QueryaddComponent } from './queryadd.component';
|
||||
|
||||
describe('demostepperComponent', () => {
|
||||
let component: demostepperComponent;
|
||||
let fixture: ComponentFixture<demostepperComponent>;
|
||||
describe('QueryaddComponent', () => {
|
||||
let component: QueryaddComponent;
|
||||
let fixture: ComponentFixture<QueryaddComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ demostepperComponent ]
|
||||
declarations: [ QueryaddComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(demostepperComponent);
|
||||
fixture = TestBed.createComponent(QueryaddComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
import { HttpErrorResponse, HttpHeaderResponse } from '@angular/common/http';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ReportBuilderService } from 'src/app/services/api/report-builder.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-queryadd',
|
||||
templateUrl: './queryadd.component.html',
|
||||
styleUrls: ['./queryadd.component.scss']
|
||||
})
|
||||
export class QueryaddComponent implements OnInit {
|
||||
public entryForm: FormGroup;
|
||||
selectedFile: File[] = [];
|
||||
type = ["MYSQL", "postgresql", "mysqllite", "oracle", "Snowflake", "BigQuery", "RedShift", "microsoft sql server", "redis", "maria_db", "MongoDB", "firebase", "dynamodb", "ibm DB2", "couchbase", "ElasticSearch", "Casandra", "OrientDB", "Neo4j", "FireBird"];
|
||||
constructor(private _fb: FormBuilder, private router: Router, private toastr: ToastrService,
|
||||
private route: ActivatedRoute, private reportBuilderService: ReportBuilderService,) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.entryForm = this._fb.group({
|
||||
name: [null],
|
||||
type: [null],
|
||||
description: [null],
|
||||
active: [null],
|
||||
driver_class_name: [null],
|
||||
conn_string: [null],
|
||||
username: [null],
|
||||
password: [null],
|
||||
});
|
||||
}
|
||||
public onFileChanged(event) {
|
||||
//Select File
|
||||
console.log(event);
|
||||
this.selectedFile = event.target.files[0];
|
||||
//for (var i = 0; i < event.target.files.length; i++) {
|
||||
// var name = event.target.files[i].name;
|
||||
// var type = event.target.files[i].type;
|
||||
// var size = event.target.files[i].size;
|
||||
// var modifiedDate = event.target.files[i].lastModifiedDate;
|
||||
// this.selectedFile.push(event.target.files[i]);
|
||||
//}
|
||||
}
|
||||
toastrShown: boolean = false;
|
||||
onSubmit() {
|
||||
console.log(this.entryForm.value);
|
||||
this.reportBuilderService.createdb(this.entryForm.value).subscribe((data) => {
|
||||
console.log(data);
|
||||
if (data) {
|
||||
if (!this.toastrShown) {
|
||||
this.toastrShown = true; // Set the flag to indicate that the toastr message has been shown
|
||||
this.toastr.success("Added Successfully");
|
||||
setTimeout(() => {
|
||||
// this.router.navigate(["../query"], { relativeTo: this.route });
|
||||
this.router.navigate([".."], { relativeTo: this.route });
|
||||
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}, (error: HttpErrorResponse) => {
|
||||
console.log(error);
|
||||
if (error.status === 202) {
|
||||
this.toastr.success("Added Succesfully");
|
||||
}
|
||||
if (error.status === 404) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
if (error.status === 400) {
|
||||
this.toastr.error("Not Added");
|
||||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
// this.router.navigate(["../query"], { relativeTo: this.route });
|
||||
this.router.navigate([".."], { relativeTo: this.route });
|
||||
|
||||
}, 500);
|
||||
}
|
||||
goback() {
|
||||
this.router.navigate(["../query"], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
// testConnection(){
|
||||
// this.dataservice.testConnection(this.entryForm.value.data_source_type, this.entryForm.value.user_name, this.entryForm.value.password, this.entryForm.value.portnumber, this.entryForm.value.db_host_name).subscribe((data)=> {
|
||||
// console.log(data);
|
||||
// this.toastr.success('Test Connection successfully');
|
||||
// },(err) => {
|
||||
// console.log(err);
|
||||
// this.toastr.error('Test Connection Failed');
|
||||
// });
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
.s-info-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.s-info-bar button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.entry-pg {
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.button1::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.button1:hover::after {
|
||||
content: "ADD ROWS";
|
||||
}
|
||||
|
||||
.section {
|
||||
background-color: #dddddd;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.section p {
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.clr-input {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.75rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.clr-file {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input[type=text], [type=date], textarea {
|
||||
width: 100%;
|
||||
padding: 15px 15px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.required-field {
|
||||
color: red;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 5px 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}/*# sourceMappingURL=queryedit.component.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["queryedit.component.scss","queryedit.component.css"],"names":[],"mappings":"AACA;EACI,aAAA;EACA,mBAAA;EACA,8BAAA;ACAJ;ADCI;EACE,aAAA;ACCN;;ADGE;EACE,YAAA;ACAJ;;ADGE;EACE,aAAA;ACAJ;;ADEE;EACE,mBAAA;ACCJ;;ADIE;EACE,yBAHS;EAIT,YAAA;ACDJ;;ADIE;EAEE,iBAAA;EACA,aAAA;EACA,eAAA;ACFJ;;ADKE;EACE,cAAA;EACA,yBAAA;EACA,sBAAA;EACA,wBAAA;EACA,eAAA;EACA,WAAA;EACA,mBAAA;ACFJ;;ADKE;EACE,cAAA;EACA,yBAAA;EACA,sBAAA;EAEA,eAAA;EACA,WAAA;EACA,mBAAA;ACHJ;;ADME;EACE,kBAAA;ACHJ;;ADKE;EACE,WAAA;EACA,kBAAA;EAED,oCAAA;EACC,qBAAA;EACA,sBAAA;EACA,kBAAA;EACA,sBAAA;ACHJ;;ADME;EACE,UAAA;ACHJ;;ADME;EACE,WAAA;EACA,gBAAA;EACA,sBAAA;EACA,kBAAA;ACHJ","file":"queryedit.component.css"}
|
||||
@@ -0,0 +1,127 @@
|
||||
<h4 style="font-weight: 300;display: inline;"><b>Database</b></h4>
|
||||
<span class="label label-light-blue" style="display: inline;margin-left: 10px;">Edit Mode</span><br>
|
||||
<hr>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- entry form-->
|
||||
<form>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectName">Name</label>
|
||||
<input id="projectName" type="text" name="name" [(ngModel)]="tdata.name" placeholder="Enter Name"
|
||||
class="clr-input" required>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="technologyStack">Type</label>
|
||||
<select name="type" class="clr-dropdown" [(ngModel)]="tdata.type">
|
||||
<option [ngValue]="null">Choose Technology</option>
|
||||
<option *ngFor="let item of type" [ngValue]="item">{{item}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="description">Description (optional)</label>
|
||||
<textarea id="" cols="10" rows="2" [(ngModel)]="tdata.description" name="description" placeholder="Enter Description">
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="workflow_name">Active</label>
|
||||
<input type="checkbox" name="active" clrToggle [(ngModel)]="tdata.active"/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px;">
|
||||
<h4 style="font-weight: 300;display: inline;"> Configurations</h4>
|
||||
</div>
|
||||
<!-- These configurations default to repositories setups. -->
|
||||
<hr>
|
||||
|
||||
<div class="clr-row">
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">Driver Class Name</label>
|
||||
<input type="text" name="driver_class_name" placeholder="Enter Driver Class Name" class="clr-input" [(ngModel)]="tdata.driver_class_name">
|
||||
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">Connection String</label>
|
||||
<input type="text" name="conn_string" placeholder="Enter Connection String Name" class="clr-input" [(ngModel)]="tdata.conn_string">
|
||||
|
||||
</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="portNumber">Port Number</label>
|
||||
<input colspan="2" type="text" name="portNumber" readonly class="clr-input" [(ngModel)]="tdata.portnumber">
|
||||
|
||||
</div> -->
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">Username</label>
|
||||
<input type="text" name="username" placeholder="Enter Username" class="clr-input" [(ngModel)]="tdata.username">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="dbPassword">Password</label>
|
||||
<input type="text" name="password" placeholder="Enter Password" class="clr-input" [(ngModel)]="tdata.password">
|
||||
|
||||
</div>
|
||||
<!-- <div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="workflow_name">Connect Through SSH</label>
|
||||
<input type="checkbox" name="connectssh" clrToggle [(ngModel)]="tdata.connectssh"/>
|
||||
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">SSH Host Name</label>
|
||||
<input type="text" name="sshusername" placeholder="Enter Host Name" class="clr-input" [(ngModel)]="tdata.ssh_host_name">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="projectPrefix">SSH User Name</label>
|
||||
<input type="text" name="sshusername" placeholder="Enter SSH Username" class="clr-input"[(ngModel)]="tdata.ssh_user_name">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="dbPassword">SSH Password</label>
|
||||
<input type="text" name="sshpassword" placeholder="Enter SSH Password" class="clr-input"[(ngModel)]="tdata.ssh_password">
|
||||
|
||||
</div>
|
||||
<div class="clr-col-md-4 clr-col-sm-12">
|
||||
<label for="dbPassword">SSH Key File</label><br>
|
||||
<input type="file" name="sshkeyfile" placeholder="Enter Database Password"(change)="onFileChanged($event)">
|
||||
{{tdata.ssh_file_key}}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="center">
|
||||
<div class="btn-group">
|
||||
<div class="checkbox btn">
|
||||
<input type="checkbox" id="btn-demo-check-1" (click)="goback()"/>
|
||||
<label for="btn-demo-check-1">Cancle</label>
|
||||
</div>
|
||||
<div class="checkbox btn">
|
||||
<input type="checkbox" id="btn-demo-check-2" checked (click)="onSubmit()"/>
|
||||
<label for="btn-demo-check-2">Update</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <button type="submit" class="btn btn-primary" [disabled]="!entryForm.valid">SUBMIT</button> -->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
//@import "../../../../assets/scss/var";
|
||||
.s-info-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
button {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.entry-pg {
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.button1::after {
|
||||
content: none;
|
||||
}
|
||||
.button1:hover::after {
|
||||
content: "ADD ROWS";
|
||||
}
|
||||
|
||||
$bg-color: #dddddd;
|
||||
|
||||
.section {
|
||||
background-color: $bg-color;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.section p {
|
||||
//color: white;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.clr-input {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.75rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.clr-file {
|
||||
color: #212529;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
//padding: 0.6rem 0.75rem;
|
||||
margin-top: 3px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
input[type=text],[type=date],textarea {
|
||||
width: 100%;
|
||||
padding: 15px 15px;
|
||||
// margin: 8px 0;
|
||||
background-color:rgb(255, 255, 255);
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.required-field{
|
||||
color: red;
|
||||
|
||||
}
|
||||
select{
|
||||
width: 100%;
|
||||
padding: 5px 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { QueryeditComponent } from './queryedit.component';
|
||||
|
||||
describe('QueryeditComponent', () => {
|
||||
let component: QueryeditComponent;
|
||||
let fixture: ComponentFixture<QueryeditComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ QueryeditComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(QueryeditComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { HttpHeaderResponse } from '@angular/common/http';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ReportBuilderService } from 'src/app/services/api/report-builder.service';
|
||||
@Component({
|
||||
selector: 'app-queryedit',
|
||||
templateUrl: './queryedit.component.html',
|
||||
styleUrls: ['./queryedit.component.scss']
|
||||
})
|
||||
export class QueryeditComponent implements OnInit {
|
||||
id:any;
|
||||
tdata:any={};
|
||||
selectedFile: File[]=[];
|
||||
type = ["MYSQL","postgresql","mysqllite","oracle","Snowflake","BigQuery","RedShift","microsoft sql server","redis","maria_db","MongoDB","firebase","dynamodb","ibm DB2","couchbase","ElasticSearch","Casandra","OrientDB","Neo4j","FireBird"];
|
||||
constructor(private _fb: FormBuilder, private router: Router,
|
||||
private toastr: ToastrService,private route: ActivatedRoute, private reportBuilderService: ReportBuilderService,) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.id = this.route.snapshot.params["id"];
|
||||
console.log("update with id = ", this.id);
|
||||
this.getById(this.id);
|
||||
}
|
||||
getById(id: number) {
|
||||
this.reportBuilderService.getSqlModelById(id).subscribe((data) => {
|
||||
this.tdata = data;
|
||||
console.log(this.tdata)
|
||||
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
public onFileChanged(event) {
|
||||
//Select File
|
||||
console.log(event);
|
||||
this.selectedFile = event.target.files[0];
|
||||
|
||||
}
|
||||
onSubmit(){
|
||||
this.reportBuilderService.updateSqlModel(this.id,this.tdata).subscribe((data)=>{
|
||||
console.log(data);
|
||||
if(data.status===202){
|
||||
this.toastr.success("Updated Succesfully");
|
||||
}
|
||||
},(error: HttpHeaderResponse)=>{
|
||||
console.log(error);
|
||||
if(error.status===202){
|
||||
this.toastr.success("Updated Successfully");
|
||||
}
|
||||
if(error.status===404){
|
||||
this.toastr.error(" NotUpdated Successfully");
|
||||
}
|
||||
if(error.status===400){
|
||||
this.toastr.error(" NotUpdated Successfully");
|
||||
}
|
||||
});
|
||||
this.router.navigate(["../../query"], { relativeTo: this.route });
|
||||
|
||||
}
|
||||
goback(){
|
||||
this.router.navigate(["../../query"], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
<!-- Theme Customization Screen -->
|
||||
<div class="theme-customization-screen">
|
||||
<!-- Header -->
|
||||
<div class="theme-header">
|
||||
<div class="header-content">
|
||||
<div class="header-left">
|
||||
<h1 class="page-title">
|
||||
<clr-icon shape="palette"></clr-icon>
|
||||
Theme Customization
|
||||
</h1>
|
||||
<p class="page-subtitle">Customize your application's appearance with colors, fonts, and styles</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="modern-btn btn-outline" (click)="resetToDefault()">
|
||||
<clr-icon shape="refresh"></clr-icon>
|
||||
Reset to Default
|
||||
</button>
|
||||
<button class="modern-btn btn-primary" (click)="exportTheme()">
|
||||
<clr-icon shape="download"></clr-icon>
|
||||
Export Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="theme-content">
|
||||
<div class="theme-layout">
|
||||
<!-- Left Sidebar - Theme Selection -->
|
||||
<div class="theme-sidebar">
|
||||
<div class="sidebar-section">
|
||||
<h3 class="section-title">Predefined Themes</h3>
|
||||
<div class="theme-grid">
|
||||
<div *ngFor="let theme of themes" class="theme-card"
|
||||
[class.active]="currentTheme?.id === theme.id" (click)="selectTheme(theme.id)">
|
||||
<div class="theme-preview" [style.background]="theme.colors.background">
|
||||
<div class="preview-header" [style.background]="theme.colors.primary"></div>
|
||||
<div class="preview-content">
|
||||
<div class="preview-card" [style.background]="theme.colors.surface"
|
||||
[style.border-radius]="theme.borderRadius">
|
||||
<div class="preview-text" [style.color]="theme.colors.text">Sample Text</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="theme-info">
|
||||
<h4 class="theme-name">{{ theme.name }}</h4>
|
||||
<div class="theme-colors">
|
||||
<div class="color-dot" [style.background]="theme.colors.primary"></div>
|
||||
<div class="color-dot" [style.background]="theme.colors.secondary"></div>
|
||||
<div class="color-dot" [style.background]="theme.colors.accent"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-section">
|
||||
<button class="modern-btn btn-primary btn-block" (click)="startCustomizing()"
|
||||
[disabled]="isCustomizing">
|
||||
<clr-icon shape="cog"></clr-icon>
|
||||
Customize Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Content - Customization Panel -->
|
||||
<div class="theme-main">
|
||||
<div *ngIf="!isCustomizing" class="welcome-state">
|
||||
<div class="welcome-content">
|
||||
<div class="welcome-icon">
|
||||
<clr-icon shape="palette" size="48"></clr-icon>
|
||||
</div>
|
||||
<h2>Choose a Theme</h2>
|
||||
<p>Select from our predefined themes or create your own custom theme to match your brand and
|
||||
preferences.</p>
|
||||
<div class="current-theme-info" *ngIf="currentTheme">
|
||||
<h3>Current Theme: {{ currentTheme.name }}</h3>
|
||||
<div class="theme-preview-large" [style.background]="currentTheme.colors.background">
|
||||
<div class="preview-header" [style.background]="currentTheme.colors.primary"></div>
|
||||
<div class="preview-content">
|
||||
<div class="preview-card" [style.background]="currentTheme.colors.surface"
|
||||
[style.border-radius]="currentTheme.borderRadius">
|
||||
<div class="preview-text" [style.color]="currentTheme.colors.text">Sample Text
|
||||
</div>
|
||||
<div class="preview-text-secondary"
|
||||
[style.color]="currentTheme.colors.textSecondary">Secondary Text</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isCustomizing" class="customization-panel">
|
||||
<!-- Customization Header -->
|
||||
<div class="customization-header">
|
||||
<h2>Customize Your Theme</h2>
|
||||
<div class="header-actions">
|
||||
<button class="modern-btn btn-outline" (click)="cancelCustomizing()">
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
Cancel
|
||||
</button>
|
||||
<button class="modern-btn btn-primary" (click)="applyCustomTheme()">
|
||||
<clr-icon shape="check"></clr-icon>
|
||||
Apply Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Color Customization -->
|
||||
<div class="customization-section">
|
||||
<h3 class="section-title">
|
||||
<clr-icon shape="color-palette"></clr-icon>
|
||||
Colors
|
||||
</h3>
|
||||
<div class="color-grid">
|
||||
<div class="color-group">
|
||||
<label class="color-label">Primary Color</label>
|
||||
<div class="color-input-group">
|
||||
<input type="color" class="color-picker" [value]="getColorValue('primary')"
|
||||
(input)="onColorChange('primary', $event.target.value); previewTheme()">
|
||||
<input type="text" class="color-text" [value]="getColorValue('primary')"
|
||||
(input)="onColorChange('primary', $event.target.value); previewTheme()">
|
||||
</div>
|
||||
<div class="color-presets">
|
||||
<div *ngFor="let preset of colorPresets" class="preset-color"
|
||||
[style.background]="preset.value" [title]="preset.name"
|
||||
(click)="onColorChange('primary', preset.value); previewTheme()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="color-group">
|
||||
<label class="color-label">Secondary Color</label>
|
||||
<div class="color-input-group">
|
||||
<input type="color" class="color-picker" [value]="getColorValue('secondary')"
|
||||
(input)="onColorChange('secondary', $event.target.value); previewTheme()">
|
||||
<input type="text" class="color-text" [value]="getColorValue('secondary')"
|
||||
(input)="onColorChange('secondary', $event.target.value); previewTheme()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="color-group">
|
||||
<label class="color-label">Accent Color</label>
|
||||
<div class="color-input-group">
|
||||
<input type="color" class="color-picker" [value]="getColorValue('accent')"
|
||||
(input)="onColorChange('accent', $event.target.value); previewTheme()">
|
||||
<input type="text" class="color-text" [value]="getColorValue('accent')"
|
||||
(input)="onColorChange('accent', $event.target.value); previewTheme()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="color-group">
|
||||
<label class="color-label">Background Color</label>
|
||||
<div class="color-input-group">
|
||||
<input type="color" class="color-picker" [value]="getColorValue('background')"
|
||||
(input)="onColorChange('background', $event.target.value); previewTheme()">
|
||||
<input type="text" class="color-text" [value]="getColorValue('background')"
|
||||
(input)="onColorChange('background', $event.target.value); previewTheme()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="color-group">
|
||||
<label class="color-label">Surface Color</label>
|
||||
<div class="color-input-group">
|
||||
<input type="color" class="color-picker" [value]="getColorValue('surface')"
|
||||
(input)="onColorChange('surface', $event.target.value); previewTheme()">
|
||||
<input type="text" class="color-text" [value]="getColorValue('surface')"
|
||||
(input)="onColorChange('surface', $event.target.value); previewTheme()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="color-group">
|
||||
<label class="color-label">Text Color</label>
|
||||
<div class="color-input-group">
|
||||
<input type="color" class="color-picker" [value]="getColorValue('text')"
|
||||
(input)="onColorChange('text', $event.target.value); previewTheme()">
|
||||
<input type="text" class="color-text" [value]="getColorValue('text')"
|
||||
(input)="onColorChange('text', $event.target.value); previewTheme()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Font Customization -->
|
||||
<div class="customization-section">
|
||||
<h3 class="section-title">
|
||||
<clr-icon shape="text"></clr-icon>
|
||||
Typography
|
||||
</h3>
|
||||
<div class="font-grid">
|
||||
<div class="font-group">
|
||||
<label class="font-label">Primary Font</label>
|
||||
<select class="font-select" [value]="getFontValue('primary')"
|
||||
(change)="onFontChange('primary', $event.target.value); previewTheme()">
|
||||
<option *ngFor="let font of fontOptions" [value]="font.value">{{ font.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="font-preview" [style.font-family]="getFontValue('primary')">
|
||||
The quick brown fox jumps over the lazy dog
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="font-group">
|
||||
<label class="font-label">Secondary Font</label>
|
||||
<select class="font-select" [value]="getFontValue('secondary')"
|
||||
(change)="onFontChange('secondary', $event.target.value); previewTheme()">
|
||||
<option *ngFor="let font of fontOptions" [value]="font.value">{{ font.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="font-preview" [style.font-family]="getFontValue('secondary')">
|
||||
The quick brown fox jumps over the lazy dog
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="font-group">
|
||||
<label class="font-label">Monospace Font</label>
|
||||
<select class="font-select" [value]="getFontValue('mono')"
|
||||
(change)="onFontChange('mono', $event.target.value); previewTheme()">
|
||||
<option *ngFor="let font of fontOptions" [value]="font.value">{{ font.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="font-preview" [style.font-family]="getFontValue('mono')">
|
||||
The quick brown fox jumps over the lazy dog
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Advanced Settings -->
|
||||
<div class="customization-section">
|
||||
<h3 class="section-title">
|
||||
<clr-icon shape="cog"></clr-icon>
|
||||
Advanced Settings
|
||||
</h3>
|
||||
<div class="advanced-grid">
|
||||
<div class="advanced-group">
|
||||
<label class="advanced-label">Border Radius</label>
|
||||
<div class="range-input-group">
|
||||
<input type="range" class="range-slider" min="0" max="2" step="0.25"
|
||||
[value]="getBorderRadiusValue().replace('rem', '')"
|
||||
(input)="onBorderRadiusChange($event.target.value + 'rem'); previewTheme()">
|
||||
<span class="range-value">{{ getBorderRadiusValue() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="advanced-group">
|
||||
<label class="advanced-label">Shadow Intensity</label>
|
||||
<div class="range-input-group">
|
||||
<input type="range" class="range-slider" min="0" max="50" step="5"
|
||||
[value]="getShadowValueNumber()"
|
||||
(input)="onShadowChange('0 ' + $event.target.value + 'px 15px -3px rgba(0, 0, 0, 0.1)'); previewTheme()">
|
||||
<span class="range-value">{{ getShadowValueNumber() }}px</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Import/Export -->
|
||||
<div class="customization-section">
|
||||
<h3 class="section-title">
|
||||
<clr-icon shape="import"></clr-icon>
|
||||
Import/Export
|
||||
</h3>
|
||||
<div class="import-export-grid">
|
||||
<div class="import-group">
|
||||
<label class="import-label">Import Theme</label>
|
||||
<input type="file" class="file-input" accept=".json" (change)="importTheme($event)">
|
||||
<button class="modern-btn btn-outline">
|
||||
<clr-icon shape="upload"></clr-icon>
|
||||
Choose File
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,622 +0,0 @@
|
||||
// ========================================
|
||||
// THEME CUSTOMIZATION COMPONENT STYLES
|
||||
// ========================================
|
||||
@import '../../../../styles/design-tokens';
|
||||
|
||||
// Main Container
|
||||
// ========================================
|
||||
|
||||
.theme-customization-screen {
|
||||
min-height: 100vh;
|
||||
background: var(--theme-background, $gray-50);
|
||||
padding: $space-6;
|
||||
}
|
||||
|
||||
// Header
|
||||
// ========================================
|
||||
|
||||
.theme-header {
|
||||
background: var(--theme-surface, $white);
|
||||
border-radius: $radius-2xl;
|
||||
box-shadow: var(--theme-shadow, $shadow-lg);
|
||||
margin-bottom: $space-8;
|
||||
padding: $space-6;
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: $space-4;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.header-left {
|
||||
.page-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
font-size: $text-3xl;
|
||||
font-weight: $font-bold;
|
||||
color: var(--theme-text, $gray-900);
|
||||
margin-bottom: $space-2;
|
||||
|
||||
clr-icon {
|
||||
color: var(--theme-primary, $primary-500);
|
||||
}
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: $text-lg;
|
||||
color: var(--theme-text-secondary, $gray-600);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: $space-3;
|
||||
flex-shrink: 0;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
width: 100%;
|
||||
justify-content: stretch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main Content
|
||||
// ========================================
|
||||
|
||||
.theme-content {
|
||||
.theme-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 350px 1fr;
|
||||
gap: $space-8;
|
||||
min-height: 600px;
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: $space-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar
|
||||
// ========================================
|
||||
|
||||
.theme-sidebar {
|
||||
background: var(--theme-surface, $white);
|
||||
border-radius: $radius-2xl;
|
||||
box-shadow: var(--theme-shadow, $shadow-lg);
|
||||
padding: $space-6;
|
||||
height: fit-content;
|
||||
|
||||
.sidebar-section {
|
||||
margin-bottom: $space-6;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: $text-lg;
|
||||
font-weight: $font-semibold;
|
||||
color: var(--theme-text, $gray-900);
|
||||
margin-bottom: $space-4;
|
||||
}
|
||||
|
||||
.theme-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: $space-4;
|
||||
}
|
||||
|
||||
.theme-card {
|
||||
border: 2px solid transparent;
|
||||
border-radius: $radius-xl;
|
||||
padding: $space-4;
|
||||
cursor: pointer;
|
||||
transition: all $duration-200 $ease-out;
|
||||
background: var(--theme-surface, $white);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--theme-primary, $primary-200);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--theme-shadow, $shadow-lg);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: var(--theme-primary, $primary-500);
|
||||
box-shadow: 0 0 0 3px rgba(var(--theme-primary, $primary-500), 0.1);
|
||||
}
|
||||
|
||||
.theme-preview {
|
||||
height: 80px;
|
||||
border-radius: $radius-lg;
|
||||
overflow: hidden;
|
||||
margin-bottom: $space-3;
|
||||
position: relative;
|
||||
|
||||
.preview-header {
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
padding: $space-3;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.preview-card {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.preview-text {
|
||||
font-size: $text-xs;
|
||||
font-weight: $font-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-info {
|
||||
.theme-name {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
color: var(--theme-text, $gray-900);
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
|
||||
.theme-colors {
|
||||
display: flex;
|
||||
gap: $space-2;
|
||||
|
||||
.color-dot {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--theme-surface, $white);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main Panel
|
||||
// ========================================
|
||||
|
||||
.theme-main {
|
||||
background: var(--theme-surface, $white);
|
||||
border-radius: $radius-2xl;
|
||||
box-shadow: var(--theme-shadow, $shadow-lg);
|
||||
padding: $space-6;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
// Welcome State
|
||||
// ========================================
|
||||
|
||||
.welcome-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
min-height: 400px;
|
||||
|
||||
.welcome-content {
|
||||
text-align: center;
|
||||
max-width: 500px;
|
||||
|
||||
.welcome-icon {
|
||||
margin-bottom: $space-6;
|
||||
|
||||
clr-icon {
|
||||
color: var(--theme-primary, $primary-500);
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $text-2xl;
|
||||
font-weight: $font-bold;
|
||||
color: var(--theme-text, $gray-900);
|
||||
margin-bottom: $space-4;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $text-lg;
|
||||
color: var(--theme-text-secondary, $gray-600);
|
||||
margin-bottom: $space-8;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.current-theme-info {
|
||||
h3 {
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-semibold;
|
||||
color: var(--theme-text, $gray-900);
|
||||
margin-bottom: $space-4;
|
||||
}
|
||||
|
||||
.theme-preview-large {
|
||||
height: 120px;
|
||||
border-radius: $radius-xl;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-shadow: var(--theme-shadow, $shadow-lg);
|
||||
|
||||
.preview-header {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
padding: $space-4;
|
||||
height: 90px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.preview-card {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.preview-text {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.preview-text-secondary {
|
||||
font-size: $text-xs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Customization Panel
|
||||
// ========================================
|
||||
|
||||
.customization-panel {
|
||||
.customization-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: $space-8;
|
||||
padding-bottom: $space-4;
|
||||
border-bottom: 1px solid var(--theme-text-secondary, $gray-200);
|
||||
|
||||
h2 {
|
||||
font-size: $text-2xl;
|
||||
font-weight: $font-bold;
|
||||
color: var(--theme-text, $gray-900);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: $space-3;
|
||||
}
|
||||
}
|
||||
|
||||
.customization-section {
|
||||
margin-bottom: $space-8;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-2;
|
||||
font-size: $text-lg;
|
||||
font-weight: $font-semibold;
|
||||
color: var(--theme-text, $gray-900);
|
||||
margin-bottom: $space-4;
|
||||
|
||||
clr-icon {
|
||||
color: var(--theme-primary, $primary-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Color Customization
|
||||
// ========================================
|
||||
|
||||
.color-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: $space-6;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.color-group {
|
||||
.color-label {
|
||||
display: block;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: var(--theme-text, $gray-700);
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
|
||||
.color-input-group {
|
||||
display: flex;
|
||||
gap: $space-2;
|
||||
margin-bottom: $space-3;
|
||||
|
||||
.color-picker {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
border-radius: $radius-lg;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
|
||||
&::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&::-webkit-color-swatch {
|
||||
border: none;
|
||||
border-radius: $radius-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.color-text {
|
||||
flex: 1;
|
||||
padding: $space-2 $space-3;
|
||||
border: 1px solid var(--theme-text-secondary, $gray-300);
|
||||
border-radius: $radius-lg;
|
||||
font-size: $text-sm;
|
||||
color: var(--theme-text, $gray-900);
|
||||
background: var(--theme-surface, $white);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary, $primary-500);
|
||||
box-shadow: 0 0 0 3px rgba(var(--theme-primary, $primary-500), 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.color-presets {
|
||||
display: flex;
|
||||
gap: $space-2;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.preset-color {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
border: 2px solid var(--theme-surface, $white);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
transition: transform $duration-200 $ease-out;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Font Customization
|
||||
// ========================================
|
||||
|
||||
.font-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: $space-6;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.font-group {
|
||||
.font-label {
|
||||
display: block;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: var(--theme-text, $gray-700);
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
|
||||
.font-select {
|
||||
width: 100%;
|
||||
padding: $space-2 $space-3;
|
||||
border: 1px solid var(--theme-text-secondary, $gray-300);
|
||||
border-radius: $radius-lg;
|
||||
font-size: $text-sm;
|
||||
color: var(--theme-text, $gray-900);
|
||||
background: var(--theme-surface, $white);
|
||||
margin-bottom: $space-3;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary, $primary-500);
|
||||
box-shadow: 0 0 0 3px rgba(var(--theme-primary, $primary-500), 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.font-preview {
|
||||
padding: $space-3;
|
||||
background: var(--theme-background, $gray-50);
|
||||
border-radius: $radius-lg;
|
||||
font-size: $text-sm;
|
||||
color: var(--theme-text, $gray-700);
|
||||
border: 1px solid var(--theme-text-secondary, $gray-200);
|
||||
}
|
||||
}
|
||||
|
||||
// Advanced Settings
|
||||
// ========================================
|
||||
|
||||
.advanced-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: $space-6;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.advanced-group {
|
||||
.advanced-label {
|
||||
display: block;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: var(--theme-text, $gray-700);
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
|
||||
.range-input-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $space-3;
|
||||
|
||||
.range-slider {
|
||||
flex: 1;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background: var(--theme-text-secondary, $gray-300);
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--theme-primary, $primary-500);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--theme-primary, $primary-500);
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.range-value {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: var(--theme-text, $gray-700);
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Import/Export
|
||||
// ========================================
|
||||
|
||||
.import-export-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: $space-6;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.import-group {
|
||||
.import-label {
|
||||
display: block;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-medium;
|
||||
color: var(--theme-text, $gray-700);
|
||||
margin-bottom: $space-2;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive Design
|
||||
// ========================================
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
.theme-customization-screen {
|
||||
padding: $space-4;
|
||||
}
|
||||
|
||||
.theme-header {
|
||||
padding: $space-4;
|
||||
}
|
||||
|
||||
.theme-sidebar,
|
||||
.theme-main {
|
||||
padding: $space-4;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
.theme-customization-screen {
|
||||
padding: $space-3;
|
||||
}
|
||||
|
||||
.theme-header {
|
||||
padding: $space-3;
|
||||
}
|
||||
|
||||
.theme-sidebar,
|
||||
.theme-main {
|
||||
padding: $space-3;
|
||||
}
|
||||
|
||||
.color-grid,
|
||||
.font-grid,
|
||||
.advanced-grid,
|
||||
.import-export-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-sm) {
|
||||
.theme-customization-screen {
|
||||
padding: $space-2;
|
||||
}
|
||||
|
||||
.theme-header {
|
||||
padding: $space-3;
|
||||
}
|
||||
|
||||
.theme-sidebar,
|
||||
.theme-main {
|
||||
padding: $space-3;
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { ThemeService, Theme } from '../../../services/theme.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-theme-customization',
|
||||
templateUrl: './theme-customization.component.html',
|
||||
styleUrls: ['./theme-customization.component.scss']
|
||||
})
|
||||
export class ThemeCustomizationComponent implements OnInit, OnDestroy {
|
||||
themes: Theme[] = [];
|
||||
currentTheme: Theme | null = null;
|
||||
customTheme: Partial<Theme> = {
|
||||
colors: {
|
||||
primary: '#0ea5e9',
|
||||
secondary: '#64748b',
|
||||
accent: '#8b5cf6',
|
||||
background: '#f8fafc',
|
||||
surface: '#ffffff',
|
||||
text: '#111827',
|
||||
textSecondary: '#6b7280'
|
||||
},
|
||||
fonts: {
|
||||
primary: 'Inter',
|
||||
secondary: 'Poppins',
|
||||
mono: 'JetBrains Mono'
|
||||
},
|
||||
borderRadius: '0.75rem',
|
||||
shadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)'
|
||||
};
|
||||
isCustomizing = false;
|
||||
showAdvanced = false;
|
||||
|
||||
private themeSubscription: Subscription = new Subscription();
|
||||
|
||||
// Color presets and font options from service
|
||||
colorPresets = this.themeService.getColorPresets();
|
||||
fontOptions = this.themeService.getFontOptions();
|
||||
|
||||
constructor(private themeService: ThemeService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.themes = this.themeService.getThemes();
|
||||
this.currentTheme = this.themeService.getCurrentTheme();
|
||||
|
||||
this.themeSubscription = this.themeService.currentTheme$.subscribe(theme => {
|
||||
this.currentTheme = theme;
|
||||
});
|
||||
|
||||
this.initializeCustomTheme();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.themeSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
selectTheme(themeId: string): void {
|
||||
this.themeService.selectTheme(themeId);
|
||||
this.isCustomizing = false;
|
||||
}
|
||||
|
||||
startCustomizing(): void {
|
||||
this.isCustomizing = true;
|
||||
this.initializeCustomTheme();
|
||||
}
|
||||
|
||||
cancelCustomizing(): void {
|
||||
this.isCustomizing = false;
|
||||
this.initializeCustomTheme();
|
||||
}
|
||||
|
||||
applyCustomTheme(): void {
|
||||
if (this.customTheme.colors && this.customTheme.fonts) {
|
||||
const customTheme: Theme = {
|
||||
id: 'custom',
|
||||
name: 'Custom Theme',
|
||||
colors: this.customTheme.colors,
|
||||
fonts: this.customTheme.fonts,
|
||||
borderRadius: this.customTheme.borderRadius || '0.5rem',
|
||||
shadow: this.customTheme.shadow || '0 10px 15px -3px rgba(0, 0, 0, 0.1)'
|
||||
};
|
||||
this.themeService.applyTheme(customTheme);
|
||||
}
|
||||
this.isCustomizing = false;
|
||||
}
|
||||
|
||||
resetToDefault(): void {
|
||||
this.themeService.resetToDefault();
|
||||
}
|
||||
|
||||
exportTheme(): void {
|
||||
const themeJson = this.themeService.exportTheme();
|
||||
this.downloadFile(themeJson, 'theme.json', 'application/json');
|
||||
}
|
||||
|
||||
importTheme(event: any): void {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const content = e.target?.result as string;
|
||||
if (this.themeService.importTheme(content)) {
|
||||
alert('Theme imported successfully!');
|
||||
} else {
|
||||
alert('Failed to import theme. Please check the file format.');
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}
|
||||
|
||||
private initializeCustomTheme(): void {
|
||||
if (this.currentTheme) {
|
||||
this.customTheme = {
|
||||
colors: {
|
||||
primary: this.currentTheme.colors.primary,
|
||||
secondary: this.currentTheme.colors.secondary,
|
||||
accent: this.currentTheme.colors.accent,
|
||||
background: this.currentTheme.colors.background,
|
||||
surface: this.currentTheme.colors.surface,
|
||||
text: this.currentTheme.colors.text,
|
||||
textSecondary: this.currentTheme.colors.textSecondary
|
||||
},
|
||||
fonts: {
|
||||
primary: this.currentTheme.fonts.primary,
|
||||
secondary: this.currentTheme.fonts.secondary,
|
||||
mono: this.currentTheme.fonts.mono
|
||||
},
|
||||
borderRadius: this.currentTheme.borderRadius,
|
||||
shadow: this.currentTheme.shadow
|
||||
};
|
||||
} else {
|
||||
// Default values if no current theme
|
||||
this.customTheme = {
|
||||
colors: {
|
||||
primary: '#0ea5e9',
|
||||
secondary: '#64748b',
|
||||
accent: '#8b5cf6',
|
||||
background: '#f8fafc',
|
||||
surface: '#ffffff',
|
||||
text: '#111827',
|
||||
textSecondary: '#6b7280'
|
||||
},
|
||||
fonts: {
|
||||
primary: 'Inter',
|
||||
secondary: 'Poppins',
|
||||
mono: 'JetBrains Mono'
|
||||
},
|
||||
borderRadius: '0.75rem',
|
||||
shadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private downloadFile(content: string, filename: string, contentType: string): void {
|
||||
const blob = new Blob([content], { type: contentType });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
link.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
// Color picker methods
|
||||
onColorChange(colorType: string, value: string): void {
|
||||
if (!this.customTheme.colors) {
|
||||
this.customTheme.colors = {
|
||||
primary: '#0ea5e9',
|
||||
secondary: '#64748b',
|
||||
accent: '#8b5cf6',
|
||||
background: '#f8fafc',
|
||||
surface: '#ffffff',
|
||||
text: '#111827',
|
||||
textSecondary: '#6b7280'
|
||||
};
|
||||
}
|
||||
(this.customTheme.colors as any)[colorType] = value;
|
||||
}
|
||||
|
||||
// Font picker methods
|
||||
onFontChange(fontType: string, value: string): void {
|
||||
if (!this.customTheme.fonts) {
|
||||
this.customTheme.fonts = {
|
||||
primary: 'Inter',
|
||||
secondary: 'Poppins',
|
||||
mono: 'JetBrains Mono'
|
||||
};
|
||||
}
|
||||
(this.customTheme.fonts as any)[fontType] = value;
|
||||
}
|
||||
|
||||
// Border radius methods
|
||||
onBorderRadiusChange(value: string): void {
|
||||
this.customTheme.borderRadius = value;
|
||||
}
|
||||
|
||||
// Shadow methods
|
||||
onShadowChange(value: string): void {
|
||||
this.customTheme.shadow = value;
|
||||
}
|
||||
|
||||
// Preview methods
|
||||
previewTheme(): void {
|
||||
if (this.isCustomizing && this.customTheme.colors && this.customTheme.fonts) {
|
||||
const previewTheme: Theme = {
|
||||
id: 'preview',
|
||||
name: 'Preview Theme',
|
||||
colors: this.customTheme.colors,
|
||||
fonts: this.customTheme.fonts,
|
||||
borderRadius: this.customTheme.borderRadius || '0.5rem',
|
||||
shadow: this.customTheme.shadow || '0 10px 15px -3px rgba(0, 0, 0, 0.1)'
|
||||
};
|
||||
this.themeService.applyTheme(previewTheme);
|
||||
}
|
||||
}
|
||||
|
||||
// Utility methods
|
||||
getColorValue(colorType: string): string {
|
||||
if (this.customTheme.colors) {
|
||||
return (this.customTheme.colors as any)[colorType] || '#0ea5e9';
|
||||
}
|
||||
return '#0ea5e9';
|
||||
}
|
||||
|
||||
getFontValue(fontType: string): string {
|
||||
if (this.customTheme.fonts) {
|
||||
return (this.customTheme.fonts as any)[fontType] || 'Inter';
|
||||
}
|
||||
return 'Inter';
|
||||
}
|
||||
|
||||
getBorderRadiusValue(): string {
|
||||
return this.customTheme.borderRadius || '0.75rem';
|
||||
}
|
||||
|
||||
getShadowValue(): string {
|
||||
return this.customTheme.shadow || '0 10px 15px -3px rgba(0, 0, 0, 0.1)';
|
||||
}
|
||||
|
||||
getShadowValueNumber(): string {
|
||||
const shadowValue = this.getShadowValue();
|
||||
const match = shadowValue.match(/\d+/);
|
||||
return match ? match[0] : '10';
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ export class LoginService {
|
||||
|
||||
this.apiRequest.loginAuthentication('token/session', bodyData)
|
||||
.subscribe(jsonResp => {
|
||||
console.log('login response in service : ', jsonResp);
|
||||
console.log('login response: ', jsonResp);
|
||||
if (jsonResp.operationMessage=='Login Failed') {
|
||||
this.toastr.warning('Not Login Getting Error check your Username and password');
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export class LoginService {
|
||||
//Create a faliure object that we want to send back to login page
|
||||
loginInfoReturn = {
|
||||
"success":false,
|
||||
"message":jsonResp.operationMessage,
|
||||
"message":jsonResp.msgDesc,
|
||||
"landingPage":"/login"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
export interface ThemeColors {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
accent: string;
|
||||
background: string;
|
||||
surface: string;
|
||||
text: string;
|
||||
textSecondary: string;
|
||||
}
|
||||
|
||||
export interface Theme {
|
||||
id: string;
|
||||
name: string;
|
||||
colors: ThemeColors;
|
||||
borderRadius: string;
|
||||
shadow: string;
|
||||
fonts: {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
mono: string;
|
||||
};
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ThemeService {
|
||||
private currentThemeSubject = new BehaviorSubject<Theme>(this.getDefaultTheme());
|
||||
public currentTheme$ = this.currentThemeSubject.asObservable();
|
||||
|
||||
private readonly STORAGE_KEY = 'cloudnsure-theme';
|
||||
|
||||
constructor() {
|
||||
this.loadThemeFromStorage();
|
||||
}
|
||||
|
||||
// Default theme
|
||||
private getDefaultTheme(): Theme {
|
||||
return {
|
||||
id: 'default',
|
||||
name: 'Default Blue',
|
||||
colors: {
|
||||
primary: '#0ea5e9',
|
||||
secondary: '#64748b',
|
||||
accent: '#8b5cf6',
|
||||
background: '#f8fafc',
|
||||
surface: '#ffffff',
|
||||
text: '#1f2937',
|
||||
textSecondary: '#6b7280'
|
||||
},
|
||||
borderRadius: '0.5rem',
|
||||
shadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)',
|
||||
fonts: {
|
||||
primary: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
secondary: 'Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
mono: 'JetBrains Mono, "Fira Code", Consolas, monospace'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Predefined themes
|
||||
getThemes(): Theme[] {
|
||||
return [
|
||||
this.getDefaultTheme(),
|
||||
{
|
||||
id: 'purple',
|
||||
name: 'Purple Dream',
|
||||
colors: {
|
||||
primary: '#8b5cf6',
|
||||
secondary: '#64748b',
|
||||
accent: '#ec4899',
|
||||
background: '#faf5ff',
|
||||
surface: '#ffffff',
|
||||
text: '#1f2937',
|
||||
textSecondary: '#6b7280'
|
||||
},
|
||||
borderRadius: '0.75rem',
|
||||
shadow: '0 10px 15px -3px rgba(139, 92, 246, 0.1)',
|
||||
fonts: {
|
||||
primary: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
secondary: 'Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
mono: 'JetBrains Mono, "Fira Code", Consolas, monospace'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'green',
|
||||
name: 'Forest Green',
|
||||
colors: {
|
||||
primary: '#10b981',
|
||||
secondary: '#64748b',
|
||||
accent: '#f59e0b',
|
||||
background: '#f0fdf4',
|
||||
surface: '#ffffff',
|
||||
text: '#1f2937',
|
||||
textSecondary: '#6b7280'
|
||||
},
|
||||
borderRadius: '0.375rem',
|
||||
shadow: '0 10px 15px -3px rgba(16, 185, 129, 0.1)',
|
||||
fonts: {
|
||||
primary: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
secondary: 'Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
mono: 'JetBrains Mono, "Fira Code", Consolas, monospace'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'orange',
|
||||
name: 'Sunset Orange',
|
||||
colors: {
|
||||
primary: '#f59e0b',
|
||||
secondary: '#64748b',
|
||||
accent: '#ef4444',
|
||||
background: '#fffbeb',
|
||||
surface: '#ffffff',
|
||||
text: '#1f2937',
|
||||
textSecondary: '#6b7280'
|
||||
},
|
||||
borderRadius: '1rem',
|
||||
shadow: '0 10px 15px -3px rgba(245, 158, 11, 0.1)',
|
||||
fonts: {
|
||||
primary: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
secondary: 'Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
mono: 'JetBrains Mono, "Fira Code", Consolas, monospace'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'dark',
|
||||
name: 'Dark Mode',
|
||||
colors: {
|
||||
primary: '#3b82f6',
|
||||
secondary: '#9ca3af',
|
||||
accent: '#8b5cf6',
|
||||
background: '#111827',
|
||||
surface: '#1f2937',
|
||||
text: '#f9fafb',
|
||||
textSecondary: '#d1d5db'
|
||||
},
|
||||
borderRadius: '0.5rem',
|
||||
shadow: '0 10px 15px -3px rgba(0, 0, 0, 0.3)',
|
||||
fonts: {
|
||||
primary: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
secondary: 'Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
mono: 'JetBrains Mono, "Fira Code", Consolas, monospace'
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// Get current theme
|
||||
getCurrentTheme(): Theme {
|
||||
return this.currentThemeSubject.value;
|
||||
}
|
||||
|
||||
// Apply theme
|
||||
applyTheme(theme: Theme): void {
|
||||
this.currentThemeSubject.next(theme);
|
||||
this.saveThemeToStorage(theme);
|
||||
this.updateCSSVariables(theme);
|
||||
}
|
||||
|
||||
// Select theme by ID
|
||||
selectTheme(themeId: string): void {
|
||||
const theme = this.getThemes().find(t => t.id === themeId);
|
||||
if (theme) {
|
||||
this.applyTheme(theme);
|
||||
}
|
||||
}
|
||||
|
||||
// Update theme colors
|
||||
updateThemeColors(colors: Partial<ThemeColors>): void {
|
||||
const currentTheme = this.getCurrentTheme();
|
||||
const updatedTheme = {
|
||||
...currentTheme,
|
||||
colors: { ...currentTheme.colors, ...colors }
|
||||
};
|
||||
this.applyTheme(updatedTheme);
|
||||
}
|
||||
|
||||
// Update theme fonts
|
||||
updateThemeFonts(fonts: Partial<Theme['fonts']>): void {
|
||||
const currentTheme = this.getCurrentTheme();
|
||||
const updatedTheme = {
|
||||
...currentTheme,
|
||||
fonts: { ...currentTheme.fonts, ...fonts }
|
||||
};
|
||||
this.applyTheme(updatedTheme);
|
||||
}
|
||||
|
||||
// Update theme properties
|
||||
updateThemeProperty(property: keyof Theme, value: any): void {
|
||||
const currentTheme = this.getCurrentTheme();
|
||||
const updatedTheme = {
|
||||
...currentTheme,
|
||||
[property]: value
|
||||
};
|
||||
this.applyTheme(updatedTheme);
|
||||
}
|
||||
|
||||
// Reset to default theme
|
||||
resetToDefault(): void {
|
||||
this.applyTheme(this.getDefaultTheme());
|
||||
}
|
||||
|
||||
// Export theme
|
||||
exportTheme(): string {
|
||||
return JSON.stringify(this.getCurrentTheme(), null, 2);
|
||||
}
|
||||
|
||||
// Import theme
|
||||
importTheme(themeJson: string): boolean {
|
||||
try {
|
||||
const theme = JSON.parse(themeJson) as Theme;
|
||||
if (this.validateTheme(theme)) {
|
||||
this.applyTheme(theme);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Invalid theme JSON:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate theme structure
|
||||
private validateTheme(theme: any): theme is Theme {
|
||||
return (
|
||||
theme &&
|
||||
typeof theme.id === 'string' &&
|
||||
typeof theme.name === 'string' &&
|
||||
theme.colors &&
|
||||
typeof theme.colors.primary === 'string' &&
|
||||
typeof theme.colors.secondary === 'string' &&
|
||||
typeof theme.colors.accent === 'string' &&
|
||||
typeof theme.colors.background === 'string' &&
|
||||
typeof theme.colors.surface === 'string' &&
|
||||
typeof theme.colors.text === 'string' &&
|
||||
typeof theme.colors.textSecondary === 'string'
|
||||
);
|
||||
}
|
||||
|
||||
// Update CSS custom properties
|
||||
private updateCSSVariables(theme: Theme): void {
|
||||
const root = document.documentElement;
|
||||
|
||||
// Update color variables
|
||||
root.style.setProperty('--theme-primary', theme.colors.primary);
|
||||
root.style.setProperty('--theme-secondary', theme.colors.secondary);
|
||||
root.style.setProperty('--theme-accent', theme.colors.accent);
|
||||
root.style.setProperty('--theme-background', theme.colors.background);
|
||||
root.style.setProperty('--theme-surface', theme.colors.surface);
|
||||
root.style.setProperty('--theme-text', theme.colors.text);
|
||||
root.style.setProperty('--theme-text-secondary', theme.colors.textSecondary);
|
||||
|
||||
// Update other properties
|
||||
root.style.setProperty('--theme-border-radius', theme.borderRadius);
|
||||
root.style.setProperty('--theme-shadow', theme.shadow);
|
||||
root.style.setProperty('--theme-font-primary', theme.fonts.primary);
|
||||
root.style.setProperty('--theme-font-secondary', theme.fonts.secondary);
|
||||
root.style.setProperty('--theme-font-mono', theme.fonts.mono);
|
||||
|
||||
// Update body class for theme-specific styling
|
||||
document.body.className = document.body.className.replace(/theme-\w+/g, '');
|
||||
document.body.classList.add(`theme-${theme.id}`);
|
||||
}
|
||||
|
||||
// Load theme from localStorage
|
||||
private loadThemeFromStorage(): void {
|
||||
try {
|
||||
const stored = localStorage.getItem(this.STORAGE_KEY);
|
||||
if (stored) {
|
||||
const theme = JSON.parse(stored) as Theme;
|
||||
if (this.validateTheme(theme)) {
|
||||
this.currentThemeSubject.next(theme);
|
||||
this.updateCSSVariables(theme);
|
||||
}
|
||||
} else {
|
||||
// Apply default theme on first load
|
||||
this.updateCSSVariables(this.getDefaultTheme());
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading theme from storage:', error);
|
||||
this.updateCSSVariables(this.getDefaultTheme());
|
||||
}
|
||||
}
|
||||
|
||||
// Save theme to localStorage
|
||||
private saveThemeToStorage(theme: Theme): void {
|
||||
try {
|
||||
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(theme));
|
||||
} catch (error) {
|
||||
console.error('Error saving theme to storage:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Get color presets for color picker
|
||||
getColorPresets(): { name: string; value: string }[] {
|
||||
return [
|
||||
{ name: 'Blue', value: '#0ea5e9' },
|
||||
{ name: 'Purple', value: '#8b5cf6' },
|
||||
{ name: 'Green', value: '#10b981' },
|
||||
{ name: 'Orange', value: '#f59e0b' },
|
||||
{ name: 'Red', value: '#ef4444' },
|
||||
{ name: 'Pink', value: '#ec4899' },
|
||||
{ name: 'Indigo', value: '#6366f1' },
|
||||
{ name: 'Teal', value: '#14b8a6' },
|
||||
{ name: 'Yellow', value: '#eab308' },
|
||||
{ name: 'Gray', value: '#64748b' }
|
||||
];
|
||||
}
|
||||
|
||||
// Get font options
|
||||
getFontOptions(): { name: string; value: string }[] {
|
||||
return [
|
||||
{ name: 'Inter', value: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
||||
{ name: 'Poppins', value: 'Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
||||
{ name: 'Roboto', value: 'Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif' },
|
||||
{ name: 'Open Sans', value: '"Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
||||
{ name: 'Lato', value: 'Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
||||
{ name: 'Montserrat', value: 'Montserrat, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
||||
{ name: 'Source Sans Pro', value: '"Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
||||
{ name: 'Nunito', value: 'Nunito, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' }
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import { Component, Input, Output, EventEmitter, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
|
||||
import { FieldConfig } from '../field-types/base-field.component';
|
||||
import { FieldFactoryService } from '../field-types/field-factory.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dynamic-form',
|
||||
template: `
|
||||
<form [class]="formClass" (ngSubmit)="onSubmit()">
|
||||
<div class="clr-row">
|
||||
<div
|
||||
*ngFor="let field of fields"
|
||||
[class]="'clr-col-' + (field.colSpan || 12) + ' clr-col-sm-12'"
|
||||
>
|
||||
<ng-container #fieldContainer></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sq-form-actions" *ngIf="showActions">
|
||||
<button
|
||||
type="button"
|
||||
class="sq-btn sq-btn-outline"
|
||||
(click)="onCancel()"
|
||||
[disabled]="isSubmitting"
|
||||
>
|
||||
<clr-icon shape="times"></clr-icon>
|
||||
<span>{{ cancelText }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="sq-btn sq-btn-primary"
|
||||
[disabled]="isSubmitting"
|
||||
>
|
||||
<clr-icon [attr.shape]="submitIcon"></clr-icon>
|
||||
<span>{{ submitText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
`
|
||||
})
|
||||
export class DynamicFormComponent {
|
||||
@Input() fields: FieldConfig[] = [];
|
||||
@Input() formData: any = {};
|
||||
@Input() formClass: string = 'sq-form';
|
||||
@Input() showActions: boolean = true;
|
||||
@Input() submitText: string = 'Submit';
|
||||
@Input() cancelText: string = 'Cancel';
|
||||
@Input() submitIcon: string = 'check';
|
||||
|
||||
@Output() formSubmit = new EventEmitter<any>();
|
||||
@Output() formCancel = new EventEmitter<void>();
|
||||
|
||||
@ViewChild('fieldContainer', { read: ViewContainerRef }) fieldContainer: ViewContainerRef;
|
||||
|
||||
isSubmitting = false;
|
||||
|
||||
constructor(
|
||||
private fieldFactory: FieldFactoryService,
|
||||
private componentFactoryResolver: ComponentFactoryResolver
|
||||
) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.renderFields();
|
||||
}
|
||||
|
||||
renderFields() {
|
||||
this.fieldContainer.clear();
|
||||
|
||||
this.fields.forEach(field => {
|
||||
this.fieldFactory.createField(
|
||||
this.fieldContainer,
|
||||
field.type,
|
||||
field,
|
||||
this.formData[field.name],
|
||||
(value) => {
|
||||
this.formData[field.name] = value;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.isSubmitting = true;
|
||||
this.formSubmit.emit(this.formData);
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
this.formCancel.emit();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
export interface FieldConfig {
|
||||
name: string;
|
||||
label: string;
|
||||
type: string;
|
||||
required?: boolean;
|
||||
placeholder?: string;
|
||||
validators?: any[];
|
||||
options?: any[];
|
||||
[key: string]: any; // For additional properties
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: ''
|
||||
})
|
||||
export class BaseFieldComponent {
|
||||
@Input() field: FieldConfig;
|
||||
@Input() value: any;
|
||||
@Output() valueChange = new EventEmitter<any>();
|
||||
|
||||
onChange(value: any) {
|
||||
this.valueChange.emit(value);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import { Injectable, ComponentFactoryResolver, ViewContainerRef } from '@angular/core';
|
||||
import { TextFieldComponent } from './text-field.component';
|
||||
import { NumberFieldComponent } from './number-field.component';
|
||||
import { PhoneFieldComponent } from './phone-field.component';
|
||||
import { ParagraphFieldComponent } from './paragraph-field.component';
|
||||
import { PasswordFieldComponent } from './password-field.component';
|
||||
import { TextareaFieldComponent } from './textarea-field.component';
|
||||
import { BaseFieldComponent } from './base-field.component';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class FieldFactoryService {
|
||||
private componentMap: any = {
|
||||
'text': TextFieldComponent,
|
||||
'number': NumberFieldComponent,
|
||||
'phone': PhoneFieldComponent,
|
||||
'paragraph': ParagraphFieldComponent,
|
||||
'password': PasswordFieldComponent,
|
||||
'textarea': TextareaFieldComponent
|
||||
};
|
||||
|
||||
constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
|
||||
|
||||
createField(
|
||||
container: ViewContainerRef,
|
||||
fieldType: string,
|
||||
fieldConfig: any,
|
||||
value: any,
|
||||
valueChangeCallback: (value: any) => void
|
||||
): any {
|
||||
const component = this.componentMap[fieldType];
|
||||
if (!component) {
|
||||
throw new Error(`Unsupported field type: ${fieldType}`);
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(component);
|
||||
const componentRef = container.createComponent(factory);
|
||||
|
||||
// Cast to BaseFieldComponent to access properties safely
|
||||
const instance = componentRef.instance as BaseFieldComponent;
|
||||
(instance as any).field = fieldConfig;
|
||||
(instance as any).value = value;
|
||||
|
||||
// Subscribe to value changes
|
||||
if ((instance as any).valueChange && typeof (instance as any).valueChange.subscribe === 'function') {
|
||||
(instance as any).valueChange.subscribe(valueChangeCallback);
|
||||
}
|
||||
|
||||
return componentRef;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ClarityModule } from '@clr/angular';
|
||||
|
||||
import { BaseFieldComponent } from './base-field.component';
|
||||
import { TextFieldComponent } from './text-field.component';
|
||||
import { NumberFieldComponent } from './number-field.component';
|
||||
import { PhoneFieldComponent } from './phone-field.component';
|
||||
import { ParagraphFieldComponent } from './paragraph-field.component';
|
||||
import { PasswordFieldComponent } from './password-field.component';
|
||||
import { TextareaFieldComponent } from './textarea-field.component';
|
||||
import { DynamicFormComponent } from '../dynamic-form/dynamic-form.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
BaseFieldComponent,
|
||||
TextFieldComponent,
|
||||
NumberFieldComponent,
|
||||
PhoneFieldComponent,
|
||||
ParagraphFieldComponent,
|
||||
PasswordFieldComponent,
|
||||
TextareaFieldComponent,
|
||||
DynamicFormComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
ClarityModule
|
||||
],
|
||||
exports: [
|
||||
BaseFieldComponent,
|
||||
TextFieldComponent,
|
||||
NumberFieldComponent,
|
||||
PhoneFieldComponent,
|
||||
ParagraphFieldComponent,
|
||||
PasswordFieldComponent,
|
||||
TextareaFieldComponent,
|
||||
DynamicFormComponent
|
||||
],
|
||||
providers: []
|
||||
})
|
||||
export class FieldTypesModule { }
|
||||
@@ -1,364 +0,0 @@
|
||||
// Shared field styles with modern UI enhancements following UI rules
|
||||
.field-container {
|
||||
margin-bottom: 24px;
|
||||
position: relative;
|
||||
animation: fadeInUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.sq-form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text);
|
||||
margin-bottom: 8px;
|
||||
font-family: var(--theme-font-primary);
|
||||
letter-spacing: 0.02em;
|
||||
|
||||
.label-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.required-indicator {
|
||||
color: var(--theme-error, #ef4444);
|
||||
margin-left: 6px;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-form-input,
|
||||
.sq-form-textarea {
|
||||
width: 100%;
|
||||
padding: 14px 16px;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
color: var(--theme-text);
|
||||
background: var(--theme-surface);
|
||||
border: 2px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: 12px;
|
||||
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
margin-bottom: 0;
|
||||
font-family: var(--theme-font-primary);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
background: var(--theme-surface);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: var(--theme-background);
|
||||
color: var(--theme-text-secondary);
|
||||
cursor: not-allowed;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border-color: var(--theme-error, #ef4444);
|
||||
box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.15);
|
||||
animation: shake 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--theme-text-secondary);
|
||||
font-style: italic;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&:hover:not(:disabled):not(:focus) {
|
||||
border-color: rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
25% { transform: translateX(-5px); }
|
||||
75% { transform: translateX(5px); }
|
||||
}
|
||||
|
||||
.sq-form-textarea {
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.field-description {
|
||||
color: var(--theme-text-secondary);
|
||||
font-size: 13px;
|
||||
margin-top: 8px;
|
||||
font-style: italic;
|
||||
line-height: 1.4;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
&::before {
|
||||
content: "ℹ";
|
||||
margin-right: 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-error-message {
|
||||
color: var(--theme-error, #ef4444);
|
||||
font-size: 13px;
|
||||
margin-top: 8px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background: rgba(239, 68, 68, 0.05);
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid var(--theme-error, #ef4444);
|
||||
|
||||
&::before {
|
||||
content: "⚠";
|
||||
margin-right: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// Phone field specific styles
|
||||
.phone-input-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.phone-input {
|
||||
flex: 1;
|
||||
border-radius: 12px;
|
||||
padding-left: 100px;
|
||||
}
|
||||
|
||||
.country-code-selector {
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 2px;
|
||||
bottom: 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
background: var(--theme-background);
|
||||
border-radius: 10px 0 0 10px;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.08);
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-surface);
|
||||
}
|
||||
|
||||
.country-flag {
|
||||
margin-right: 8px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.country-code {
|
||||
font-weight: 500;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
margin-left: 6px;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.country-code-btn {
|
||||
margin-left: 8px;
|
||||
min-width: 80px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
// Password field specific styles with modern enhancements
|
||||
.password-input-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
.password-input {
|
||||
flex: 1;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.password-toggle {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-left: none;
|
||||
height: 48px;
|
||||
background: var(--theme-background);
|
||||
border: 2px solid rgba(0, 0, 0, 0.08);
|
||||
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
color: var(--theme-text-secondary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 16px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--theme-surface);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--theme-primary);
|
||||
box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.15);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
clr-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.password-strength {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
padding: 12px;
|
||||
background: var(--theme-background);
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.weak {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border: 1px solid rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
|
||||
&.medium {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
border: 1px solid rgba(245, 158, 11, 0.2);
|
||||
}
|
||||
|
||||
&.strong {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
border: 1px solid rgba(16, 185, 129, 0.2);
|
||||
}
|
||||
|
||||
.strength-meter {
|
||||
flex: 1;
|
||||
height: 10px;
|
||||
background-color: #e5e7eb;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
margin-right: 16px;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.strength-bar {
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&.weak {
|
||||
background: linear-gradient(90deg, #ef4444 0%, #ef4444 100%);
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
background: linear-gradient(90deg, #ef4444 0%, #f59e0b 100%);
|
||||
width: 66%;
|
||||
}
|
||||
|
||||
&.strong {
|
||||
background: linear-gradient(90deg, #ef4444, #f59e0b, #10b981);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.strength-label {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--theme-text-secondary);
|
||||
min-width: 100px;
|
||||
text-align: right;
|
||||
|
||||
&.weak {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
&.strong {
|
||||
color: #10b981;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Character count for text areas with modern styling
|
||||
.character-count {
|
||||
text-align: right;
|
||||
font-size: 13px;
|
||||
color: var(--theme-text-secondary);
|
||||
margin-top: 8px;
|
||||
font-weight: 500;
|
||||
padding: 6px 12px;
|
||||
background: var(--theme-background);
|
||||
border-radius: 20px;
|
||||
display: inline-block;
|
||||
float: right;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&.warning {
|
||||
color: #f59e0b;
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: #ef4444;
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
// Enhanced input group for better visual hierarchy
|
||||
.input-group {
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.input-group-prepend,
|
||||
.input-group-append {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 2;
|
||||
color: var(--theme-text-secondary);
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.input-group-prepend {
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.input-group-append {
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.input-with-addon {
|
||||
padding-left: 40px;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export * from './base-field.component';
|
||||
export * from './text-field.component';
|
||||
export * from './number-field.component';
|
||||
export * from './phone-field.component';
|
||||
export * from './paragraph-field.component';
|
||||
export * from './password-field.component';
|
||||
export * from './textarea-field.component';
|
||||
export * from './field-factory.service';
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { BaseFieldComponent, FieldConfig } from './base-field.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-number-field',
|
||||
template: `
|
||||
<div class="field-container">
|
||||
<label [for]="field.name" class="sq-form-label">
|
||||
<span class="label-text">{{ field.label }}</span>
|
||||
<span *ngIf="field.required" class="required-indicator">*</span>
|
||||
</label>
|
||||
<input
|
||||
[id]="field.name"
|
||||
type="number"
|
||||
class="sq-form-input"
|
||||
[placeholder]="field.placeholder || 'Enter ' + field.label.toLowerCase()"
|
||||
[value]="value"
|
||||
(input)="onChange($event.target.value)"
|
||||
[required]="field.required"
|
||||
[min]="field.min"
|
||||
[max]="field.max"
|
||||
[step]="field.step || 1"
|
||||
[readonly]="field.readonly"
|
||||
[disabled]="field.disabled"
|
||||
/>
|
||||
<div *ngIf="field.description" class="field-description">
|
||||
{{ field.description }}
|
||||
</div>
|
||||
<div *ngIf="field.errorMessage" class="sq-error-message">
|
||||
{{ field.errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class NumberFieldComponent extends BaseFieldComponent {
|
||||
@Input() field: FieldConfig;
|
||||
@Input() value: number;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { BaseFieldComponent, FieldConfig } from './base-field.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-paragraph-field',
|
||||
template: `
|
||||
<div class="field-container">
|
||||
<label [for]="field.name" class="sq-form-label">
|
||||
<span class="label-text">{{ field.label }}</span>
|
||||
<span *ngIf="field.required" class="required-indicator">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
[id]="field.name"
|
||||
class="sq-form-textarea"
|
||||
[placeholder]="field.placeholder || 'Enter ' + field.label.toLowerCase()"
|
||||
[value]="value"
|
||||
(input)="onChange($event.target.value)"
|
||||
[required]="field.required"
|
||||
[rows]="field.rows || 4"
|
||||
[cols]="field.cols || 50"
|
||||
[attr.maxlength]="field.maxLength"
|
||||
[readonly]="field.readonly"
|
||||
[disabled]="field.disabled"
|
||||
></textarea>
|
||||
<div class="character-count" *ngIf="field.showCharacterCount && field.maxLength" [ngClass]="{
|
||||
'warning': value?.length > field.maxLength * 0.8,
|
||||
'error': value?.length >= field.maxLength
|
||||
}">
|
||||
{{ value?.length || 0 }}/{{ field.maxLength }}
|
||||
</div>
|
||||
<div *ngIf="field.description" class="field-description">
|
||||
{{ field.description }}
|
||||
</div>
|
||||
<div *ngIf="field.errorMessage" class="sq-error-message">
|
||||
{{ field.errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class ParagraphFieldComponent extends BaseFieldComponent {
|
||||
@Input() field: FieldConfig;
|
||||
@Input() value: string;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { BaseFieldComponent, FieldConfig } from './base-field.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-password-field',
|
||||
template: `
|
||||
<div class="field-container">
|
||||
<label [for]="field.name" class="sq-form-label">
|
||||
<span class="label-text">{{ field.label }}</span>
|
||||
<span *ngIf="field.required" class="required-indicator">*</span>
|
||||
</label>
|
||||
<div class="password-input-container">
|
||||
<input
|
||||
[id]="field.name"
|
||||
[type]="isPasswordVisible ? 'text' : 'password'"
|
||||
class="sq-form-input password-input"
|
||||
[placeholder]="field.placeholder || 'Enter ' + field.label.toLowerCase()"
|
||||
[value]="value"
|
||||
(input)="onChange($event.target.value)"
|
||||
[required]="field.required"
|
||||
[attr.minlength]="field.minLength"
|
||||
[attr.maxlength]="field.maxLength"
|
||||
[readonly]="field.readonly"
|
||||
[disabled]="field.disabled"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="password-toggle"
|
||||
(click)="togglePasswordVisibility()"
|
||||
[attr.aria-label]="isPasswordVisible ? 'Hide password' : 'Show password'"
|
||||
[title]="isPasswordVisible ? 'Hide password' : 'Show password'"
|
||||
>
|
||||
<clr-icon [attr.shape]="isPasswordVisible ? 'eye-hide' : 'eye'"></clr-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="password-strength" *ngIf="field.showStrengthIndicator && value" [ngClass]="getPasswordStrengthClass()">
|
||||
<div class="strength-meter">
|
||||
<div class="strength-bar" [ngClass]="getPasswordStrengthClass()"></div>
|
||||
</div>
|
||||
<span class="strength-label" [ngClass]="getPasswordStrengthClass()">{{ passwordStrengthLabel }}</span>
|
||||
</div>
|
||||
<div *ngIf="field.description" class="field-description">
|
||||
{{ field.description }}
|
||||
</div>
|
||||
<div *ngIf="field.errorMessage" class="sq-error-message">
|
||||
{{ field.errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class PasswordFieldComponent extends BaseFieldComponent {
|
||||
@Input() field: FieldConfig;
|
||||
@Input() value: string;
|
||||
|
||||
isPasswordVisible = false;
|
||||
|
||||
get passwordStrength(): number {
|
||||
if (!this.value) return 0;
|
||||
|
||||
let strength = 0;
|
||||
if (this.value.length >= 8) strength += 25;
|
||||
if (/[A-Z]/.test(this.value)) strength += 25;
|
||||
if (/[0-9]/.test(this.value)) strength += 25;
|
||||
if (/[^A-Za-z0-9]/.test(this.value)) strength += 25;
|
||||
|
||||
return strength;
|
||||
}
|
||||
|
||||
get passwordStrengthLabel(): string {
|
||||
const strength = this.passwordStrength;
|
||||
if (strength < 25) return 'Very Weak';
|
||||
if (strength < 50) return 'Weak';
|
||||
if (strength < 75) return 'Medium';
|
||||
if (strength < 100) return 'Strong';
|
||||
return 'Very Strong';
|
||||
}
|
||||
|
||||
getPasswordStrengthClass(): string {
|
||||
const strength = this.passwordStrength;
|
||||
if (strength < 25) return 'weak';
|
||||
if (strength < 50) return 'weak';
|
||||
if (strength < 75) return 'medium';
|
||||
return 'strong';
|
||||
}
|
||||
|
||||
togglePasswordVisibility() {
|
||||
this.isPasswordVisible = !this.isPasswordVisible;
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { BaseFieldComponent, FieldConfig } from './base-field.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-phone-field',
|
||||
template: `
|
||||
<div class="field-container">
|
||||
<label [for]="field.name" class="sq-form-label">
|
||||
<span class="label-text">{{ field.label }}</span>
|
||||
<span *ngIf="field.required" class="required-indicator">*</span>
|
||||
</label>
|
||||
<div class="phone-input-container">
|
||||
<div class="country-code-selector" (click)="toggleCountryCodeSelector()" *ngIf="field.showCountryCodeSelector">
|
||||
<span class="country-flag">🇺🇸</span>
|
||||
<span class="country-code">{{ selectedCountryCode }}</span>
|
||||
<span class="dropdown-icon">▼</span>
|
||||
</div>
|
||||
<input
|
||||
[id]="field.name"
|
||||
type="tel"
|
||||
class="sq-form-input phone-input"
|
||||
[placeholder]="field.placeholder || 'Enter ' + field.label.toLowerCase()"
|
||||
[value]="value"
|
||||
(input)="onPhoneChange($event.target.value)"
|
||||
[required]="field.required"
|
||||
[pattern]="field.pattern || '.*'"
|
||||
[readonly]="field.readonly"
|
||||
[disabled]="field.disabled"
|
||||
/>
|
||||
<button
|
||||
*ngIf="field.showCountryCodeSelector"
|
||||
class="sq-btn sq-btn-outline sq-btn-sm country-code-btn"
|
||||
type="button"
|
||||
(click)="toggleCountryCodeSelector()"
|
||||
>
|
||||
{{ selectedCountryCode }}
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="errorMessage" class="sq-error-message">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
<div *ngIf="field.description" class="field-description">
|
||||
{{ field.description }}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class PhoneFieldComponent extends BaseFieldComponent {
|
||||
@Input() field: FieldConfig;
|
||||
@Input() value: string;
|
||||
|
||||
selectedCountryCode = '+91';
|
||||
errorMessage = '';
|
||||
|
||||
onPhoneChange(value: string) {
|
||||
// Validate phone number format
|
||||
if (this.field.pattern) {
|
||||
const regex = new RegExp(this.field.pattern);
|
||||
if (!regex.test(value)) {
|
||||
this.errorMessage = this.field.errorMessage || 'Please enter a valid phone number';
|
||||
} else {
|
||||
this.errorMessage = '';
|
||||
}
|
||||
}
|
||||
this.onChange(value);
|
||||
}
|
||||
|
||||
toggleCountryCodeSelector() {
|
||||
// Implementation for country code selector
|
||||
// This would typically open a modal or dropdown
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { BaseFieldComponent, FieldConfig } from './base-field.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-text-field',
|
||||
template: `
|
||||
<div class="field-container">
|
||||
<label [for]="field.name" class="sq-form-label">
|
||||
<span class="label-text">{{ field.label }}</span>
|
||||
<span *ngIf="field.required" class="required-indicator">*</span>
|
||||
</label>
|
||||
<input
|
||||
[id]="field.name"
|
||||
type="text"
|
||||
class="sq-form-input"
|
||||
[placeholder]="field.placeholder || 'Enter ' + field.label.toLowerCase()"
|
||||
[value]="value"
|
||||
(input)="onChange($event.target.value)"
|
||||
[required]="field.required"
|
||||
[attr.maxlength]="field.maxLength"
|
||||
[attr.minlength]="field.minLength"
|
||||
[readonly]="field.readonly"
|
||||
[disabled]="field.disabled"
|
||||
/>
|
||||
<div *ngIf="field.description" class="field-description">
|
||||
{{ field.description }}
|
||||
</div>
|
||||
<div class="character-count" *ngIf="field.showCharacterCount && value" [ngClass]="{
|
||||
'warning': field.maxLength && value?.length > field.maxLength * 0.8,
|
||||
'error': field.maxLength && value?.length >= field.maxLength
|
||||
}">
|
||||
{{ value?.length || 0 }}{{ field.maxLength ? '/' + field.maxLength : '' }}
|
||||
</div>
|
||||
<div *ngIf="field.errorMessage" class="sq-error-message">
|
||||
{{ field.errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class TextFieldComponent extends BaseFieldComponent {
|
||||
@Input() field: FieldConfig;
|
||||
@Input() value: string;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { BaseFieldComponent, FieldConfig } from './base-field.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-textarea-field',
|
||||
template: `
|
||||
<div class="field-container">
|
||||
<label [for]="field.name" class="sq-form-label">
|
||||
<span class="label-text">{{ field.label }}</span>
|
||||
<span *ngIf="field.required" class="required-indicator">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
[id]="field.name"
|
||||
class="sq-form-textarea"
|
||||
[placeholder]="field.placeholder || 'Enter ' + field.label.toLowerCase()"
|
||||
[value]="value"
|
||||
(input)="onChange($event.target.value)"
|
||||
[required]="field.required"
|
||||
[rows]="field.rows || 4"
|
||||
[cols]="field.cols || 50"
|
||||
[attr.maxlength]="field.maxLength"
|
||||
[readonly]="field.readonly"
|
||||
[disabled]="field.disabled"
|
||||
></textarea>
|
||||
<div class="character-count" *ngIf="field.showCharacterCount && field.maxLength" [ngClass]="{
|
||||
'warning': value?.length > field.maxLength * 0.8,
|
||||
'error': value?.length >= field.maxLength
|
||||
}">
|
||||
{{ value?.length || 0 }}/{{ field.maxLength }}
|
||||
</div>
|
||||
<div *ngIf="field.description" class="field-description">
|
||||
{{ field.description }}
|
||||
</div>
|
||||
<div *ngIf="field.errorMessage" class="sq-error-message">
|
||||
{{ field.errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class TextareaFieldComponent extends BaseFieldComponent {
|
||||
@Input() field: FieldConfig;
|
||||
@Input() value: string;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FieldTypesModule } from './components/field-types/field-types.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FieldTypesModule
|
||||
],
|
||||
exports: [
|
||||
FieldTypesModule
|
||||
]
|
||||
})
|
||||
export class SharedModule { }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user