@dizmo/dcs-client-library 4.1.2 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,7 +12,7 @@ npm i @dizmo/dcs-client-library
12
12
  ## Usage
13
13
  The modules for the different data types are separated and can be individually imported
14
14
  ```js
15
- import { templates, items, allocations, dcs, config, events, analytics, language, needs, packages, translations } from '@dizmo/dcs-client-library'
15
+ import { templates, items, allocations, dcs, config, events, analytics, language, needs, packages, translations, components } from '@dizmo/dcs-client-library'
16
16
 
17
17
  // Most functions throw errors, so they can be caught when they are called
18
18
  try {
@@ -26,42 +26,46 @@ The modules all have separate documentation files to keep this main README short
26
26
 
27
27
  ### Templates Module
28
28
  Contains all template-related functions of the DCS.
29
- Documentation can be found [here](./documentation/templates/templates.md).
29
+ Documentation can be found [here](./docs/public/templates/templates.md).
30
30
  ### Items Module
31
31
  Contains all item-related functions of the DCS.
32
- Documentation can be found [here](./documentation/items/items.md).
32
+ Documentation can be found [here](./docs/public/items/items.md).
33
33
  ### Allocations Module
34
34
  Contains all allocation-related functions of the DCS.
35
- Documentation can be found [here](./documentation/allocations/allocations.md).
35
+ Documentation can be found [here](./docs/public/allocations/allocations.md).
36
36
  ### DCS Module
37
37
  Contains all company and system-related functions of the DCS.
38
- Documentation can be found [here](./documentation/dcs/dcs.md).
38
+ Documentation can be found [here](./docs/public/dcs/dcs.md).
39
39
  ### Analytics Module
40
40
  Contains the analytics functionality to process database data.
41
- Documentation can be found [here](./documentation/analytics/analytics.md).
41
+ Documentation can be found [here](./docs/public/analytics/analytics.md).
42
42
  ### Config Module
43
43
  Contains library configuration functions.
44
- Documentation can be found [here](./documentation/config/config.md).
44
+ Documentation can be found [here](./docs/public/config/config.md).
45
45
  ### Language Module
46
46
  Contains all language and translation related functions.
47
- Documentation can be found [here](./documentation/language/language.md).
47
+ Documentation can be found [here](./docs/public/language/language.md).
48
48
 
49
49
  ### Events Module
50
50
  Contains the function that informs the client on database updates.
51
- Documentation can be found [here](./documentation/events/events.md).
51
+ Documentation can be found [here](./docs/public/events/events.md).
52
52
 
53
53
  ### Needs Module
54
54
  Contains functions for creating and managing needs (requirements/demands).
55
- Documentation can be found [here](./documentation/needs/needs.md).
55
+ Documentation can be found [here](./docs/public/needs/needs.md).
56
56
 
57
57
  ### Packages Module
58
58
  Contains functions for creating and managing allocation packages (reusable allocation templates).
59
- Documentation can be found [here](./documentation/packages/packages.md).
59
+ Documentation can be found [here](./docs/public/packages/packages.md).
60
60
 
61
61
  ### Translations Module
62
62
  Contains DeepL translation API integration for translating text content.
63
- Documentation can be found [here](./documentation/translations/translations.md).
63
+ Documentation can be found [here](./docs/public/translations/translations.md).
64
+
65
+ ### Components Module
66
+ Contains shared web components (`<item-element>` and `<allocation-element>`) for displaying items and allocations.
67
+ Documentation can be found [here](./docs/public/components/components.md).
64
68
 
65
69
  ### Data Structures
66
70
  Common data structures used across modules.
67
- Documentation can be found [here](./documentation/datastructures/datastructures.md).
71
+ Documentation can be found [here](./docs/public/datastructures/datastructures.md).
@@ -0,0 +1 @@
1
+ import "./itemElement";
@@ -0,0 +1,214 @@
1
+ // Composite component that displays item-elements with additional information.
2
+ // Three modes:
3
+ // - Package: 1 itemElement + startOffset/duration info
4
+ // - Allocation: 2 itemElements + from/to/name info
5
+ // - CompactAllocation: 1 itemElement + from/to/name info
6
+ import { language } from "../modules/language";
7
+ import { HumanizeDurationLanguage, HumanizeDuration, } from "humanize-duration-ts";
8
+ import { AllocationMode } from "../types/types";
9
+ import "./itemElement";
10
+ class AllocationElement extends HTMLElement {
11
+ constructor() {
12
+ super();
13
+ this.attachShadow({ mode: "open" });
14
+ }
15
+ connectedCallback() {
16
+ const mode = this.getAttribute("mode") || AllocationMode.Allocation;
17
+ if (!this.shadowRoot) {
18
+ console.error("ShadowRoot is not attached.");
19
+ return;
20
+ }
21
+ if (mode === AllocationMode.Package) {
22
+ this.renderPackageMode();
23
+ }
24
+ else {
25
+ this.renderAllocationMode(mode === AllocationMode.CompactAllocation);
26
+ }
27
+ }
28
+ getItemAttrs(suffix = "") {
29
+ return {
30
+ template: this.getAttribute(`template${suffix}`),
31
+ firstline: this.getAttribute(`firstline${suffix}`),
32
+ secondline: this.getAttribute(`secondline${suffix}`),
33
+ imgUrl: this.getAttribute(`imgUrl${suffix}`),
34
+ iconUrl: this.getAttribute(`iconUrl${suffix}`),
35
+ itemId: this.getAttribute(`itemId${suffix}`),
36
+ color: this.getAttribute(`color${suffix}`),
37
+ };
38
+ }
39
+ buildItemElement(attrs, dataAttrs = {}, leafType = "resource") {
40
+ const dataAttrStr = Object.entries(dataAttrs)
41
+ .map(([key, val]) => `data-${key}="${val}"`)
42
+ .join(" ");
43
+ return `
44
+ <item-element
45
+ itemType="${leafType}"
46
+ template="${attrs.template}"
47
+ firstline="${attrs.firstline}"
48
+ secondline="${attrs.secondline}"
49
+ imgUrl="${attrs.imgUrl}"
50
+ iconUrl="${attrs.iconUrl}"
51
+ itemId="${attrs.itemId}"
52
+ color="${attrs.color}"
53
+ ${dataAttrStr}
54
+ ></item-element>
55
+ `;
56
+ }
57
+ buildInfoRows(rows) {
58
+ return rows
59
+ .map((row) => `
60
+ <div class="info-row">
61
+ <div class="info-label">${row.label}</div>
62
+ <div>${row.value}</div>
63
+ </div>
64
+ `)
65
+ .join("");
66
+ }
67
+ getAllocationInfo() {
68
+ return {
69
+ allocationId: this.getAttribute("allocationId"),
70
+ from: this.getAttribute("from"),
71
+ to: this.getAttribute("to"),
72
+ name: this.getAttribute("name"),
73
+ };
74
+ }
75
+ buildAllocationInfoSection(from, to, name) {
76
+ const nameDiv = name && name !== "undefined"
77
+ ? `<div class="alloc-name">${name}</div>`
78
+ : "";
79
+ const infoRows = this.buildInfoRows([
80
+ {
81
+ label: language.translateString("js_from"),
82
+ value: from ? getReadableTime(parseInt(from)) : "",
83
+ },
84
+ {
85
+ label: language.translateString("js_to"),
86
+ value: to ? getReadableTime(parseInt(to)) : "",
87
+ },
88
+ ]);
89
+ return `${nameDiv}<div class="info-section">${infoRows}</div>`;
90
+ }
91
+ renderAllocationMode(compact = false) {
92
+ const { allocationId, from, to, name } = this.getAllocationInfo();
93
+ const dataAttrs = { "allocation-id": allocationId, from, to };
94
+ const items = compact
95
+ ? this.buildItemElement(this.getItemAttrs(), dataAttrs, this.getAttribute("leafType") || "resource")
96
+ : this.buildItemElement(this.getItemAttrs("1"), dataAttrs, this.getAttribute("leafType1") || "resource") +
97
+ this.buildItemElement(this.getItemAttrs("2"), dataAttrs, this.getAttribute("leafType2") || "resource");
98
+ this.shadowRoot.innerHTML = `
99
+ <style>${this.getStyles()}</style>
100
+ <div class="container">
101
+ ${items}
102
+ ${this.buildAllocationInfoSection(from, to, name)}
103
+ </div>
104
+ `;
105
+ this.attachJumpToAllocationHandlers();
106
+ }
107
+ attachJumpToAllocationHandlers() {
108
+ const items = this.shadowRoot?.querySelectorAll("item-element");
109
+ items?.forEach((item) => {
110
+ item.addEventListener("click", () => {
111
+ const { allocationId, from, to } = this.getAllocationInfo();
112
+ const template = item.getAttribute("template");
113
+ this.dispatchEvent(new CustomEvent("jump-to-allocation", {
114
+ detail: { allocationId, template, from, to },
115
+ bubbles: true,
116
+ composed: true,
117
+ }));
118
+ });
119
+ });
120
+ }
121
+ renderPackageMode() {
122
+ const LANG = language.getUILanguage();
123
+ const langService = new HumanizeDurationLanguage();
124
+ const humanizer = new HumanizeDuration(langService);
125
+ const item = this.getItemAttrs();
126
+ const startOffset = this.getAttribute("startOffset");
127
+ const duration = this.getAttribute("duration");
128
+ const infoRows = this.buildInfoRows([
129
+ {
130
+ label: language.translateString("js_start"),
131
+ value: item.template
132
+ ? formatStartOffset(startOffset, humanizer, LANG)
133
+ : "",
134
+ },
135
+ {
136
+ label: language.translateString("js_duration"),
137
+ value: item.template ? formatDuration(duration, humanizer, LANG) : "",
138
+ },
139
+ ]);
140
+ this.shadowRoot.innerHTML = `
141
+ <style>${this.getStyles()}</style>
142
+ <div class="container">
143
+ ${this.buildItemElement(item)}
144
+ <div class="info-section">${infoRows}</div>
145
+ </div>
146
+ `;
147
+ }
148
+ getStyles() {
149
+ return `
150
+ .container {
151
+ min-height: 40px;
152
+ border-radius: 4px;
153
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.522815);
154
+ margin-bottom: 10px;
155
+ padding: 5px;
156
+ transition: transform 0.2s ease-in;
157
+ position: relative;
158
+ overflow: hidden;
159
+ background-color: var(--current-color);
160
+ }
161
+ .alloc-name {
162
+ padding: 4px;
163
+ font-size: 14px;
164
+ font-weight: bold;
165
+ }
166
+ .info-section {
167
+ margin-top: 4px;
168
+ padding: 4px;
169
+ padding-bottom: 0px;
170
+ font-size: 14px;
171
+ }
172
+ .info-row {
173
+ display: flex;
174
+ flex-direction: row;
175
+ }
176
+ .info-label {
177
+ width: 80px;
178
+ font-weight: bold;
179
+ }
180
+ `;
181
+ }
182
+ }
183
+ const getReadableTime = (timestamp) => {
184
+ const date = new Date(timestamp);
185
+ return date.toLocaleString(undefined, {
186
+ year: "numeric",
187
+ month: "short",
188
+ day: "numeric",
189
+ hour: "2-digit",
190
+ minute: "2-digit",
191
+ });
192
+ };
193
+ const formatStartOffset = (startOffset, humanizer, lang) => {
194
+ if (!startOffset)
195
+ return "";
196
+ const offset = parseInt(startOffset);
197
+ if (offset === 0) {
198
+ return language.translateString("js_at-start");
199
+ }
200
+ return ("+" +
201
+ humanizer.humanize(offset, {
202
+ language: lang,
203
+ units: ["w", "d", "h", "m", "s"],
204
+ }));
205
+ };
206
+ const formatDuration = (duration, humanizer, lang) => {
207
+ if (!duration)
208
+ return "";
209
+ return humanizer.humanize(parseInt(duration), {
210
+ language: lang,
211
+ units: ["w", "d", "h", "m", "s"],
212
+ });
213
+ };
214
+ customElements.define("allocation-element", AllocationElement);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,170 @@
1
+ // Shared web component that can display resource, package, need, and event items.
2
+ import { ItemType } from "../types/types";
3
+ class ItemElement extends HTMLElement {
4
+ constructor() {
5
+ super();
6
+ this.attachShadow({ mode: "open" });
7
+ }
8
+ attachOpenItemClickHandler() {
9
+ const button = this.shadowRoot?.querySelector("#open-item-btn");
10
+ if (button) {
11
+ const itemType = this.getAttribute("itemType") || ItemType.Resource;
12
+ const itemId = this.getAttribute("itemId");
13
+ const template = this.getAttribute("template");
14
+ const color = this.getAttribute("color");
15
+ button.addEventListener("click", (e) => {
16
+ e.preventDefault();
17
+ e.stopPropagation();
18
+ this.dispatchEvent(new CustomEvent("open-item", {
19
+ detail: { itemId, template, color, itemType },
20
+ bubbles: true,
21
+ composed: true,
22
+ }));
23
+ });
24
+ }
25
+ }
26
+ connectedCallback() {
27
+ const itemType = this.getAttribute("itemType") || ItemType.Resource;
28
+ const template = this.getAttribute("template");
29
+ const firstline = this.getAttribute("firstline");
30
+ const secondline = this.getAttribute("secondline");
31
+ const imgUrl = this.getAttribute("imgUrl");
32
+ const iconUrl = this.getAttribute("iconUrl");
33
+ const itemId = this.getAttribute("itemId");
34
+ const color = this.getAttribute("color");
35
+ // Only resources show left image
36
+ const showLeftImage = itemType === ItemType.Resource && (imgUrl || iconUrl);
37
+ // Resources and needs show secondline, events show formatted date
38
+ const displaySecondLine = itemType === ItemType.Need && secondline
39
+ ? `${secondline} Need`
40
+ : secondline;
41
+ const showSecondLine = (itemType === ItemType.Resource || itemType === ItemType.Need) &&
42
+ displaySecondLine;
43
+ const showEventDate = itemType === ItemType.Event && secondline;
44
+ // Format date for events
45
+ const formattedDate = showEventDate ? formatDateToLocale(secondline) : null;
46
+ if (!this.shadowRoot) {
47
+ console.error("ShadowRoot is not attached.");
48
+ return;
49
+ }
50
+ this.shadowRoot.innerHTML = `
51
+ <style>
52
+ .item {
53
+ display: flex;
54
+ min-height: 40px;
55
+ border-radius: 4px;
56
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.522815);
57
+ margin-bottom: 5px;
58
+ align-items: center;
59
+ padding: 0 5px;
60
+ transition: transform 0.2s ease-in;
61
+ position: relative;
62
+ overflow: hidden;
63
+ }
64
+ .item_image {
65
+ width: 30px;
66
+ height: 30px;
67
+ overflow: hidden;
68
+ border-radius: 50%;
69
+ flex-shrink: 0;
70
+ margin-right: 6px;
71
+ }
72
+ .item_image img {
73
+ width: 100%;
74
+ height: 100%;
75
+ object-fit: cover;
76
+ }
77
+ .item_title {
78
+ font-size: 14px;
79
+ line-height: 14px;
80
+ white-space: nowrap;
81
+ width: calc(100% - 64px);
82
+ overflow: hidden;
83
+ text-overflow: ellipsis;
84
+ }
85
+ .item_title.no-image {
86
+ margin-left: 6px;
87
+ }
88
+ .item_first, .item_second {
89
+ overflow: hidden;
90
+ text-overflow: ellipsis;
91
+ }
92
+ .item_button {
93
+ width: 30px;
94
+ height: 30px;
95
+ padding: unset;
96
+ background-repeat: no-repeat;
97
+ background-position: center;
98
+ min-width: 30px;
99
+ position: absolute;
100
+ right: 5px;
101
+ background-color: var(--current-color);
102
+ display: flex;
103
+ justify-content: center;
104
+ align-items: center;
105
+ border-radius: 4px;
106
+ border: 1px solid var(--dizmo-font-color);
107
+ box-shadow: 0 3px 10px rgba(0,0,0,.16);
108
+ }
109
+ .item_button-image {
110
+ pointer-events: none;
111
+ }
112
+ .not-invert {
113
+ filter: invert(0);
114
+ }
115
+ .invert {
116
+ filter: invert(1);
117
+ }
118
+ </style>
119
+ <div class="item">
120
+ ${showLeftImage
121
+ ? `
122
+ <div class="item_image">
123
+ <img class="item_button-image" loading="lazy" src="${imgUrl || iconUrl}" />
124
+ </div>
125
+ `
126
+ : ""}
127
+ <div class="item_title${showLeftImage ? "" : " no-image"}">
128
+ <div class="item_first">${firstline}</div>
129
+ ${showSecondLine ? `<div class="item_second">${displaySecondLine}</div>` : ""}
130
+ ${showEventDate ? `<div class="item_second">${formattedDate}</div>` : ""}
131
+ </div>
132
+ <button class="item_button not-invert" id="open-item-btn" itemid="${itemId}"
133
+ template="${template}" icolor="${color}"${color ? ` style="background-color: ${color} !important"` : ""}>
134
+ <img class="item_button-image${invertIcon(color)}" loading="lazy" src="${iconUrl}" />
135
+ </button>
136
+ </div>
137
+ `;
138
+ this.attachOpenItemClickHandler();
139
+ }
140
+ }
141
+ const formatDateToLocale = (dateString) => {
142
+ try {
143
+ const date = new Date(dateString);
144
+ if (isNaN(date.getTime())) {
145
+ return dateString;
146
+ }
147
+ return date.toLocaleDateString(undefined, {
148
+ year: "numeric",
149
+ month: "short",
150
+ day: "numeric",
151
+ });
152
+ }
153
+ catch {
154
+ return dateString;
155
+ }
156
+ };
157
+ const invertIcon = (backgroundColor) => {
158
+ if (!backgroundColor ||
159
+ backgroundColor === "transparent" ||
160
+ backgroundColor === "" ||
161
+ backgroundColor === "#00000000") {
162
+ return "";
163
+ }
164
+ return dizmo.getAdaptiveColor("#ffffff", "#000000", {
165
+ color: backgroundColor,
166
+ }) === "#000000"
167
+ ? " not-invert"
168
+ : " invert";
169
+ };
170
+ customElements.define("item-element", ItemElement);
package/dist/index.d.ts CHANGED
@@ -9,3 +9,4 @@ export { events } from "./modules/events";
9
9
  export { needs } from "./modules/needs";
10
10
  export { packages } from "./modules/packages";
11
11
  export { translations } from "./modules/translations";
12
+ export { components } from "./modules/components";
package/dist/index.js CHANGED
@@ -13,3 +13,4 @@ export { events } from "./modules/events";
13
13
  export { needs } from "./modules/needs";
14
14
  export { packages } from "./modules/packages";
15
15
  export { translations } from "./modules/translations";
16
+ export { components } from "./modules/components";
@@ -0,0 +1,7 @@
1
+ import "../components/itemElement";
2
+ import "../components/allocationElement";
3
+ import { ItemType, AllocationMode } from "../types/types";
4
+ export declare const components: {
5
+ ItemType: typeof ItemType;
6
+ AllocationMode: typeof AllocationMode;
7
+ };
@@ -0,0 +1,8 @@
1
+ // Side-effect imports register the custom elements
2
+ import "../components/itemElement";
3
+ import "../components/allocationElement";
4
+ import { ItemType, AllocationMode } from "../types/types";
5
+ export const components = {
6
+ ItemType,
7
+ AllocationMode,
8
+ };
@@ -589,3 +589,14 @@ export type FileInfoResult = {
589
589
  blobURL: string | undefined;
590
590
  previewURL: string;
591
591
  };
592
+ export declare enum ItemType {
593
+ Resource = "resource",
594
+ Package = "package",
595
+ Need = "need",
596
+ Event = "event"
597
+ }
598
+ export declare enum AllocationMode {
599
+ Package = "package",
600
+ Allocation = "allocation",
601
+ CompactAllocation = "compact-allocation"
602
+ }
@@ -1 +1,13 @@
1
- export {};
1
+ export var ItemType;
2
+ (function (ItemType) {
3
+ ItemType["Resource"] = "resource";
4
+ ItemType["Package"] = "package";
5
+ ItemType["Need"] = "need";
6
+ ItemType["Event"] = "event";
7
+ })(ItemType || (ItemType = {}));
8
+ export var AllocationMode;
9
+ (function (AllocationMode) {
10
+ AllocationMode["Package"] = "package";
11
+ AllocationMode["Allocation"] = "allocation";
12
+ AllocationMode["CompactAllocation"] = "compact-allocation";
13
+ })(AllocationMode || (AllocationMode = {}));
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "@dizmo/dcs-client-library",
3
- "version": "4.1.2",
3
+ "version": "4.2.1",
4
4
  "description": "A library that allows connection and management of dcs",
5
5
  "source": "source/index.ts",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
- "files": ["dist"],
8
+ "files": [
9
+ "dist"
10
+ ],
9
11
  "scripts": {
10
12
  "test": "mocha source/test/**/*.js",
11
13
  "build": "tsc",
@@ -15,10 +17,12 @@
15
17
  "license": "ISC",
16
18
  "devDependencies": {
17
19
  "@dizmo/dizmo.js": "^1.4.77",
20
+ "@dizmo/docs": "git+ssh://git@git.dizmo.com:dizmo/docs.git#semver:^999.0",
18
21
  "prettier": "3.1.0",
19
22
  "typescript": "^5.7.3"
20
23
  },
21
24
  "dependencies": {
22
- "deepl-node": "^1.19.0"
25
+ "deepl-node": "^1.19.0",
26
+ "humanize-duration-ts": "^2.1.1"
23
27
  }
24
28
  }