Skip to content

Cpmplete develop Framework for web (front, back and SQL) with out web programing

Notifications You must be signed in to change notification settings

siavcom/web-ones-technology

Repository files navigation

This Framework is to make a simple SQL web data capture program in TypeScript (class-based), without knowledge of web programming (HTML, CSS, VUE).

This Framework uses Vue 3 with Nuxt and SQL databases (MSSQL and POSTGRES).

This Framework is based on VFP (Visual Fox Pro) functions and instructions.

It uses:

Objective:

  • Make a simple program in TypeScript (class-based), without knowledge of web programming (HTML, CSS, VUE).

It's based on using a main form (like ThisForm in VFP) made only in TypeScript, where each form has its own components (editBox, comboBox, checkBox, grid, modalContainer, etc.) and its own methods (click(), when, valid(), etc.), forming a component tree.

                this.Form
             /     |      \
            /      |       \
           /       |        \
          /        |         \
         /         |          \
    Component1  Component2  Component..n
                /     |     \ 
               /      |      \
           click() when()  valid()...etc()

There are some components where each one has its own components (container and grid has several components and column components).

            container
        /     |      \
       /      |       \
      /       |        \
     /        |         \
    Component1 Component2 Component..n

            grid
        /     |       \
       /      |        \
      /       |         \
     /        |          \
    Column1 Column2 Column..n

Each component has its own properties.

  • Basic props
  • Style props
  • Position props (outdated)

and methods

  • click
  • when
  • valid
  • setFocus
  • interactiveChange
  • init
  • keyPress Handles key press events for the input. The pressed key value is stored in this.prop.Key.
  • onChangeValue When the value of this component changes, this method is called. It receives an optional parameter styles, which is the styles of the component (style, inputStyle, labelsStyle). If it is not provided, it uses the component styles of the object. Example: The method changes the color of the input depending on the value selected. A = green, B = red, X = blue. @param {any} styles - The style of the component.

To make a reference to a specific property you can do so by using a complete name reference tree Map (Object). Example: Properties: this.Form.style.display="inline-block" this.Form.style.width='800px'. this.Form.component1.prop.Type = 'editText' this.Form.component2.prop.Value='Customer name 1' or this.Parent.component2.prop.Value='Customer name 1' this.Parent.component1.component2.prop.Value='Customer name 1'

Calling a method:

this.Form.component4.click(). this.Parent.component1.component2.click()

Web components (vue/nuxt components)

  • base64. Load and display base64 imgage.
  • browse. Display table.
  • checkBox. Check Box input.
  • comboBox. Combo Vox Input.
  • container. Component container.
  • editText. Text, number, json and check input.
  • form. Form component container.
  • grid. Grid componet container.
  • image. Display image.
  • imgButton. Button with image.
  • modalComponent. Modal component container.
  • optionGroup. Option group input.
  • textLabel. Text label.

TypeScript component

TypeScript components has to be in a TypeScrip container component (Form, container or another component ) except Form component.

Each component commonly is made for a simple file in a page Form pages/clientForm/index.vue // Only file pages/clientForm/ThisForm.ts // Principal form pages/clientForm/component1.ts // component 1 pages/clientForm/component2.ts // component 2 . . . pages/clientForm/componentn.ts // component n

Each component arr compund by 3 part

Example of component

// Clase : dic_dat
// Descripcion : tipo de mantenimiento del diccionario de datos
// Author : Fernando Cuadras Angulo
// Creacion : Diciembre/2021
// Ult.Mod : 6/Septiembre/2022

import { COMPONENT } from "@/classes/Component";

export class dic_dat extends COMPONENT {

constructor() {
super();
//****** Propierties ********//
this.prop.BaseClass = "comboBox";
this.prop.textLabel = "Diccionario de datos";
this.prop.ToolTipText = this.prop.textLabel;
this.prop.ReadOnly = false;
this.prop.Capture = false;
this.prop.RowSource = [
["Tablas del SQL Server", "Definicion de Tabla", "Menú de programas"],
["T", "D", "M"],];
this.prop.ControlSource = "vi_cap_comedat.dic_dat";
this.prop.RowSourceType = 5; //1-Value, 2-Alias, 5-Array
this.prop.ColumnCount = 2;
this.prop.BoundColumn = 2;
this.prop.ColumnWidths = "200px,10px";

//****** Component Style *******//
this.style.width = "500px";
this.style.fontSize = "17px";
this.style.fontWeight = "bold";

//****** input style component *******//
this.inputStyle.fontSize = "17px";
this.inputStyle.fontWeight = "bold";
this.inputStyle.width = "300px";

//****** label style component *******//
this.labelStyle.fontSize = "17px";
this.labelStyle.fontWeight = "bold";
}
//*********** Methods *******************//
public init = async (form: any) => {
this.prop.Value = "T";
[](http://_vscodecontentref_/0) = true;
};

async interactiveChange() {
this.Form.nom_tab.prop.Visible = false
this.Form.bt_gen_all_models.prop.Visible = false
if (this.prop.Value == "M") {
this.Form.sis_sis.prop.Visible = false;
this.Form.bt_aceptar.prop.Visible = true;
} else {
this.Form.sis_sis.prop.Visible = true;
this.Form.bt_aceptar.prop.Visible = false;
}
}

public async when(sis_sis?: boolean) {
await this.interactiveChange()

this.Form.nom_tab.prop.Visible = false;
this.Form.tpr_prg.prop.Visible = false;

this.Form.grid_datos.prop.Visible = false;
this.Form.grid_indices.prop.Visible = false;
this.Form.grid_vistas.prop.Visible = false;
this.Form.grid_menu.prop.Visible = false;
this.Form.grid_tablas.prop.Visible = false;

this.Form.bt_gen_model.prop.Visible = false;
this.Form.bt_gen_indices.prop.Visible = false;
this.Form.bt_gen_vistas.prop.Visible = false;
this.Form.bt_gen_all_models.prop.Visible = false;
return !this.prop.ReadOnly;
} }

TypeScript components

  • Browse. Table display

  • CaptureComponent. Component of CaptureForm

  • CaptureForm. Main maintenance page form container

  • Column. Column component in a grid component

  • Component. Basic component

  • Form. Main page container

  • Grid. Table maintenance container

    Each component is a TypeScipt class and has several properties where each property affects visual and database behavior as values too.

Base properties

this.prop.<Name of propierty>'.<Value>` Propierty :

  • BaseClass: <webComponent>
    Type: string
    Values : 'Form','editText', 'textLabel', 'comboBox', 'checkBox', 'optionGroup', 'grid', 'base64', 'container'.

  • Name:<Name of the component>
    Type :string

  • textLabel:<Text label showing before input>
    Type: string

  • Type:<Data types when BaseClass="editText">
    Type: string
    Values : 'number',
    'text' 'date', 'dateTime', 'spinner', 'checkBox', 'json', 'checkBox'.

  • Position : = <position in a form > Type : string. Values : 'header',
    'main',
    'footer'

  • Value:<Value of the component>

Visual properties

this.prop.. Values :

  • First:<true. Component that receives focus when a new record is inserted>
    Type: boolean

  • Disabled:<True when disabled>
    Type: boolean

  • ErrorMessage:<Error message if the component is not valid (after valid()=false or prop.Valid=false)>
    Type: string

  • Format: <``>
    Type: string

  • InputMask: <``>
    Type: string

  • MaxLength:<Maximum character length>
    Type: number

  • Min:<Minimum value for number>
    Type: number

  • Max:<Maximum value for number>
    Type: number

  • Placeholder:<label inside input blurred>
    Type: string

  • Position:<Position in a form component>
    Type: string
    Values: 'header', 'main', 'footer'.

  • ReadOnly:<true when component is only readable>
    Type: boolean

  • TabIndex:<Component tab index in a form component>
    Type: number

  • Image:<Component background image path>
    Type : string

  • ToolTipText:<Component tool tip text>
    Type: string

  • Visible: <true when component is visible>
    Type: string

Database components properties

Each prop.Value component can be gathered from a field of local SQL where:

this.prop.<name of propierty>.<Value> Values :

  • ControlSource: <Name of SQL field>
    Type : string
    Example value: 'localTable.field'

  • RecordSource: <local or remote table name>
    Type :string Example value: 'viewTableName'

  • SqlUpdate: <True, when the component loses focus, update field component. When false, update field component using the tableUpdate method.> Type : boolean

Behaivor properties

this.prop.<name of propierty>.<Value>

Values :

  • Capture: <When capture is true, can't lose focus until Validate or esc> Type : boolean

  • First: <In a Form or grid component it has to be true the first capture component> false Type : boolean

  • Focus: <When set to true, this component takes focus> Type : boolean

  • Map: <Show the structure map of this component> Type : string Example : "this.Form.componentName"

  • Status: <Status of component> Type : string Values : P=Process, A=Active, I=Initialization.

  • Valid: <True when component value is good> Type : boolean

  • Recno : <Record Number for localSql field value>

Numeric components propierties

this.prop.<name of propierty>.<Value>

Values :

  • Currency: <Currency to display> Type : string Example : 'USD', 'EUR', 'MXN'

  • CurrencyDisplay: 'code' // To use the ISO currency code Type

  • Decimals: <Decimals to show and capture> Type : number

  • Max: <Maximus value in this component> Type : number

  • Min: <Minumus value in this component> Type : number

  • Step: <When a spinner component number step> Type : number

Combo box properties

this.prop.<name of propierty>.<Value>

Values :

  • Style : <Type of combo box> Type : number Values : 0=DropDown.
    2=DropDown List

  • BoundColumn <The value is attached to the column> Type : number

  • ColumnCount: <Total column numbers in a comboBox> Type : number

  • ColumnWidths: <Width of each column> Type : number Example : '80%', '20%'

  • MultiSelect: <Can multiple select> Type : boolean

  • List: <List array result when MultiSelect is true> Type : array

  • RowSource : <Sql query or table.field> Type : string Example : - when RowSourceType=2 : 'tablename.field1,field2' - When RowSourceType=3 or 4 : ' select column1,column2 from tablefield '

  • RowSourceType: <How to fill the comboBox> Type : number Values : 1-Value.
    Example RowSourceType=1 ColumnCount =2 RowSource="House,H,Building,B,Department,D"

      2-Alias. 
        Example RowSourceType=2 
        ColumnCount =3
        RowSource="tablename.House,Building,Department"
    
      3-Query SQL Server.  
        Example RowSourceType=3
        ColumnCount =2  
        RowSource= 'select column1,column2 from servertable '
    
      4-Local SQL.  
        Example RowSourceType=4
        ColumnCount =2  
        RowSource= 'select column1,column2 from localable '
        > [!NOTE] You already have a local table SQL
    
      5-Array.  
        Example RowSourceType=5
        ColumnCount =2  
        RowSource= [['column1','column2'],
                    ['value1','value2']]
    

style, inputStyle,labelStylenent and componentStyle properties ( all html style)

this.style.<name of propierty>.<Value> this.inputStyle.<name of propierty>.<Value> this.labelStyle.<name of propierty>.<Value>

Values :

example:

  • background: "white",
  • color: "#b94295",
  • width: "64px",
  • height: "auto",
  • Maxheight: '13px',
  • MaxWidth: 'auto',
  • fontFamily: "Arial",
  • fontSize: "13px",
  • textAlign: "left",
  • ...... several CSS style properties: .

Form (Main Form container)

This is the principal main form ( SPA ). A complete system is made for serverlas Forms.

Each one for is folder ubicated in a page directory of NUXT structure.

Important

Each page folder is minimun composed of two files: index.vue and ThisForm.ts

index.vue will always have this content

<template>
<VueForm v-bind:ThisForm="ThisForm">
<template #header />
<template #main />
<template #footer />
</VueForm>
</template>

<script lang="ts" setup>
import VueForm from "@/components/form.vue";
import { ThisForm } from './ThisForm'
</script>

ThisForm.ts

//////////////////////////////////////////////
// Page: SqlDictionary
// Clase base : ThisForm
// Author : Fernando Cuadras Angulo
// Creacion : Septiembre/2021
// Ult.Mod : Enero/2025
/////////////////////////////////////////////

/////////////////////////////////////////
// TypeScript base class
/////////////////////////////////////////
import { FORM } from "@/classes/Form"

/////////////////////////////////////////
// TypeScript component
/////////////////////////////////////////

import { dic_dat } from "./dic_dat"
import { nom_tab } from "./nom_tab"
import { sis_sis } from "./sis_sis"

import { tpr_prg } from "./tpr_prg"
import { bt_aceptar } from "./bt_aceptar"
import { bt_gen_indices } from "./bt_gen_indices"
import { bt_gen_model } from "./bt_gen_model"
import { bt_gen_vistas } from "./bt_gen_vistas"
import { bt_gen_all_models } from "./bt_gen_all_models"

import { grid_datos } from "./grid_datos/grid_datos"
import { grid_indices } from "./grid_indices/grid_indices"
import { grid_vistas } from "./grid_vistas/grid_vistas"
import { grid_menu } from "./grid_menu/grid_menu"
import { grid_tablas } from "./grid_tablas/grid_tablas"

export class ThisForm extends FORM {
public dic_dat = new dic_dat()
public tpr_prg = new tpr_prg()
public sis_sis = new sis_sis()
public nom_tab = new nom_tab()

public bt_aceptar = new bt_aceptar()
public bt_gen_indices = new bt_gen_indices()
public bt_gen_model = new bt_gen_model()
public bt_gen_vistas = new bt_gen_vistas()
public bt_gen_all_models = new bt_gen_all_models()

public grid_datos = new grid_datos()
public grid_indices = new grid_indices()
public grid_vistas = new grid_vistas()
public grid_tablas = new grid_tablas()
public grid_menu = new grid_menu()

constructor() {
super()
// Propierties
this.prop.Name = "SqlDictionary"
this.prop.tag = ""
this.prop.textLabel = "Mantenimiento al diccionario de datos"
this.prop.Status = "A"

// Style  
this.style.display = "inline-flex"  
this.style.background = "white"  
this.style.color = "#b94295"  
this.style.fontSize = "13px"   
this.style.position = "center"   

}
}

[!NOTE] : To see the complete Form of this example, look in pages/SqlDictionary.

Grid (component container). This component is for localSql table capture

A grid has several columns table where each column is a column component.

Grid component has it's own propierties

  • textLabel = <Grid title>
    Type: string

  • ControlSource: <Name of localSQL table>
    Type : string
    Example value: 'capture_view_items'.

  • SqlUpdate: < Automatic update> Type : boolean Value = true enable automatic update. Value = false disable automati update

  • addButton = <Show add button > Type : boolean Value = true to show add button. Value = false to hide add button.

  • saveButton = <Show save button > Type : boolean Value = true to show save button. Value = false to hide save button.

  • deleteButton = <Show delete button > Type : boolean Value = true to show delete button. Value = false to hide delete button.

  • insertButton = <Show insert button > Type : boolean Value = true to show insert button. Value = false to hide insert button.

Grid component has it's own methods

  • appendRow(<memoryVariables>: {}) Append a row where memoryVariables is a object contain values of variables definided in values of field in SqlDictionary table design Example : m={ firstName: this.Form.name, age : this.Form.age, newcustomer : true, }

  • deleteRow( <recno to delete>?: number) if , delete the grid row positioned

Column (Column component)

Eqch column component has a label for the header this.Label='Header 1'

and an another type script component (editText, imgButton.. almost all type script component)

And each column component has it's owns propierties

  • ControlSource = <localSqltable.field> Type : string Value = local Sql Table + field

[!NOTE] : For a complete example, take a look in the page directory. Each directory is a Vue View Page. pages/SqlDictionary is the SQL database maintenance dictionary, you can add tables with fields, index, and SQL views for manipulating data access.

Container (container component). Is a component contain one or containers blocks

by default has this Style
this.containerStyle.display = 'flex' this.containerStyle.flexWrap = 'wrap' this.style.maxWidth = '600px'

and each block has to be is defined
// =======================<Bloque 0 >=============== const container = this.container this.block[0] = structuredClone(container)

this.block[0].component = {
  [0]: this.name,
  [1]: this.age,

}
this.block[0].title = 'Cliente Nuevo'
this.block[0].style.width = '95%'

container component has it's own methods

async open() { this.prop.Visible = true }

async close() { this.prop.Visible = false }

SQL Database class (This method is based in VFP SQL instructions)

  • select(<area>).

  • useNodata(<table>,<alias?>).

  • use(<table>,<memoryObject>,<alias?>).

  • tableUpdate(<updateType>,<force>,<alias>).

  • appendBlank(<alias>,<memoryObject>).

  • deleteRow(<key_pri>,<alias?>).

  • delete(<recno>,<alias>,<SqlUpdate>).

  • insert(<alias>,<memoryObject>).

  • execute(<query>,<alias>,<resultType>).

  • select(<alias>).

  • recCount(<alias?>).

  • recno(<alias?>).

  • goto(<row>).

  • skip(<rowNumbers>).

  • scatter(<type>,<fieldArray>).

Values

<area> type: number. VFP Area number

<alias> type: string. Local SQL table alias.

<table> type: string. SQL Server remote view name.

<memoryObject> type: Object. It has field and value field SQL table. (In VFP is named only m )

Example:

const m={ code_id : '000021', PurchaseDate : '2022-10-21' }

<updateType> type: number. Value = 0 Only row which positioned. Value = 1 All table rows until update error. If error, return false else return true. Value= 2 All table rows.

<force> type: boolean. Value = false If an update table fails because another user changed data first, return false. Value = true If an update table fails because another user changed data first.

<key_pri> type: number. Table key_pri(id) number in SQLServer.

<recno> type: number. Local SQL id recno number.

<SqlUpdate> type: boolean. Value = true. Delete SQLServer. Value = false. Only local SQL.

<sqlQuery> type: string. SQL Server query to execute.

<resultType> type: string.

<row> type: number. Recno row id to go.

<rowNumbers> type: number. Row number. Forward it is positive and backward it is negative.

<type> type: string. Value = 'MEMVAR'. Return an object with all field values. Value = 'FIELDS'. Return an object with specific field values.

<fieldArray> type: array. Array with specific fields to obtain values.

Recommended IDE Setup

  • VSCode

  • Useful extensions for VSCode:

    • Eslint
    • Prettier Eslint
    • Vue Official
  • Download the back-end framework from https://github.com/siavcom/VFP-NODE and extract it in a folder.

  • Make a company folder in the back-end folder/app/empresas/<your company name>

  • Copy a example folder company in the company folder

  • Rename the example folder to your company name

  • Change the db.config.js file and use your SQL Server connection parameters

  • Open a terminal in the back-end folder and run node server_socket.js

How to use this framework

This procedure install all libreries needed for this proyect

-In the project directory, you will find a zip file called web-ones. This file should be in a directory called systems that you need to create at the root of your disk where you have your project

Example:   If you use Linux .- Generate the systems directory in /systems

  If you use Windows and the project is on drive C: .- Generate the systems directory in C:\systems

-Give read/write permission to this directory. In this directory put the web-ones.zip file and unzip it.

This will generate a web-ones directory and inside web-ones is the public folder and in that folder is the communication definition with the back-end server "arcor": { "url": "http://:/", "nem_emp": "", "nom_sis": "menu", "path": { "name": "Menu" }, "logoEmp": "/logos/YourLogo.bmp" }

"url": "http://192.168.154.1:38080/"   Where the back-end server is "nem_emp": "My company "     Company name "nom_sis": "menu",      "path": { "name": "Menu" },             Path where the system will start "logoEmp": "/logos/YourLogo.bmp"       Company logo

The fields you can modify are "nem_emp": "My Name company"     Company name "logoEmp": "/logos/MyLogo.bmp"       Company logo

Edit it and indicate the name of the file where your logo is. The logos are in the logos directory in the web-ones directory

Change to the project directory and now run the command npm run dev This will start the project and you can start seeing it in your browser at http://localhost:3000

Begining to work

  • Login

Design a SQL Table

  • Create a new SQL table. Go to SQL data dictionary in the menu.

  • Choose SQL Server table

  • Choose system menu

  • Add a new table

  • Fill all data table characteristics

  • Save table

  • Create a new definition SQL table Go to SQL data dictionary in the menu.

    • Choose table definition
    • Choose system menu
    • Choose table
    • Add a new definition
    • Click accept
    • Insert fields
    • Fill up all characteristics
    • Click accept

    [!NOTE]: When a field is a primary key, the default value has to be m.<namefield>

  • Create a new SQL view.

  • Create a new SQL index.

Make a personal menu pages

In this framework use the file directory structure of NUXT . All pages are in page directory and each page must have 3 directories

  1. Mto . Maintenance pages
  2. Rep. Reporting pages
  3. Pro. Process pages and in this directories has a directory for each page

To make a menu : Go to SQL data dictionary in the menu.

  • Choose Menu pages
  • Chose menu type
  • Chose system fill data execpt data of VFP

This project uses

  • Vue 3 SFC

  • Nuxt 3

  • @nuxtjs/axios

  • @pinia/nuxt

  • pinia-plugin-persistedstate

  • @zip.js/zip.js

  • alasql

  • buffer

  • file-saver

  • socket.io-client

  • vue-sweetalert2

  • xlsx

  • @nuxt/image

  • maska

  • Back End https://github.com/siavcom/VFP-NODE

  • SQL Server (MSSQL, Postgres soon)

Necessary Knowledge:

  • Object class programming.
  • TypeScript.
  • Some basic HTML CSS styles properties.
  • ANSI 99 standard SQL instructions.
  • SQL Server skills (MSSQL or/and Postgres).

[!NOTES]: This framework is based on a SQL database. It's not complete yet. If you require installation and use, let me know by mail or Skype siavcom@hotmail.com. If you want a new feature, let me know by mail or Skype siavcom@hotmail.com. To use this Framework, you have to restore an initial SQL backup. If you are a VFP programmer, clipper, dbase III or IV, this is the right option for programming on the web. If you have a question, let me know by mail or Skype siavcom@hotmail.com. I can help you if you want to use this framework. I use Linux (Ubuntu 22.04, Ubuntu 24.04) and Windows 10 to make this project.

About

[!IMPORTANT] Reserved Word position estatus

[!NOTES] Development: $ npx nuxi dev --port=3000 $ npm run dev

Other function:

// Append data in m

const m = { name: 'John', phone: '(312) 123-1234' }

m = appendM(m, { zipCode: '23455' })

Result: console.log(m) = { name: 'John', phone: '(312) 123-1234', zipCode: '23455' }

Other

Login to the framework <user>@<busines nickname> <user> : personal login <busines nickname> : SQL data base name

Tip

Helpful advice for doing things better or more easily.

Important

Key information users need to know to achieve their goal.

Warning

Urgent info that needs immediate user attention to avoid problems.

Caution

Advises about risks or negative outcomes of certain actions.