Compare commits
11 Commits
87f738702a
...
v0.0.1-alp
| Author | SHA1 | Date | |
|---|---|---|---|
| ba3227545d | |||
| 84909bfcf8 | |||
| e0d0ac2077 | |||
| 52a6c821f4 | |||
| eccaf17332 | |||
| 6307037985 | |||
| 4b6061c478 | |||
| fc6dc82d84 | |||
| 6ba905a887 | |||
| f33587a3d9 | |||
| 80189baf90 |
@@ -2,6 +2,7 @@ NODE_ENV=development
|
||||
# Server
|
||||
PORT=3000
|
||||
URL=http://localhost:3000
|
||||
SERVER_IP=10.75.2.38
|
||||
TIMEZONE=America/New_York
|
||||
TCP_PORT=2222
|
||||
|
||||
@@ -22,7 +23,7 @@ DEFAULT_DOCK=
|
||||
DEFAULT_LOAD_TYPE=
|
||||
DEFAULT_CARRIER=
|
||||
|
||||
# prodServer when runing on an actual prod server use localhost this way we dont go out and back in.
|
||||
# prodServer when ruining on an actual prod server use localhost this way we don't go out and back in.
|
||||
PROD_SERVER=
|
||||
PROD_PLANT_TOKEN=
|
||||
PROD_USER=
|
||||
|
||||
3
.vscode/settings.json
vendored
@@ -71,7 +71,8 @@
|
||||
"prodlabels",
|
||||
"prolink",
|
||||
"Skelly",
|
||||
"trycatch"
|
||||
"trycatch",
|
||||
"whse"
|
||||
],
|
||||
"gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db",
|
||||
"gitea.instanceURL": "https://git.tuffraid.net",
|
||||
|
||||
44
CHANGELOG.md
@@ -1,5 +1,49 @@
|
||||
# All Changes to LST can be found below.
|
||||
|
||||
## [0.0.1-alpha.4](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.1-alpha.3...v0.0.1-alpha.4) (2026-04-15)
|
||||
|
||||
|
||||
### 🌟 Enhancements
|
||||
|
||||
* **datamart:** migrations completed remaining is the deactivation that will be ran by anylitics ([eccaf17](https://git.tuffraid.net/cowch/lst_v3/commits/eccaf17332fb1c63b8d6bbea6f668c3bb42d44b7))
|
||||
* **datamart:** psi data has been added :D ([e0d0ac2](https://git.tuffraid.net/cowch/lst_v3/commits/e0d0ac20773159373495d65023587b76b47df34f))
|
||||
* **migrate:** quality alert migrated ([b0e5fd7](https://git.tuffraid.net/cowch/lst_v3/commits/b0e5fd79998d551d4f155d58416157a324498fbd))
|
||||
* **ocp:** printer sync and logging logic added ([80189ba](https://git.tuffraid.net/cowch/lst_v3/commits/80189baf906224da43ec1b9b7521153d2a49e059))
|
||||
* **tcp crud:** tcp server start, stop, restart endpoints + status check ([6307037](https://git.tuffraid.net/cowch/lst_v3/commits/6307037985162bc6b49f9f711132853296f43eee))
|
||||
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
* **datamart:** error when running build and crashed everything ([52a6c82](https://git.tuffraid.net/cowch/lst_v3/commits/52a6c821f4632e4b5b51e0528a0d620e2e0deffc))
|
||||
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
* **docs:** removed docusorus as all docs will be inside lst now to better assist users ([6ba905a](https://git.tuffraid.net/cowch/lst_v3/commits/6ba905a887dbd8f306d71fed75bb34c71fee74c9))
|
||||
* **env example:** updated the file ([ca3425d](https://git.tuffraid.net/cowch/lst_v3/commits/ca3425d327757120c2cc876fff28e8668c76838d))
|
||||
* **notifcations:** docs for intro, notifcations, reprint added ([87f7387](https://git.tuffraid.net/cowch/lst_v3/commits/87f738702a935279a248d471541cdd9d49330565))
|
||||
|
||||
|
||||
### 🛠️ Code Refactor
|
||||
|
||||
* **agent:** changed to have the test servers on there own push for better testing ([3bf024c](https://git.tuffraid.net/cowch/lst_v3/commits/3bf024cfc97d2841130d54d1a7c5cb5f09f0f598))
|
||||
* **connection:** corrected the connection to the old system ([38a0b65](https://git.tuffraid.net/cowch/lst_v3/commits/38a0b65e9450c65b8300a10058a8f0357400f4e6))
|
||||
* **logging:** when notify is true send the error to systemAdmins ([79e653e](https://git.tuffraid.net/cowch/lst_v3/commits/79e653efa3bcb2941ccee06b28378e709e085ec0))
|
||||
* **notification:** blocking added ([9a0ef8e](https://git.tuffraid.net/cowch/lst_v3/commits/9a0ef8e51a36e3ab45b601b977f1b5cf35d56947))
|
||||
* **puchase:** changes how the error handling works so a better email can be sent ([9d39c13](https://git.tuffraid.net/cowch/lst_v3/commits/9d39c13510974b5ada2a6f6c2448da3f1b755a5c))
|
||||
* **reprint:** new query added to deactivate the old notifcation so no chance of duplicates ([c9eb59e](https://git.tuffraid.net/cowch/lst_v3/commits/c9eb59e2ad9847418ac55cb8a4a91c013f6c97bb))
|
||||
* **server:** added in serverCrash email ([dcb3f2d](https://git.tuffraid.net/cowch/lst_v3/commits/dcb3f2dd1382986639b722778fad113392533b28))
|
||||
* **services:** added in examples for migration stuff ([fc6dc82](https://git.tuffraid.net/cowch/lst_v3/commits/fc6dc82d8458a9928050dd3770778d6a6e1eea7f))
|
||||
* **sql:** corrections to the way we reconnect so the app can error out and be reactivated later ([f33587a](https://git.tuffraid.net/cowch/lst_v3/commits/f33587a3d9a72ca72806635fac9d1214bb1452f1))
|
||||
* **templates:** corrections for new notify process on critcal errors ([07ebf88](https://git.tuffraid.net/cowch/lst_v3/commits/07ebf88806b93b9320f8f9d36b867572dd9a9580))
|
||||
|
||||
|
||||
### 📈 Project changes
|
||||
|
||||
* **agent:** added in jeff city ([e47ea9e](https://git.tuffraid.net/cowch/lst_v3/commits/e47ea9ec52a6ebaf5a8f67a7e8bd2c73da6186fb))
|
||||
* **agent:** added in sherman ([4b6061c](https://git.tuffraid.net/cowch/lst_v3/commits/4b6061c478cbeba7c845dc1c8a015b9998721456))
|
||||
* **service:** changes to the script to allow running the powershell on execution palicy restrictions ([84909bf](https://git.tuffraid.net/cowch/lst_v3/commits/84909bfcf85b91d085ea9dca78be00482b7fd231))
|
||||
|
||||
## [0.0.1-alpha.3](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.1-alpha.2...v0.0.1-alpha.3) (2026-04-10)
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Quick summary of current rewrite/migration goal.
|
||||
| User Profile | ~~Edit profile~~, upload avatar | 🟨 In Progress |
|
||||
| User Admin | Edit user, create user, remove user, alplaprod user integration | ⏳ Not Started |
|
||||
| Notifications | ~~Subscribe~~, ~~Create~~, ~~Update~~, ~~~~Remove~~, Manual Trigger | 🟨 In Progress |
|
||||
| Datamart | Create, Update, Run, Deactivate | 🔧 In Progress |
|
||||
| Datamart | ~~Create~~, ~~Update~~, ~~Run~~, Deactivate | 🟨 In Progress |
|
||||
| Frontend | Analytics and charts | ⏳ Not Started |
|
||||
| Docs | Instructions and trouble shooting | ⏳ Not Started |
|
||||
| One Click Print | Get printers, monitor printers, label process, material process, Special processes | ⏳ Not Started |
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
*
|
||||
* when a criteria is password over we will handle it by counting how many were passed up to 3 then deal with each one respectively
|
||||
*/
|
||||
|
||||
import { and, between, inArray, notInArray } from "drizzle-orm";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { invHistoricalData } from "../db/schema/historicalInv.schema.js";
|
||||
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||
import {
|
||||
type SqlQuery,
|
||||
@@ -22,37 +26,93 @@ import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
import { datamartData } from "./datamartData.utlis.js";
|
||||
|
||||
type Options = {
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
type Data = {
|
||||
name: string;
|
||||
options: Options;
|
||||
options: any;
|
||||
optionsRequired?: boolean;
|
||||
howManyOptionsRequired?: number;
|
||||
};
|
||||
|
||||
const lstDbRun = async (data: Data) => {
|
||||
if (data.options) {
|
||||
if (data.name === "psiInventory") {
|
||||
const ids = data.options.articles.split(",").map((id: any) => id.trim());
|
||||
const whse = data.options.whseToInclude
|
||||
? data.options.whseToInclude
|
||||
.split(",")
|
||||
.map((w: any) => w.trim())
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
|
||||
const locations = data.options.exludeLanes
|
||||
? data.options.exludeLanes
|
||||
.split(",")
|
||||
.map((l: any) => l.trim())
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
|
||||
const conditions = [
|
||||
inArray(invHistoricalData.article, ids),
|
||||
between(
|
||||
invHistoricalData.histDate,
|
||||
data.options.startDate,
|
||||
data.options.endDate,
|
||||
),
|
||||
];
|
||||
|
||||
// only add the warehouse condition if there are any whse values
|
||||
if (whse.length > 0) {
|
||||
conditions.push(inArray(invHistoricalData.whseId, whse));
|
||||
}
|
||||
|
||||
// locations we dont want in the system
|
||||
if (locations.length > 0) {
|
||||
conditions.push(notInArray(invHistoricalData.location, locations));
|
||||
}
|
||||
|
||||
return await db
|
||||
.select()
|
||||
.from(invHistoricalData)
|
||||
.where(and(...conditions));
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
export const runDatamartQuery = async (data: Data) => {
|
||||
// search the query db for the query by name
|
||||
const sqlQuery = sqlQuerySelector(`${data.name}`) as SqlQuery;
|
||||
const considerLstDBRuns = ["psiInventory"];
|
||||
|
||||
if (considerLstDBRuns.includes(data.name)) {
|
||||
const lstDB = await lstDbRun(data);
|
||||
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "datamart",
|
||||
subModule: "lstDBrn",
|
||||
message: `Data for: ${data.name}`,
|
||||
data: lstDB,
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
const sqlQuery = sqlQuerySelector(`datamart.${data.name}`) as SqlQuery;
|
||||
|
||||
const getDataMartInfo = datamartData.filter((x) => x.endpoint === data.name);
|
||||
|
||||
// const optionsMissing =
|
||||
// !data.options || Object.keys(data.options).length === 0;
|
||||
|
||||
const optionCount =
|
||||
Object.keys(data.options).length ===
|
||||
getDataMartInfo[0]?.howManyOptionsRequired;
|
||||
const isValid =
|
||||
Object.keys(data.options ?? {}).length >=
|
||||
(getDataMartInfo[0]?.howManyOptionsRequired ?? 0);
|
||||
|
||||
if (getDataMartInfo[0]?.optionsRequired && !optionCount) {
|
||||
if (getDataMartInfo[0]?.optionsRequired && !isValid) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "datamart",
|
||||
subModule: "query",
|
||||
message: `This query is required to have the ${getDataMartInfo[0]?.howManyOptionsRequired} options set in order use it.`,
|
||||
message: `This query is required to have ${getDataMartInfo[0]?.howManyOptionsRequired} option(s) set in order use it, please add in your option(s) data and try again.`,
|
||||
data: [getDataMartInfo[0].options],
|
||||
notify: false,
|
||||
});
|
||||
@@ -75,10 +135,129 @@ export const runDatamartQuery = async (data: Data) => {
|
||||
|
||||
// split the criteria by "," then and then update the query
|
||||
if (data.options) {
|
||||
Object.entries(data.options ?? {}).forEach(([key, value]) => {
|
||||
const pattern = new RegExp(`\\[${key.trim()}\\]`, "g");
|
||||
datamartQuery = datamartQuery.replace(pattern, String(value).trim());
|
||||
});
|
||||
switch (data.name) {
|
||||
case "activeArticles":
|
||||
break;
|
||||
case "deliveryByDateRange":
|
||||
datamartQuery = datamartQuery
|
||||
.replace("[startDate]", `${data.options.startDate}`)
|
||||
.replace("[endDate]", `${data.options.endDate}`);
|
||||
|
||||
break;
|
||||
case "customerInventory":
|
||||
datamartQuery = datamartQuery
|
||||
.replace(
|
||||
"--and IdAdressen",
|
||||
`and IdAdressen in (${data.options.customer})`,
|
||||
)
|
||||
.replace(
|
||||
"--and x.IdWarenlager in (0)",
|
||||
`${data.options.whseToInclude ? `and x.IdWarenlager in (${data.options.whseToInclude})` : `--and x.IdWarenlager in (0)`}`,
|
||||
);
|
||||
break;
|
||||
case "openOrders":
|
||||
datamartQuery = datamartQuery
|
||||
.replace("[startDay]", `${data.options.startDay}`)
|
||||
.replace("[endDay]", `${data.options.endDay}`);
|
||||
break;
|
||||
case "inventory":
|
||||
datamartQuery = datamartQuery
|
||||
.replaceAll(
|
||||
"--,l.RunningNumber",
|
||||
`${data.options.includeRunningNumbers ? `,l.RunningNumber` : `--,l.RunningNumber`}`,
|
||||
)
|
||||
.replaceAll(
|
||||
"--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot",
|
||||
`${data.options.lots ? `,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot` : `--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot`}`,
|
||||
)
|
||||
.replaceAll(
|
||||
"--,l.WarehouseDescription,l.LaneDescription",
|
||||
`${data.options.locations ? `,l.WarehouseDescription,l.LaneDescription` : `--,l.WarehouseDescription,l.LaneDescription`}`,
|
||||
);
|
||||
|
||||
// adding in a test for historical check.
|
||||
if (data.options.historical) {
|
||||
datamartQuery = datamartQuery
|
||||
.replace(
|
||||
"--,l.ProductionLotRunningNumber as lot,l.warehousehumanreadableid as warehouseId,l.WarehouseDescription as warehouseDescription,l.lanehumanreadableid as locationId,l.lanedescription as laneDescription",
|
||||
",l.ProductionLotRunningNumber as lot,l.warehousehumanreadableid as warehouseId,l.WarehouseDescription as warehouseDescription,l.lanehumanreadableid as locationId,l.lanedescription as laneDescription",
|
||||
)
|
||||
.replace(
|
||||
"--,l.ProductionLotRunningNumber,l.warehousehumanreadableid,l.WarehouseDescription,l.lanehumanreadableid,l.lanedescription",
|
||||
",l.ProductionLotRunningNumber,l.warehousehumanreadableid,l.WarehouseDescription,l.lanehumanreadableid,l.lanedescription",
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "fakeEDIUpdate":
|
||||
datamartQuery = datamartQuery.replace(
|
||||
"--AND h.CustomerHumanReadableId in (0)",
|
||||
`${data.options.address ? `AND h.CustomerHumanReadableId in (${data.options.address})` : `--AND h.CustomerHumanReadableId in (0)`}`,
|
||||
);
|
||||
|
||||
break;
|
||||
case "forecast":
|
||||
datamartQuery = datamartQuery.replace(
|
||||
"where DeliveryAddressHumanReadableId in ([customers])",
|
||||
data.options.customers
|
||||
? `where DeliveryAddressHumanReadableId in (${data.options.customers})`
|
||||
: "--where DeliveryAddressHumanReadableId in ([customers])",
|
||||
);
|
||||
|
||||
break;
|
||||
case "activeArticles2":
|
||||
datamartQuery = datamartQuery.replace(
|
||||
"and a.HumanReadableId in ([articles])",
|
||||
data.options.articles
|
||||
? `and a.HumanReadableId in (${data.options.articles})`
|
||||
: "--and a.HumanReadableId in ([articles])",
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case "psiDeliveryData":
|
||||
datamartQuery = datamartQuery
|
||||
.replace("[startDate]", `${data.options.startDate}`)
|
||||
.replace("[endDate]", `${data.options.endDate}`)
|
||||
.replace(
|
||||
"and IdArtikelVarianten in ([articles])",
|
||||
data.options.articles
|
||||
? `and IdArtikelVarianten in (${data.options.articles})`
|
||||
: "--and IdArtikelVarianten in ([articles])",
|
||||
);
|
||||
break;
|
||||
case "productionData":
|
||||
datamartQuery = datamartQuery
|
||||
.replace("[startDate]", `${data.options.startDate}`)
|
||||
.replace("[endDate]", `${data.options.endDate}`)
|
||||
.replace(
|
||||
"and ArticleHumanReadableId in ([articles])",
|
||||
data.options.articles
|
||||
? `and ArticleHumanReadableId in (${data.options.articles})`
|
||||
: "--and ArticleHumanReadableId in ([articles])",
|
||||
);
|
||||
break;
|
||||
case "psiPlanningData":
|
||||
datamartQuery = datamartQuery
|
||||
.replace("[startDate]", `${data.options.startDate}`)
|
||||
.replace("[endDate]", `${data.options.endDate}`)
|
||||
.replace(
|
||||
"and p.IdArtikelvarianten in ([articles])",
|
||||
data.options.articles
|
||||
? `and p.IdArtikelvarianten in (${data.options.articles})`
|
||||
: "--and p.IdArtikelvarianten in ([articles])",
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "datamart",
|
||||
subModule: "query",
|
||||
message: `${data.name} encountered an error as it might not exist in LST please contact support if this continues to happen`,
|
||||
data: [sqlQuery.message],
|
||||
notify: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const { data: queryRun, error } = await tryCatch(
|
||||
|
||||
@@ -10,14 +10,50 @@ export const datamartData = [
|
||||
name: "Active articles",
|
||||
endpoint: "activeArticles",
|
||||
description: "returns all active articles for the server with custom data",
|
||||
options: "", // set as a string and each item will be seperated by a , this way we can split it later in the excel file.
|
||||
options: "",
|
||||
optionsRequired: false,
|
||||
},
|
||||
{
|
||||
name: "Delivery by date range",
|
||||
endpoint: "deliveryByDateRange",
|
||||
description: `Returns all Deliverys in selected date range IE: 1/1/${new Date(Date.now()).getFullYear()} to 1/31/${new Date(Date.now()).getFullYear()}`,
|
||||
options: "startDate,endDate", // set as a string and each item will be seperated by a , this way we can split it later in the excel file.
|
||||
description: `Returns all Deliveries in selected date range IE: 1/1/${new Date(Date.now()).getFullYear()} to 1/31/${new Date(Date.now()).getFullYear()}`,
|
||||
options: "startDate,endDate",
|
||||
optionsRequired: true,
|
||||
howManyOptionsRequired: 2,
|
||||
},
|
||||
{
|
||||
name: "Get Customer Inventory",
|
||||
endpoint: "customerInventory",
|
||||
description: `Returns specific customer inventory based on there address ID, IE: 8,12,145. \nWith option to include specific warehousesIds, IE 36,41,5. \nNOTES: *leaving warehouse blank will just pull everything for the customer, Inventory dose not include PPOO or INV`,
|
||||
options: "customer,whseToInclude",
|
||||
optionsRequired: true,
|
||||
howManyOptionsRequired: 1,
|
||||
},
|
||||
{
|
||||
name: "Get open order",
|
||||
endpoint: "openOrders",
|
||||
description: `Returns open orders based on day count sent over, IE: startDay 15 days in the past endDay 5 days in the future, can be left empty for this default days`,
|
||||
options: "startDay,endDay",
|
||||
optionsRequired: true,
|
||||
howManyOptionsRequired: 2,
|
||||
},
|
||||
{
|
||||
name: "Get inventory",
|
||||
endpoint: "inventory",
|
||||
description: `Returns all inventory, excludes inv location. adding an x in one of the options will enable it.`,
|
||||
options: "includeRunningNumbers,locations,lots",
|
||||
},
|
||||
{
|
||||
name: "Fake EDI Update",
|
||||
endpoint: "fakeEDIUpdate",
|
||||
description: `Returns all open orders to correct and resubmit via lst demand mgt, leaving blank will get everything putting an address only returns the specified address. \nNOTE: only orders that were created via edi will populate here.`,
|
||||
options: "address",
|
||||
},
|
||||
{
|
||||
name: "Production Data",
|
||||
endpoint: "productionData",
|
||||
description: `Returns all production data from the date range with the option to have 1 to many avs to search by.`,
|
||||
options: "startDate,endDate,articles",
|
||||
optionsRequired: true,
|
||||
howManyOptionsRequired: 2,
|
||||
},
|
||||
|
||||
30
backend/db/schema/historicalInv.schema.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { date, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||
import type z from "zod";
|
||||
|
||||
export const invHistoricalData = pgTable("inv_historical_data", {
|
||||
inv: uuid("id").defaultRandom().primaryKey(),
|
||||
histDate: date("hist_date").notNull(), // this date should always be yesterday when we post it.
|
||||
plantToken: text("plant_token"),
|
||||
article: text("article").notNull(),
|
||||
articleDescription: text("article_description").notNull(),
|
||||
materialType: text("material_type"),
|
||||
total_QTY: text("total_QTY"),
|
||||
available_QTY: text("available_QTY"),
|
||||
coa_QTY: text("coa_QTY"),
|
||||
held_QTY: text("held_QTY"),
|
||||
consignment_QTY: text("consignment_qty"),
|
||||
lot_Number: text("lot_number"),
|
||||
locationId: text("location_id"),
|
||||
location: text("location"),
|
||||
whseId: text("whse_id").default(""),
|
||||
whseName: text("whse_name").default("missing whseName"),
|
||||
upd_user: text("upd_user").default("lst-system"),
|
||||
upd_date: timestamp("upd_date").defaultNow(),
|
||||
});
|
||||
|
||||
export const invHistoricalDataSchema = createSelectSchema(invHistoricalData);
|
||||
export const newInvHistoricalDataSchema = createInsertSchema(invHistoricalData);
|
||||
|
||||
export type InvHistoricalData = z.infer<typeof invHistoricalDataSchema>;
|
||||
export type NewInvHistoricalData = z.infer<typeof newInvHistoricalDataSchema>;
|
||||
@@ -1,6 +1,11 @@
|
||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
|
||||
export const opendockApt = pgTable("printer_log", {
|
||||
export const printerLog = pgTable("printer_log", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity(),
|
||||
name: text("name").notNull(),
|
||||
name: text("name"),
|
||||
ip: text("ip"),
|
||||
printerSN: text("printer_sn"),
|
||||
condition: text("condition").notNull(),
|
||||
message: text("message"),
|
||||
createdAt: timestamp("created_at").defaultNow(),
|
||||
});
|
||||
|
||||
44
backend/db/schema/printers.schema.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {
|
||||
boolean,
|
||||
integer,
|
||||
jsonb,
|
||||
pgTable,
|
||||
text,
|
||||
timestamp,
|
||||
uniqueIndex,
|
||||
uuid,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||
import type z from "zod";
|
||||
|
||||
export const printerData = pgTable(
|
||||
"printer_data",
|
||||
{
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
humanReadableId: text("humanReadable_id").unique().notNull(),
|
||||
name: text("name").notNull(),
|
||||
ipAddress: text("ipAddress"),
|
||||
port: integer("port"),
|
||||
status: text("status"),
|
||||
statusText: text("statusText"),
|
||||
printerSN: text("printer_sn"),
|
||||
lastTimePrinted: timestamp("last_time_printed").notNull().defaultNow(),
|
||||
assigned: boolean("assigned").default(false),
|
||||
remark: text("remark"),
|
||||
printDelay: integer("printDelay").default(90),
|
||||
processes: jsonb("processes").default([]),
|
||||
printDelayOverride: boolean("print_delay_override").default(false), // this will be more for if we have the lot time active but want to over ride this single line for some reason
|
||||
add_Date: timestamp("add_Date").defaultNow(),
|
||||
upd_date: timestamp("upd_date").defaultNow(),
|
||||
},
|
||||
(table) => [
|
||||
//uniqueIndex("emailUniqueIndex").on(sql`lower(${table.email})`),
|
||||
uniqueIndex("printer_id").on(table.humanReadableId),
|
||||
],
|
||||
);
|
||||
|
||||
export const printerSchema = createSelectSchema(printerData);
|
||||
export const newPrinterSchema = createInsertSchema(printerData);
|
||||
|
||||
export type Printer = z.infer<typeof printerSchema>;
|
||||
export type NewPrinter = z.infer<typeof newPrinterSchema>;
|
||||
@@ -7,12 +7,17 @@ import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
export let pool2: sql.ConnectionPool;
|
||||
export let connected: boolean = false;
|
||||
export let reconnecting = false;
|
||||
// start the delay out as 2 seconds
|
||||
let delayStart = 2000;
|
||||
let attempt = 0;
|
||||
const maxAttempts = 10;
|
||||
|
||||
export const connectGPSql = async () => {
|
||||
const serverUp = await checkHostnamePort(`USMCD1VMS011:1433`);
|
||||
if (!serverUp) {
|
||||
// we will try to reconnect
|
||||
connected = false;
|
||||
reconnectToSql;
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
@@ -48,6 +53,7 @@ export const connectGPSql = async () => {
|
||||
notify: false,
|
||||
});
|
||||
} catch (error) {
|
||||
reconnectToSql;
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
@@ -104,11 +110,6 @@ export const reconnectToSql = async () => {
|
||||
//set reconnecting to true while we try to reconnect
|
||||
reconnecting = true;
|
||||
|
||||
// start the delay out as 2 seconds
|
||||
let delayStart = 2000;
|
||||
let attempt = 0;
|
||||
const maxAttempts = 10;
|
||||
|
||||
while (!connected && attempt < maxAttempts) {
|
||||
attempt++;
|
||||
log.info(
|
||||
@@ -121,7 +122,7 @@ export const reconnectToSql = async () => {
|
||||
|
||||
if (!serverUp) {
|
||||
delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -131,19 +132,11 @@ export const reconnectToSql = async () => {
|
||||
log.info(`${gpSqlConfig.server} is connected to ${gpSqlConfig.database}`);
|
||||
} catch (error) {
|
||||
delayStart = Math.min(delayStart * 2, 30000);
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "db",
|
||||
message: "Failed to reconnect to the prod sql server.",
|
||||
data: [error],
|
||||
notify: false,
|
||||
});
|
||||
log.error({ error }, "Failed to reconnect to the prod sql server.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
if (!connected && attempt >= maxAttempts) {
|
||||
log.error(
|
||||
{ notify: true },
|
||||
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
import {
|
||||
connected,
|
||||
pool2,
|
||||
reconnecting,
|
||||
reconnectToSql,
|
||||
} from "./gpSqlConnection.controller.js";
|
||||
import { connected, pool2 } from "./gpSqlConnection.controller.js";
|
||||
|
||||
interface SqlError extends Error {
|
||||
code?: string;
|
||||
@@ -22,29 +17,15 @@ interface SqlError extends Error {
|
||||
*/
|
||||
export const gpQuery = async (queryToRun: string, name: string) => {
|
||||
if (!connected) {
|
||||
reconnectToSql();
|
||||
|
||||
if (reconnecting) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "gpSql",
|
||||
message: `The sql ${process.env.PROD_PLANT_TOKEN} is trying to reconnect already`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
} else {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "gpSql",
|
||||
message: `${process.env.PROD_PLANT_TOKEN} is not connected, and failed to connect.`,
|
||||
data: [],
|
||||
notify: true,
|
||||
});
|
||||
}
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "gpSql",
|
||||
message: `${process.env.PROD_PLANT_TOKEN} is offline or attempting to reconnect`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
//change to the correct server
|
||||
|
||||
220
backend/logistics/logistics.historicalInv.ts
Normal file
@@ -0,0 +1,220 @@
|
||||
import { format } from "date-fns";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { runDatamartQuery } from "../datamart/datamart.controller.js";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { invHistoricalData } from "../db/schema/historicalInv.schema.js";
|
||||
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||
import {
|
||||
type SqlQuery,
|
||||
sqlQuerySelector,
|
||||
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||
import { createCronJob } from "../utils/croner.utils.js";
|
||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
|
||||
type Inventory = {
|
||||
article: string;
|
||||
alias: string;
|
||||
materialType: string;
|
||||
total_palletQTY: string;
|
||||
available_QTY: string;
|
||||
coa_QTY: string;
|
||||
held_QTY: string;
|
||||
consignment_qty: string;
|
||||
lot: string;
|
||||
locationId: string;
|
||||
laneDescription: string;
|
||||
warehouseId: string;
|
||||
warehouseDescription: string;
|
||||
};
|
||||
|
||||
const historicalInvImport = async () => {
|
||||
const today = new Date();
|
||||
const { data, error } = await tryCatch(
|
||||
db
|
||||
.select()
|
||||
.from(invHistoricalData)
|
||||
.where(eq(invHistoricalData.histDate, format(today, "yyyy-MM-dd"))),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "query",
|
||||
message: `Error getting historical inv info`,
|
||||
data: error as any,
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (data?.length === 0) {
|
||||
const avSQLQuery = sqlQuerySelector(`datamart.activeArticles`) as SqlQuery;
|
||||
|
||||
if (!avSQLQuery.success) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "logistics",
|
||||
subModule: "inv",
|
||||
message: `Error getting Article info`,
|
||||
data: [avSQLQuery.message],
|
||||
notify: true,
|
||||
});
|
||||
}
|
||||
|
||||
const { data: inv, error: invError } = await tryCatch(
|
||||
//prodQuery(sqlQuery.query, "Inventory data"),
|
||||
runDatamartQuery({ name: "inventory", options: { historical: "x" } }),
|
||||
);
|
||||
|
||||
const { data: av, error: avError } = (await tryCatch(
|
||||
runDatamartQuery({ name: "activeArticles", options: {} }),
|
||||
)) as any;
|
||||
|
||||
if (invError) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "logistics",
|
||||
subModule: "inv",
|
||||
message: `Error getting inventory info from prod query`,
|
||||
data: invError as any,
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (avError) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "logistics",
|
||||
subModule: "inv",
|
||||
message: `Error getting article info from prod query`,
|
||||
data: invError as any,
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
// shape the data to go into our table
|
||||
const plantToken = process.env.PROD_PLANT_TOKEN ?? "test1";
|
||||
const importInv = (inv.data ? inv.data : []) as Inventory[];
|
||||
const importData = importInv.map((i) => {
|
||||
return {
|
||||
histDate: sql`(NOW())::date`,
|
||||
plantToken: plantToken,
|
||||
article: i.article,
|
||||
articleDescription: i.alias,
|
||||
materialType:
|
||||
av.data.filter((a: any) => a.article === i.article).length > 0
|
||||
? av.data.filter((a: any) => a.article === i.article)[0]
|
||||
?.TypeOfMaterial
|
||||
: "Item not defined",
|
||||
total_QTY: i.total_palletQTY ?? "0.00",
|
||||
available_QTY: i.available_QTY ?? "0.00",
|
||||
coa_QTY: i.coa_QTY ?? "0.00",
|
||||
held_QTY: i.held_QTY ?? "0.00",
|
||||
consignment_QTY: i.consignment_qty ?? "0.00",
|
||||
lot_Number: i.lot ?? "0",
|
||||
locationId: i.locationId ?? "0",
|
||||
location: i.laneDescription ?? "Missing lane",
|
||||
whseId: i.warehouseId ?? "0",
|
||||
whseName: i.warehouseDescription ?? "Missing warehouse",
|
||||
};
|
||||
});
|
||||
|
||||
const { data: dataImport, error: errorImport } = await tryCatch(
|
||||
db.insert(invHistoricalData).values(importData),
|
||||
);
|
||||
|
||||
if (errorImport) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "logistics",
|
||||
subModule: "inv",
|
||||
message: `Error adding historical data to lst db`,
|
||||
data: errorImport as any,
|
||||
notify: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (dataImport) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "info",
|
||||
module: "logistics",
|
||||
subModule: "inv",
|
||||
message: `Historical data was added to lst :D`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "info",
|
||||
module: "logistics",
|
||||
subModule: "inv",
|
||||
message: `Historical Data for: ${format(today, "yyyy-MM-dd")}, is already added and nothing to do.`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "info",
|
||||
module: "logistics",
|
||||
subModule: "inv",
|
||||
message: `Some weird crazy error just happened and didnt get captured during the historical inv check.`,
|
||||
data: [],
|
||||
notify: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const historicalSchedule = async () => {
|
||||
// running the history in case my silly ass dose an update around the shift change time lol, this will prevent loss data. it might be off a little but no one cares
|
||||
historicalInvImport();
|
||||
|
||||
const sqlQuery = sqlQuerySelector(`shiftChange`) as SqlQuery;
|
||||
|
||||
if (!sqlQuery.success) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "logistics",
|
||||
subModule: "query",
|
||||
message: `Error getting shiftChange sql file`,
|
||||
data: [sqlQuery.message],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
const { data, error } = await tryCatch(
|
||||
prodQuery(sqlQuery.query, "Shift Change data"),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "logistics",
|
||||
subModule: "query",
|
||||
message: `Error getting shiftChange info`,
|
||||
data: error as any,
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
// shift split
|
||||
const shiftTimeSplit = data?.data[0]?.shiftChange.split(":");
|
||||
|
||||
const cronSetup = `0 ${
|
||||
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0"
|
||||
} ${
|
||||
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7"
|
||||
} * * *`;
|
||||
|
||||
createCronJob("historicalInv", cronSetup, () => historicalInvImport());
|
||||
};
|
||||
@@ -14,20 +14,82 @@
|
||||
*/
|
||||
|
||||
import { Router } from "express";
|
||||
import multer from "multer";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { printerLog } from "../db/schema/printerLogs.schema.js";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
|
||||
type PrinterEvent = {
|
||||
name: string;
|
||||
condition: string;
|
||||
message: string;
|
||||
};
|
||||
const r = Router();
|
||||
const upload = multer();
|
||||
|
||||
r.post("/printer/listener/:printer", async (req, res) => {
|
||||
const parseZebraAlert = (body: any): PrinterEvent => {
|
||||
const name = body.uniqueId || "unknown";
|
||||
const decoded = decodeURIComponent(body.alertMsg || "");
|
||||
|
||||
const [conditionRaw, ...rest] = decoded.split(":");
|
||||
const condition = conditionRaw?.toLowerCase()?.trim() || "unknown";
|
||||
const message = rest.join(":").trim();
|
||||
|
||||
return {
|
||||
name,
|
||||
condition,
|
||||
message,
|
||||
};
|
||||
};
|
||||
|
||||
r.post("/printer/listener/:printer", upload.any(), async (req, res) => {
|
||||
const { printer: printerName } = req.params;
|
||||
console.log(req.body);
|
||||
const event: PrinterEvent = parseZebraAlert(req.body);
|
||||
|
||||
const rawIp =
|
||||
req.headers["x-forwarded-for"]?.toString().split(",")[0]?.trim() ||
|
||||
req.socket.remoteAddress ||
|
||||
req.ip;
|
||||
|
||||
const ip = rawIp?.replace("::ffff:", "");
|
||||
|
||||
// post the new message
|
||||
const { data, error } = await tryCatch(
|
||||
db
|
||||
.insert(printerLog)
|
||||
.values({
|
||||
ip: ip?.replace("::ffff:", ""),
|
||||
name: printerName,
|
||||
printerSN: event.name,
|
||||
condition: event.condition,
|
||||
message: event.message,
|
||||
})
|
||||
.returning(),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return apiReturn(res, {
|
||||
success: false,
|
||||
level: "info",
|
||||
module: "ocp",
|
||||
subModule: "printing",
|
||||
message: `${printerName} encountered an error posting the log`,
|
||||
data: error as any,
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (data) {
|
||||
// TODO: send message over to the controller to decide what to do next with it
|
||||
}
|
||||
|
||||
return apiReturn(res, {
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "ocp",
|
||||
subModule: "printing",
|
||||
message: `${printerName} just passed over a message`,
|
||||
message: `${printerName} just sent a message`,
|
||||
data: req.body ?? [],
|
||||
status: 200,
|
||||
});
|
||||
|
||||
@@ -10,10 +10,323 @@
|
||||
* printer status will live here this will be how we manage all the levels of status like 3 paused, 1 printing, 8 error, 10 power up, etc...
|
||||
*/
|
||||
|
||||
import { eq } from "drizzle-orm";
|
||||
import net from "net";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { printerData } from "../db/schema/printers.schema.js";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
import { delay } from "../utils/delay.utils.js";
|
||||
import { runProdApi } from "../utils/prodEndpoint.utils.js";
|
||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
|
||||
type Printer = {
|
||||
name: string;
|
||||
humanReadableId: string;
|
||||
type: number;
|
||||
ipAddress: string;
|
||||
port: number;
|
||||
default: boolean;
|
||||
labelInstanceIpAddress: string;
|
||||
labelInstancePort: number;
|
||||
active: boolean;
|
||||
remark: string;
|
||||
processes: number[];
|
||||
};
|
||||
|
||||
const log = createLogger({ module: "ocp", subModule: "printers" });
|
||||
|
||||
export const printerManager = async () => {};
|
||||
|
||||
export const printerHeartBeat = async () => {
|
||||
// heat heats will be defaulted to 60 seconds no reason to allow anything else
|
||||
// heat heats will be defaulted to 60 seconds no reason to allow anything else, and heart beats will only go to assigned printers no need to be monitoring non labeling printers
|
||||
};
|
||||
|
||||
//export const printerStatus = async (statusNr: number, printerId: number) => {};
|
||||
export const printerSync = async () => {
|
||||
// pull the printers from alpla prod and update them in lst
|
||||
|
||||
const printers = await runProdApi({
|
||||
method: "get",
|
||||
endpoint: "/public/v1.0/Administration/Printers",
|
||||
});
|
||||
|
||||
if (!printers?.success) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "ocp",
|
||||
subModule: "printer",
|
||||
message: printers?.message ?? "",
|
||||
data: printers?.data ?? [],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (printers?.success) {
|
||||
const ignorePrinters = ["pdf24", "standard"];
|
||||
|
||||
const validPrinters =
|
||||
printers.data.filter(
|
||||
(n: any) =>
|
||||
!ignorePrinters.includes(n.name.toLowerCase()) && n.ipAddress,
|
||||
) ?? [];
|
||||
if (validPrinters.length) {
|
||||
for (const printer of validPrinters as Printer[]) {
|
||||
// run an update for each printer, do on conflicts based on the printer id
|
||||
log.debug({}, `Add/Updating ${printer.name}`);
|
||||
|
||||
if (printer.active) {
|
||||
await db
|
||||
.insert(printerData)
|
||||
.values({
|
||||
name: printer.name,
|
||||
humanReadableId: printer.humanReadableId,
|
||||
ipAddress: printer.ipAddress,
|
||||
port: printer.port,
|
||||
remark: printer.remark,
|
||||
processes: printer.processes,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: printerData.humanReadableId,
|
||||
set: {
|
||||
name: printer.name,
|
||||
humanReadableId: printer.humanReadableId,
|
||||
ipAddress: printer.ipAddress,
|
||||
port: printer.port,
|
||||
remark: printer.remark,
|
||||
processes: printer.processes,
|
||||
},
|
||||
})
|
||||
.returning();
|
||||
await tcpPrinter(printer);
|
||||
}
|
||||
|
||||
if (!printer.active) {
|
||||
log.warn({}, `${printer.name} is not active so removing from lst.`);
|
||||
await db
|
||||
.delete(printerData)
|
||||
.where(eq(printerData.humanReadableId, printer.humanReadableId));
|
||||
}
|
||||
}
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "ocp",
|
||||
subModule: "printer",
|
||||
message: `${printers.data.length} printers were just synced, this includes new and old printers`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "ocp",
|
||||
subModule: "printer",
|
||||
message: `No printers to update`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
};
|
||||
|
||||
const tcpPrinter = (printer: Printer) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
const socket = new net.Socket();
|
||||
const timeoutMs = 15 * 1000;
|
||||
|
||||
const commands = [
|
||||
{
|
||||
key: "clearAlerts",
|
||||
command: '! U1 setvar "alerts.configured" ""\r\n',
|
||||
},
|
||||
{
|
||||
key: "addAlert",
|
||||
command: `! U1 setvar "alerts.add" "ALL MESSAGES,HTTP-POST,Y,Y,http://${process.env.SERVER_IP}:${process.env.PORT}/lst/api/ocp/printer/listener/${printer.name},0,N,printer"\r\n`,
|
||||
},
|
||||
{
|
||||
key: "setFriendlyName",
|
||||
command: `! U1 setvar "device.friendly_name" "${printer.name}"\r\n`,
|
||||
},
|
||||
{
|
||||
key: "getUniqueId",
|
||||
command: '! U1 getvar "device.unique_id"\r\n',
|
||||
},
|
||||
] as const;
|
||||
|
||||
let currentCommandIndex = 0;
|
||||
let awaitingSerial = false;
|
||||
let settled = false;
|
||||
|
||||
const cleanup = () => {
|
||||
socket.removeAllListeners();
|
||||
socket.destroy();
|
||||
};
|
||||
|
||||
const finish = (err?: unknown) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
clearTimeout(timeout);
|
||||
cleanup();
|
||||
|
||||
if (err) {
|
||||
log.error(
|
||||
{ err, printer: printer.name },
|
||||
`Printer update failed for ${printer.name}: doing the name and alert add directly on the printer.`,
|
||||
);
|
||||
}
|
||||
|
||||
resolve();
|
||||
};
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
finish(`${printer.name} timed out while updating printer config`);
|
||||
}, timeoutMs);
|
||||
|
||||
const sendNext = async () => {
|
||||
if (currentCommandIndex >= commands.length) {
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const current = commands[currentCommandIndex];
|
||||
|
||||
if (!current) {
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
|
||||
awaitingSerial = current.key === "getUniqueId";
|
||||
|
||||
log.info(
|
||||
{ printer: printer.name, command: current.key },
|
||||
`Sending command to ${printer.name}`,
|
||||
);
|
||||
|
||||
socket.write(current.command);
|
||||
|
||||
currentCommandIndex++;
|
||||
|
||||
// Small pause between commands so the printer has breathing room
|
||||
if (currentCommandIndex < commands.length) {
|
||||
await delay(1500);
|
||||
await sendNext();
|
||||
} else {
|
||||
// last command was sent, now wait for final data/close
|
||||
await delay(1500);
|
||||
socket.end();
|
||||
}
|
||||
};
|
||||
|
||||
socket.connect(printer.port, printer.ipAddress, async () => {
|
||||
log.info({}, `Connected to ${printer.name}`);
|
||||
|
||||
try {
|
||||
await sendNext();
|
||||
} catch (error) {
|
||||
finish(
|
||||
error instanceof Error
|
||||
? error
|
||||
: new Error(
|
||||
`Unknown error while sending commands to ${printer.name}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("data", async (data) => {
|
||||
const response = data.toString().trim().replaceAll('"', "");
|
||||
|
||||
log.info(
|
||||
{ printer: printer.name, response },
|
||||
`Received printer response from ${printer.name}`,
|
||||
);
|
||||
|
||||
if (!awaitingSerial) return;
|
||||
|
||||
awaitingSerial = false;
|
||||
|
||||
try {
|
||||
await db
|
||||
.update(printerData)
|
||||
.set({ printerSN: response })
|
||||
.where(eq(printerData.humanReadableId, printer.humanReadableId));
|
||||
} catch (error) {
|
||||
finish(
|
||||
error instanceof Error
|
||||
? error
|
||||
: new Error(`Failed to update printer SN for ${printer.name}`),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("close", () => {
|
||||
log.info({}, `Closed connection to ${printer.name}`);
|
||||
finish();
|
||||
});
|
||||
|
||||
socket.on("error", (err) => {
|
||||
finish(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// const tcpPrinter = async (printer: Printer) => {
|
||||
// const p = new net.Socket();
|
||||
// const commands = [
|
||||
// '! U1 setvar "alerts.configured" ""\r\n', // clean install just remove all alerts
|
||||
// `! U1 setvar "alerts.add" "ALL MESSAGES,HTTP-POST,Y,Y,http://${process.env.SERVER_IP}:${process.env.PORT}/lst/api/ocp/printer/listener/${printer.name},0,N,printer"\r\n`, // add in the all alert
|
||||
// `! U1 setvar "device.friendly_name" "${printer.name}"\r\n`, // change the name to match the alplaprod name
|
||||
// `! U1 getvar "device.unique_id"\r\n`, // this will get mapped into the printer as this is the one we will link to in the db.
|
||||
// //'! U1 getvar "alerts.configured" ""\r\n',
|
||||
// ];
|
||||
|
||||
// let index = 0;
|
||||
// const sendNext = async () => {
|
||||
// if (index >= commands.length) {
|
||||
// p.end();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const cmd = commands[index] as string;
|
||||
// p.write(cmd);
|
||||
// return;
|
||||
// };
|
||||
|
||||
// p.connect(printer.port, printer.ipAddress, async () => {
|
||||
// log.info({}, `Connected to ${printer.name}`);
|
||||
// while (index < commands.length) {
|
||||
// await sendNext();
|
||||
// await delay(2000);
|
||||
// index++;
|
||||
// }
|
||||
// });
|
||||
|
||||
// p.on("data", async (data) => {
|
||||
// // this is just the sn that comes over so we will update this printer.
|
||||
// await db
|
||||
// .update(printerData)
|
||||
// .set({ printerSN: data.toString().trim().replaceAll('"', "") })
|
||||
// .where(eq(printerData.humanReadableId, printer.humanReadableId));
|
||||
|
||||
// // get the name
|
||||
// // p.write('! U1 getvar "device.friendly_name"\r\n');
|
||||
// // p.write('! U1 getvar "device.unique_id"\r\n');
|
||||
// // p.write('! U1 getvar "alerts.configured"\r\n');
|
||||
// });
|
||||
|
||||
// p.on("close", () => {
|
||||
// log.info({}, `Closed connection to ${printer.name}`);
|
||||
// p.destroy();
|
||||
// return;
|
||||
// });
|
||||
|
||||
// p.on("error", (err) => {
|
||||
// log.info(
|
||||
// { stack: err },
|
||||
// `${printer.name} encountered an error while trying to update`,
|
||||
// );
|
||||
// return;
|
||||
// });
|
||||
// };
|
||||
|
||||
38
backend/ocp/ocp.printer.update.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* the route that listens for the printers post.
|
||||
*
|
||||
* and http-post alert should be setup on each printer pointing to at min you will want to make the alert for
|
||||
* pause printer, you can have all on here as it will also monitor and do things on all messages
|
||||
*
|
||||
* http://{serverIP}:2222/lst/api/ocp/printer/listener/{printerName}
|
||||
*
|
||||
* the messages will be sent over to the db for logging as well as specific ones will do something
|
||||
*
|
||||
* pause will validate if can print
|
||||
* close head will repause the printer so it wont print a label
|
||||
* power up will just repause the printer so it wont print a label
|
||||
*/
|
||||
|
||||
import { Router } from "express";
|
||||
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
//import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
import { printerSync } from "./ocp.printer.manage.js";
|
||||
|
||||
const r = Router();
|
||||
|
||||
r.post("/printer/update", async (_, res) => {
|
||||
printerSync();
|
||||
return apiReturn(res, {
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "ocp",
|
||||
subModule: "printing",
|
||||
message:
|
||||
"Printer update has been triggered to monitor progress please head to the logs.",
|
||||
data: [],
|
||||
status: 200,
|
||||
});
|
||||
});
|
||||
|
||||
export default r;
|
||||
@@ -2,6 +2,7 @@ import { type Express, Router } from "express";
|
||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
||||
import listener from "./ocp.printer.listener.js";
|
||||
import update from "./ocp.printer.update.js";
|
||||
|
||||
export const setupOCPRoutes = (baseUrl: string, app: Express) => {
|
||||
//setup all the routes
|
||||
@@ -16,6 +17,7 @@ export const setupOCPRoutes = (baseUrl: string, app: Express) => {
|
||||
// auth routes below here
|
||||
router.use(requireAuth);
|
||||
|
||||
router.use(update);
|
||||
//router.use("");
|
||||
|
||||
app.use(`${baseUrl}/api/ocp`, router);
|
||||
|
||||
@@ -7,12 +7,17 @@ import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
export let pool: sql.ConnectionPool;
|
||||
export let connected: boolean = false;
|
||||
export let reconnecting = false;
|
||||
// start the delay out as 2 seconds
|
||||
let delayStart = 2000;
|
||||
let attempt = 0;
|
||||
const maxAttempts = 10;
|
||||
|
||||
export const connectProdSql = async () => {
|
||||
const serverUp = await checkHostnamePort(`${process.env.PROD_SERVER}:1433`);
|
||||
if (!serverUp) {
|
||||
// we will try to reconnect
|
||||
connected = false;
|
||||
reconnectToSql();
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
@@ -48,6 +53,7 @@ export const connectProdSql = async () => {
|
||||
notify: false,
|
||||
});
|
||||
} catch (error) {
|
||||
reconnectToSql();
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
@@ -104,11 +110,6 @@ export const reconnectToSql = async () => {
|
||||
//set reconnecting to true while we try to reconnect
|
||||
reconnecting = true;
|
||||
|
||||
// start the delay out as 2 seconds
|
||||
let delayStart = 2000;
|
||||
let attempt = 0;
|
||||
const maxAttempts = 10;
|
||||
|
||||
while (!connected && attempt < maxAttempts) {
|
||||
attempt++;
|
||||
log.info(
|
||||
@@ -121,7 +122,7 @@ export const reconnectToSql = async () => {
|
||||
|
||||
if (!serverUp) {
|
||||
delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -133,19 +134,12 @@ export const reconnectToSql = async () => {
|
||||
);
|
||||
} catch (error) {
|
||||
delayStart = Math.min(delayStart * 2, 30000);
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "db",
|
||||
message: "Failed to reconnect to the prod sql server.",
|
||||
data: [error],
|
||||
notify: false,
|
||||
});
|
||||
delayStart = Math.min(delayStart * 2, 30000);
|
||||
log.error({ error }, "Failed to reconnect to the prod sql server.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
if (!connected && attempt >= maxAttempts) {
|
||||
log.error(
|
||||
{ notify: true },
|
||||
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
import {
|
||||
connected,
|
||||
pool,
|
||||
reconnecting,
|
||||
reconnectToSql,
|
||||
} from "./prodSqlConnection.controller.js";
|
||||
import { connected, pool } from "./prodSqlConnection.controller.js";
|
||||
|
||||
interface SqlError extends Error {
|
||||
code?: string;
|
||||
@@ -22,29 +17,15 @@ interface SqlError extends Error {
|
||||
*/
|
||||
export const prodQuery = async (queryToRun: string, name: string) => {
|
||||
if (!connected) {
|
||||
reconnectToSql();
|
||||
|
||||
if (reconnecting) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "prodSql",
|
||||
message: `The sql ${process.env.PROD_PLANT_TOKEN} is trying to reconnect already`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
} else {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "prodSql",
|
||||
message: `${process.env.PROD_PLANT_TOKEN} is not connected, and failed to connect.`,
|
||||
data: [],
|
||||
notify: true,
|
||||
});
|
||||
}
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "prodSql",
|
||||
message: `${process.env.PROD_PLANT_TOKEN} is offline or attempting to reconnect`,
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
//change to the correct server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use AlplaPROD_test1
|
||||
|
||||
SELECT V_Artikel.IdArtikelvarianten,
|
||||
SELECT V_Artikel.IdArtikelvarianten as article,
|
||||
V_Artikel.Bezeichnung,
|
||||
V_Artikel.ArtikelvariantenTypBez,
|
||||
V_Artikel.PreisEinheitBez,
|
||||
43
backend/prodSql/queries/datamart.activeArticles2.sql
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
This will be replacing activeArticles once all data is remapped into this query.
|
||||
make a note in the docs this activeArticles will go stale sooner or later.
|
||||
**/
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
select a.Id,
|
||||
a.HumanReadableId as av,
|
||||
a.Alias as alias,
|
||||
p.LoadingUnitsPerTruck as loadingUnitsPerTruck,
|
||||
p.LoadingUnitsPerTruck * p.LoadingUnitPieces as qtyPerTruck,
|
||||
p.LoadingUnitPieces,
|
||||
case when i.MinQuantity IS NOT NULL then round(cast(i.MinQuantity as float), 2) else 0 end as min,
|
||||
case when i.MaxQuantity IS NOT NULL then round(cast(i.MaxQuantity as float),2) else 0 end as max
|
||||
from masterData.Article (nolock) as a
|
||||
|
||||
/* sales price */
|
||||
left join
|
||||
(select *
|
||||
from (select
|
||||
id,
|
||||
PackagingId,
|
||||
ArticleId,
|
||||
DefaultCustomer,
|
||||
ROW_NUMBER() OVER (PARTITION BY ArticleId ORDER BY ValidAfter DESC) AS RowNum
|
||||
from masterData.SalesPrice (nolock)
|
||||
where DefaultCustomer = 1) as x
|
||||
where RowNum = 1
|
||||
) as s
|
||||
on a.id = s.ArticleId
|
||||
|
||||
/* pkg instructions */
|
||||
left join
|
||||
masterData.PackagingInstruction (nolock) as p
|
||||
on s.PackagingId = p.id
|
||||
|
||||
/* stock limits */
|
||||
left join
|
||||
masterData.StockLimit (nolock) as i
|
||||
on a.id = i.ArticleId
|
||||
|
||||
where a.active = 1
|
||||
and a.HumanReadableId in ([articles])
|
||||
45
backend/prodSql/queries/datamart.customerInventory.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
select x.idartikelVarianten as av
|
||||
,ArtikelVariantenAlias as Alias
|
||||
--x.Lfdnr as RunningNumber,
|
||||
--,round(sum(EinlagerungsMengeVPKSum),0) as Total_Pallets
|
||||
--,sum(EinlagerungsMengeSum) as Total_PalletQTY
|
||||
,round(sum(VerfuegbareMengeVPKSum),0) as Avalible_Pallets
|
||||
,sum(VerfuegbareMengeSum) as Avaliable_PalletQTY
|
||||
,sum(case when c.Description LIKE '%COA%' then GesperrteMengeVPKSum else 0 end) as COA_Pallets
|
||||
,sum(case when c.Description LIKE '%COA%' then GesperrteMengeSum else 0 end) as COA_QTY
|
||||
--,sum(case when c.Description NOT LIKE '%COA%' then GesperrteMengeVPKSum else 0 end) as Held_Pallets
|
||||
--,sum(case when c.Description NOT LIKE '%COA%' then GesperrteMengeSum else 0 end) as Held_QTY
|
||||
,IdProdPlanung as Lot
|
||||
--,IdAdressen
|
||||
--,x.AdressBez
|
||||
--,*
|
||||
from [AlplaPROD_test1].dbo.[V_LagerPositionenBarcodes] (nolock) x
|
||||
|
||||
left join
|
||||
[AlplaPROD_test1].dbo.T_EtikettenGedruckt (nolock) on
|
||||
x.Lfdnr = T_EtikettenGedruckt.Lfdnr AND T_EtikettenGedruckt.Lfdnr > 1
|
||||
|
||||
left join
|
||||
|
||||
(SELECT *
|
||||
FROM [AlplaPROD_test1].[dbo].[T_BlockingDefects] (nolock) where Active = 1) as c
|
||||
on x.IdMainDefect = c.IdBlockingDefect
|
||||
/*
|
||||
The data below will be controlled by the user in excell by default everything will be passed over
|
||||
IdAdressen = 3
|
||||
*/
|
||||
where
|
||||
--IdArtikelTyp = 1
|
||||
x.IdWarenlager not in (6, 1)
|
||||
--and IdAdressen
|
||||
--and x.IdWarenlager in (0)
|
||||
|
||||
|
||||
group by x.IdArtikelVarianten
|
||||
,ArtikelVariantenAlias
|
||||
,IdProdPlanung
|
||||
--,c.Description
|
||||
,IdAdressen
|
||||
,x.AdressBez
|
||||
--, x.Lfdnr
|
||||
order by x.IdArtikelVarianten
|
||||
29
backend/prodSql/queries/datamart.fakeEDIUpdate.sql
Normal file
@@ -0,0 +1,29 @@
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
select
|
||||
customerartno as CustomerArticleNumber
|
||||
,h.CustomerOrderNumber as CustomerOrderNumber
|
||||
,l.CustomerLineItemNumber as CustomerLineNumber
|
||||
,r.CustomerReleaseNumber as CustomerRealeaseNumber
|
||||
,r.Quantity
|
||||
,format(r.DeliveryDate, 'MM/dd/yyyy HH:mm') as DeliveryDate
|
||||
,h.CustomerHumanReadableId as CustomerID
|
||||
,r.Remark
|
||||
--,*
|
||||
from [order].[Release] as r (nolock)
|
||||
|
||||
left join
|
||||
[order].LineItem as l (nolock) on
|
||||
l.id = r.LineItemId
|
||||
|
||||
left join
|
||||
[order].Header as h (nolock) on
|
||||
h.id = l.HeaderId
|
||||
|
||||
WHERE releaseState not in (1, 2, 3, 4)
|
||||
AND h.CreatedByEdi = 1
|
||||
AND r.deliveryDate < getdate() + 1
|
||||
--AND h.CustomerHumanReadableId in (0)
|
||||
|
||||
|
||||
order by r.deliveryDate
|
||||
8
backend/prodSql/queries/datamart.forecast.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
SELECT format(RequirementDate, 'yyyy-MM-dd') as requirementDate
|
||||
,ArticleHumanReadableId
|
||||
,CustomerArticleNumber
|
||||
,ArticleDescription
|
||||
,Quantity
|
||||
FROM [test1_AlplaPROD2.0_Read].[forecast].[Forecast]
|
||||
where DeliveryAddressHumanReadableId in ([customers])
|
||||
order by RequirementDate
|
||||
64
backend/prodSql/queries/datamart.inventory.sql
Normal file
@@ -0,0 +1,64 @@
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
select
|
||||
ArticleHumanReadableId as article
|
||||
,ArticleAlias as alias
|
||||
,round(sum(QuantityLoadingUnits),2) total_pallets
|
||||
,round(sum(Quantity),2) as total_palletQTY
|
||||
,round(sum(case when State = 0 then QuantityLoadingUnits else 0 end),2) available_Pallets
|
||||
,round(sum(case when State = 0 then Quantity else 0 end),2) available_QTY
|
||||
,round(sum(case when b.HumanReadableId = 864 then QuantityLoadingUnits else 0 end),2) as coa_Pallets
|
||||
,round(sum(case when b.HumanReadableId = 864 then Quantity else 0 end),2) as coa_QTY
|
||||
,round(sum(case when b.HumanReadableId <> 864 then QuantityLoadingUnits else 0 end),2) as held_Pallets
|
||||
,round(sum(case when b.HumanReadableId <> 864 then Quantity else 0 end),2) as held_QTY
|
||||
,round(sum(case when w.type = 7 then QuantityLoadingUnits else 0 end),2) as consignment_Pallets
|
||||
,round(sum(case when w.type = 7 then Quantity else 0 end),2) as consignment_qty
|
||||
--,l.RunningNumber
|
||||
|
||||
/** datamart include lot number **/
|
||||
--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot
|
||||
|
||||
/** data mart include location data **/
|
||||
--,l.WarehouseDescription,l.LaneDescription
|
||||
|
||||
/** historical section **/
|
||||
--,l.ProductionLotRunningNumber as lot,l.warehousehumanreadableid as warehouseId,l.WarehouseDescription as warehouseDescription,l.lanehumanreadableid as locationId,l.lanedescription as laneDescription
|
||||
|
||||
,articleTypeName
|
||||
|
||||
FROM [warehousing].[WarehouseUnit] as l (nolock)
|
||||
left join
|
||||
(
|
||||
SELECT [Id]
|
||||
,[HumanReadableId]
|
||||
,d.[Description]
|
||||
,[DefectGroupId]
|
||||
,[IsActive]
|
||||
FROM [blocking].[BlockingDefect] as g (nolock)
|
||||
|
||||
left join
|
||||
[AlplaPROD_test1].dbo.[T_BlockingDefects] as d (nolock) on
|
||||
d.IdGlobalBlockingDefect = g.HumanReadableId
|
||||
) as b on
|
||||
b.id = l.MainDefectId
|
||||
|
||||
left join
|
||||
[warehousing].[warehouse] as w (nolock) on
|
||||
w.id = l.warehouseid
|
||||
|
||||
where LaneHumanReadableId not in (20000,21000)
|
||||
group by ArticleHumanReadableId,
|
||||
ArticleAlias,
|
||||
ArticleTypeName
|
||||
--,l.RunningNumber
|
||||
|
||||
/** datamart include lot number **/
|
||||
--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber
|
||||
|
||||
/** data mart include location data **/
|
||||
--,l.WarehouseDescription,l.LaneDescription
|
||||
|
||||
/** historical section **/
|
||||
--,l.ProductionLotRunningNumber,l.warehousehumanreadableid,l.WarehouseDescription,l.lanehumanreadableid,l.lanedescription
|
||||
|
||||
order by ArticleHumanReadableId
|
||||
33
backend/prodSql/queries/datamart.openOrders.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
select
|
||||
customerartno
|
||||
,r.ArticleHumanReadableId as article
|
||||
,r.ArticleAlias as articleAlias
|
||||
,ReleaseNumber
|
||||
,h.CustomerOrderNumber as header
|
||||
,l.CustomerLineItemNumber as lineItem
|
||||
,r.CustomerReleaseNumber as releaseNumber
|
||||
,r.LoadingUnits
|
||||
,r.Quantity
|
||||
,r.TradeUnits
|
||||
,h.CustomerHumanReadableId
|
||||
,r.DeliveryAddressDescription
|
||||
,format(r.LoadingDate, 'MM/dd/yyyy HH:mm') as loadingDate
|
||||
,format(r.DeliveryDate, 'MM/dd/yyyy HH:mm') as deliveryDate
|
||||
,r.Remark
|
||||
--,*
|
||||
from [order].[Release] as r (nolock)
|
||||
|
||||
left join
|
||||
[order].LineItem as l (nolock) on
|
||||
l.id = r.LineItemId
|
||||
|
||||
left join
|
||||
[order].Header as h (nolock) on
|
||||
h.id = l.HeaderId
|
||||
|
||||
WHERE releasestate not in (1, 2, 4)
|
||||
AND r.deliverydate between getDate() + -[startDay] and getdate() + [endDay]
|
||||
|
||||
order by r.deliverydate
|
||||
19
backend/prodSql/queries/datamart.productionData.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
use [test1_AlplaPROD2.0_Reporting]
|
||||
|
||||
declare @startDate nvarchar(30) = '[startDate]' --'2024-12-30'
|
||||
declare @endDate nvarchar(30) = '[endDate]' --'2025-08-09'
|
||||
|
||||
select MachineLocation,
|
||||
ArticleHumanReadableId as article,
|
||||
sum(Quantity) as Produced,
|
||||
count(Quantity) as palletsProdued,
|
||||
FORMAT(convert(date, ProductionDay), 'M/d/yyyy') as ProductionDay,
|
||||
ProductionLotHumanReadableId as productionLot
|
||||
|
||||
from [reporting_productionControlling].[ScannedUnit] (nolock)
|
||||
|
||||
where convert(date, ProductionDay) between @startDate and @endDate
|
||||
and ArticleHumanReadableId in ([articles])
|
||||
and BookedOut is null
|
||||
|
||||
group by MachineLocation, ArticleHumanReadableId,ProductionDay, ProductionLotHumanReadableId
|
||||
23
backend/prodSql/queries/datamart.psiDeliveryData.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
use AlplaPROD_test1
|
||||
/**
|
||||
|
||||
move this over to the delivery date range query once we have the shift data mapped over correctly.
|
||||
|
||||
update the psi stuff on this as well.
|
||||
**/
|
||||
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
|
||||
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
|
||||
|
||||
|
||||
select IdArtikelVarianten,
|
||||
ArtikelVariantenBez,
|
||||
sum(Menge) totalDelivered,
|
||||
case when convert(time, upd_date) between '00:00' and '07:00' then convert(date, upd_date - 1) else convert(date, upd_date) end as ShippingDate
|
||||
|
||||
from dbo.V_LadePlanungenLadeAuftragAbruf (nolock)
|
||||
|
||||
where upd_date between CONVERT(datetime, @start_date + ' 7:00') and CONVERT(datetime, @end_date + ' 7:00')
|
||||
and IdArtikelVarianten in ([articles])
|
||||
|
||||
group by IdArtikelVarianten, upd_date,
|
||||
ArtikelVariantenBez
|
||||
32
backend/prodSql/queries/datamart.psiPlanningData.sql
Normal file
@@ -0,0 +1,32 @@
|
||||
use AlplaPROD_test1
|
||||
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
|
||||
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
|
||||
/*
|
||||
articles will need to be passed over as well as the date structure we want to see
|
||||
*/
|
||||
|
||||
select x.IdArtikelvarianten As Article,
|
||||
ProduktionAlias as Description,
|
||||
standort as MachineId,
|
||||
MaschinenBezeichnung as MachineName,
|
||||
--MaschZyklus as PlanningCycleTime,
|
||||
x.IdProdPlanung as LotNumber,
|
||||
FORMAT(ProdTag, 'MM/dd/yyyy') as ProductionDay,
|
||||
x.planMenge as TotalPlanned,
|
||||
ProduktionMenge as QTYPerDay,
|
||||
round(ProduktionMengeVPK, 2) PalDay,
|
||||
Status as finished
|
||||
--MaschStdAuslastung as nee
|
||||
|
||||
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock) as x
|
||||
|
||||
left join
|
||||
dbo.V_ProdPlanung (nolock) as p on
|
||||
x.IdProdPlanung = p.IdProdPlanung
|
||||
|
||||
where ProdTag between @start_date and @end_date
|
||||
and p.IdArtikelvarianten in ([articles])
|
||||
--and V_ProdLosProduktionJeProdTag_PLANNING.IdKunde = 10
|
||||
--and IdProdPlanung = 18442
|
||||
|
||||
order by ProdTag desc
|
||||
4
backend/prodSql/queries/shiftChange.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
select top(1) convert(varchar(8) ,
|
||||
convert(time,startdate), 108) as shiftChange
|
||||
from [test1_AlplaPROD2.0_Read].[masterData].[ShiftDefinition]
|
||||
where teamNumber = 1
|
||||
@@ -10,6 +10,7 @@ import { setupOCPRoutes } from "./ocp/ocp.routes.js";
|
||||
import { setupOpendockRoutes } from "./opendock/opendock.routes.js";
|
||||
import { setupProdSqlRoutes } from "./prodSql/prodSql.routes.js";
|
||||
import { setupSystemRoutes } from "./system/system.routes.js";
|
||||
import { setupTCPRoutes } from "./tcpServer/tcp.routes.js";
|
||||
import { setupUtilsRoutes } from "./utils/utils.routes.js";
|
||||
|
||||
export const setupRoutes = (baseUrl: string, app: Express) => {
|
||||
@@ -24,4 +25,5 @@ export const setupRoutes = (baseUrl: string, app: Express) => {
|
||||
setupOpendockRoutes(baseUrl, app);
|
||||
setupNotificationRoutes(baseUrl, app);
|
||||
setupOCPRoutes(baseUrl, app);
|
||||
setupTCPRoutes(baseUrl, app);
|
||||
};
|
||||
|
||||
@@ -6,14 +6,17 @@ import { dbCleanup } from "./db/dbCleanup.controller.js";
|
||||
import { type Setting, settings } from "./db/schema/settings.schema.js";
|
||||
import { connectGPSql } from "./gpSql/gpSqlConnection.controller.js";
|
||||
import { createLogger } from "./logger/logger.controller.js";
|
||||
import { historicalSchedule } from "./logistics/logistics.historicalInv.js";
|
||||
import { startNotifications } from "./notification/notification.controller.js";
|
||||
import { createNotifications } from "./notification/notifications.master.js";
|
||||
import { printerSync } from "./ocp/ocp.printer.manage.js";
|
||||
import { monitorReleaseChanges } from "./opendock/openDockRreleaseMonitor.utils.js";
|
||||
import { opendockSocketMonitor } from "./opendock/opendockSocketMonitor.utils.js";
|
||||
import { connectProdSql } from "./prodSql/prodSqlConnection.controller.js";
|
||||
import { monitorAlplaPurchase } from "./purchase/purchase.controller.js";
|
||||
import { setupSocketIORoutes } from "./socket.io/serverSetup.js";
|
||||
import { baseSettingValidationCheck } from "./system/settingsBase.controller.js";
|
||||
import { startTCPServer } from "./tcpServer/tcp.server.js";
|
||||
import { createCronJob } from "./utils/croner.utils.js";
|
||||
import { sendEmail } from "./utils/sendEmail.utils.js";
|
||||
|
||||
@@ -29,6 +32,7 @@ const start = async () => {
|
||||
const log = createLogger({ module: "system", subModule: "main start" });
|
||||
|
||||
// triggering long lived processes
|
||||
startTCPServer();
|
||||
connectProdSql();
|
||||
connectGPSql();
|
||||
|
||||
@@ -52,11 +56,16 @@ const start = async () => {
|
||||
monitorAlplaPurchase();
|
||||
}
|
||||
|
||||
if (systemSettings.filter((n) => n.name === "ocp")[0]?.active) {
|
||||
printerSync();
|
||||
}
|
||||
|
||||
// these jobs below are system jobs and should run no matter what.
|
||||
createCronJob("JobAuditLogCleanUp", "0 0 5 * * *", () =>
|
||||
dbCleanup("jobs", 30),
|
||||
);
|
||||
createCronJob("logsCleanup", "0 15 5 * * *", () => dbCleanup("logs", 120));
|
||||
historicalSchedule();
|
||||
|
||||
// one shots only needed to run on server startups
|
||||
createNotifications();
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { Router } from "express";
|
||||
import { connected as gpSql } from "../gpSql/gpSqlConnection.controller.js";
|
||||
import { connected as prodSql } from "../prodSql/prodSqlConnection.controller.js";
|
||||
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||
import {
|
||||
type SqlQuery,
|
||||
sqlQuerySelector,
|
||||
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||
import { isServerRunning } from "../tcpServer/tcp.server.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -25,6 +28,9 @@ router.get("/", async (_, res) => {
|
||||
: [],
|
||||
eomFGPkgSheetVersion: 1, // this is the excel file version when we have a change to the macro we want to grab this
|
||||
masterMacroFile: 1,
|
||||
tcpServerOnline: isServerRunning,
|
||||
sqlServerConnected: prodSql,
|
||||
gpServerConnected: gpSql,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
51
backend/tcpServer/tcp.printerListener.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { printerLog } from "../db/schema/printerLogs.schema.js";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
|
||||
export type PrinterData = {
|
||||
ip: string;
|
||||
name: string;
|
||||
condition: string;
|
||||
message: string;
|
||||
date?: string;
|
||||
printerSN: string;
|
||||
};
|
||||
|
||||
const log = createLogger({ module: "tcp", submodule: "create_server" });
|
||||
|
||||
export const printerListen = async (tcpData: PrinterData) => {
|
||||
const ip = tcpData.ip?.replace("::ffff:", "");
|
||||
|
||||
// post the new message
|
||||
const { data, error } = await tryCatch(
|
||||
db
|
||||
.insert(printerLog)
|
||||
.values({
|
||||
ip,
|
||||
name: tcpData.name,
|
||||
condition: tcpData.condition,
|
||||
message: tcpData.message,
|
||||
printerSN: tcpData.printerSN,
|
||||
})
|
||||
.returning(),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "tcp",
|
||||
subModule: "post",
|
||||
message: "Failed to post tcp printer data.",
|
||||
data: [],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (data) {
|
||||
log.info({}, `${tcpData.name} sent a message over`);
|
||||
// TODO: send message over to the controller to decide what to do next with it
|
||||
}
|
||||
};
|
||||
14
backend/tcpServer/tcp.routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { Express } from "express";
|
||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||
import restart from "./tcpRestart.route.js";
|
||||
import start from "./tcpStart.route.js";
|
||||
import stop from "./tcpStop.route.js";
|
||||
|
||||
export const setupTCPRoutes = (baseUrl: string, app: Express) => {
|
||||
//stats will be like this as we dont need to change this
|
||||
app.use(`${baseUrl}/api/tcp/start`, requireAuth, start);
|
||||
app.use(`${baseUrl}/api/tcp/stop`, requireAuth, stop);
|
||||
app.use(`${baseUrl}/api/tcp/restart`, requireAuth, restart);
|
||||
|
||||
// all other system should be under /api/system/*
|
||||
};
|
||||
180
backend/tcpServer/tcp.server.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
import net from "node:net";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { printerData } from "../db/schema/printers.schema.js";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
import { delay } from "../utils/delay.utils.js";
|
||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
import { type PrinterData, printerListen } from "./tcp.printerListener.js";
|
||||
|
||||
let tcpServer: net.Server;
|
||||
const tcpSockets: Set<net.Socket> = new Set();
|
||||
export let isServerRunning = false;
|
||||
|
||||
const port = parseInt(process.env.TCP_PORT ?? "2222", 10);
|
||||
|
||||
const parseTcpAlert = (input: string) => {
|
||||
// guard
|
||||
const colonIndex = input.indexOf(":");
|
||||
if (colonIndex === -1) return null;
|
||||
|
||||
const condition = input.slice(0, colonIndex).trim();
|
||||
const rest = input.slice(colonIndex + 1).trim();
|
||||
|
||||
// extract all [ ... ] blocks from rest
|
||||
const matches = [...rest.matchAll(/\[(.*?)\]/g)];
|
||||
|
||||
const date = matches[0]?.[1] ?? "";
|
||||
const name = matches[1]?.[1] ?? "";
|
||||
|
||||
// message = everything before first "["
|
||||
const bracketIndex = rest.indexOf("[");
|
||||
const message =
|
||||
bracketIndex !== -1 ? rest.slice(0, bracketIndex).trim() : rest;
|
||||
|
||||
return {
|
||||
condition,
|
||||
message,
|
||||
date,
|
||||
name,
|
||||
};
|
||||
};
|
||||
const log = createLogger({ module: "tcp", submodule: "create_server" });
|
||||
export const startTCPServer = async () => {
|
||||
tcpServer = net.createServer(async (socket) => {
|
||||
tcpSockets.add(socket);
|
||||
socket.on("data", async (data: Buffer) => {
|
||||
const parseData = data.toString("utf-8").trimEnd();
|
||||
|
||||
// check where the data came from then we do something.
|
||||
|
||||
const ip = socket.remoteAddress ?? "127.0.0.1";
|
||||
const { data: printer, error: pError } = await tryCatch(
|
||||
db
|
||||
.select()
|
||||
.from(printerData)
|
||||
.where(eq(printerData.ipAddress, ip.replace("::ffff:", ""))),
|
||||
);
|
||||
if (pError) {
|
||||
log.error(
|
||||
{ stack: pError },
|
||||
"There was an error getting printer data for tcp check",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (printer?.length) {
|
||||
const printerData = {
|
||||
...parseTcpAlert(parseData),
|
||||
ip,
|
||||
printerSN: printer[0]?.printerSN,
|
||||
name: printer[0]?.name,
|
||||
};
|
||||
|
||||
printerListen(printerData as PrinterData);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("end", () => {
|
||||
log.debug({}, "Client disconnected");
|
||||
// just in case we dont fully disconnect
|
||||
setTimeout(() => {
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
}, 1000);
|
||||
tcpSockets.delete(socket);
|
||||
});
|
||||
|
||||
socket.on("error", (err: Error) => {
|
||||
log.error({ stack: err }, `Socket error:", ${err}`);
|
||||
// just in case we dont fully disconnect
|
||||
setTimeout(() => {
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
}, 1000);
|
||||
tcpSockets.delete(socket);
|
||||
});
|
||||
});
|
||||
|
||||
tcpServer.listen(port, () => {
|
||||
log.info({}, `TCP Server listening on port ${port}`);
|
||||
});
|
||||
|
||||
isServerRunning = true;
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "tcp",
|
||||
subModule: "create_server",
|
||||
message: "TCP server started.",
|
||||
data: [],
|
||||
notify: false,
|
||||
room: "",
|
||||
});
|
||||
};
|
||||
|
||||
export const stopTCPServer = async () => {
|
||||
if (!isServerRunning)
|
||||
return { success: false, message: "Server is not running" };
|
||||
for (const socket of tcpSockets) {
|
||||
socket.destroy();
|
||||
}
|
||||
tcpSockets.clear();
|
||||
tcpServer.close(() => {
|
||||
log.info({}, "TCP Server stopped");
|
||||
});
|
||||
isServerRunning = false;
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "tcp",
|
||||
subModule: "create_server",
|
||||
message: "TCP server stopped.",
|
||||
data: [],
|
||||
notify: false,
|
||||
room: "",
|
||||
});
|
||||
};
|
||||
|
||||
export const restartTCPServer = async () => {
|
||||
if (!isServerRunning) {
|
||||
startTCPServer();
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "warn",
|
||||
module: "tcp",
|
||||
subModule: "create_server",
|
||||
message: "Server is not running will try to start it",
|
||||
data: [],
|
||||
notify: false,
|
||||
room: "",
|
||||
});
|
||||
} else {
|
||||
for (const socket of tcpSockets) {
|
||||
socket.destroy();
|
||||
}
|
||||
tcpSockets.clear();
|
||||
tcpServer.close(() => {
|
||||
log.info({}, "TCP Server stopped");
|
||||
});
|
||||
isServerRunning = false;
|
||||
|
||||
await delay(1500);
|
||||
|
||||
startTCPServer();
|
||||
}
|
||||
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "tcp",
|
||||
subModule: "create_server",
|
||||
message: "TCP server has been restarted.",
|
||||
data: [],
|
||||
notify: false,
|
||||
room: "",
|
||||
});
|
||||
};
|
||||
19
backend/tcpServer/tcpRestart.route.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Router } from "express";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { restartTCPServer } from "./tcp.server.js";
|
||||
|
||||
const r = Router();
|
||||
|
||||
r.post("/restart", async (_, res) => {
|
||||
const connect = await restartTCPServer();
|
||||
apiReturn(res, {
|
||||
success: connect.success,
|
||||
level: connect.success ? "info" : "error",
|
||||
module: "tcp",
|
||||
subModule: "post",
|
||||
message: "TCP Server has been restarted",
|
||||
data: connect.data,
|
||||
status: connect.success ? 200 : 400,
|
||||
});
|
||||
});
|
||||
export default r;
|
||||
20
backend/tcpServer/tcpStart.route.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Router } from "express";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { startTCPServer } from "./tcp.server.js";
|
||||
|
||||
const r = Router();
|
||||
|
||||
r.post("/start", async (_, res) => {
|
||||
const connect = await startTCPServer();
|
||||
apiReturn(res, {
|
||||
success: connect.success,
|
||||
level: connect.success ? "info" : "error",
|
||||
module: "routes",
|
||||
subModule: "prodSql",
|
||||
message: connect.message,
|
||||
data: connect.data,
|
||||
status: connect.success ? 200 : 400,
|
||||
});
|
||||
});
|
||||
|
||||
export default r;
|
||||
20
backend/tcpServer/tcpStop.route.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Router } from "express";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { stopTCPServer } from "./tcp.server.js";
|
||||
|
||||
const r = Router();
|
||||
|
||||
r.post("/stop", async (_, res) => {
|
||||
const connect = await stopTCPServer();
|
||||
apiReturn(res, {
|
||||
success: connect.success,
|
||||
level: connect.success ? "info" : "error",
|
||||
module: "routes",
|
||||
subModule: "prodSql",
|
||||
message: connect.message,
|
||||
data: [],
|
||||
status: connect.success ? 200 : 400,
|
||||
});
|
||||
});
|
||||
|
||||
export default r;
|
||||
@@ -3,6 +3,7 @@ import { eq } from "drizzle-orm";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { jobAuditLog } from "../db/schema/auditLog.schema.js";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
import type { ReturnHelper } from "./returnHelper.utils.js";
|
||||
|
||||
// example createJob
|
||||
// createCronJob("test Cron", "*/5 * * * * *", async () => {
|
||||
@@ -45,7 +46,7 @@ const cronStats: Record<string, { created: number; replaced: number }> = {};
|
||||
export const createCronJob = async (
|
||||
name: string,
|
||||
schedule: string, // cron string with 8 8 IE: */5 * * * * * every 5th second
|
||||
task: () => Promise<void>, // what function are we passing over
|
||||
task: () => Promise<void | ReturnHelper>, // what function are we passing over
|
||||
source = "unknown",
|
||||
) => {
|
||||
// get the timezone based on the os timezone set
|
||||
|
||||
124
backend/utils/prodEndpoint.utils.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import https from "node:https";
|
||||
import axios from "axios";
|
||||
import { returnFunc } from "./returnHelper.utils.js";
|
||||
import { tryCatch } from "./trycatch.utils.js";
|
||||
|
||||
type bodyData = any;
|
||||
|
||||
type Data = {
|
||||
endpoint: string;
|
||||
data?: bodyData[];
|
||||
method: "post" | "get" | "delete" | "patch";
|
||||
};
|
||||
|
||||
// type ApiResponse<T = unknown> = {
|
||||
// status: number;
|
||||
// statusText: string;
|
||||
// data: T;
|
||||
// };
|
||||
|
||||
// create the test server stuff
|
||||
const testServers = [
|
||||
{ token: "test1", port: 8940 },
|
||||
{ token: "test2", port: 8941 },
|
||||
{ token: "test3", port: 8942 },
|
||||
];
|
||||
|
||||
const agent = new https.Agent({
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
|
||||
export const prodEndpointCreation = async (endpoint: string) => {
|
||||
let url = "";
|
||||
//get the plant token
|
||||
const plantToken = process.env.PROD_PLANT_TOKEN ?? "test1";
|
||||
|
||||
// check if we are a test server
|
||||
const testServer = testServers.some((server) => server.token === plantToken);
|
||||
|
||||
// await db
|
||||
// .select()
|
||||
// .from(settings)
|
||||
// .where(eq(settings.name, "dbServer"));
|
||||
|
||||
if (testServer) {
|
||||
//filter out what testserver we are
|
||||
const test = testServers.filter((t) => t.token === plantToken);
|
||||
// "https://usmcd1vms036.alpla.net:8942/application/public/v1.0/DemandManagement/ORDERS"
|
||||
url = `https://${process.env.PROD_SERVER}.alpla.net:${test[0]?.port}/application${endpoint}`;
|
||||
return url;
|
||||
} else {
|
||||
url = `https://${plantToken}prod.alpla.net/application${endpoint}`;
|
||||
return url;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param timeoutDelay
|
||||
* @returns
|
||||
*/
|
||||
export const runProdApi = async (data: Data) => {
|
||||
const url = await prodEndpointCreation(data.endpoint);
|
||||
|
||||
const { data: d, error } = await tryCatch(
|
||||
axios({
|
||||
method: data.method as string,
|
||||
url,
|
||||
data: data.data ? data.data[0] : undefined,
|
||||
headers: {
|
||||
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
validateStatus: () => true,
|
||||
httpsAgent: agent,
|
||||
}),
|
||||
);
|
||||
|
||||
switch (d?.status) {
|
||||
case 200:
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "utils",
|
||||
subModule: "prodEndpoint",
|
||||
message: "Data from prod endpoint",
|
||||
data: d.data,
|
||||
notify: false,
|
||||
});
|
||||
|
||||
case 401:
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "utils",
|
||||
subModule: "prodEndpoint",
|
||||
message: "Data from prod endpoint",
|
||||
data: d.data,
|
||||
notify: false,
|
||||
});
|
||||
case 400:
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "utils",
|
||||
subModule: "prodEndpoint",
|
||||
message: "Data from prod endpoint",
|
||||
data: d.data,
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return returnFunc({
|
||||
success: true,
|
||||
level: "error",
|
||||
module: "utils",
|
||||
subModule: "prodEndpoint",
|
||||
message: "Failed to get data from the prod endpoint",
|
||||
data: error as any,
|
||||
notify: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Response } from "express";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
|
||||
interface Data<T = unknown[]> {
|
||||
export interface ReturnHelper<T = unknown[]> {
|
||||
success: boolean;
|
||||
module:
|
||||
| "system"
|
||||
@@ -12,30 +12,12 @@ interface Data<T = unknown[]> {
|
||||
| "opendock"
|
||||
| "notification"
|
||||
| "email"
|
||||
| "purchase";
|
||||
subModule:
|
||||
| "db"
|
||||
| "labeling"
|
||||
| "printer"
|
||||
| "prodSql"
|
||||
| "query"
|
||||
| "sendmail"
|
||||
| "auth"
|
||||
| "datamart"
|
||||
| "jobs"
|
||||
| "apt"
|
||||
| "settings"
|
||||
| "get"
|
||||
| "update"
|
||||
| "delete"
|
||||
| "post"
|
||||
| "notification"
|
||||
| "delete"
|
||||
| "printing"
|
||||
| "gpSql"
|
||||
| "email"
|
||||
| "gpChecks";
|
||||
level: "info" | "error" | "debug" | "fatal";
|
||||
| "purchase"
|
||||
| "tcp"
|
||||
| "logistics";
|
||||
subModule: string;
|
||||
|
||||
level: "info" | "error" | "debug" | "fatal" | "warn";
|
||||
message: string;
|
||||
room?: string;
|
||||
data?: T;
|
||||
@@ -56,7 +38,7 @@ interface Data<T = unknown[]> {
|
||||
* data: [] the data that will be passed back
|
||||
* notify: false by default this is to send a notification to a users email to alert them of an issue.
|
||||
*/
|
||||
export const returnFunc = (data: Data) => {
|
||||
export const returnFunc = (data: ReturnHelper) => {
|
||||
const notify = data.notify ? data.notify : false;
|
||||
const room = data.room ?? data.room;
|
||||
const log = createLogger({ module: data.module, subModule: data.subModule });
|
||||
@@ -89,7 +71,7 @@ export const returnFunc = (data: Data) => {
|
||||
|
||||
export function apiReturn(
|
||||
res: Response,
|
||||
opts: Data & { status?: number },
|
||||
opts: ReturnHelper & { status?: number },
|
||||
optional?: unknown, // leave this as unknown so we can pass an object or an array over.
|
||||
): Response {
|
||||
const result = returnFunc(opts);
|
||||
|
||||
@@ -5,13 +5,17 @@ meta {
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{url}}/api/datamart/:name
|
||||
url: {{url}}/api/datamart/:name?historical=x
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
historical: x
|
||||
}
|
||||
|
||||
params:path {
|
||||
name: activeArticles
|
||||
name: inventory
|
||||
}
|
||||
|
||||
settings {
|
||||
|
||||
20
lst_docs/.gitignore
vendored
@@ -1,20 +0,0 @@
|
||||
# Dependencies
|
||||
/node_modules
|
||||
|
||||
# Production
|
||||
/build
|
||||
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -1,41 +0,0 @@
|
||||
# Website
|
||||
|
||||
This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
|
||||
## Local Development
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
```
|
||||
|
||||
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
This command generates static content into the `build` directory and can be served using any static contents hosting service.
|
||||
|
||||
## Deployment
|
||||
|
||||
Using SSH:
|
||||
|
||||
```bash
|
||||
USE_SSH=true yarn deploy
|
||||
```
|
||||
|
||||
Not using SSH:
|
||||
|
||||
```bash
|
||||
GIT_USER=<Your GitHub username> yarn deploy
|
||||
```
|
||||
|
||||
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
slug: first-blog-post
|
||||
title: First Blog Post
|
||||
authors: [slorber, yangshun]
|
||||
tags: [hola, docusaurus]
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet...
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
@@ -1,44 +0,0 @@
|
||||
---
|
||||
slug: long-blog-post
|
||||
title: Long Blog Post
|
||||
authors: yangshun
|
||||
tags: [hello, docusaurus]
|
||||
---
|
||||
|
||||
This is the summary of a very long blog post,
|
||||
|
||||
Use a `<!--` `truncate` `-->` comment to limit blog post size in the list view.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
slug: mdx-blog-post
|
||||
title: MDX Blog Post
|
||||
authors: [slorber]
|
||||
tags: [docusaurus]
|
||||
---
|
||||
|
||||
Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/).
|
||||
|
||||
:::tip
|
||||
|
||||
Use the power of React to create interactive blog posts.
|
||||
|
||||
:::
|
||||
|
||||
{/* truncate */}
|
||||
|
||||
For example, use JSX to create an interactive button:
|
||||
|
||||
```js
|
||||
<button onClick={() => alert('button clicked!')}>Click me!</button>
|
||||
```
|
||||
|
||||
<button onClick={() => alert('button clicked!')}>Click me!</button>
|
||||
|
Before Width: | Height: | Size: 94 KiB |
@@ -1,29 +0,0 @@
|
||||
---
|
||||
slug: welcome
|
||||
title: Welcome
|
||||
authors: [slorber, yangshun]
|
||||
tags: [facebook, hello, docusaurus]
|
||||
---
|
||||
|
||||
[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).
|
||||
|
||||
Here are a few tips you might find useful.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Simply add Markdown files (or folders) to the `blog` directory.
|
||||
|
||||
Regular blog authors can be added to `authors.yml`.
|
||||
|
||||
The blog post date can be extracted from filenames, such as:
|
||||
|
||||
- `2019-05-30-welcome.md`
|
||||
- `2019-05-30-welcome/index.md`
|
||||
|
||||
A blog post folder can be convenient to co-locate blog post images:
|
||||
|
||||

|
||||
|
||||
The blog supports tags as well!
|
||||
|
||||
**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.
|
||||
@@ -1,25 +0,0 @@
|
||||
yangshun:
|
||||
name: Yangshun Tay
|
||||
title: Ex-Meta Staff Engineer, Co-founder GreatFrontEnd
|
||||
url: https://linkedin.com/in/yangshun
|
||||
image_url: https://github.com/yangshun.png
|
||||
page: true
|
||||
socials:
|
||||
x: yangshunz
|
||||
linkedin: yangshun
|
||||
github: yangshun
|
||||
newsletter: https://www.greatfrontend.com
|
||||
|
||||
slorber:
|
||||
name: Sébastien Lorber
|
||||
title: Docusaurus maintainer
|
||||
url: https://sebastienlorber.com
|
||||
image_url: https://github.com/slorber.png
|
||||
page:
|
||||
# customize the url of the author page at /blog/authors/<permalink>
|
||||
permalink: '/all-sebastien-lorber-articles'
|
||||
socials:
|
||||
x: sebastienlorber
|
||||
linkedin: sebastienlorber
|
||||
github: slorber
|
||||
newsletter: https://thisweekinreact.com
|
||||
@@ -1,19 +0,0 @@
|
||||
facebook:
|
||||
label: Facebook
|
||||
permalink: /facebook
|
||||
description: Facebook tag description
|
||||
|
||||
hello:
|
||||
label: Hello
|
||||
permalink: /hello
|
||||
description: Hello tag description
|
||||
|
||||
docusaurus:
|
||||
label: Docusaurus
|
||||
permalink: /docusaurus
|
||||
description: Docusaurus tag description
|
||||
|
||||
hola:
|
||||
label: Hola
|
||||
permalink: /hola
|
||||
description: Hola tag description
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Tutorial Intro
|
||||
|
||||
Let's discover **Docusaurus in less than 5 minutes**.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Get started by **creating a new site**.
|
||||
|
||||
Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**.
|
||||
|
||||
### What you'll need
|
||||
|
||||
- [Node.js](https://nodejs.org/en/download/) version 20.0 or above:
|
||||
- When installing Node.js, you are recommended to check all checkboxes related to dependencies.
|
||||
|
||||
## Generate a new site
|
||||
|
||||
Generate a new Docusaurus site using the **classic template**.
|
||||
|
||||
The classic template will automatically be added to your project after you run the command:
|
||||
|
||||
```bash
|
||||
npm init docusaurus@latest my-website classic
|
||||
```
|
||||
|
||||
You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor.
|
||||
|
||||
The command also installs all necessary dependencies you need to run Docusaurus.
|
||||
|
||||
## Start your site
|
||||
|
||||
Run the development server:
|
||||
|
||||
```bash
|
||||
cd my-website
|
||||
npm run start
|
||||
```
|
||||
|
||||
The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there.
|
||||
|
||||
The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/.
|
||||
|
||||
Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes.
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"label": "Tutorial - Basics",
|
||||
"position": 2,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "5 minutes to learn the most important Docusaurus concepts."
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# Congratulations!
|
||||
|
||||
You have just learned the **basics of Docusaurus** and made some changes to the **initial template**.
|
||||
|
||||
Docusaurus has **much more to offer**!
|
||||
|
||||
Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**.
|
||||
|
||||
Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610)
|
||||
|
||||
## What's next?
|
||||
|
||||
- Read the [official documentation](https://docusaurus.io/)
|
||||
- Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config)
|
||||
- Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration)
|
||||
- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
|
||||
- Add a [search bar](https://docusaurus.io/docs/search)
|
||||
- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
|
||||
- Get involved in the [Docusaurus Community](https://docusaurus.io/community/support)
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Create a Blog Post
|
||||
|
||||
Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed...
|
||||
|
||||
## Create your first Post
|
||||
|
||||
Create a file at `blog/2021-02-28-greetings.md`:
|
||||
|
||||
```md title="blog/2021-02-28-greetings.md"
|
||||
---
|
||||
slug: greetings
|
||||
title: Greetings!
|
||||
authors:
|
||||
- name: Joel Marcey
|
||||
title: Co-creator of Docusaurus 1
|
||||
url: https://github.com/JoelMarcey
|
||||
image_url: https://github.com/JoelMarcey.png
|
||||
- name: Sébastien Lorber
|
||||
title: Docusaurus maintainer
|
||||
url: https://sebastienlorber.com
|
||||
image_url: https://github.com/slorber.png
|
||||
tags: [greetings]
|
||||
---
|
||||
|
||||
Congratulations, you have made your first post!
|
||||
|
||||
Feel free to play around and edit this post as much as you like.
|
||||
```
|
||||
|
||||
A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings).
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Create a Document
|
||||
|
||||
Documents are **groups of pages** connected through:
|
||||
|
||||
- a **sidebar**
|
||||
- **previous/next navigation**
|
||||
- **versioning**
|
||||
|
||||
## Create your first Doc
|
||||
|
||||
Create a Markdown file at `docs/hello.md`:
|
||||
|
||||
```md title="docs/hello.md"
|
||||
# Hello
|
||||
|
||||
This is my **first Docusaurus document**!
|
||||
```
|
||||
|
||||
A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello).
|
||||
|
||||
## Configure the Sidebar
|
||||
|
||||
Docusaurus automatically **creates a sidebar** from the `docs` folder.
|
||||
|
||||
Add metadata to customize the sidebar label and position:
|
||||
|
||||
```md title="docs/hello.md" {1-4}
|
||||
---
|
||||
sidebar_label: 'Hi!'
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Hello
|
||||
|
||||
This is my **first Docusaurus document**!
|
||||
```
|
||||
|
||||
It is also possible to create your sidebar explicitly in `sidebars.js`:
|
||||
|
||||
```js title="sidebars.js"
|
||||
export default {
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
// highlight-next-line
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
items: ['tutorial-basics/create-a-document'],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
@@ -1,43 +0,0 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Create a Page
|
||||
|
||||
Add **Markdown or React** files to `src/pages` to create a **standalone page**:
|
||||
|
||||
- `src/pages/index.js` → `localhost:3000/`
|
||||
- `src/pages/foo.md` → `localhost:3000/foo`
|
||||
- `src/pages/foo/bar.js` → `localhost:3000/foo/bar`
|
||||
|
||||
## Create your first React Page
|
||||
|
||||
Create a file at `src/pages/my-react-page.js`:
|
||||
|
||||
```jsx title="src/pages/my-react-page.js"
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default function MyReactPage() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>My React page</h1>
|
||||
<p>This is a React page</p>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page).
|
||||
|
||||
## Create your first Markdown Page
|
||||
|
||||
Create a file at `src/pages/my-markdown-page.md`:
|
||||
|
||||
```mdx title="src/pages/my-markdown-page.md"
|
||||
# My Markdown page
|
||||
|
||||
This is a Markdown page
|
||||
```
|
||||
|
||||
A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page).
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Deploy your site
|
||||
|
||||
Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**).
|
||||
|
||||
It builds your site as simple **static HTML, JavaScript and CSS files**.
|
||||
|
||||
## Build your site
|
||||
|
||||
Build your site **for production**:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The static files are generated in the `build` folder.
|
||||
|
||||
## Deploy your site
|
||||
|
||||
Test your production build locally:
|
||||
|
||||
```bash
|
||||
npm run serve
|
||||
```
|
||||
|
||||
The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/).
|
||||
|
||||
You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**).
|
||||
@@ -1,152 +0,0 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Markdown Features
|
||||
|
||||
Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**.
|
||||
|
||||
## Front Matter
|
||||
|
||||
Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/):
|
||||
|
||||
```text title="my-doc.md"
|
||||
// highlight-start
|
||||
---
|
||||
id: my-doc-id
|
||||
title: My document title
|
||||
description: My document description
|
||||
slug: /my-custom-url
|
||||
---
|
||||
// highlight-end
|
||||
|
||||
## Markdown heading
|
||||
|
||||
Markdown text with [links](./hello.md)
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
Regular Markdown links are supported, using url paths or relative file paths.
|
||||
|
||||
```md
|
||||
Let's see how to [Create a page](/create-a-page).
|
||||
```
|
||||
|
||||
```md
|
||||
Let's see how to [Create a page](./create-a-page.md).
|
||||
```
|
||||
|
||||
**Result:** Let's see how to [Create a page](./create-a-page.md).
|
||||
|
||||
## Images
|
||||
|
||||
Regular Markdown images are supported.
|
||||
|
||||
You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`):
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||

|
||||
|
||||
You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them:
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
## Code Blocks
|
||||
|
||||
Markdown code blocks are supported with Syntax highlighting.
|
||||
|
||||
````md
|
||||
```jsx title="src/components/HelloDocusaurus.js"
|
||||
function HelloDocusaurus() {
|
||||
return <h1>Hello, Docusaurus!</h1>;
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
```jsx title="src/components/HelloDocusaurus.js"
|
||||
function HelloDocusaurus() {
|
||||
return <h1>Hello, Docusaurus!</h1>;
|
||||
}
|
||||
```
|
||||
|
||||
## Admonitions
|
||||
|
||||
Docusaurus has a special syntax to create admonitions and callouts:
|
||||
|
||||
```md
|
||||
:::tip My tip
|
||||
|
||||
Use this awesome feature option
|
||||
|
||||
:::
|
||||
|
||||
:::danger Take care
|
||||
|
||||
This action is dangerous
|
||||
|
||||
:::
|
||||
```
|
||||
|
||||
:::tip My tip
|
||||
|
||||
Use this awesome feature option
|
||||
|
||||
:::
|
||||
|
||||
:::danger Take care
|
||||
|
||||
This action is dangerous
|
||||
|
||||
:::
|
||||
|
||||
## MDX and React Components
|
||||
|
||||
[MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**:
|
||||
|
||||
```jsx
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '20px',
|
||||
color: '#fff',
|
||||
padding: '10px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
onClick={() => {
|
||||
alert(`You clicked the color ${color} with label ${children}`)
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
This is <Highlight color="#25c2a0">Docusaurus green</Highlight> !
|
||||
|
||||
This is <Highlight color="#1877F2">Facebook blue</Highlight> !
|
||||
```
|
||||
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '20px',
|
||||
color: '#fff',
|
||||
padding: '10px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
onClick={() => {
|
||||
alert(`You clicked the color ${color} with label ${children}`);
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
This is <Highlight color="#25c2a0">Docusaurus green</Highlight> !
|
||||
|
||||
This is <Highlight color="#1877F2">Facebook blue</Highlight> !
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"label": "Tutorial - Extras",
|
||||
"position": 3,
|
||||
"link": {
|
||||
"type": "generated-index"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 27 KiB |
@@ -1,55 +0,0 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Manage Docs Versions
|
||||
|
||||
Docusaurus can manage multiple versions of your docs.
|
||||
|
||||
## Create a docs version
|
||||
|
||||
Release a version 1.0 of your project:
|
||||
|
||||
```bash
|
||||
npm run docusaurus docs:version 1.0
|
||||
```
|
||||
|
||||
The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created.
|
||||
|
||||
Your docs now have 2 versions:
|
||||
|
||||
- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs
|
||||
- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs**
|
||||
|
||||
## Add a Version Dropdown
|
||||
|
||||
To navigate seamlessly across versions, add a version dropdown.
|
||||
|
||||
Modify the `docusaurus.config.js` file:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
export default {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'docsVersionDropdown',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
The docs version dropdown appears in your navbar:
|
||||
|
||||

|
||||
|
||||
## Update an existing version
|
||||
|
||||
It is possible to edit versioned docs in their respective folder:
|
||||
|
||||
- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello`
|
||||
- `docs/hello.md` updates `http://localhost:3000/docs/next/hello`
|
||||
@@ -1,88 +0,0 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Translate your site
|
||||
|
||||
Let's translate `docs/intro.md` to French.
|
||||
|
||||
## Configure i18n
|
||||
|
||||
Modify `docusaurus.config.js` to add support for the `fr` locale:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
export default {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'fr'],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Translate a doc
|
||||
|
||||
Copy the `docs/intro.md` file to the `i18n/fr` folder:
|
||||
|
||||
```bash
|
||||
mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/
|
||||
|
||||
cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md
|
||||
```
|
||||
|
||||
Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French.
|
||||
|
||||
## Start your localized site
|
||||
|
||||
Start your site on the French locale:
|
||||
|
||||
```bash
|
||||
npm run start -- --locale fr
|
||||
```
|
||||
|
||||
Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated.
|
||||
|
||||
:::caution
|
||||
|
||||
In development, you can only use one locale at a time.
|
||||
|
||||
:::
|
||||
|
||||
## Add a Locale Dropdown
|
||||
|
||||
To navigate seamlessly across languages, add a locale dropdown.
|
||||
|
||||
Modify the `docusaurus.config.js` file:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
export default {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'localeDropdown',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
The locale dropdown now appears in your navbar:
|
||||
|
||||

|
||||
|
||||
## Build your localized site
|
||||
|
||||
Build your site for a specific locale:
|
||||
|
||||
```bash
|
||||
npm run build -- --locale fr
|
||||
```
|
||||
|
||||
Or build your site to include all the locales at once:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
@@ -1,150 +0,0 @@
|
||||
import {themes as prismThemes} from 'prism-react-renderer';
|
||||
import type {Config} from '@docusaurus/types';
|
||||
import type * as Preset from '@docusaurus/preset-classic';
|
||||
|
||||
// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
|
||||
|
||||
const config: Config = {
|
||||
title: 'My Site',
|
||||
tagline: 'Dinosaurs are cool',
|
||||
favicon: 'img/favicon.ico',
|
||||
|
||||
// Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future
|
||||
future: {
|
||||
v4: true, // Improve compatibility with the upcoming Docusaurus v4
|
||||
},
|
||||
|
||||
// Set the production url of your site here
|
||||
url: 'https://your-docusaurus-site.example.com',
|
||||
// Set the /<baseUrl>/ pathname under which your site is served
|
||||
// For GitHub pages deployment, it is often '/<projectName>/'
|
||||
baseUrl: '/',
|
||||
|
||||
// GitHub pages deployment config.
|
||||
// If you aren't using GitHub pages, you don't need these.
|
||||
organizationName: 'facebook', // Usually your GitHub org/user name.
|
||||
projectName: 'docusaurus', // Usually your repo name.
|
||||
|
||||
onBrokenLinks: 'throw',
|
||||
|
||||
// Even if you don't use internationalization, you can use this field to set
|
||||
// useful metadata like html lang. For example, if your site is Chinese, you
|
||||
// may want to replace "en" with "zh-Hans".
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en'],
|
||||
},
|
||||
|
||||
presets: [
|
||||
[
|
||||
'classic',
|
||||
{
|
||||
docs: {
|
||||
sidebarPath: './sidebars.ts',
|
||||
// Please change this to your repo.
|
||||
// Remove this to remove the "edit this page" links.
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
|
||||
},
|
||||
blog: {
|
||||
showReadingTime: true,
|
||||
feedOptions: {
|
||||
type: ['rss', 'atom'],
|
||||
xslt: true,
|
||||
},
|
||||
// Please change this to your repo.
|
||||
// Remove this to remove the "edit this page" links.
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
|
||||
// Useful options to enforce blogging best practices
|
||||
onInlineTags: 'warn',
|
||||
onInlineAuthors: 'warn',
|
||||
onUntruncatedBlogPosts: 'warn',
|
||||
},
|
||||
theme: {
|
||||
customCss: './src/css/custom.css',
|
||||
},
|
||||
} satisfies Preset.Options,
|
||||
],
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
// Replace with your project's social card
|
||||
image: 'img/docusaurus-social-card.jpg',
|
||||
colorMode: {
|
||||
respectPrefersColorScheme: true,
|
||||
},
|
||||
navbar: {
|
||||
title: 'My Site',
|
||||
logo: {
|
||||
alt: 'My Site Logo',
|
||||
src: 'img/logo.svg',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
type: 'docSidebar',
|
||||
sidebarId: 'tutorialSidebar',
|
||||
position: 'left',
|
||||
label: 'Tutorial',
|
||||
},
|
||||
{to: '/blog', label: 'Blog', position: 'left'},
|
||||
{
|
||||
href: 'https://github.com/facebook/docusaurus',
|
||||
label: 'GitHub',
|
||||
position: 'right',
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
style: 'dark',
|
||||
links: [
|
||||
{
|
||||
title: 'Docs',
|
||||
items: [
|
||||
{
|
||||
label: 'Tutorial',
|
||||
to: '/docs/intro',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Community',
|
||||
items: [
|
||||
{
|
||||
label: 'Stack Overflow',
|
||||
href: 'https://stackoverflow.com/questions/tagged/docusaurus',
|
||||
},
|
||||
{
|
||||
label: 'Discord',
|
||||
href: 'https://discordapp.com/invite/docusaurus',
|
||||
},
|
||||
{
|
||||
label: 'X',
|
||||
href: 'https://x.com/docusaurus',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'More',
|
||||
items: [
|
||||
{
|
||||
label: 'Blog',
|
||||
to: '/blog',
|
||||
},
|
||||
{
|
||||
label: 'GitHub',
|
||||
href: 'https://github.com/facebook/docusaurus',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`,
|
||||
},
|
||||
prism: {
|
||||
theme: prismThemes.github,
|
||||
darkTheme: prismThemes.dracula,
|
||||
},
|
||||
} satisfies Preset.ThemeConfig,
|
||||
};
|
||||
|
||||
export default config;
|
||||
18455
lst_docs/package-lock.json
generated
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"name": "lst-docs",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids",
|
||||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "3.9.2",
|
||||
"@docusaurus/preset-classic": "3.9.2",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
"prism-react-renderer": "^2.3.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "3.9.2",
|
||||
"@docusaurus/tsconfig": "3.9.2",
|
||||
"@docusaurus/types": "3.9.2",
|
||||
"typescript": "~5.6.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 3 chrome version",
|
||||
"last 3 firefox version",
|
||||
"last 5 safari version"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0"
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
|
||||
|
||||
/**
|
||||
* Creating a sidebar enables you to:
|
||||
- create an ordered group of docs
|
||||
- render a sidebar for each doc of that group
|
||||
- provide next/previous navigation
|
||||
|
||||
The sidebars can be generated from the filesystem, or explicitly defined here.
|
||||
|
||||
Create as many sidebars as you want.
|
||||
*/
|
||||
const sidebars: SidebarsConfig = {
|
||||
// By default, Docusaurus generates a sidebar from the docs folder structure
|
||||
tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
|
||||
|
||||
// But you can create a sidebar manually
|
||||
/*
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
items: ['tutorial-basics/create-a-document'],
|
||||
},
|
||||
],
|
||||
*/
|
||||
};
|
||||
|
||||
export default sidebars;
|
||||
@@ -1,71 +0,0 @@
|
||||
import type {ReactNode} from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Heading from '@theme/Heading';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
type FeatureItem = {
|
||||
title: string;
|
||||
Svg: React.ComponentType<React.ComponentProps<'svg'>>;
|
||||
description: ReactNode;
|
||||
};
|
||||
|
||||
const FeatureList: FeatureItem[] = [
|
||||
{
|
||||
title: 'Easy to Use',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus was designed from the ground up to be easily installed and
|
||||
used to get your website up and running quickly.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Focus on What Matters',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus lets you focus on your docs, and we'll do the chores. Go
|
||||
ahead and move your docs into the <code>docs</code> directory.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Powered by React',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Extend or customize your website layout by reusing React. Docusaurus can
|
||||
be extended while reusing the same header and footer.
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
function Feature({title, Svg, description}: FeatureItem) {
|
||||
return (
|
||||
<div className={clsx('col col--4')}>
|
||||
<div className="text--center">
|
||||
<Svg className={styles.featureSvg} role="img" />
|
||||
</div>
|
||||
<div className="text--center padding-horiz--md">
|
||||
<Heading as="h3">{title}</Heading>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomepageFeatures(): ReactNode {
|
||||
return (
|
||||
<section className={styles.features}>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
{FeatureList.map((props, idx) => (
|
||||
<Feature key={idx} {...props} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
.features {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2rem 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.featureSvg {
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Any CSS included here will be global. The classic template
|
||||
* bundles Infima by default. Infima is a CSS framework designed to
|
||||
* work well for content-centric websites.
|
||||
*/
|
||||
|
||||
/* You can override the default Infima variables here. */
|
||||
:root {
|
||||
--ifm-color-primary: #2e8555;
|
||||
--ifm-color-primary-dark: #29784c;
|
||||
--ifm-color-primary-darker: #277148;
|
||||
--ifm-color-primary-darkest: #205d3b;
|
||||
--ifm-color-primary-light: #33925d;
|
||||
--ifm-color-primary-lighter: #359962;
|
||||
--ifm-color-primary-lightest: #3cad6e;
|
||||
--ifm-code-font-size: 95%;
|
||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* For readability concerns, you should choose a lighter palette in dark mode. */
|
||||
[data-theme='dark'] {
|
||||
--ifm-color-primary: #25c2a0;
|
||||
--ifm-color-primary-dark: #21af90;
|
||||
--ifm-color-primary-darker: #1fa588;
|
||||
--ifm-color-primary-darkest: #1a8870;
|
||||
--ifm-color-primary-light: #29d5b0;
|
||||
--ifm-color-primary-lighter: #32d8b4;
|
||||
--ifm-color-primary-lightest: #4fddbf;
|
||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* CSS files with the .module.css suffix will be treated as CSS modules
|
||||
* and scoped locally.
|
||||
*/
|
||||
|
||||
.heroBanner {
|
||||
padding: 4rem 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 996px) {
|
||||
.heroBanner {
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import type {ReactNode} from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import Layout from '@theme/Layout';
|
||||
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
||||
import Heading from '@theme/Heading';
|
||||
|
||||
import styles from './index.module.css';
|
||||
|
||||
function HomepageHeader() {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
return (
|
||||
<header className={clsx('hero hero--primary', styles.heroBanner)}>
|
||||
<div className="container">
|
||||
<Heading as="h1" className="hero__title">
|
||||
{siteConfig.title}
|
||||
</Heading>
|
||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||
<div className={styles.buttons}>
|
||||
<Link
|
||||
className="button button--secondary button--lg"
|
||||
to="/docs/intro">
|
||||
Docusaurus Tutorial - 5min ⏱️
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Home(): ReactNode {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
return (
|
||||
<Layout
|
||||
title={`Hello from ${siteConfig.title}`}
|
||||
description="Description will go into a meta tag in <head />">
|
||||
<HomepageHeader />
|
||||
<main>
|
||||
<HomepageFeatures />
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Markdown page example
|
||||
---
|
||||
|
||||
# Markdown page example
|
||||
|
||||
You don't need React to write simple standalone pages.
|
||||
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
@@ -1,171 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1088" height="687.962" viewBox="0 0 1088 687.962">
|
||||
<title>Easy to Use</title>
|
||||
<g id="Group_12" data-name="Group 12" transform="translate(-57 -56)">
|
||||
<g id="Group_11" data-name="Group 11" transform="translate(57 56)">
|
||||
<path id="Path_83" data-name="Path 83" d="M1017.81,560.461c-5.27,45.15-16.22,81.4-31.25,110.31-20,38.52-54.21,54.04-84.77,70.28a193.275,193.275,0,0,1-27.46,11.94c-55.61,19.3-117.85,14.18-166.74,3.99a657.282,657.282,0,0,0-104.09-13.16q-14.97-.675-29.97-.67c-15.42.02-293.07,5.29-360.67-131.57-16.69-33.76-28.13-75-32.24-125.27-11.63-142.12,52.29-235.46,134.74-296.47,155.97-115.41,369.76-110.57,523.43,7.88C941.15,276.621,1036.99,396.031,1017.81,560.461Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
||||
<path id="Path_84" data-name="Path 84" d="M986.56,670.771c-20,38.52-47.21,64.04-77.77,80.28a193.272,193.272,0,0,1-27.46,11.94c-55.61,19.3-117.85,14.18-166.74,3.99a657.3,657.3,0,0,0-104.09-13.16q-14.97-.675-29.97-.67-23.13.03-46.25,1.72c-100.17,7.36-253.82-6.43-321.42-143.29L382,283.981,444.95,445.6l20.09,51.59,55.37-75.98L549,381.981l130.2,149.27,36.8-81.27L970.78,657.9l14.21,11.59Z" transform="translate(-56 -106.019)" fill="#f2f2f2"/>
|
||||
<path id="Path_85" data-name="Path 85" d="M302,282.962l26-57,36,83-31-60Z" opacity="0.1"/>
|
||||
<path id="Path_86" data-name="Path 86" d="M610.5,753.821q-14.97-.675-29.97-.67L465.04,497.191Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
||||
<path id="Path_87" data-name="Path 87" d="M464.411,315.191,493,292.962l130,150-132-128Z" opacity="0.1"/>
|
||||
<path id="Path_88" data-name="Path 88" d="M908.79,751.051a193.265,193.265,0,0,1-27.46,11.94L679.2,531.251Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
||||
<circle id="Ellipse_11" data-name="Ellipse 11" cx="3" cy="3" r="3" transform="translate(479 98.962)" fill="#f2f2f2"/>
|
||||
<circle id="Ellipse_12" data-name="Ellipse 12" cx="3" cy="3" r="3" transform="translate(396 201.962)" fill="#f2f2f2"/>
|
||||
<circle id="Ellipse_13" data-name="Ellipse 13" cx="2" cy="2" r="2" transform="translate(600 220.962)" fill="#f2f2f2"/>
|
||||
<circle id="Ellipse_14" data-name="Ellipse 14" cx="2" cy="2" r="2" transform="translate(180 265.962)" fill="#f2f2f2"/>
|
||||
<circle id="Ellipse_15" data-name="Ellipse 15" cx="2" cy="2" r="2" transform="translate(612 96.962)" fill="#f2f2f2"/>
|
||||
<circle id="Ellipse_16" data-name="Ellipse 16" cx="2" cy="2" r="2" transform="translate(736 192.962)" fill="#f2f2f2"/>
|
||||
<circle id="Ellipse_17" data-name="Ellipse 17" cx="2" cy="2" r="2" transform="translate(858 344.962)" fill="#f2f2f2"/>
|
||||
<path id="Path_89" data-name="Path 89" d="M306,121.222h-2.76v-2.76h-1.48v2.76H299V122.7h2.76v2.759h1.48V122.7H306Z" fill="#f2f2f2"/>
|
||||
<path id="Path_90" data-name="Path 90" d="M848,424.222h-2.76v-2.76h-1.48v2.76H841V425.7h2.76v2.759h1.48V425.7H848Z" fill="#f2f2f2"/>
|
||||
<path id="Path_91" data-name="Path 91" d="M1144,719.981c0,16.569-243.557,74-544,74s-544-57.431-544-74,243.557,14,544,14S1144,703.413,1144,719.981Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
||||
<path id="Path_92" data-name="Path 92" d="M1144,719.981c0,16.569-243.557,74-544,74s-544-57.431-544-74,243.557,14,544,14S1144,703.413,1144,719.981Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
||||
<ellipse id="Ellipse_18" data-name="Ellipse 18" cx="544" cy="30" rx="544" ry="30" transform="translate(0 583.962)" fill="#3f3d56"/>
|
||||
<path id="Path_93" data-name="Path 93" d="M624,677.981c0,33.137-14.775,24-33,24s-33,9.137-33-24,33-96,33-96S624,644.844,624,677.981Z" transform="translate(-56 -106.019)" fill="#ff6584"/>
|
||||
<path id="Path_94" data-name="Path 94" d="M606,690.66c0,15.062-6.716,10.909-15,10.909s-15,4.153-15-10.909,15-43.636,15-43.636S606,675.6,606,690.66Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
||||
<rect id="Rectangle_97" data-name="Rectangle 97" width="92" height="18" rx="9" transform="translate(489 604.962)" fill="#2f2e41"/>
|
||||
<rect id="Rectangle_98" data-name="Rectangle 98" width="92" height="18" rx="9" transform="translate(489 586.962)" fill="#2f2e41"/>
|
||||
<path id="Path_95" data-name="Path 95" d="M193,596.547c0,55.343,34.719,100.126,77.626,100.126" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
||||
<path id="Path_96" data-name="Path 96" d="M270.626,696.673c0-55.965,38.745-101.251,86.626-101.251" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
||||
<path id="Path_97" data-name="Path 97" d="M221.125,601.564c0,52.57,22.14,95.109,49.5,95.109" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
||||
<path id="Path_98" data-name="Path 98" d="M270.626,696.673c0-71.511,44.783-129.377,100.126-129.377" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
||||
<path id="Path_99" data-name="Path 99" d="M254.3,697.379s11.009-.339,14.326-2.7,16.934-5.183,17.757-1.395,16.544,18.844,4.115,18.945-28.879-1.936-32.19-3.953S254.3,697.379,254.3,697.379Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
||||
<path id="Path_100" data-name="Path 100" d="M290.716,710.909c-12.429.1-28.879-1.936-32.19-3.953-2.522-1.536-3.527-7.048-3.863-9.591l-.368.014s.7,8.879,4.009,10.9,19.761,4.053,32.19,3.953c3.588-.029,4.827-1.305,4.759-3.2C294.755,710.174,293.386,710.887,290.716,710.909Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
||||
<path id="Path_101" data-name="Path 101" d="M777.429,633.081c0,38.029,23.857,68.8,53.341,68.8" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
||||
<path id="Path_102" data-name="Path 102" d="M830.769,701.882c0-38.456,26.623-69.575,59.525-69.575" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
||||
<path id="Path_103" data-name="Path 103" d="M796.755,636.528c0,36.124,15.213,65.354,34.014,65.354" transform="translate(-56 -106.019)" fill="#6c63ff"/>
|
||||
<path id="Path_104" data-name="Path 104" d="M830.769,701.882c0-49.139,30.773-88.9,68.8-88.9" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
||||
<path id="Path_105" data-name="Path 105" d="M819.548,702.367s7.565-.233,9.844-1.856,11.636-3.562,12.2-.958,11.368,12.949,2.828,13.018-19.844-1.33-22.119-2.716S819.548,702.367,819.548,702.367Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
||||
<path id="Path_106" data-name="Path 106" d="M844.574,711.664c-8.54.069-19.844-1.33-22.119-2.716-1.733-1.056-2.423-4.843-2.654-6.59l-.253.01s.479,6.1,2.755,7.487,13.579,2.785,22.119,2.716c2.465-.02,3.317-.9,3.27-2.2C847.349,711.159,846.409,711.649,844.574,711.664Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
||||
<path id="Path_107" data-name="Path 107" d="M949.813,724.718s11.36-1.729,14.5-4.591,16.89-7.488,18.217-3.667,19.494,17.447,6.633,19.107-30.153,1.609-33.835-.065S949.813,724.718,949.813,724.718Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
||||
<path id="Path_108" data-name="Path 108" d="M989.228,734.173c-12.86,1.659-30.153,1.609-33.835-.065-2.8-1.275-4.535-6.858-5.2-9.45l-.379.061s1.833,9.109,5.516,10.783,20.975,1.725,33.835.065c3.712-.479,4.836-1.956,4.529-3.906C993.319,732.907,991.991,733.817,989.228,734.173Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
||||
<path id="Path_109" data-name="Path 109" d="M670.26,723.9s9.587-1.459,12.237-3.875,14.255-6.32,15.374-3.095,16.452,14.725,5.6,16.125-25.448,1.358-28.555-.055S670.26,723.9,670.26,723.9Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
||||
<path id="Path_110" data-name="Path 110" d="M703.524,731.875c-10.853,1.4-25.448,1.358-28.555-.055-2.367-1.076-3.827-5.788-4.39-7.976l-.32.051s1.547,7.687,4.655,9.1,17.7,1.456,28.555.055c3.133-.4,4.081-1.651,3.822-3.3C706.977,730.807,705.856,731.575,703.524,731.875Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
||||
<path id="Path_111" data-name="Path 111" d="M178.389,719.109s7.463-1.136,9.527-3.016,11.1-4.92,11.969-2.409,12.808,11.463,4.358,12.553-19.811,1.057-22.23-.043S178.389,719.109,178.389,719.109Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
|
||||
<path id="Path_112" data-name="Path 112" d="M204.285,725.321c-8.449,1.09-19.811,1.057-22.23-.043-1.842-.838-2.979-4.506-3.417-6.209l-.249.04s1.2,5.984,3.624,7.085,13.781,1.133,22.23.043c2.439-.315,3.177-1.285,2.976-2.566C206.973,724.489,206.1,725.087,204.285,725.321Z" transform="translate(-56 -106.019)" opacity="0.2"/>
|
||||
<path id="Path_113" data-name="Path 113" d="M439.7,707.337c0,30.22-42.124,20.873-93.7,20.873s-93.074,9.347-93.074-20.873,42.118-36.793,93.694-36.793S439.7,677.117,439.7,707.337Z" transform="translate(-56 -106.019)" opacity="0.1"/>
|
||||
<path id="Path_114" data-name="Path 114" d="M439.7,699.9c0,30.22-42.124,20.873-93.7,20.873s-93.074,9.347-93.074-20.873S295.04,663.1,346.616,663.1,439.7,669.676,439.7,699.9Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
|
||||
</g>
|
||||
<g id="docusaurus_keytar" transform="translate(312.271 493.733)">
|
||||
<path id="Path_40" data-name="Path 40" d="M99,52h91.791V89.153H99Z" transform="translate(5.904 -14.001)" fill="#fff" fill-rule="evenodd"/>
|
||||
<path id="Path_41" data-name="Path 41" d="M24.855,163.927A21.828,21.828,0,0,1,5.947,153a21.829,21.829,0,0,0,18.908,32.782H46.71V163.927Z" transform="translate(-3 -4.634)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_42" data-name="Path 42" d="M121.861,61.1l76.514-4.782V45.39A21.854,21.854,0,0,0,176.52,23.535H78.173L75.441,18.8a3.154,3.154,0,0,0-5.464,0l-2.732,4.732L64.513,18.8a3.154,3.154,0,0,0-5.464,0l-2.732,4.732L53.586,18.8a3.154,3.154,0,0,0-5.464,0L45.39,23.535c-.024,0-.046,0-.071,0l-4.526-4.525a3.153,3.153,0,0,0-5.276,1.414l-1.5,5.577-5.674-1.521a3.154,3.154,0,0,0-3.863,3.864L26,34.023l-5.575,1.494a3.155,3.155,0,0,0-1.416,5.278l4.526,4.526c0,.023,0,.046,0,.07L18.8,48.122a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,59.05a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,69.977a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,80.9a3.154,3.154,0,0,0,0,5.464L23.535,89.1,18.8,91.832a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,102.76a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,113.687a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,124.615a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,135.542a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,146.469a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,157.4a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,168.324a3.154,3.154,0,0,0,0,5.464l4.732,2.732A21.854,21.854,0,0,0,45.39,198.375H176.52a21.854,21.854,0,0,0,21.855-21.855V89.1l-76.514-4.782a11.632,11.632,0,0,1,0-23.219" transform="translate(-1.681 -17.226)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_43" data-name="Path 43" d="M143,186.71h32.782V143H143Z" transform="translate(9.984 -5.561)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_44" data-name="Path 44" d="M196.71,159.855a5.438,5.438,0,0,0-.7.07c-.042-.164-.081-.329-.127-.493a5.457,5.457,0,1,0-5.4-9.372q-.181-.185-.366-.367a5.454,5.454,0,1,0-9.384-5.4c-.162-.046-.325-.084-.486-.126a5.467,5.467,0,1,0-10.788,0c-.162.042-.325.08-.486.126a5.457,5.457,0,1,0-9.384,5.4,21.843,21.843,0,1,0,36.421,21.02,5.452,5.452,0,1,0,.7-10.858" transform="translate(10.912 -6.025)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_45" data-name="Path 45" d="M153,124.855h32.782V103H153Z" transform="translate(10.912 -9.271)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_46" data-name="Path 46" d="M194.855,116.765a2.732,2.732,0,1,0,0-5.464,2.811,2.811,0,0,0-.349.035c-.022-.082-.04-.164-.063-.246a2.733,2.733,0,0,0-1.052-5.253,2.7,2.7,0,0,0-1.648.566q-.09-.093-.184-.184a2.7,2.7,0,0,0,.553-1.633,2.732,2.732,0,0,0-5.245-1.07,10.928,10.928,0,1,0,0,21.031,2.732,2.732,0,0,0,5.245-1.07,2.7,2.7,0,0,0-.553-1.633q.093-.09.184-.184a2.7,2.7,0,0,0,1.648.566,2.732,2.732,0,0,0,1.052-5.253c.023-.081.042-.164.063-.246a2.814,2.814,0,0,0,.349.035" transform="translate(12.767 -9.377)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_47" data-name="Path 47" d="M65.087,56.891a2.732,2.732,0,0,1-2.732-2.732,8.2,8.2,0,0,0-16.391,0,2.732,2.732,0,0,1-5.464,0,13.659,13.659,0,0,1,27.319,0,2.732,2.732,0,0,1-2.732,2.732" transform="translate(0.478 -15.068)" fill-rule="evenodd"/>
|
||||
<path id="Path_48" data-name="Path 48" d="M103,191.347h65.565a21.854,21.854,0,0,0,21.855-21.855V93H124.855A21.854,21.854,0,0,0,103,114.855Z" transform="translate(6.275 -10.199)" fill="#ffff50" fill-rule="evenodd"/>
|
||||
<path id="Path_49" data-name="Path 49" d="M173.216,129.787H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0,21.855H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186m0,21.855H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0-54.434H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0,21.652H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186m0,21.855H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186M189.585,61.611c-.013,0-.024-.007-.037-.005-3.377.115-4.974,3.492-6.384,6.472-1.471,3.114-2.608,5.139-4.473,5.078-2.064-.074-3.244-2.406-4.494-4.874-1.436-2.835-3.075-6.049-6.516-5.929-3.329.114-4.932,3.053-6.346,5.646-1.5,2.762-2.529,4.442-4.5,4.364-2.106-.076-3.225-1.972-4.52-4.167-1.444-2.443-3.112-5.191-6.487-5.1-3.272.113-4.879,2.606-6.3,4.808-1.5,2.328-2.552,3.746-4.551,3.662-2.156-.076-3.27-1.65-4.558-3.472-1.447-2.047-3.077-4.363-6.442-4.251-3.2.109-4.807,2.153-6.224,3.954-1.346,1.709-2.4,3.062-4.621,2.977a1.093,1.093,0,0,0-.079,2.186c3.3.11,4.967-1.967,6.417-3.81,1.286-1.635,2.4-3.045,4.582-3.12,2.1-.09,3.091,1.218,4.584,3.327,1.417,2,3.026,4.277,6.263,4.394,3.391.114,5.022-2.42,6.467-4.663,1.292-2,2.406-3.734,4.535-3.807,1.959-.073,3.026,1.475,4.529,4.022,1.417,2.4,3.023,5.121,6.324,5.241,3.415.118,5.064-2.863,6.5-5.5,1.245-2.282,2.419-4.437,4.5-4.509,1.959-.046,2.981,1.743,4.492,4.732,1.412,2.79,3.013,5.95,6.365,6.071l.185,0c3.348,0,4.937-3.36,6.343-6.331,1.245-2.634,2.423-5.114,4.444-5.216Z" transform="translate(7.109 -13.11)" fill-rule="evenodd"/>
|
||||
<path id="Path_50" data-name="Path 50" d="M83,186.71h43.71V143H83Z" transform="translate(4.42 -5.561)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<g id="Group_8" data-name="Group 8" transform="matrix(0.966, -0.259, 0.259, 0.966, 109.327, 91.085)">
|
||||
<rect id="Rectangle_3" data-name="Rectangle 3" width="92.361" height="36.462" rx="2" transform="translate(0 0)" fill="#d8d8d8"/>
|
||||
<g id="Group_2" data-name="Group 2" transform="translate(1.531 23.03)">
|
||||
<rect id="Rectangle_4" data-name="Rectangle 4" width="5.336" height="5.336" rx="1" transform="translate(16.797 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_5" data-name="Rectangle 5" width="5.336" height="5.336" rx="1" transform="translate(23.12 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_6" data-name="Rectangle 6" width="5.336" height="5.336" rx="1" transform="translate(29.444 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_7" data-name="Rectangle 7" width="5.336" height="5.336" rx="1" transform="translate(35.768 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_8" data-name="Rectangle 8" width="5.336" height="5.336" rx="1" transform="translate(42.091 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_9" data-name="Rectangle 9" width="5.336" height="5.336" rx="1" transform="translate(48.415 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_10" data-name="Rectangle 10" width="5.336" height="5.336" rx="1" transform="translate(54.739 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_11" data-name="Rectangle 11" width="5.336" height="5.336" rx="1" transform="translate(61.063 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_12" data-name="Rectangle 12" width="5.336" height="5.336" rx="1" transform="translate(67.386 0)" fill="#4a4a4a"/>
|
||||
<path id="Path_51" data-name="Path 51" d="M1.093,0H14.518a1.093,1.093,0,0,1,1.093,1.093V4.243a1.093,1.093,0,0,1-1.093,1.093H1.093A1.093,1.093,0,0,1,0,4.243V1.093A1.093,1.093,0,0,1,1.093,0ZM75,0H88.426a1.093,1.093,0,0,1,1.093,1.093V4.243a1.093,1.093,0,0,1-1.093,1.093H75a1.093,1.093,0,0,1-1.093-1.093V1.093A1.093,1.093,0,0,1,75,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g id="Group_3" data-name="Group 3" transform="translate(1.531 10.261)">
|
||||
<path id="Path_52" data-name="Path 52" d="M1.093,0H6.218A1.093,1.093,0,0,1,7.31,1.093V4.242A1.093,1.093,0,0,1,6.218,5.335H1.093A1.093,1.093,0,0,1,0,4.242V1.093A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<rect id="Rectangle_13" data-name="Rectangle 13" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_14" data-name="Rectangle 14" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_15" data-name="Rectangle 15" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_16" data-name="Rectangle 16" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_17" data-name="Rectangle 17" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_18" data-name="Rectangle 18" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_19" data-name="Rectangle 19" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_20" data-name="Rectangle 20" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_21" data-name="Rectangle 21" width="5.336" height="5.336" rx="1" transform="translate(58.888 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_22" data-name="Rectangle 22" width="5.336" height="5.336" rx="1" transform="translate(65.212 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_23" data-name="Rectangle 23" width="5.336" height="5.336" rx="1" transform="translate(71.536 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_24" data-name="Rectangle 24" width="5.336" height="5.336" rx="1" transform="translate(77.859 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_25" data-name="Rectangle 25" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<g id="Group_4" data-name="Group 4" transform="translate(91.05 9.546) rotate(180)">
|
||||
<path id="Path_53" data-name="Path 53" d="M1.093,0H6.219A1.093,1.093,0,0,1,7.312,1.093v3.15A1.093,1.093,0,0,1,6.219,5.336H1.093A1.093,1.093,0,0,1,0,4.243V1.093A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<rect id="Rectangle_26" data-name="Rectangle 26" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_27" data-name="Rectangle 27" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_28" data-name="Rectangle 28" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_29" data-name="Rectangle 29" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_30" data-name="Rectangle 30" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_31" data-name="Rectangle 31" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_32" data-name="Rectangle 32" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_33" data-name="Rectangle 33" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_34" data-name="Rectangle 34" width="5.336" height="5.336" rx="1" transform="translate(58.889 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_35" data-name="Rectangle 35" width="5.336" height="5.336" rx="1" transform="translate(65.213 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_36" data-name="Rectangle 36" width="5.336" height="5.336" rx="1" transform="translate(71.537 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_37" data-name="Rectangle 37" width="5.336" height="5.336" rx="1" transform="translate(77.86 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_38" data-name="Rectangle 38" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_39" data-name="Rectangle 39" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_40" data-name="Rectangle 40" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_41" data-name="Rectangle 41" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_42" data-name="Rectangle 42" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_43" data-name="Rectangle 43" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_44" data-name="Rectangle 44" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_45" data-name="Rectangle 45" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_46" data-name="Rectangle 46" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_47" data-name="Rectangle 47" width="5.336" height="5.336" rx="1" transform="translate(58.889 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_48" data-name="Rectangle 48" width="5.336" height="5.336" rx="1" transform="translate(65.213 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_49" data-name="Rectangle 49" width="5.336" height="5.336" rx="1" transform="translate(71.537 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_50" data-name="Rectangle 50" width="5.336" height="5.336" rx="1" transform="translate(77.86 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_51" data-name="Rectangle 51" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<g id="Group_6" data-name="Group 6" transform="translate(1.531 16.584)">
|
||||
<path id="Path_54" data-name="Path 54" d="M1.093,0h7.3A1.093,1.093,0,0,1,9.485,1.093v3.15A1.093,1.093,0,0,1,8.392,5.336h-7.3A1.093,1.093,0,0,1,0,4.243V1.094A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<g id="Group_5" data-name="Group 5" transform="translate(10.671 0)">
|
||||
<rect id="Rectangle_52" data-name="Rectangle 52" width="5.336" height="5.336" rx="1" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_53" data-name="Rectangle 53" width="5.336" height="5.336" rx="1" transform="translate(6.324 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_54" data-name="Rectangle 54" width="5.336" height="5.336" rx="1" transform="translate(12.647 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_55" data-name="Rectangle 55" width="5.336" height="5.336" rx="1" transform="translate(18.971 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_56" data-name="Rectangle 56" width="5.336" height="5.336" rx="1" transform="translate(25.295 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_57" data-name="Rectangle 57" width="5.336" height="5.336" rx="1" transform="translate(31.619 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_58" data-name="Rectangle 58" width="5.336" height="5.336" rx="1" transform="translate(37.942 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_59" data-name="Rectangle 59" width="5.336" height="5.336" rx="1" transform="translate(44.265 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_60" data-name="Rectangle 60" width="5.336" height="5.336" rx="1" transform="translate(50.589 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_61" data-name="Rectangle 61" width="5.336" height="5.336" rx="1" transform="translate(56.912 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_62" data-name="Rectangle 62" width="5.336" height="5.336" rx="1" transform="translate(63.236 0)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<path id="Path_55" data-name="Path 55" d="M1.094,0H8A1.093,1.093,0,0,1,9.091,1.093v3.15A1.093,1.093,0,0,1,8,5.336H1.093A1.093,1.093,0,0,1,0,4.243V1.094A1.093,1.093,0,0,1,1.093,0Z" transform="translate(80.428 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g id="Group_7" data-name="Group 7" transform="translate(1.531 29.627)">
|
||||
<rect id="Rectangle_63" data-name="Rectangle 63" width="5.336" height="5.336" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_64" data-name="Rectangle 64" width="5.336" height="5.336" rx="1" transform="translate(6.324 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_65" data-name="Rectangle 65" width="5.336" height="5.336" rx="1" transform="translate(12.647 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_66" data-name="Rectangle 66" width="5.336" height="5.336" rx="1" transform="translate(18.971 0)" fill="#4a4a4a"/>
|
||||
<path id="Path_56" data-name="Path 56" d="M1.093,0H31.515a1.093,1.093,0,0,1,1.093,1.093V4.244a1.093,1.093,0,0,1-1.093,1.093H1.093A1.093,1.093,0,0,1,0,4.244V1.093A1.093,1.093,0,0,1,1.093,0ZM34.687,0h3.942a1.093,1.093,0,0,1,1.093,1.093V4.244a1.093,1.093,0,0,1-1.093,1.093H34.687a1.093,1.093,0,0,1-1.093-1.093V1.093A1.093,1.093,0,0,1,34.687,0Z" transform="translate(25.294 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<rect id="Rectangle_67" data-name="Rectangle 67" width="5.336" height="5.336" rx="1" transform="translate(66.003 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_68" data-name="Rectangle 68" width="5.336" height="5.336" rx="1" transform="translate(72.327 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_69" data-name="Rectangle 69" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
|
||||
<path id="Path_57" data-name="Path 57" d="M5.336,0V1.18A1.093,1.093,0,0,1,4.243,2.273H1.093A1.093,1.093,0,0,1,0,1.18V0Z" transform="translate(83.59 2.273) rotate(180)" fill="#4a4a4a"/>
|
||||
<path id="Path_58" data-name="Path 58" d="M5.336,0V1.18A1.093,1.093,0,0,1,4.243,2.273H1.093A1.093,1.093,0,0,1,0,1.18V0Z" transform="translate(78.255 3.063)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<rect id="Rectangle_70" data-name="Rectangle 70" width="88.927" height="2.371" rx="1.085" transform="translate(1.925 1.17)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_71" data-name="Rectangle 71" width="4.986" height="1.581" rx="0.723" transform="translate(4.1 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_72" data-name="Rectangle 72" width="4.986" height="1.581" rx="0.723" transform="translate(10.923 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_73" data-name="Rectangle 73" width="4.986" height="1.581" rx="0.723" transform="translate(16.173 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_74" data-name="Rectangle 74" width="4.986" height="1.581" rx="0.723" transform="translate(21.421 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_75" data-name="Rectangle 75" width="4.986" height="1.581" rx="0.723" transform="translate(26.671 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_76" data-name="Rectangle 76" width="4.986" height="1.581" rx="0.723" transform="translate(33.232 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_77" data-name="Rectangle 77" width="4.986" height="1.581" rx="0.723" transform="translate(38.48 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_78" data-name="Rectangle 78" width="4.986" height="1.581" rx="0.723" transform="translate(43.73 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_79" data-name="Rectangle 79" width="4.986" height="1.581" rx="0.723" transform="translate(48.978 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_80" data-name="Rectangle 80" width="4.986" height="1.581" rx="0.723" transform="translate(55.54 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_81" data-name="Rectangle 81" width="4.986" height="1.581" rx="0.723" transform="translate(60.788 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_82" data-name="Rectangle 82" width="4.986" height="1.581" rx="0.723" transform="translate(66.038 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_83" data-name="Rectangle 83" width="4.986" height="1.581" rx="0.723" transform="translate(72.599 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_84" data-name="Rectangle 84" width="4.986" height="1.581" rx="0.723" transform="translate(77.847 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_85" data-name="Rectangle 85" width="4.986" height="1.581" rx="0.723" transform="translate(83.097 1.566)" fill="#d8d8d8" opacity="0.136"/>
|
||||
</g>
|
||||
<path id="Path_59" data-name="Path 59" d="M146.71,159.855a5.439,5.439,0,0,0-.7.07c-.042-.164-.081-.329-.127-.493a5.457,5.457,0,1,0-5.4-9.372q-.181-.185-.366-.367a5.454,5.454,0,1,0-9.384-5.4c-.162-.046-.325-.084-.486-.126a5.467,5.467,0,1,0-10.788,0c-.162.042-.325.08-.486.126a5.457,5.457,0,1,0-9.384,5.4,21.843,21.843,0,1,0,36.421,21.02,5.452,5.452,0,1,0,.7-10.858" transform="translate(6.275 -6.025)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_60" data-name="Path 60" d="M83,124.855h43.71V103H83Z" transform="translate(4.42 -9.271)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_61" data-name="Path 61" d="M134.855,116.765a2.732,2.732,0,1,0,0-5.464,2.811,2.811,0,0,0-.349.035c-.022-.082-.04-.164-.063-.246a2.733,2.733,0,0,0-1.052-5.253,2.7,2.7,0,0,0-1.648.566q-.09-.093-.184-.184a2.7,2.7,0,0,0,.553-1.633,2.732,2.732,0,0,0-5.245-1.07,10.928,10.928,0,1,0,0,21.031,2.732,2.732,0,0,0,5.245-1.07,2.7,2.7,0,0,0-.553-1.633q.093-.09.184-.184a2.7,2.7,0,0,0,1.648.566,2.732,2.732,0,0,0,1.052-5.253c.023-.081.042-.164.063-.246a2.811,2.811,0,0,0,.349.035" transform="translate(7.202 -9.377)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_62" data-name="Path 62" d="M143.232,42.33a2.967,2.967,0,0,1-.535-.055,2.754,2.754,0,0,1-.514-.153,2.838,2.838,0,0,1-.471-.251,4.139,4.139,0,0,1-.415-.339,3.2,3.2,0,0,1-.338-.415A2.7,2.7,0,0,1,140.5,39.6a2.968,2.968,0,0,1,.055-.535,3.152,3.152,0,0,1,.152-.514,2.874,2.874,0,0,1,.252-.47,2.633,2.633,0,0,1,.753-.754,2.837,2.837,0,0,1,.471-.251,2.753,2.753,0,0,1,.514-.153,2.527,2.527,0,0,1,1.071,0,2.654,2.654,0,0,1,.983.4,4.139,4.139,0,0,1,.415.339,4.019,4.019,0,0,1,.339.415,2.786,2.786,0,0,1,.251.47,2.864,2.864,0,0,1,.208,1.049,2.77,2.77,0,0,1-.8,1.934,4.139,4.139,0,0,1-.415.339,2.722,2.722,0,0,1-1.519.459m21.855-1.366a2.789,2.789,0,0,1-1.935-.8,4.162,4.162,0,0,1-.338-.415,2.7,2.7,0,0,1-.459-1.519,2.789,2.789,0,0,1,.8-1.934,4.139,4.139,0,0,1,.415-.339,2.838,2.838,0,0,1,.471-.251,2.752,2.752,0,0,1,.514-.153,2.527,2.527,0,0,1,1.071,0,2.654,2.654,0,0,1,.983.4,4.139,4.139,0,0,1,.415.339,2.79,2.79,0,0,1,.8,1.934,3.069,3.069,0,0,1-.055.535,2.779,2.779,0,0,1-.153.514,3.885,3.885,0,0,1-.251.47,4.02,4.02,0,0,1-.339.415,4.138,4.138,0,0,1-.415.339,2.722,2.722,0,0,1-1.519.459" transform="translate(9.753 -15.532)" fill-rule="evenodd"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 31 KiB |
@@ -1,170 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1041.277" height="554.141" viewBox="0 0 1041.277 554.141">
|
||||
<title>Powered by React</title>
|
||||
<g id="Group_24" data-name="Group 24" transform="translate(-440 -263)">
|
||||
<g id="Group_23" data-name="Group 23" transform="translate(439.989 262.965)">
|
||||
<path id="Path_299" data-name="Path 299" d="M1040.82,611.12q-1.74,3.75-3.47,7.4-2.7,5.67-5.33,11.12c-.78,1.61-1.56,3.19-2.32,4.77-8.6,17.57-16.63,33.11-23.45,45.89A73.21,73.21,0,0,1,942.44,719l-151.65,1.65h-1.6l-13,.14-11.12.12-34.1.37h-1.38l-17.36.19h-.53l-107,1.16-95.51,1-11.11.12-69,.75H429l-44.75.48h-.48l-141.5,1.53-42.33.46a87.991,87.991,0,0,1-10.79-.54h0c-1.22-.14-2.44-.3-3.65-.49a87.38,87.38,0,0,1-51.29-27.54C116,678.37,102.75,655,93.85,629.64q-1.93-5.49-3.6-11.12C59.44,514.37,97,380,164.6,290.08q4.25-5.64,8.64-11l.07-.08c20.79-25.52,44.1-46.84,68.93-62,44-26.91,92.75-34.49,140.7-11.9,40.57,19.12,78.45,28.11,115.17,30.55,3.71.24,7.42.42,11.11.53,84.23,2.65,163.17-27.7,255.87-47.29,3.69-.78,7.39-1.55,11.12-2.28,66.13-13.16,139.49-20.1,226.73-5.51a189.089,189.089,0,0,1,26.76,6.4q5.77,1.86,11.12,4c41.64,16.94,64.35,48.24,74,87.46q1.37,5.46,2.37,11.11C1134.3,384.41,1084.19,518.23,1040.82,611.12Z" transform="translate(-79.34 -172.91)" fill="#f2f2f2"/>
|
||||
<path id="Path_300" data-name="Path 300" d="M576.36,618.52a95.21,95.21,0,0,1-1.87,11.12h93.7V618.52Zm-78.25,62.81,11.11-.09V653.77c-3.81-.17-7.52-.34-11.11-.52ZM265.19,618.52v11.12h198.5V618.52ZM1114.87,279h-74V191.51q-5.35-2.17-11.12-4V279H776.21V186.58c-3.73.73-7.43,1.5-11.12,2.28V279H509.22V236.15c-3.69-.11-7.4-.29-11.11-.53V279H242.24V217c-24.83,15.16-48.14,36.48-68.93,62h-.07v.08q-4.4,5.4-8.64,11h8.64V618.52h-83q1.66,5.63,3.6,11.12h79.39v93.62a87,87,0,0,0,12.2,2.79c1.21.19,2.43.35,3.65.49h0a87.991,87.991,0,0,0,10.79.54l42.33-.46v-97H498.11v94.21l11.11-.12V629.64H765.09V721l11.12-.12V629.64H1029.7v4.77c.76-1.58,1.54-3.16,2.32-4.77q2.63-5.45,5.33-11.12,1.73-3.64,3.47-7.4v-321h76.42Q1116.23,284.43,1114.87,279ZM242.24,618.52V290.08H498.11V618.52Zm267,0V290.08H765.09V618.52Zm520.48,0H776.21V290.08H1029.7Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_301" data-name="Path 301" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l46.65-28,93.6-.78,2-.01.66-.01,2-.03,44.94-.37,2.01-.01.64-.01,2-.01L315,509.3l.38-.01,35.55-.3h.29l277.4-2.34,6.79-.05h.68l5.18-.05,37.65-.31,2-.03,1.85-.02h.96l11.71-.09,2.32-.03,3.11-.02,9.75-.09,15.47-.13,2-.02,3.48-.02h.65l74.71-.64Z" fill="#65617d"/>
|
||||
<path id="Path_302" data-name="Path 302" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l46.65-28,93.6-.78,2-.01.66-.01,2-.03,44.94-.37,2.01-.01.64-.01,2-.01L315,509.3l.38-.01,35.55-.3h.29l277.4-2.34,6.79-.05h.68l5.18-.05,37.65-.31,2-.03,1.85-.02h.96l11.71-.09,2.32-.03,3.11-.02,9.75-.09,15.47-.13,2-.02,3.48-.02h.65l74.71-.64Z" opacity="0.2"/>
|
||||
<path id="Path_303" data-name="Path 303" d="M375.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
||||
<path id="Path_304" data-name="Path 304" d="M375.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_305" data-name="Path 305" d="M377.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
||||
<rect id="Rectangle_137" data-name="Rectangle 137" width="47.17" height="31.5" transform="translate(680.92 483.65)" fill="#3f3d56"/>
|
||||
<rect id="Rectangle_138" data-name="Rectangle 138" width="47.17" height="31.5" transform="translate(680.92 483.65)" opacity="0.1"/>
|
||||
<rect id="Rectangle_139" data-name="Rectangle 139" width="47.17" height="31.5" transform="translate(678.92 483.65)" fill="#3f3d56"/>
|
||||
<path id="Path_306" data-name="Path 306" d="M298.09,483.65v4.97l-47.17,1.26v-6.23Z" opacity="0.1"/>
|
||||
<path id="Path_307" data-name="Path 307" d="M460.69,485.27v168.2a4,4,0,0,1-3.85,3.95l-191.65,5.1h-.05a4,4,0,0,1-3.95-3.95V485.27a4,4,0,0,1,3.95-3.95h191.6a4,4,0,0,1,3.95,3.95Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
|
||||
<path id="Path_308" data-name="Path 308" d="M265.19,481.32v181.2h-.05a4,4,0,0,1-3.95-3.95V485.27a4,4,0,0,1,3.95-3.95Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_309" data-name="Path 309" d="M194.59,319.15h177.5V467.4l-177.5,4Z" fill="#39374d"/>
|
||||
<path id="Path_310" data-name="Path 310" d="M726.09,483.65v6.41l-47.17-1.26v-5.15Z" opacity="0.1"/>
|
||||
<path id="Path_311" data-name="Path 311" d="M867.69,485.27v173.3a4,4,0,0,1-4,3.95h0L672,657.42a4,4,0,0,1-3.85-3.95V485.27a4,4,0,0,1,3.95-3.95H863.7a4,4,0,0,1,3.99,3.95Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
|
||||
<path id="Path_312" data-name="Path 312" d="M867.69,485.27v173.3a4,4,0,0,1-4,3.95h0V481.32h0a4,4,0,0,1,4,3.95Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_313" data-name="Path 313" d="M775.59,319.15H598.09V467.4l177.5,4Z" fill="#39374d"/>
|
||||
<path id="Path_314" data-name="Path 314" d="M663.19,485.27v168.2a4,4,0,0,1-3.85,3.95l-191.65,5.1h0a4,4,0,0,1-4-3.95V485.27a4,4,0,0,1,3.95-3.95h191.6A4,4,0,0,1,663.19,485.27Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
|
||||
<path id="Path_315" data-name="Path 315" d="M397.09,319.15h177.5V467.4l-177.5,4Z" fill="#4267b2"/>
|
||||
<path id="Path_316" data-name="Path 316" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l202.51-1.33h.48l40.99-.28h.19l283.08-1.87h.29l.17-.01h.47l4.79-.03h1.46l74.49-.5,4.4-.02.98-.01Z" opacity="0.1"/>
|
||||
<circle id="Ellipse_111" data-name="Ellipse 111" cx="51.33" cy="51.33" r="51.33" transform="translate(435.93 246.82)" fill="#fbbebe"/>
|
||||
<path id="Path_317" data-name="Path 317" d="M617.94,550.07s-99.5,12-90,0c3.44-4.34,4.39-17.2,4.2-31.85-.06-4.45-.22-9.06-.45-13.65-1.1-22-3.75-43.5-3.75-43.5s87-41,77-8.5c-4,13.13-2.69,31.57.35,48.88.89,5.05,1.92,10,3,14.7a344.66,344.66,0,0,0,9.65,33.92Z" transform="translate(-79.34 -172.91)" fill="#fbbebe"/>
|
||||
<path id="Path_318" data-name="Path 318" d="M585.47,546c11.51-2.13,23.7-6,34.53-1.54,2.85,1.17,5.47,2.88,8.39,3.86s6.12,1.22,9.16,1.91c10.68,2.42,19.34,10.55,24.9,20s8.44,20.14,11.26,30.72l6.9,25.83c6,22.45,12,45.09,13.39,68.3a2437.506,2437.506,0,0,1-250.84,1.43c5.44-10.34,11-21.31,10.54-33s-7.19-23.22-4.76-34.74c1.55-7.34,6.57-13.39,9.64-20.22,8.75-19.52,1.94-45.79,17.32-60.65,6.92-6.68,17-9.21,26.63-8.89,12.28.41,24.85,4.24,37,6.11C555.09,547.48,569.79,548.88,585.47,546Z" transform="translate(-79.34 -172.91)" fill="#ff6584"/>
|
||||
<path id="Path_319" data-name="Path 319" d="M716.37,657.17l-.1,1.43v.1l-.17,2.3-1.33,18.51-1.61,22.3-.46,6.28-1,13.44v.17l-107,1-175.59,1.9v.84h-.14v-1.12l.45-14.36.86-28.06.74-23.79.07-2.37a10.53,10.53,0,0,1,11.42-10.17c4.72.4,10.85.89,18.18,1.41l3,.22c42.33,2.94,120.56,6.74,199.5,2,1.66-.09,3.33-.19,5-.31,12.24-.77,24.47-1.76,36.58-3a10.53,10.53,0,0,1,11.6,11.23Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_320" data-name="Path 320" d="M429.08,725.44v-.84l175.62-1.91,107-1h.3v-.17l1-13.44.43-6,1.64-22.61,1.29-17.9v-.44a10.617,10.617,0,0,0-.11-2.47.3.3,0,0,0,0-.1,10.391,10.391,0,0,0-2-4.64,10.54,10.54,0,0,0-9.42-4c-12.11,1.24-24.34,2.23-36.58,3-1.67.12-3.34.22-5,.31-78.94,4.69-157.17.89-199.5-2l-3-.22c-7.33-.52-13.46-1-18.18-1.41a10.54,10.54,0,0,0-11.24,8.53,11,11,0,0,0-.18,1.64l-.68,22.16L429.54,710l-.44,14.36v1.12Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
||||
<path id="Path_321" data-name="Path 321" d="M716.67,664.18l-1.23,15.33-1.83,22.85-.46,5.72-1,12.81-.06.64v.17h0l-.15,1.48.11-1.48h-.29l-107,1-175.65,1.9v-.28l.49-14.36,1-28.06.64-18.65A6.36,6.36,0,0,1,434.3,658a6.25,6.25,0,0,1,3.78-.9c2.1.17,4.68.37,7.69.59,4.89.36,10.92.78,17.94,1.22,13,.82,29.31,1.7,48,2.42,52,2,122.2,2.67,188.88-3.17,3-.26,6.1-.55,9.13-.84a6.26,6.26,0,0,1,3.48.66,5.159,5.159,0,0,1,.86.54,6.14,6.14,0,0,1,2,2.46,3.564,3.564,0,0,1,.25.61A6.279,6.279,0,0,1,716.67,664.18Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_322" data-name="Path 322" d="M377.44,677.87v3.19a6.13,6.13,0,0,1-3.5,5.54l-40.1.77a6.12,6.12,0,0,1-3.57-5.57v-3Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_323" data-name="Path 323" d="M298.59,515.57l-52.25,1V507.9l52.25-1Z" fill="#3f3d56"/>
|
||||
<path id="Path_324" data-name="Path 324" d="M298.59,515.57l-52.25,1V507.9l52.25-1Z" opacity="0.1"/>
|
||||
<path id="Path_325" data-name="Path 325" d="M300.59,515.57l-52.25,1V507.9l52.25-1Z" fill="#3f3d56"/>
|
||||
<path id="Path_326" data-name="Path 326" d="M758.56,679.87v3.19a6.13,6.13,0,0,0,3.5,5.54l40.1.77a6.12,6.12,0,0,0,3.57-5.57v-3Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
|
||||
<path id="Path_327" data-name="Path 327" d="M678.72,517.57l52.25,1V509.9l-52.25-1Z" opacity="0.1"/>
|
||||
<path id="Path_328" data-name="Path 328" d="M676.72,517.57l52.25,1V509.9l-52.25-1Z" fill="#3f3d56"/>
|
||||
<path id="Path_329" data-name="Path 329" d="M534.13,486.79c.08,7-3.16,13.6-5.91,20.07a163.491,163.491,0,0,0-12.66,74.71c.73,11,2.58,22,.73,32.9s-8.43,21.77-19,24.9c17.53,10.45,41.26,9.35,57.76-2.66,8.79-6.4,15.34-15.33,21.75-24.11a97.86,97.86,0,0,1-13.31,44.75A103.43,103.43,0,0,0,637,616.53c4.31-5.81,8.06-12.19,9.72-19.23,3.09-13-1.22-26.51-4.51-39.5a266.055,266.055,0,0,1-6.17-33c-.43-3.56-.78-7.22.1-10.7,1-4.07,3.67-7.51,5.64-11.22,5.6-10.54,5.73-23.3,2.86-34.88s-8.49-22.26-14.06-32.81c-4.46-8.46-9.3-17.31-17.46-22.28-5.1-3.1-11-4.39-16.88-5.64l-25.37-5.43c-5.55-1.19-11.26-2.38-16.87-1.51-9.47,1.48-16.14,8.32-22,15.34-4.59,5.46-15.81,15.71-16.6,22.86-.72,6.59,5.1,17.63,6.09,24.58,1.3,9,2.22,6,7.3,11.52C532,478.05,534.07,482,534.13,486.79Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
|
||||
</g>
|
||||
<g id="docusaurus_keytar" transform="translate(670.271 615.768)">
|
||||
<path id="Path_40" data-name="Path 40" d="M99,52h43.635V69.662H99Z" transform="translate(-49.132 -33.936)" fill="#fff" fill-rule="evenodd"/>
|
||||
<path id="Path_41" data-name="Path 41" d="M13.389,158.195A10.377,10.377,0,0,1,4.4,153a10.377,10.377,0,0,0,8.988,15.584H23.779V158.195Z" transform="translate(-3 -82.47)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_42" data-name="Path 42" d="M66.967,38.083l36.373-2.273V30.615A10.389,10.389,0,0,0,92.95,20.226H46.2l-1.3-2.249a1.5,1.5,0,0,0-2.6,0L41,20.226l-1.3-2.249a1.5,1.5,0,0,0-2.6,0l-1.3,2.249-1.3-2.249a1.5,1.5,0,0,0-2.6,0l-1.3,2.249-.034,0-2.152-2.151a1.5,1.5,0,0,0-2.508.672L25.21,21.4l-2.7-.723a1.5,1.5,0,0,0-1.836,1.837l.722,2.7-2.65.71a1.5,1.5,0,0,0-.673,2.509l2.152,2.152c0,.011,0,.022,0,.033l-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6L20.226,41l-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3A10.389,10.389,0,0,0,30.615,103.34H92.95A10.389,10.389,0,0,0,103.34,92.95V51.393L66.967,49.12a5.53,5.53,0,0,1,0-11.038" transform="translate(-9.836 -17.226)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_43" data-name="Path 43" d="M143,163.779h15.584V143H143Z" transform="translate(-70.275 -77.665)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_44" data-name="Path 44" d="M173.779,148.389a2.582,2.582,0,0,0-.332.033c-.02-.078-.038-.156-.06-.234a2.594,2.594,0,1,0-2.567-4.455q-.086-.088-.174-.175a2.593,2.593,0,1,0-4.461-2.569c-.077-.022-.154-.04-.231-.06a2.6,2.6,0,1,0-5.128,0c-.077.02-.154.038-.231.06a2.594,2.594,0,1,0-4.461,2.569,10.384,10.384,0,1,0,17.314,9.992,2.592,2.592,0,1,0,.332-5.161" transform="translate(-75.08 -75.262)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_45" data-name="Path 45" d="M153,113.389h15.584V103H153Z" transform="translate(-75.08 -58.444)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_46" data-name="Path 46" d="M183.389,108.944a1.3,1.3,0,1,0,0-2.6,1.336,1.336,0,0,0-.166.017c-.01-.039-.019-.078-.03-.117a1.3,1.3,0,0,0-.5-2.5,1.285,1.285,0,0,0-.783.269q-.043-.044-.087-.087a1.285,1.285,0,0,0,.263-.776,1.3,1.3,0,0,0-2.493-.509,5.195,5.195,0,1,0,0,10,1.3,1.3,0,0,0,2.493-.509,1.285,1.285,0,0,0-.263-.776q.044-.043.087-.087a1.285,1.285,0,0,0,.783.269,1.3,1.3,0,0,0,.5-2.5c.011-.038.02-.078.03-.117a1.337,1.337,0,0,0,.166.017" transform="translate(-84.691 -57.894)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_47" data-name="Path 47" d="M52.188,48.292a1.3,1.3,0,0,1-1.3-1.3,3.9,3.9,0,0,0-7.792,0,1.3,1.3,0,1,1-2.6,0,6.493,6.493,0,0,1,12.987,0,1.3,1.3,0,0,1-1.3,1.3" transform="translate(-21.02 -28.41)" fill-rule="evenodd"/>
|
||||
<path id="Path_48" data-name="Path 48" d="M103,139.752h31.168a10.389,10.389,0,0,0,10.389-10.389V93H113.389A10.389,10.389,0,0,0,103,103.389Z" transform="translate(-51.054 -53.638)" fill="#ffff50" fill-rule="evenodd"/>
|
||||
<path id="Path_49" data-name="Path 49" d="M141.1,94.017H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0-25.877H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.293H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m7.782-47.993c-.006,0-.011,0-.018,0-1.605.055-2.365,1.66-3.035,3.077-.7,1.48-1.24,2.443-2.126,2.414-.981-.035-1.542-1.144-2.137-2.317-.683-1.347-1.462-2.876-3.1-2.819-1.582.054-2.344,1.451-3.017,2.684-.715,1.313-1.2,2.112-2.141,2.075-1-.036-1.533-.938-2.149-1.981-.686-1.162-1.479-2.467-3.084-2.423-1.555.053-2.319,1.239-2.994,2.286-.713,1.106-1.213,1.781-2.164,1.741-1.025-.036-1.554-.784-2.167-1.65-.688-.973-1.463-2.074-3.062-2.021a3.815,3.815,0,0,0-2.959,1.879c-.64.812-1.14,1.456-2.2,1.415a.52.52,0,0,0-.037,1.039,3.588,3.588,0,0,0,3.05-1.811c.611-.777,1.139-1.448,2.178-1.483,1-.043,1.47.579,2.179,1.582.674.953,1.438,2.033,2.977,2.089,1.612.054,2.387-1.151,3.074-2.217.614-.953,1.144-1.775,2.156-1.81.931-.035,1.438.7,2.153,1.912.674,1.141,1.437,2.434,3.006,2.491,1.623.056,2.407-1.361,3.09-2.616.592-1.085,1.15-2.109,2.14-2.143.931-.022,1.417.829,2.135,2.249.671,1.326,1.432,2.828,3.026,2.886l.088,0c1.592,0,2.347-1.6,3.015-3.01.592-1.252,1.152-2.431,2.113-2.479Z" transform="translate(-55.378 -38.552)" fill-rule="evenodd"/>
|
||||
<path id="Path_50" data-name="Path 50" d="M83,163.779h20.779V143H83Z" transform="translate(-41.443 -77.665)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<g id="Group_8" data-name="Group 8" transform="matrix(0.966, -0.259, 0.259, 0.966, 51.971, 43.3)">
|
||||
<rect id="Rectangle_3" data-name="Rectangle 3" width="43.906" height="17.333" rx="2" transform="translate(0 0)" fill="#d8d8d8"/>
|
||||
<g id="Group_2" data-name="Group 2" transform="translate(0.728 10.948)">
|
||||
<rect id="Rectangle_4" data-name="Rectangle 4" width="2.537" height="2.537" rx="1" transform="translate(7.985 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_5" data-name="Rectangle 5" width="2.537" height="2.537" rx="1" transform="translate(10.991 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_6" data-name="Rectangle 6" width="2.537" height="2.537" rx="1" transform="translate(13.997 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_7" data-name="Rectangle 7" width="2.537" height="2.537" rx="1" transform="translate(17.003 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_8" data-name="Rectangle 8" width="2.537" height="2.537" rx="1" transform="translate(20.009 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_9" data-name="Rectangle 9" width="2.537" height="2.537" rx="1" transform="translate(23.015 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_10" data-name="Rectangle 10" width="2.537" height="2.537" rx="1" transform="translate(26.021 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_11" data-name="Rectangle 11" width="2.537" height="2.537" rx="1" transform="translate(29.028 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_12" data-name="Rectangle 12" width="2.537" height="2.537" rx="1" transform="translate(32.034 0)" fill="#4a4a4a"/>
|
||||
<path id="Path_51" data-name="Path 51" d="M.519,0H6.9A.519.519,0,0,1,7.421.52v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0ZM35.653,0h6.383a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H35.652a.519.519,0,0,1-.519-.519V.519A.519.519,0,0,1,35.652,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g id="Group_3" data-name="Group 3" transform="translate(0.728 4.878)">
|
||||
<path id="Path_52" data-name="Path 52" d="M.519,0H2.956a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<rect id="Rectangle_13" data-name="Rectangle 13" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_14" data-name="Rectangle 14" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_15" data-name="Rectangle 15" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_16" data-name="Rectangle 16" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_17" data-name="Rectangle 17" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_18" data-name="Rectangle 18" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_19" data-name="Rectangle 19" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_20" data-name="Rectangle 20" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_21" data-name="Rectangle 21" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_22" data-name="Rectangle 22" width="2.537" height="2.537" rx="1" transform="translate(31 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_23" data-name="Rectangle 23" width="2.537" height="2.537" rx="1" transform="translate(34.006 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_24" data-name="Rectangle 24" width="2.537" height="2.537" rx="1" transform="translate(37.012 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_25" data-name="Rectangle 25" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<g id="Group_4" data-name="Group 4" transform="translate(43.283 4.538) rotate(180)">
|
||||
<path id="Path_53" data-name="Path 53" d="M.519,0H2.956a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<rect id="Rectangle_26" data-name="Rectangle 26" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_27" data-name="Rectangle 27" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_28" data-name="Rectangle 28" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_29" data-name="Rectangle 29" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_30" data-name="Rectangle 30" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_31" data-name="Rectangle 31" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_32" data-name="Rectangle 32" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_33" data-name="Rectangle 33" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_34" data-name="Rectangle 34" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_35" data-name="Rectangle 35" width="2.537" height="2.537" rx="1" transform="translate(31.001 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_36" data-name="Rectangle 36" width="2.537" height="2.537" rx="1" transform="translate(34.007 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_37" data-name="Rectangle 37" width="2.537" height="2.537" rx="1" transform="translate(37.013 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_38" data-name="Rectangle 38" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_39" data-name="Rectangle 39" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_40" data-name="Rectangle 40" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_41" data-name="Rectangle 41" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_42" data-name="Rectangle 42" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_43" data-name="Rectangle 43" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_44" data-name="Rectangle 44" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_45" data-name="Rectangle 45" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_46" data-name="Rectangle 46" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_47" data-name="Rectangle 47" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_48" data-name="Rectangle 48" width="2.537" height="2.537" rx="1" transform="translate(31.001 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_49" data-name="Rectangle 49" width="2.537" height="2.537" rx="1" transform="translate(34.007 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_50" data-name="Rectangle 50" width="2.537" height="2.537" rx="1" transform="translate(37.013 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_51" data-name="Rectangle 51" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<g id="Group_6" data-name="Group 6" transform="translate(0.728 7.883)">
|
||||
<path id="Path_54" data-name="Path 54" d="M.519,0h3.47a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.52A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<g id="Group_5" data-name="Group 5" transform="translate(5.073 0)">
|
||||
<rect id="Rectangle_52" data-name="Rectangle 52" width="2.537" height="2.537" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_53" data-name="Rectangle 53" width="2.537" height="2.537" rx="1" transform="translate(3.006 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_54" data-name="Rectangle 54" width="2.537" height="2.537" rx="1" transform="translate(6.012 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_55" data-name="Rectangle 55" width="2.537" height="2.537" rx="1" transform="translate(9.018 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_56" data-name="Rectangle 56" width="2.537" height="2.537" rx="1" transform="translate(12.025 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_57" data-name="Rectangle 57" width="2.537" height="2.537" rx="1" transform="translate(15.031 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_58" data-name="Rectangle 58" width="2.537" height="2.537" rx="1" transform="translate(18.037 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_59" data-name="Rectangle 59" width="2.537" height="2.537" rx="1" transform="translate(21.042 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_60" data-name="Rectangle 60" width="2.537" height="2.537" rx="1" transform="translate(24.049 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_61" data-name="Rectangle 61" width="2.537" height="2.537" rx="1" transform="translate(27.055 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_62" data-name="Rectangle 62" width="2.537" height="2.537" rx="1" transform="translate(30.061 0)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<path id="Path_55" data-name="Path 55" d="M.52,0H3.8a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.52A.519.519,0,0,1,.519,0Z" transform="translate(38.234 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g id="Group_7" data-name="Group 7" transform="translate(0.728 14.084)">
|
||||
<rect id="Rectangle_63" data-name="Rectangle 63" width="2.537" height="2.537" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_64" data-name="Rectangle 64" width="2.537" height="2.537" rx="1" transform="translate(3.006 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_65" data-name="Rectangle 65" width="2.537" height="2.537" rx="1" transform="translate(6.012 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_66" data-name="Rectangle 66" width="2.537" height="2.537" rx="1" transform="translate(9.018 0)" fill="#4a4a4a"/>
|
||||
<path id="Path_56" data-name="Path 56" d="M.519,0H14.981A.519.519,0,0,1,15.5.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.018V.519A.519.519,0,0,1,.519,0Zm15.97,0h1.874a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H16.489a.519.519,0,0,1-.519-.519V.519A.519.519,0,0,1,16.489,0Z" transform="translate(12.024 0)" fill="#4a4a4a" fill-rule="evenodd"/>
|
||||
<rect id="Rectangle_67" data-name="Rectangle 67" width="2.537" height="2.537" rx="1" transform="translate(31.376 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_68" data-name="Rectangle 68" width="2.537" height="2.537" rx="1" transform="translate(34.382 0)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_69" data-name="Rectangle 69" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
|
||||
<path id="Path_57" data-name="Path 57" d="M2.537,0V.561a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,.561V0Z" transform="translate(39.736 1.08) rotate(180)" fill="#4a4a4a"/>
|
||||
<path id="Path_58" data-name="Path 58" d="M2.537,0V.561a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,.561V0Z" transform="translate(37.2 1.456)" fill="#4a4a4a"/>
|
||||
</g>
|
||||
<rect id="Rectangle_70" data-name="Rectangle 70" width="42.273" height="1.127" rx="0.564" transform="translate(0.915 0.556)" fill="#4a4a4a"/>
|
||||
<rect id="Rectangle_71" data-name="Rectangle 71" width="2.37" height="0.752" rx="0.376" transform="translate(1.949 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_72" data-name="Rectangle 72" width="2.37" height="0.752" rx="0.376" transform="translate(5.193 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_73" data-name="Rectangle 73" width="2.37" height="0.752" rx="0.376" transform="translate(7.688 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_74" data-name="Rectangle 74" width="2.37" height="0.752" rx="0.376" transform="translate(10.183 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_75" data-name="Rectangle 75" width="2.37" height="0.752" rx="0.376" transform="translate(12.679 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_76" data-name="Rectangle 76" width="2.37" height="0.752" rx="0.376" transform="translate(15.797 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_77" data-name="Rectangle 77" width="2.37" height="0.752" rx="0.376" transform="translate(18.292 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_78" data-name="Rectangle 78" width="2.37" height="0.752" rx="0.376" transform="translate(20.788 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_79" data-name="Rectangle 79" width="2.37" height="0.752" rx="0.376" transform="translate(23.283 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_80" data-name="Rectangle 80" width="2.37" height="0.752" rx="0.376" transform="translate(26.402 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_81" data-name="Rectangle 81" width="2.37" height="0.752" rx="0.376" transform="translate(28.897 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_82" data-name="Rectangle 82" width="2.37" height="0.752" rx="0.376" transform="translate(31.393 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_83" data-name="Rectangle 83" width="2.37" height="0.752" rx="0.376" transform="translate(34.512 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_84" data-name="Rectangle 84" width="2.37" height="0.752" rx="0.376" transform="translate(37.007 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
<rect id="Rectangle_85" data-name="Rectangle 85" width="2.37" height="0.752" rx="0.376" transform="translate(39.502 0.744)" fill="#d8d8d8" opacity="0.136"/>
|
||||
</g>
|
||||
<path id="Path_59" data-name="Path 59" d="M123.779,148.389a2.583,2.583,0,0,0-.332.033c-.02-.078-.038-.156-.06-.234a2.594,2.594,0,1,0-2.567-4.455q-.086-.088-.174-.175a2.593,2.593,0,1,0-4.461-2.569c-.077-.022-.154-.04-.231-.06a2.6,2.6,0,1,0-5.128,0c-.077.02-.154.038-.231.06a2.594,2.594,0,1,0-4.461,2.569,10.384,10.384,0,1,0,17.314,9.992,2.592,2.592,0,1,0,.332-5.161" transform="translate(-51.054 -75.262)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_60" data-name="Path 60" d="M83,113.389h20.779V103H83Z" transform="translate(-41.443 -58.444)" fill="#3ecc5f" fill-rule="evenodd"/>
|
||||
<path id="Path_61" data-name="Path 61" d="M123.389,108.944a1.3,1.3,0,1,0,0-2.6,1.338,1.338,0,0,0-.166.017c-.01-.039-.019-.078-.03-.117a1.3,1.3,0,0,0-.5-2.5,1.285,1.285,0,0,0-.783.269q-.043-.044-.087-.087a1.285,1.285,0,0,0,.263-.776,1.3,1.3,0,0,0-2.493-.509,5.195,5.195,0,1,0,0,10,1.3,1.3,0,0,0,2.493-.509,1.285,1.285,0,0,0-.263-.776q.044-.043.087-.087a1.285,1.285,0,0,0,.783.269,1.3,1.3,0,0,0,.5-2.5c.011-.038.02-.078.03-.117a1.335,1.335,0,0,0,.166.017" transform="translate(-55.859 -57.894)" fill="#44d860" fill-rule="evenodd"/>
|
||||
<path id="Path_62" data-name="Path 62" d="M141.8,38.745a1.41,1.41,0,0,1-.255-.026,1.309,1.309,0,0,1-.244-.073,1.349,1.349,0,0,1-.224-.119,1.967,1.967,0,0,1-.2-.161,1.52,1.52,0,0,1-.161-.2,1.282,1.282,0,0,1-.218-.722,1.41,1.41,0,0,1,.026-.255,1.5,1.5,0,0,1,.072-.244,1.364,1.364,0,0,1,.12-.223,1.252,1.252,0,0,1,.358-.358,1.349,1.349,0,0,1,.224-.119,1.309,1.309,0,0,1,.244-.073,1.2,1.2,0,0,1,.509,0,1.262,1.262,0,0,1,.468.192,1.968,1.968,0,0,1,.2.161,1.908,1.908,0,0,1,.161.2,1.322,1.322,0,0,1,.12.223,1.361,1.361,0,0,1,.1.5,1.317,1.317,0,0,1-.379.919,1.968,1.968,0,0,1-.2.161,1.346,1.346,0,0,1-.223.119,1.332,1.332,0,0,1-.5.1m10.389-.649a1.326,1.326,0,0,1-.92-.379,1.979,1.979,0,0,1-.161-.2,1.282,1.282,0,0,1-.218-.722,1.326,1.326,0,0,1,.379-.919,1.967,1.967,0,0,1,.2-.161,1.351,1.351,0,0,1,.224-.119,1.308,1.308,0,0,1,.244-.073,1.2,1.2,0,0,1,.509,0,1.262,1.262,0,0,1,.468.192,1.967,1.967,0,0,1,.2.161,1.326,1.326,0,0,1,.379.919,1.461,1.461,0,0,1-.026.255,1.323,1.323,0,0,1-.073.244,1.847,1.847,0,0,1-.119.223,1.911,1.911,0,0,1-.161.2,1.967,1.967,0,0,1-.2.161,1.294,1.294,0,0,1-.722.218" transform="translate(-69.074 -26.006)" fill-rule="evenodd"/>
|
||||
</g>
|
||||
<g id="React-icon" transform="translate(906.3 541.56)">
|
||||
<path id="Path_330" data-name="Path 330" d="M263.668,117.179c0-5.827-7.3-11.35-18.487-14.775,2.582-11.4,1.434-20.477-3.622-23.382a7.861,7.861,0,0,0-4.016-1v4a4.152,4.152,0,0,1,2.044.466c2.439,1.4,3.5,6.724,2.672,13.574-.2,1.685-.52,3.461-.914,5.272a86.9,86.9,0,0,0-11.386-1.954,87.469,87.469,0,0,0-7.459-8.965c5.845-5.433,11.332-8.41,15.062-8.41V78h0c-4.931,0-11.386,3.514-17.913,9.611-6.527-6.061-12.982-9.539-17.913-9.539v4c3.712,0,9.216,2.959,15.062,8.356a84.687,84.687,0,0,0-7.405,8.947,83.732,83.732,0,0,0-11.4,1.972c-.412-1.793-.717-3.532-.932-5.2-.843-6.85.2-12.175,2.618-13.592a3.991,3.991,0,0,1,2.062-.466v-4h0a8,8,0,0,0-4.052,1c-5.039,2.9-6.168,11.96-3.568,23.328-11.153,3.443-18.415,8.947-18.415,14.757,0,5.828,7.3,11.35,18.487,14.775-2.582,11.4-1.434,20.477,3.622,23.382a7.882,7.882,0,0,0,4.034,1c4.931,0,11.386-3.514,17.913-9.611,6.527,6.061,12.982,9.539,17.913,9.539a8,8,0,0,0,4.052-1c5.039-2.9,6.168-11.96,3.568-23.328C256.406,128.511,263.668,122.988,263.668,117.179Zm-23.346-11.96c-.663,2.313-1.488,4.7-2.421,7.083-.735-1.434-1.506-2.869-2.349-4.3-.825-1.434-1.7-2.833-2.582-4.2C235.517,104.179,237.974,104.645,240.323,105.219Zm-8.212,19.1c-1.4,2.421-2.833,4.716-4.321,6.85-2.672.233-5.379.359-8.1.359-2.708,0-5.415-.126-8.069-.341q-2.232-3.2-4.339-6.814-2.044-3.523-3.73-7.136c1.112-2.4,2.367-4.805,3.712-7.154,1.4-2.421,2.833-4.716,4.321-6.85,2.672-.233,5.379-.359,8.1-.359,2.708,0,5.415.126,8.069.341q2.232,3.2,4.339,6.814,2.044,3.523,3.73,7.136C234.692,119.564,233.455,121.966,232.11,124.315Zm5.792-2.331c.968,2.4,1.793,4.805,2.474,7.136-2.349.574-4.823,1.058-7.387,1.434.879-1.381,1.757-2.8,2.582-4.25C236.4,124.871,237.167,123.419,237.9,121.984ZM219.72,141.116a73.921,73.921,0,0,1-4.985-5.738c1.614.072,3.263.126,4.931.126,1.685,0,3.353-.036,4.985-.126A69.993,69.993,0,0,1,219.72,141.116ZM206.38,130.555c-2.546-.377-5-.843-7.352-1.417.663-2.313,1.488-4.7,2.421-7.083.735,1.434,1.506,2.869,2.349,4.3S205.5,129.192,206.38,130.555ZM219.63,93.241a73.924,73.924,0,0,1,4.985,5.738c-1.614-.072-3.263-.126-4.931-.126-1.686,0-3.353.036-4.985.126A69.993,69.993,0,0,1,219.63,93.241ZM206.362,103.8c-.879,1.381-1.757,2.8-2.582,4.25-.825,1.434-1.6,2.869-2.331,4.3-.968-2.4-1.793-4.805-2.474-7.136C201.323,104.663,203.8,104.179,206.362,103.8Zm-16.227,22.449c-6.348-2.708-10.454-6.258-10.454-9.073s4.106-6.383,10.454-9.073c1.542-.663,3.228-1.255,4.967-1.811a86.122,86.122,0,0,0,4.034,10.92,84.9,84.9,0,0,0-3.981,10.866C193.38,127.525,191.694,126.915,190.134,126.252Zm9.647,25.623c-2.439-1.4-3.5-6.724-2.672-13.574.2-1.686.52-3.461.914-5.272a86.9,86.9,0,0,0,11.386,1.954,87.465,87.465,0,0,0,7.459,8.965c-5.845,5.433-11.332,8.41-15.062,8.41A4.279,4.279,0,0,1,199.781,151.875Zm42.532-13.663c.843,6.85-.2,12.175-2.618,13.592a3.99,3.99,0,0,1-2.062.466c-3.712,0-9.216-2.959-15.062-8.356a84.689,84.689,0,0,0,7.405-8.947,83.731,83.731,0,0,0,11.4-1.972A50.194,50.194,0,0,1,242.313,138.212Zm6.9-11.96c-1.542.663-3.228,1.255-4.967,1.811a86.12,86.12,0,0,0-4.034-10.92,84.9,84.9,0,0,0,3.981-10.866c1.775.556,3.461,1.165,5.039,1.829,6.348,2.708,10.454,6.258,10.454,9.073C259.67,119.994,255.564,123.562,249.216,126.252Z" fill="#61dafb"/>
|
||||
<path id="Path_331" data-name="Path 331" d="M320.8,78.4Z" transform="translate(-119.082 -0.328)" fill="#61dafb"/>
|
||||
<circle id="Ellipse_112" data-name="Ellipse 112" cx="8.194" cy="8.194" r="8.194" transform="translate(211.472 108.984)" fill="#61dafb"/>
|
||||
<path id="Path_332" data-name="Path 332" d="M520.5,78.1Z" transform="translate(-282.975 -0.082)" fill="#61dafb"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,40 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1129" height="663" viewBox="0 0 1129 663">
|
||||
<title>Focus on What Matters</title>
|
||||
<circle cx="321" cy="321" r="321" fill="#f2f2f2" />
|
||||
<ellipse cx="559" cy="635.49998" rx="514" ry="27.50002" fill="#3f3d56" />
|
||||
<ellipse cx="558" cy="627" rx="460" ry="22" opacity="0.2" />
|
||||
<rect x="131" y="152.5" width="840" height="50" fill="#3f3d56" />
|
||||
<path d="M166.5,727.3299A21.67009,21.67009,0,0,0,188.1701,749H984.8299A21.67009,21.67009,0,0,0,1006.5,727.3299V296h-840Z" transform="translate(-35.5 -118.5)" fill="#3f3d56" />
|
||||
<path d="M984.8299,236H188.1701A21.67009,21.67009,0,0,0,166.5,257.6701V296h840V257.6701A21.67009,21.67009,0,0,0,984.8299,236Z" transform="translate(-35.5 -118.5)" fill="#3f3d56" />
|
||||
<path d="M984.8299,236H188.1701A21.67009,21.67009,0,0,0,166.5,257.6701V296h840V257.6701A21.67009,21.67009,0,0,0,984.8299,236Z" transform="translate(-35.5 -118.5)" opacity="0.2" />
|
||||
<circle cx="181" cy="147.5" r="13" fill="#3f3d56" />
|
||||
<circle cx="217" cy="147.5" r="13" fill="#3f3d56" />
|
||||
<circle cx="253" cy="147.5" r="13" fill="#3f3d56" />
|
||||
<rect x="168" y="213.5" width="337" height="386" rx="5.33505" fill="#606060" />
|
||||
<rect x="603" y="272.5" width="284" height="22" rx="5.47638" fill="#2e8555" />
|
||||
<rect x="537" y="352.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
|
||||
<rect x="537" y="396.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
|
||||
<rect x="537" y="440.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
|
||||
<rect x="537" y="484.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
|
||||
<rect x="865" y="552.5" width="88" height="26" rx="7.02756" fill="#3ecc5f" />
|
||||
<path d="M1088.60287,624.61594a30.11371,30.11371,0,0,0,3.98291-15.266c0-13.79652-8.54358-24.98081-19.08256-24.98081s-19.08256,11.18429-19.08256,24.98081a30.11411,30.11411,0,0,0,3.98291,15.266,31.248,31.248,0,0,0,0,30.53213,31.248,31.248,0,0,0,0,30.53208,31.248,31.248,0,0,0,0,30.53208,30.11408,30.11408,0,0,0-3.98291,15.266c0,13.79652,8.54353,24.98081,19.08256,24.98081s19.08256-11.18429,19.08256-24.98081a30.11368,30.11368,0,0,0-3.98291-15.266,31.248,31.248,0,0,0,0-30.53208,31.248,31.248,0,0,0,0-30.53208,31.248,31.248,0,0,0,0-30.53213Z" transform="translate(-35.5 -118.5)" fill="#3f3d56" />
|
||||
<ellipse cx="1038.00321" cy="460.31783" rx="19.08256" ry="24.9808" fill="#3f3d56" />
|
||||
<ellipse cx="1038.00321" cy="429.78574" rx="19.08256" ry="24.9808" fill="#3f3d56" />
|
||||
<path d="M1144.93871,339.34489a91.61081,91.61081,0,0,0,7.10658-10.46092l-50.141-8.23491,54.22885.4033a91.566,91.566,0,0,0,1.74556-72.42605l-72.75449,37.74139,67.09658-49.32086a91.41255,91.41255,0,1,0-150.971,102.29805,91.45842,91.45842,0,0,0-10.42451,16.66946l65.0866,33.81447-69.40046-23.292a91.46011,91.46011,0,0,0,14.73837,85.83669,91.40575,91.40575,0,1,0,143.68892,0,91.41808,91.41808,0,0,0,0-113.02862Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
|
||||
<path d="M981.6885,395.8592a91.01343,91.01343,0,0,0,19.56129,56.51431,91.40575,91.40575,0,1,0,143.68892,0C1157.18982,436.82067,981.6885,385.60008,981.6885,395.8592Z" transform="translate(-35.5 -118.5)" opacity="0.1" />
|
||||
<path d="M365.62,461.43628H477.094v45.12043H365.62Z" transform="translate(-35.5 -118.5)" fill="#fff" fill-rule="evenodd" />
|
||||
<path d="M264.76252,608.74122a26.50931,26.50931,0,0,1-22.96231-13.27072,26.50976,26.50976,0,0,0,22.96231,39.81215H291.304V608.74122Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
|
||||
<path d="M384.17242,468.57061l92.92155-5.80726V449.49263a26.54091,26.54091,0,0,0-26.54143-26.54143H331.1161l-3.31768-5.74622a3.83043,3.83043,0,0,0-6.63536,0l-3.31768,5.74622-3.31767-5.74622a3.83043,3.83043,0,0,0-6.63536,0l-3.31768,5.74622L301.257,417.205a3.83043,3.83043,0,0,0-6.63536,0L291.304,422.9512c-.02919,0-.05573.004-.08625.004l-5.49674-5.49541a3.8293,3.8293,0,0,0-6.4071,1.71723l-1.81676,6.77338L270.607,424.1031a3.82993,3.82993,0,0,0-4.6912,4.69253l1.84463,6.89148-6.77072,1.81411a3.8315,3.8315,0,0,0-1.71988,6.40975l5.49673,5.49673c0,.02787-.004.05574-.004.08493l-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74621,3.31768L259.0163,466.081a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31767a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31767a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83042,3.83042,0,0,0,0,6.63535l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768L259.0163,558.976a3.83042,3.83042,0,0,0,0,6.63535l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83042,3.83042,0,0,0,0,6.63535l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768A26.54091,26.54091,0,0,0,291.304,635.28265H450.55254A26.5409,26.5409,0,0,0,477.094,608.74122V502.5755l-92.92155-5.80727a14.12639,14.12639,0,0,1,0-28.19762" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
|
||||
<path d="M424.01111,635.28265h39.81214V582.19979H424.01111Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
|
||||
<path d="M490.36468,602.10586a6.60242,6.60242,0,0,0-.848.08493c-.05042-.19906-.09821-.39945-.15393-.59852A6.62668,6.62668,0,1,0,482.80568,590.21q-.2203-.22491-.44457-.44589a6.62391,6.62391,0,1,0-11.39689-6.56369c-.1964-.05575-.39414-.10218-.59056-.15262a6.63957,6.63957,0,1,0-13.10086,0c-.1964.05042-.39414.09687-.59056.15262a6.62767,6.62767,0,1,0-11.39688,6.56369,26.52754,26.52754,0,1,0,44.23127,25.52756,6.6211,6.6211,0,1,0,.848-13.18579" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
|
||||
<path d="M437.28182,555.65836H477.094V529.11693H437.28182Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
|
||||
<path d="M490.36468,545.70532a3.31768,3.31768,0,0,0,0-6.63536,3.41133,3.41133,0,0,0-.42333.04247c-.02655-.09953-.04911-.19907-.077-.29859a3.319,3.319,0,0,0-1.278-6.37923,3.28174,3.28174,0,0,0-2.00122.68742q-.10947-.11346-.22294-.22295a3.282,3.282,0,0,0,.67149-1.98265,3.31768,3.31768,0,0,0-6.37-1.2992,13.27078,13.27078,0,1,0,0,25.54082,3.31768,3.31768,0,0,0,6.37-1.2992,3.282,3.282,0,0,0-.67149-1.98265q.11347-.10947.22294-.22294a3.28174,3.28174,0,0,0,2.00122.68742,3.31768,3.31768,0,0,0,1.278-6.37923c.02786-.0982.05042-.19907.077-.29859a3.41325,3.41325,0,0,0,.42333.04246" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
|
||||
<path d="M317.84538,466.081a3.31768,3.31768,0,0,1-3.31767-3.31768,9.953,9.953,0,1,0-19.90608,0,3.31768,3.31768,0,1,1-6.63535,0,16.58839,16.58839,0,1,1,33.17678,0,3.31768,3.31768,0,0,1-3.31768,3.31768" transform="translate(-35.5 -118.5)" fill-rule="evenodd" />
|
||||
<path d="M370.92825,635.28265h79.62429A26.5409,26.5409,0,0,0,477.094,608.74122v-92.895H397.46968a26.54091,26.54091,0,0,0-26.54143,26.54143Z" transform="translate(-35.5 -118.5)" fill="#ffff50" fill-rule="evenodd" />
|
||||
<path d="M457.21444,556.98543H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.54143H390.80778a1.32707,1.32707,0,1,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.54143H390.80778a1.32707,1.32707,0,1,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0-66.10674H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.29459H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.54143H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414M477.094,474.19076c-.01592,0-.0292-.008-.04512-.00663-4.10064.13934-6.04083,4.24132-7.75274,7.86024-1.78623,3.78215-3.16771,6.24122-5.43171,6.16691-2.50685-.09024-3.94007-2.92222-5.45825-5.91874-1.74377-3.44243-3.73438-7.34667-7.91333-7.20069-4.04227.138-5.98907,3.70784-7.70631,6.857-1.82738,3.35484-3.07084,5.39455-5.46887,5.30033-2.55727-.09289-3.91619-2.39536-5.48877-5.06013-1.75306-2.96733-3.77951-6.30359-7.8775-6.18946-3.97326.13669-5.92537,3.16507-7.64791,5.83912-1.82207,2.82666-3.09872,4.5492-5.52725,4.447-2.61832-.09289-3.9706-2.00388-5.53522-4.21611-1.757-2.4856-3.737-5.299-7.82308-5.16231-3.88567.13271-5.83779,2.61434-7.559,4.80135-1.635,2.07555-2.9116,3.71846-5.61218,3.615a1.32793,1.32793,0,1,0-.09555,2.65414c4.00377.134,6.03154-2.38873,7.79257-4.6275,1.562-1.9853,2.91027-3.69855,5.56441-3.78879,2.55594-.10882,3.75429,1.47968,5.56707,4.04093,1.7212,2.43385,3.67465,5.19416,7.60545,5.33616,4.11789.138,6.09921-2.93946,7.8536-5.66261,1.56861-2.43385,2.92221-4.53461,5.50734-4.62352,2.37944-.08892,3.67466,1.79154,5.50072,4.885,1.72121,2.91557,3.67069,6.21865,7.67977,6.36463,4.14709.14332,6.14965-3.47693,7.89475-6.68181,1.51155-2.77092,2.93814-5.38791,5.46621-5.4755,2.37944-.05573,3.62025,2.11668,5.45558,5.74622,1.71459,3.388,3.65875,7.22591,7.73019,7.37321l.22429.004c4.06614,0,5.99571-4.08074,7.70364-7.68905,1.51154-3.19825,2.94211-6.21069,5.3972-6.33411Z" transform="translate(-35.5 -118.5)" fill-rule="evenodd" />
|
||||
<path d="M344.38682,635.28265h53.08286V582.19979H344.38682Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
|
||||
<path d="M424.01111,602.10586a6.60242,6.60242,0,0,0-.848.08493c-.05042-.19906-.09821-.39945-.15394-.59852A6.62667,6.62667,0,1,0,416.45211,590.21q-.2203-.22491-.44458-.44589a6.62391,6.62391,0,1,0-11.39689-6.56369c-.1964-.05575-.39413-.10218-.59054-.15262a6.63957,6.63957,0,1,0-13.10084,0c-.19641.05042-.39414.09687-.59055.15262a6.62767,6.62767,0,1,0-11.39689,6.56369,26.52755,26.52755,0,1,0,44.2313,25.52756,6.6211,6.6211,0,1,0,.848-13.18579" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
|
||||
<path d="M344.38682,555.65836h53.08286V529.11693H344.38682Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
|
||||
<path d="M410.74039,545.70532a3.31768,3.31768,0,1,0,0-6.63536,3.41133,3.41133,0,0,0-.42333.04247c-.02655-.09953-.04911-.19907-.077-.29859a3.319,3.319,0,0,0-1.278-6.37923,3.28174,3.28174,0,0,0-2.00122.68742q-.10947-.11346-.22294-.22295a3.282,3.282,0,0,0,.67149-1.98265,3.31768,3.31768,0,0,0-6.37-1.2992,13.27078,13.27078,0,1,0,0,25.54082,3.31768,3.31768,0,0,0,6.37-1.2992,3.282,3.282,0,0,0-.67149-1.98265q.11347-.10947.22294-.22294a3.28174,3.28174,0,0,0,2.00122.68742,3.31768,3.31768,0,0,0,1.278-6.37923c.02786-.0982.05042-.19907.077-.29859a3.41325,3.41325,0,0,0,.42333.04246" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
|
||||
<path d="M424.01111,447.8338a3.60349,3.60349,0,0,1-.65028-.06636,3.34415,3.34415,0,0,1-.62372-.18579,3.44679,3.44679,0,0,1-.572-.30522,5.02708,5.02708,0,0,1-.50429-.4114,3.88726,3.88726,0,0,1-.41007-.50428,3.27532,3.27532,0,0,1-.55737-1.84463,3.60248,3.60248,0,0,1,.06636-.65027,3.82638,3.82638,0,0,1,.18447-.62373,3.48858,3.48858,0,0,1,.30656-.57064,3.197,3.197,0,0,1,.91436-.91568,3.44685,3.44685,0,0,1,.572-.30523,3.344,3.344,0,0,1,.62372-.18578,3.06907,3.06907,0,0,1,1.30053,0,3.22332,3.22332,0,0,1,1.19436.491,5.02835,5.02835,0,0,1,.50429.41139,4.8801,4.8801,0,0,1,.41139.50429,3.38246,3.38246,0,0,1,.30522.57064,3.47806,3.47806,0,0,1,.25215,1.274A3.36394,3.36394,0,0,1,426.36,446.865a5.02708,5.02708,0,0,1-.50429.4114,3.3057,3.3057,0,0,1-1.84463.55737m26.54143-1.65884a3.38754,3.38754,0,0,1-2.35024-.96877,5.04185,5.04185,0,0,1-.41007-.50428,3.27532,3.27532,0,0,1-.55737-1.84463,3.38659,3.38659,0,0,1,.96744-2.34892,5.02559,5.02559,0,0,1,.50429-.41139,3.44685,3.44685,0,0,1,.572-.30523,3.3432,3.3432,0,0,1,.62373-.18579,3.06952,3.06952,0,0,1,1.30052,0,3.22356,3.22356,0,0,1,1.19436.491,5.02559,5.02559,0,0,1,.50429.41139,3.38792,3.38792,0,0,1,.96876,2.34892,3.72635,3.72635,0,0,1-.06636.65026,3.37387,3.37387,0,0,1-.18579.62373,4.71469,4.71469,0,0,1-.30522.57064,4.8801,4.8801,0,0,1-.41139.50429,5.02559,5.02559,0,0,1-.50429.41139,3.30547,3.30547,0,0,1-1.84463.55737" transform="translate(-35.5 -118.5)" fill-rule="evenodd" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,8 +0,0 @@
|
||||
{
|
||||
// This file is not used in compilation. It is here just for a nice editor experience.
|
||||
"extends": "@docusaurus/tsconfig",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
},
|
||||
"exclude": [".docusaurus", "build"]
|
||||
}
|
||||
24
migrations/0027_free_green_goblin.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
CREATE TABLE "printer_data" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"humanReadable_id" text NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"ipAddress" text,
|
||||
"port" numeric,
|
||||
"status" text,
|
||||
"statusText" text,
|
||||
"last_time_printed" timestamp DEFAULT now() NOT NULL,
|
||||
"assigned" boolean DEFAULT false,
|
||||
"remark" text,
|
||||
"printDelay" numeric DEFAULT '90',
|
||||
"processes" jsonb DEFAULT '[]'::jsonb,
|
||||
"print_delay_override" boolean DEFAULT false,
|
||||
"add_Date" timestamp DEFAULT now(),
|
||||
"upd_date" timestamp DEFAULT now(),
|
||||
CONSTRAINT "printer_data_humanReadable_id_unique" UNIQUE("humanReadable_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "printer_log" RENAME COLUMN "name" TO "ip";--> statement-breakpoint
|
||||
ALTER TABLE "printer_log" ADD COLUMN "printer_sn" text;--> statement-breakpoint
|
||||
ALTER TABLE "printer_log" ADD COLUMN "condition" text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "printer_log" ADD COLUMN "message" text;--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "printer_id" ON "printer_data" USING btree ("humanReadable_id");
|
||||
1
migrations/0028_keen_the_fallen.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "printer_log" ADD COLUMN "name" text;
|
||||
1
migrations/0029_gigantic_thunderbolt_ross.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "printer_data" ADD COLUMN "printer_sn" text;
|
||||
3
migrations/0030_high_invisible_woman.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE "printer_data" ALTER COLUMN "port" SET DATA TYPE integer;--> statement-breakpoint
|
||||
ALTER TABLE "printer_data" ALTER COLUMN "printDelay" SET DATA TYPE integer;--> statement-breakpoint
|
||||
ALTER TABLE "printer_data" ALTER COLUMN "printDelay" SET DEFAULT 90;
|
||||
1
migrations/0031_numerous_the_phantom.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "printer_log" ADD COLUMN "created_at" timestamp DEFAULT now();
|
||||
20
migrations/0032_tranquil_onslaught.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
CREATE TABLE "inv_historical_data" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"hist_date" date NOT NULL,
|
||||
"plant_token" text,
|
||||
"article" text NOT NULL,
|
||||
"article_description" text NOT NULL,
|
||||
"material_type" text,
|
||||
"total_QTY" text,
|
||||
"available_QTY" text,
|
||||
"coa_QTY" text,
|
||||
"held_QTY" text,
|
||||
"consignment_qty" text,
|
||||
"lot_number" text,
|
||||
"location_id" text,
|
||||
"location" text,
|
||||
"whse_id" text DEFAULT '',
|
||||
"whse_name" text DEFAULT 'missing whseName',
|
||||
"upd_user" text DEFAULT 'lst',
|
||||
"upd_date" timestamp DEFAULT now()
|
||||
);
|
||||
1
migrations/0033_elite_adam_warlock.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "inv_historical_data" ALTER COLUMN "upd_user" SET DEFAULT 'lst-system';
|
||||
1627
migrations/meta/0027_snapshot.json
Normal file
1633
migrations/meta/0028_snapshot.json
Normal file
1639
migrations/meta/0029_snapshot.json
Normal file
1639
migrations/meta/0030_snapshot.json
Normal file
1646
migrations/meta/0031_snapshot.json
Normal file
1772
migrations/meta/0032_snapshot.json
Normal file
1772
migrations/meta/0033_snapshot.json
Normal file
@@ -190,6 +190,55 @@
|
||||
"when": 1775786221817,
|
||||
"tag": "0026_vengeful_wiccan",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 27,
|
||||
"version": "7",
|
||||
"when": 1776085181774,
|
||||
"tag": "0027_free_green_goblin",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 28,
|
||||
"version": "7",
|
||||
"when": 1776085921073,
|
||||
"tag": "0028_keen_the_fallen",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 29,
|
||||
"version": "7",
|
||||
"when": 1776087535705,
|
||||
"tag": "0029_gigantic_thunderbolt_ross",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 30,
|
||||
"version": "7",
|
||||
"when": 1776087914328,
|
||||
"tag": "0030_high_invisible_woman",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 31,
|
||||
"version": "7",
|
||||
"when": 1776098377074,
|
||||
"tag": "0031_numerous_the_phantom",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 32,
|
||||
"version": "7",
|
||||
"when": 1776245938243,
|
||||
"tag": "0032_tranquil_onslaught",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 33,
|
||||
"version": "7",
|
||||
"when": 1776256060808,
|
||||
"tag": "0033_elite_adam_warlock",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "lst_v3",
|
||||
"version": "0.0.1-alpha.3",
|
||||
"version": "0.0.1-alpha.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "lst_v3",
|
||||
"version": "0.0.1-alpha.3",
|
||||
"version": "0.0.1-alpha.4",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.57.0",
|
||||
|
||||