retold-data-service 2.0.12 → 2.0.13
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 +64 -55
- package/docs/README.md +24 -66
- package/docs/_cover.md +7 -7
- package/docs/_sidebar.md +24 -11
- package/docs/_topbar.md +2 -0
- package/docs/api/constructor.md +67 -0
- package/docs/api/initializeDataEndpoints.md +54 -0
- package/docs/api/initializePersistenceEngine.md +34 -0
- package/docs/api/initializeService.md +44 -0
- package/docs/api/onAfterInitialize.md +48 -0
- package/docs/api/onBeforeInitialize.md +45 -0
- package/docs/api/onInitialize.md +38 -0
- package/docs/api/reference.md +35 -0
- package/docs/api/stopService.md +34 -0
- package/docs/architecture.md +78 -14
- package/docs/behavior-injection.md +121 -78
- package/docs/css/docuserve.css +73 -0
- package/docs/dal-access.md +135 -56
- package/docs/index.html +1 -1
- package/docs/quick-start.md +169 -0
- package/docs/retold-catalog.json +144 -0
- package/docs/retold-keyword-index.json +3530 -0
- package/package.json +2 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# onInitialize
|
|
2
|
+
|
|
3
|
+
Lifecycle hook called after Orator starts and the persistence engine loads, but before data endpoints are created.
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
`onInitialize(fCallback)`
|
|
8
|
+
|
|
9
|
+
## Parameters
|
|
10
|
+
|
|
11
|
+
| Parameter | Type | Description |
|
|
12
|
+
|-----------|------|-------------|
|
|
13
|
+
| `fCallback` | Function | Callback `(pError)` to continue the initialization chain |
|
|
14
|
+
|
|
15
|
+
## Default Behavior
|
|
16
|
+
|
|
17
|
+
No-op -- calls `fCallback()` immediately.
|
|
18
|
+
|
|
19
|
+
## Override
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
class MyDataService extends require('retold-data-service')
|
|
23
|
+
{
|
|
24
|
+
onInitialize(fCallback)
|
|
25
|
+
{
|
|
26
|
+
this.fable.log.info('Running database migrations...');
|
|
27
|
+
// The persistence engine is connected but endpoints don't exist yet
|
|
28
|
+
return fCallback();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Use Cases
|
|
34
|
+
|
|
35
|
+
- Database migrations
|
|
36
|
+
- Additional service registration
|
|
37
|
+
- Custom route registration before entity routes
|
|
38
|
+
- Schema transformations
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
Complete method reference for the `RetoldDataService` class.
|
|
4
|
+
|
|
5
|
+
## Class: RetoldDataService
|
|
6
|
+
|
|
7
|
+
Extends `fable-serviceproviderbase`. Registered as service type `'RetoldDataService'`.
|
|
8
|
+
|
|
9
|
+
**Source:** `source/Retold-Data-Service.js`
|
|
10
|
+
|
|
11
|
+
### Methods
|
|
12
|
+
|
|
13
|
+
| Method | Description |
|
|
14
|
+
|--------|-------------|
|
|
15
|
+
| [constructor](api/constructor.md) | Create a new RetoldDataService instance |
|
|
16
|
+
| [initializeService](api/initializeService.md) | Initialize the full service stack |
|
|
17
|
+
| [stopService](api/stopService.md) | Stop the Orator web server |
|
|
18
|
+
| [initializePersistenceEngine](api/initializePersistenceEngine.md) | Load the storage provider module |
|
|
19
|
+
| [initializeDataEndpoints](api/initializeDataEndpoints.md) | Load model and create DAL + endpoints |
|
|
20
|
+
| [onBeforeInitialize](api/onBeforeInitialize.md) | Pre-initialization lifecycle hook |
|
|
21
|
+
| [onInitialize](api/onInitialize.md) | Mid-initialization lifecycle hook |
|
|
22
|
+
| [onAfterInitialize](api/onAfterInitialize.md) | Post-initialization lifecycle hook |
|
|
23
|
+
|
|
24
|
+
### Properties
|
|
25
|
+
|
|
26
|
+
| Property | Type | Description |
|
|
27
|
+
|----------|------|-------------|
|
|
28
|
+
| `serviceType` | String | Always `'RetoldDataService'` |
|
|
29
|
+
| `serviceInitialized` | Boolean | Whether the service has been initialized |
|
|
30
|
+
| `fullModel` | Object/Boolean | The loaded Stricture model, or `false` before init |
|
|
31
|
+
| `entityList` | Array/Boolean | Array of entity names, or `false` before init |
|
|
32
|
+
| `_DAL` | Object | Map of entity name to Meadow DAL instance |
|
|
33
|
+
| `_MeadowEndpoints` | Object | Map of entity name to MeadowEndpoints controller |
|
|
34
|
+
| `fable.DAL` | Object | Same as `_DAL` (decorated on Fable) |
|
|
35
|
+
| `fable.MeadowEndpoints` | Object | Same as `_MeadowEndpoints` (decorated on Fable) |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# stopService
|
|
2
|
+
|
|
3
|
+
Stop the Orator web server and reset the service state.
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
`stopService(fCallback)`
|
|
8
|
+
|
|
9
|
+
## Parameters
|
|
10
|
+
|
|
11
|
+
| Parameter | Type | Description |
|
|
12
|
+
|-----------|------|-------------|
|
|
13
|
+
| `fCallback` | Function | Callback `(pError)` when the service is stopped |
|
|
14
|
+
|
|
15
|
+
## Behavior
|
|
16
|
+
|
|
17
|
+
- Stops the Orator web server via `fable.Orator.stopWebServer()`
|
|
18
|
+
- Sets `serviceInitialized = false`
|
|
19
|
+
- Returns error if the service is not currently initialized
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
_Fable.RetoldDataService.stopService(
|
|
25
|
+
(pError) =>
|
|
26
|
+
{
|
|
27
|
+
if (pError)
|
|
28
|
+
{
|
|
29
|
+
console.error('Stop failed:', pError);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
console.log('Service stopped');
|
|
33
|
+
});
|
|
34
|
+
```
|
package/docs/architecture.md
CHANGED
|
@@ -8,7 +8,7 @@ Retold Data Service orchestrates several Retold modules into a unified service t
|
|
|
8
8
|
┌─────────────────────────────────────────────┐
|
|
9
9
|
│ Your Application Code │
|
|
10
10
|
│ - Configure options │
|
|
11
|
-
│ - Override lifecycle hooks
|
|
11
|
+
│ - Override lifecycle hooks │
|
|
12
12
|
│ - Inject behaviors │
|
|
13
13
|
└──────────────────┬──────────────────────────┘
|
|
14
14
|
│
|
|
@@ -49,18 +49,66 @@ Retold Data Service orchestrates several Retold modules into a unified service t
|
|
|
49
49
|
└─────────────────────────────────────────────┘
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Initialization Flow
|
|
53
|
+
|
|
54
|
+
The `initializeService()` method runs an ordered sequence of asynchronous steps using Fable's Anticipate pattern:
|
|
55
|
+
|
|
56
|
+
```mermaid
|
|
57
|
+
sequenceDiagram
|
|
58
|
+
participant App as Application
|
|
59
|
+
participant RDS as RetoldDataService
|
|
60
|
+
participant O as Orator
|
|
61
|
+
participant PE as PersistenceEngine
|
|
62
|
+
participant M as Meadow
|
|
63
|
+
participant ME as MeadowEndpoints
|
|
64
|
+
|
|
65
|
+
App->>RDS: initializeService()
|
|
66
|
+
RDS->>RDS: onBeforeInitialize()
|
|
67
|
+
RDS->>O: startWebServer()
|
|
68
|
+
RDS->>PE: initializePersistenceEngine()
|
|
69
|
+
RDS->>RDS: onInitialize()
|
|
70
|
+
RDS->>M: Load Stricture model
|
|
71
|
+
loop Each Entity
|
|
72
|
+
RDS->>M: loadFromPackageObject(schema)
|
|
73
|
+
M-->>RDS: DAL instance
|
|
74
|
+
RDS->>ME: new MeadowEndpoints(DAL)
|
|
75
|
+
ME->>O: connectRoutes()
|
|
76
|
+
end
|
|
77
|
+
RDS->>RDS: onAfterInitialize()
|
|
78
|
+
RDS-->>App: callback()
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Component Diagram
|
|
82
|
+
|
|
83
|
+
```mermaid
|
|
84
|
+
graph TD
|
|
85
|
+
A[Application Code] --> B[RetoldDataService]
|
|
86
|
+
B --> C[Orator + Restify]
|
|
87
|
+
B --> D[Meadow DAL]
|
|
88
|
+
B --> E[MeadowEndpoints]
|
|
89
|
+
D --> F[FoxHound Query DSL]
|
|
90
|
+
D --> G[Storage Provider]
|
|
91
|
+
G --> H[MySQL]
|
|
92
|
+
G --> I[SQLite]
|
|
93
|
+
G --> J[MSSQL]
|
|
94
|
+
G --> K[PostgreSQL]
|
|
95
|
+
G --> L[MongoDB]
|
|
96
|
+
E --> M[REST Routes]
|
|
97
|
+
E --> N[Behavior Injection]
|
|
98
|
+
```
|
|
99
|
+
|
|
52
100
|
## How It Works
|
|
53
101
|
|
|
54
|
-
1. **Registration**
|
|
55
|
-
2. **Server Setup**
|
|
56
|
-
3. **Initialization**
|
|
57
|
-
- `onBeforeInitialize()`
|
|
102
|
+
1. **Registration** -- `RetoldDataService` is registered with Fable's service manager and instantiated with options
|
|
103
|
+
2. **Server Setup** -- Orator and its Restify service server are registered and configured
|
|
104
|
+
3. **Initialization** -- calling `initializeService()` triggers an ordered sequence:
|
|
105
|
+
- `onBeforeInitialize()` -- your custom pre-initialization logic
|
|
58
106
|
- Orator web server start (if `AutoStartOrator` is true)
|
|
59
107
|
- Persistence engine initialization (loads the storage provider module)
|
|
60
|
-
- `onInitialize()`
|
|
108
|
+
- `onInitialize()` -- your custom initialization logic
|
|
61
109
|
- Data endpoint initialization (loads model, creates DALs and endpoints)
|
|
62
|
-
- `onAfterInitialize()`
|
|
63
|
-
4. **Serving**
|
|
110
|
+
- `onAfterInitialize()` -- your custom post-initialization logic
|
|
111
|
+
4. **Serving** -- the Restify server listens for HTTP requests and routes them through Meadow Endpoints to the DAL
|
|
64
112
|
|
|
65
113
|
## Key Objects
|
|
66
114
|
|
|
@@ -83,12 +131,28 @@ const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
|
83
131
|
|
|
84
132
|
class RetoldDataService extends libFableServiceProviderBase
|
|
85
133
|
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
134
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
135
|
+
{
|
|
136
|
+
super(pFable, pOptions, pServiceHash);
|
|
137
|
+
this.serviceType = 'RetoldDataService';
|
|
138
|
+
}
|
|
91
139
|
}
|
|
92
140
|
```
|
|
93
141
|
|
|
94
|
-
This means it inherits logging, configuration access, and service lifecycle management from the base class.
|
|
142
|
+
This means it inherits logging, configuration access, and service lifecycle management from the base class. You register it with Fable's service manager like any other service:
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
const libRetoldDataService = require('retold-data-service');
|
|
146
|
+
|
|
147
|
+
_Fable.serviceManager.addServiceType('RetoldDataService', libRetoldDataService);
|
|
148
|
+
let _DataService = _Fable.serviceManager.instantiateServiceProvider('RetoldDataService',
|
|
149
|
+
{
|
|
150
|
+
FullMeadowSchemaPath: `${__dirname}/model/`,
|
|
151
|
+
FullMeadowSchemaFilename: 'MeadowModel-Extended.json',
|
|
152
|
+
StorageProvider: 'MySQL',
|
|
153
|
+
StorageProviderModule: 'meadow-connection-mysql',
|
|
154
|
+
AutoStartOrator: true
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Once instantiated, the service is available at `_Fable.RetoldDataService` and can be initialized with `initializeService()`.
|
|
@@ -1,111 +1,154 @@
|
|
|
1
1
|
# Behavior Injection
|
|
2
2
|
|
|
3
|
-
Behavior injection lets you add custom logic before
|
|
3
|
+
Behavior injection lets you add custom logic before or after any CRUD operation on any entity. This is the primary extension mechanism for adding business rules, validation, enrichment, and side effects.
|
|
4
4
|
|
|
5
5
|
## How It Works
|
|
6
6
|
|
|
7
|
-
Each
|
|
7
|
+
Each MeadowEndpoints controller has a `BehaviorInjection` object that manages hooks for every CRUD operation. You set behaviors by specifying the operation and timing (pre or post).
|
|
8
|
+
|
|
9
|
+
## Available Hooks
|
|
10
|
+
|
|
11
|
+
| Hook | Fires |
|
|
12
|
+
|------|-------|
|
|
13
|
+
| `Create-PreOperation` | Before a record is created |
|
|
14
|
+
| `Create-PostOperation` | After a record is created |
|
|
15
|
+
| `Read-PreOperation` | Before a single record is read |
|
|
16
|
+
| `Read-PostOperation` | After a single record is read |
|
|
17
|
+
| `Reads-PreOperation` | Before multiple records are read |
|
|
18
|
+
| `Reads-PostOperation` | After multiple records are read |
|
|
19
|
+
| `Update-PreOperation` | Before a record is updated |
|
|
20
|
+
| `Update-PostOperation` | After a record is updated |
|
|
21
|
+
| `Delete-PreOperation` | Before a record is deleted |
|
|
22
|
+
| `Delete-PostOperation` | After a record is deleted |
|
|
23
|
+
| `Count-PreOperation` | Before a count query |
|
|
24
|
+
| `Count-PostOperation` | After a count query |
|
|
8
25
|
|
|
9
26
|
## Setting a Behavior
|
|
10
27
|
|
|
11
28
|
```javascript
|
|
12
29
|
_Fable.MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
});
|
|
30
|
+
'Create-PreOperation',
|
|
31
|
+
(pRequest, pRequestState, fRequestComplete) =>
|
|
32
|
+
{
|
|
33
|
+
// Your custom logic here
|
|
34
|
+
return fRequestComplete(false);
|
|
35
|
+
});
|
|
20
36
|
```
|
|
21
37
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|-----------|-------|
|
|
28
|
-
| `Create-PreOperation` | Before a CREATE |
|
|
29
|
-
| `Create-PostOperation` | After a CREATE |
|
|
30
|
-
| `Read-PreOperation` | Before a single READ |
|
|
31
|
-
| `Read-PostOperation` | After a single READ |
|
|
32
|
-
| `Reads-PreOperation` | Before a READ-many |
|
|
33
|
-
| `Reads-PostOperation` | After a READ-many |
|
|
34
|
-
| `Update-PreOperation` | Before an UPDATE |
|
|
35
|
-
| `Update-PostOperation` | After an UPDATE |
|
|
36
|
-
| `Delete-PreOperation` | Before a DELETE |
|
|
37
|
-
| `Delete-PostOperation` | After a DELETE |
|
|
38
|
-
| `Count-PreOperation` | Before a COUNT |
|
|
39
|
-
| `Count-PostOperation` | After a COUNT |
|
|
40
|
-
| `Schema-PreOperation` | Before a SCHEMA read |
|
|
41
|
-
| `Schema-PostOperation` | After a SCHEMA read |
|
|
42
|
-
|
|
43
|
-
## Request State
|
|
44
|
-
|
|
45
|
-
The `pRequestState` object contains:
|
|
46
|
-
|
|
47
|
-
| Property | Description |
|
|
48
|
-
|----------|-------------|
|
|
49
|
-
| `Record` | The current record being operated on |
|
|
50
|
-
| `RecordToCreate` | The record being created (Create operations) |
|
|
51
|
-
| `Query` | The FoxHound query object |
|
|
52
|
-
| `SessionData` | Session data for the current request |
|
|
38
|
+
## Callback Convention
|
|
39
|
+
|
|
40
|
+
The `fRequestComplete` callback accepts a single boolean argument:
|
|
41
|
+
- `false` -- Continue normal processing
|
|
42
|
+
- `true` -- Halt processing (request is already handled)
|
|
53
43
|
|
|
54
44
|
## Examples
|
|
55
45
|
|
|
56
|
-
###
|
|
46
|
+
### Validation
|
|
57
47
|
|
|
58
48
|
```javascript
|
|
59
49
|
_Fable.MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return fRequestComplete(false);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
50
|
+
'Create-PreOperation',
|
|
51
|
+
(pRequest, pRequestState, fRequestComplete) =>
|
|
52
|
+
{
|
|
53
|
+
if (!pRequestState.RecordToCreate.Title)
|
|
54
|
+
{
|
|
55
|
+
pRequest.CommonServices.sendCodedResponse(
|
|
56
|
+
pRequestState.response, 400, 'Title is required');
|
|
57
|
+
return fRequestComplete(true);
|
|
58
|
+
}
|
|
59
|
+
return fRequestComplete(false);
|
|
60
|
+
});
|
|
74
61
|
```
|
|
75
62
|
|
|
76
|
-
###
|
|
63
|
+
### Record Enrichment
|
|
77
64
|
|
|
78
65
|
```javascript
|
|
79
66
|
_Fable.MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
return fRequestComplete(false);
|
|
90
|
-
});
|
|
67
|
+
'Read-PostOperation',
|
|
68
|
+
(pRequest, pRequestState, fRequestComplete) =>
|
|
69
|
+
{
|
|
70
|
+
// Add computed fields to the response
|
|
71
|
+
pRequestState.Record.DisplayTitle =
|
|
72
|
+
`${pRequestState.Record.Title} (${pRequestState.Record.PublicationYear})`;
|
|
73
|
+
return fRequestComplete(false);
|
|
74
|
+
});
|
|
91
75
|
```
|
|
92
76
|
|
|
93
|
-
###
|
|
77
|
+
### Cross-Entity Enrichment
|
|
94
78
|
|
|
95
79
|
```javascript
|
|
96
80
|
_Fable.MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
81
|
+
'Read-PostOperation',
|
|
82
|
+
(pRequest, pRequestState, fRequestComplete) =>
|
|
83
|
+
{
|
|
84
|
+
_Fable.DAL.BookAuthorJoin.doReads(
|
|
85
|
+
_Fable.DAL.BookAuthorJoin.query.addFilter('IDBook', pRequestState.Record.IDBook),
|
|
86
|
+
(pJoinError, pJoinQuery, pJoinRecords) =>
|
|
87
|
+
{
|
|
88
|
+
let tmpAuthors = [];
|
|
89
|
+
let tmpRemaining = pJoinRecords.length;
|
|
90
|
+
|
|
91
|
+
if (tmpRemaining < 1)
|
|
92
|
+
{
|
|
93
|
+
pRequestState.Record.Authors = [];
|
|
94
|
+
return fRequestComplete(false);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (let j = 0; j < pJoinRecords.length; j++)
|
|
98
|
+
{
|
|
99
|
+
_Fable.DAL.Author.doRead(
|
|
100
|
+
_Fable.DAL.Author.query.addFilter('IDAuthor', pJoinRecords[j].IDAuthor),
|
|
101
|
+
(pReadError, pReadQuery, pAuthor) =>
|
|
102
|
+
{
|
|
103
|
+
if (pAuthor && pAuthor.IDAuthor)
|
|
104
|
+
{
|
|
105
|
+
tmpAuthors.push(pAuthor);
|
|
106
|
+
}
|
|
107
|
+
tmpRemaining--;
|
|
108
|
+
if (tmpRemaining <= 0)
|
|
109
|
+
{
|
|
110
|
+
pRequestState.Record.Authors = tmpAuthors;
|
|
111
|
+
return fRequestComplete(false);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
104
117
|
```
|
|
105
118
|
|
|
106
|
-
|
|
119
|
+
### Audit Logging
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
_Fable.MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior(
|
|
123
|
+
'Delete-PreOperation',
|
|
124
|
+
(pRequest, pRequestState, fRequestComplete) =>
|
|
125
|
+
{
|
|
126
|
+
_Fable.log.warn(`Book ${pRequestState.RecordToDelete.IDBook} is being deleted`);
|
|
127
|
+
return fRequestComplete(false);
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Timing
|
|
132
|
+
|
|
133
|
+
- **PreOperation** hooks run before the database operation. Use them for validation, transformation, or authorization.
|
|
134
|
+
- **PostOperation** hooks run after the database operation. Use them for enrichment, logging, or triggering side effects.
|
|
135
|
+
|
|
136
|
+
## Using with Lifecycle Hooks
|
|
137
|
+
|
|
138
|
+
The best place to inject behaviors is in the `onAfterInitialize` lifecycle hook:
|
|
107
139
|
|
|
108
140
|
```javascript
|
|
109
|
-
|
|
110
|
-
|
|
141
|
+
class MyDataService extends require('retold-data-service')
|
|
142
|
+
{
|
|
143
|
+
onAfterInitialize(fCallback)
|
|
144
|
+
{
|
|
145
|
+
this.fable.MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior(
|
|
146
|
+
'Read-PostOperation', myBookEnrichmentHook);
|
|
147
|
+
|
|
148
|
+
this.fable.MeadowEndpoints.Review.controller.BehaviorInjection.setBehavior(
|
|
149
|
+
'Create-PreOperation', myReviewValidationHook);
|
|
150
|
+
|
|
151
|
+
return fCallback();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
111
154
|
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
Pict Docuserve - Base Styles
|
|
3
|
+
============================================================================ */
|
|
4
|
+
|
|
5
|
+
/* Reset and base */
|
|
6
|
+
*, *::before, *::after {
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
html, body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
14
|
+
font-size: 16px;
|
|
15
|
+
line-height: 1.5;
|
|
16
|
+
color: #423D37;
|
|
17
|
+
background-color: #fff;
|
|
18
|
+
-webkit-font-smoothing: antialiased;
|
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Typography */
|
|
23
|
+
h1, h2, h3, h4, h5, h6 {
|
|
24
|
+
margin-top: 0;
|
|
25
|
+
line-height: 1.3;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
a {
|
|
29
|
+
color: #2E7D74;
|
|
30
|
+
text-decoration: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
a:hover {
|
|
34
|
+
color: #256861;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Application container */
|
|
38
|
+
#Docuserve-Application-Container {
|
|
39
|
+
min-height: 100vh;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Utility: scrollbar styling */
|
|
43
|
+
::-webkit-scrollbar {
|
|
44
|
+
width: 8px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
::-webkit-scrollbar-track {
|
|
48
|
+
background: #F5F0E8;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::-webkit-scrollbar-thumb {
|
|
52
|
+
background: #D4CCBE;
|
|
53
|
+
border-radius: 4px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
::-webkit-scrollbar-thumb:hover {
|
|
57
|
+
background: #B5AA9A;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Responsive adjustments */
|
|
61
|
+
@media (max-width: 768px) {
|
|
62
|
+
html {
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#Docuserve-Sidebar-Container {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.docuserve-body {
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
}
|
|
73
|
+
}
|