@iyulab/enterprise 0.12.0 → 0.14.0
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/CHANGELOG.md +44 -0
- package/README.md +22 -1
- package/dist/FormRow.d.ts +16 -0
- package/dist/data/ODataService.d.ts +18 -6
- package/dist/index.js +66 -20
- package/package.json +3 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.14.0] - 2026-09-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **A failed `api*` write told the user nothing.** `notify.error` was wired into the OData writes
|
|
8
|
+
only, so a custom REST write that came back 4xx threw an `ApiError` and left the screen exactly as
|
|
9
|
+
it was — indistinguishable from nothing having happened, even when the server had returned a
|
|
10
|
+
precise reason. The four `api*` writes now notify on failure and rethrow, on the same terms as
|
|
11
|
+
their OData siblings (401 excluded, since `onUnauthorized` already covers it). Reads are unchanged
|
|
12
|
+
and still silent on both sides.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`apiPostQuiet`, `apiPutQuiet`, `apiPatchQuiet`, `apiDeleteQuiet`.** The opt-out for the above,
|
|
17
|
+
matching the existing `odata*Quiet` naming: use them when one user action issues several requests,
|
|
18
|
+
or when the calling code already reports failures itself and would otherwise show two messages.
|
|
19
|
+
|
|
20
|
+
### Documentation
|
|
21
|
+
|
|
22
|
+
- **The README said which hooks exist but not where they apply**, which read as "wire `notify` and
|
|
23
|
+
failures become visible". It now carries a per-method table and states the axis: writes notify,
|
|
24
|
+
reads do not, `*Quiet` opts out, 401 never notifies, and `api*` has no success message because the
|
|
25
|
+
library cannot invent wording for an arbitrary endpoint.
|
|
26
|
+
|
|
27
|
+
## 0.13.0
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **`FormRow`'s grid tracks are now `minmax(0, 1fr)` rather than `1fr`, so columns declared
|
|
32
|
+
equal actually render equal.** A grid item's default `min-width: auto` refuses to shrink below
|
|
33
|
+
its content's min-content width, so one long value in a row was enough to blow out its own
|
|
34
|
+
column and squeeze the rest. Measured in a 400px container with one long unbreakable string:
|
|
35
|
+
a two-column row laid out at **425px / 8px** and a three-column row at **425px / 8px / 8px**,
|
|
36
|
+
and the row overflowed its container. With `minmax(0, 1fr)` the same cases lay out at
|
|
37
|
+
**196 / 196** and **128 / 128 / 128**. Nothing about the API changes, and rows whose content
|
|
38
|
+
already fit are unaffected.
|
|
39
|
+
- Long unbreakable content still overflows its own column — that is a separate axis, handled
|
|
40
|
+
on the cell with `overflow-wrap` (this package's peer elements already set it).
|
|
41
|
+
|
|
42
|
+
- **`@iyulab/components` is no longer an optional peer dependency.** The main entry imports it
|
|
43
|
+
unconditionally, so declaring it optional meant a consumer installing this package alone got
|
|
44
|
+
nothing installed and no warning — the failure surfaced only as a module-not-found at
|
|
45
|
+
runtime. Consumers already installing it are unaffected.
|
|
46
|
+
|
|
3
47
|
## 0.12.0
|
|
4
48
|
|
|
5
49
|
### Added
|
package/README.md
CHANGED
|
@@ -51,6 +51,8 @@ import { FormSection, FormRow } from '@iyulab/enterprise'
|
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
- `FormRow`는 기본 2컬럼 그리드입니다. 한 칸을 차지하려면 `full`을, 다른 열 수가 필요하면 `columns`를 씁니다.
|
|
54
|
+
- **열 폭 — 선언한 열은 실제로 균등합니다.** 트랙은 `1fr`이 아니라 `minmax(0, 1fr)`입니다. 그리드 아이템의 기본 `min-width: auto`는 내용의 min-content 아래로 줄어들기를 거부해서, 순수 `1fr`로 두면 긴 내용이 든 칸만 부풀고 나머지가 찌그러집니다(400px 컨테이너 실측: 2열 **425/8**, 3열 **425/8/8**). `minmax(0, 1fr)`은 트랙 최소를 0으로 만들어 같은 경우를 **196/196**·**128/128/128**로 만듭니다.
|
|
55
|
+
- ⚠**긴 불가분 문자열 자체의 넘침은 별개 축입니다.** 칸이 균등해져도 그 안의 긴 문자열은 자기 칸을 넘습니다 — 셀 쪽에서 `overflow-wrap`으로 다룹니다(`@iyulab/components`의 엘리먼트는 이미 그 값을 갖습니다).
|
|
54
56
|
- 두 컴포넌트 모두 `className`·`style`을 받아 기본값 **뒤에** 병합합니다 — 블록을 복제하지 않고 조정하는 정규 경로입니다. `FormSection`은 제목 줄만 바꾸는 `titleStyle`도 받습니다.
|
|
55
57
|
|
|
56
58
|
```tsx
|
|
@@ -119,10 +121,29 @@ await svc.apiPost<Order>('orders/7/attachments', form)
|
|
|
119
121
|
| `baseUrl` | 모든 요청의 오리진 (필수) |
|
|
120
122
|
| `odataPrefix` / `apiPrefix` | 엔드포인트 prefix (기본 `$data` / `api`) |
|
|
121
123
|
| `onUnauthorized(status)` | 401 시 호출 — 리다이렉트/재진입 가드는 앱이 처리 |
|
|
122
|
-
| `notify.success/error` | 토스트 훅 (생략 시 토스트 없음 — 순수) |
|
|
124
|
+
| `notify.success/error` | 토스트 훅 (생략 시 토스트 없음 — 순수). **메서드마다 걸리는 방식이 다르다 — 바로 아래 표 참조** |
|
|
123
125
|
| `messages` | 사용자 대면 문구 (기본 영어, 지정 키만 대체) |
|
|
124
126
|
| `formatError(info)` | 에러 메시지 포매팅 오버라이드 (앱별 정책) — `info` 는 `status`/`statusText`/`rawMessage`/`details`(검증된 `error.details`)/`body` 를 받는다 |
|
|
125
127
|
|
|
128
|
+
#### `notify` 가 걸리는 자리 — 축은 «쓰기 ↔ 읽기» 다
|
|
129
|
+
|
|
130
|
+
| 메서드 | 실패 시 `error` | 성공 시 `success` |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `odataPost` · `odataPatch` · `odataDelete` | ✅ (401 제외) | ✅ `saved`·`updated`·`deleted` |
|
|
133
|
+
| `apiPost` · `apiPut` · `apiPatch` · `apiDelete` | ✅ (401 제외) | ❌ |
|
|
134
|
+
| `*Quiet` 전부 (`odataPostQuiet` … `apiDeleteQuiet`) | ❌ | ❌ |
|
|
135
|
+
| `odataGet` · `odataGetById` · `odataCount` · `apiGet` · `fetchRaw` | ❌ | ❌ |
|
|
136
|
+
|
|
137
|
+
- **조회는 통지하지 않는다.** 빈 화면 자체가 신호이고, 목록을 열 때마다 토스트가 뜨면 읽을 수 없다.
|
|
138
|
+
- **쓰기는 통지한다.** 결과가 화면에 안 보일 수 있기 때문이다 — 서버가 409 와 사유를 돌려줘도,
|
|
139
|
+
통지가 없으면 아무 일도 일어나지 않은 화면과 구별되지 않는다.
|
|
140
|
+
- **401 은 통지하지 않는다** — `onUnauthorized` 가 이미 안내하므로 겹친다.
|
|
141
|
+
- **`api*` 에는 성공 토스트가 없다.** 임의의 RPC(상태 전이·발행·업로드)를 태우는 경로라
|
|
142
|
+
«저장되었습니다» 같은 문구를 라이브러리가 지어낼 수 없다. 실패 메시지는 서버가 주므로 어느
|
|
143
|
+
엔드포인트에서나 뜻이 통하지만, 성공 문구는 그렇지 않다 — 필요하면 호출한 쪽이 띄운다.
|
|
144
|
+
- **이미 자기 래퍼로 통지하고 있다면 `*Quiet` 로 바꾼다.** 이중 토스트를 막는 탈출구이고,
|
|
145
|
+
`odata*Quiet` 와 같은 관용구다(한 사용자 액션이 여러 요청을 낼 때도 같은 것을 쓴다).
|
|
146
|
+
|
|
126
147
|
> 도메인 액션(상태 전이 등)·엔티티 목록·권한 코드는 라이브러리에 넣지 말고 앱 adapter 에 둔다.
|
|
127
148
|
|
|
128
149
|
#### 실패 응답 — `ApiError`
|
package/dist/FormRow.d.ts
CHANGED
|
@@ -5,6 +5,22 @@ import { CSSProperties, ReactNode } from 'react';
|
|
|
5
5
|
* 오버라이드 계약(docs/lob-layers.md §2)에 따라 `className`·`style` 을 받아 병합한다.
|
|
6
6
|
* `columns` 는 2열 고정이 맞지 않는 소비자가 **컴포넌트를 복제하지 않고** 조정하는 경로다
|
|
7
7
|
* — 복제가 시작되면 이 계층은 쓰기 전보다 나쁜 상태를 만든다.
|
|
8
|
+
*
|
|
9
|
+
* 🔴**트랙은 `minmax(0, 1fr)` 이지 `1fr` 이 아니다 — 순수 `1fr` 은 «균등» 을 약속하고**
|
|
10
|
+
* **지키지 않는다.** 그리드 아이템의 기본 `min-width: auto` 는 내용의 min-content 아래로
|
|
11
|
+
* 줄어들기를 거부하므로, 한 칸에 긴 내용이 들어오면 그 칸만 부풀고 나머지가 찌그러진다.
|
|
12
|
+
* 실측(400px 컨테이너 · 한 칸에 긴 불가분 문자열): 2열이 **425/8**, 3열이 **425/8/8** 이었고
|
|
13
|
+
* 행 자체가 컨테이너를 넘쳤다. `minmax(0, 1fr)` 은 트랙의 최소를 0 으로 만들어 **자식을**
|
|
14
|
+
* **건드리지 않고** 이를 고친다 — 같은 실측에서 **196/196** · **128/128/128**.
|
|
15
|
+
*
|
|
16
|
+
* ⚠**긴 불가분 내용 자체의 넘침은 별개 축이고 이 컴포넌트의 몫이 아니다.** 칸이 균등해져도
|
|
17
|
+
* 그 안의 긴 문자열은 여전히 자기 칸을 넘는다 — 그것은 셀의 `overflow-wrap` 이 답이다
|
|
18
|
+
* (`@iyulab/components` 의 엘리먼트는 이미 그 값을 갖는다). 같은 실측에서 `overflow-wrap` 을
|
|
19
|
+
* 주면 행의 넘침이 0 이 됐다.
|
|
20
|
+
*
|
|
21
|
+
* 계약은 `tests/form-layout-contract.test.ts` 가 고정한다 — 다만 그 파일은 **«선언» 을 재지**
|
|
22
|
+
* **«배치» 를 재지 않는다**(이 패키지엔 레이아웃을 계산하는 테스트 자리가 없다). 위 수치는
|
|
23
|
+
* 형제 패키지의 브라우저 프로젝트를 계측기로 빌린 일회성 탐침으로 쟀다.
|
|
8
24
|
*/
|
|
9
25
|
export declare function FormRow({ children, full, columns, className, style, }: {
|
|
10
26
|
children: ReactNode;
|
|
@@ -94,16 +94,28 @@ export interface ODataService {
|
|
|
94
94
|
odataDelete(entity: string, id: string): Promise<void>;
|
|
95
95
|
/** custom REST GET — 204 등 빈 바디를 안전 파싱. */
|
|
96
96
|
apiGet<T>(path: string): Promise<T>;
|
|
97
|
-
/** custom REST POST
|
|
98
|
-
* 전송된다 — `@iyulab/http-client`가
|
|
99
|
-
* JSON 직렬화 분기를 타지 않는다.
|
|
97
|
+
/** custom REST POST — 실패 시 `error` 토스트 후 rethrow(401 제외). `body`가 `FormData`
|
|
98
|
+
* 인스턴스면 그대로(직렬화 없이) 멀티파트로 전송된다 — `@iyulab/http-client`가
|
|
99
|
+
* Content-Type을 브라우저 자동 설정에 맡기고 JSON 직렬화 분기를 타지 않는다.
|
|
100
|
+
* `apiPut`/`apiPatch`도 동일하게 동작한다. */
|
|
100
101
|
apiPost<T>(path: string, body?: unknown): Promise<T>;
|
|
101
|
-
/** custom REST
|
|
102
|
+
/** custom REST POST — 토스트 없이 결과만(`odataPostQuiet`와 같은 이유: 한 사용자 액션이
|
|
103
|
+
* 여러 요청을 내거나, 소비자가 자기 래퍼로 이미 통지할 때). */
|
|
104
|
+
apiPostQuiet<T>(path: string, body?: unknown): Promise<T>;
|
|
105
|
+
/** custom REST PUT(리소스 전체 교체/생성) — 실패 시 `error` 토스트 후 rethrow(401 제외).
|
|
106
|
+
* `body`의 `FormData` 처리는 `apiPost` 참조. */
|
|
102
107
|
apiPut<T>(path: string, body?: unknown): Promise<T>;
|
|
103
|
-
/** custom REST
|
|
108
|
+
/** custom REST PUT — 토스트 없이 결과만. */
|
|
109
|
+
apiPutQuiet<T>(path: string, body?: unknown): Promise<T>;
|
|
110
|
+
/** custom REST PATCH — 실패 시 `error` 토스트 후 rethrow(401 제외). `body`의 `FormData`
|
|
111
|
+
* 처리는 `apiPost` 참조. */
|
|
104
112
|
apiPatch<T>(path: string, body?: unknown): Promise<T>;
|
|
105
|
-
/** custom REST
|
|
113
|
+
/** custom REST PATCH — 토스트 없이 결과만. */
|
|
114
|
+
apiPatchQuiet<T>(path: string, body?: unknown): Promise<T>;
|
|
115
|
+
/** custom REST DELETE — 실패 시 `error` 토스트 후 rethrow(401 제외). 대부분 204 No Content. */
|
|
106
116
|
apiDelete<T = void>(path: string): Promise<T>;
|
|
117
|
+
/** custom REST DELETE — 토스트 없이 결과만. */
|
|
118
|
+
apiDeleteQuiet<T = void>(path: string): Promise<T>;
|
|
107
119
|
/** URL 을 직접 조립한 커스텀 조회(csv-export 등)를 위해 raw 응답을 반환. */
|
|
108
120
|
fetchRaw(url: string): Promise<HttpResponse>;
|
|
109
121
|
/**
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,22 @@ function FormSection({ title, children, className, style, titleStyle }) {
|
|
|
59
59
|
* 오버라이드 계약(docs/lob-layers.md §2)에 따라 `className`·`style` 을 받아 병합한다.
|
|
60
60
|
* `columns` 는 2열 고정이 맞지 않는 소비자가 **컴포넌트를 복제하지 않고** 조정하는 경로다
|
|
61
61
|
* — 복제가 시작되면 이 계층은 쓰기 전보다 나쁜 상태를 만든다.
|
|
62
|
+
*
|
|
63
|
+
* 🔴**트랙은 `minmax(0, 1fr)` 이지 `1fr` 이 아니다 — 순수 `1fr` 은 «균등» 을 약속하고**
|
|
64
|
+
* **지키지 않는다.** 그리드 아이템의 기본 `min-width: auto` 는 내용의 min-content 아래로
|
|
65
|
+
* 줄어들기를 거부하므로, 한 칸에 긴 내용이 들어오면 그 칸만 부풀고 나머지가 찌그러진다.
|
|
66
|
+
* 실측(400px 컨테이너 · 한 칸에 긴 불가분 문자열): 2열이 **425/8**, 3열이 **425/8/8** 이었고
|
|
67
|
+
* 행 자체가 컨테이너를 넘쳤다. `minmax(0, 1fr)` 은 트랙의 최소를 0 으로 만들어 **자식을**
|
|
68
|
+
* **건드리지 않고** 이를 고친다 — 같은 실측에서 **196/196** · **128/128/128**.
|
|
69
|
+
*
|
|
70
|
+
* ⚠**긴 불가분 내용 자체의 넘침은 별개 축이고 이 컴포넌트의 몫이 아니다.** 칸이 균등해져도
|
|
71
|
+
* 그 안의 긴 문자열은 여전히 자기 칸을 넘는다 — 그것은 셀의 `overflow-wrap` 이 답이다
|
|
72
|
+
* (`@iyulab/components` 의 엘리먼트는 이미 그 값을 갖는다). 같은 실측에서 `overflow-wrap` 을
|
|
73
|
+
* 주면 행의 넘침이 0 이 됐다.
|
|
74
|
+
*
|
|
75
|
+
* 계약은 `tests/form-layout-contract.test.ts` 가 고정한다 — 다만 그 파일은 **«선언» 을 재지**
|
|
76
|
+
* **«배치» 를 재지 않는다**(이 패키지엔 레이아웃을 계산하는 테스트 자리가 없다). 위 수치는
|
|
77
|
+
* 형제 패키지의 브라우저 프로젝트를 계측기로 빌린 일회성 탐침으로 쟀다.
|
|
62
78
|
*/
|
|
63
79
|
function FormRow({ children, full, columns = 2, className, style }) {
|
|
64
80
|
if (full) return /* @__PURE__ */ jsx("div", {
|
|
@@ -73,7 +89,7 @@ function FormRow({ children, full, columns = 2, className, style }) {
|
|
|
73
89
|
className,
|
|
74
90
|
style: {
|
|
75
91
|
display: "grid",
|
|
76
|
-
gridTemplateColumns: `repeat(${columns}, 1fr)`,
|
|
92
|
+
gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
|
|
77
93
|
gap: "var(--u-space-sm, 8px)",
|
|
78
94
|
...style
|
|
79
95
|
},
|
|
@@ -758,44 +774,58 @@ function createODataService(config) {
|
|
|
758
774
|
await throwIfError(res);
|
|
759
775
|
return (await res.json())["@odata.count"] ?? 0;
|
|
760
776
|
}
|
|
777
|
+
/**
|
|
778
|
+
* 쓰기 실패를 사용자에게 알린 뒤 그대로 다시 던진다.
|
|
779
|
+
*
|
|
780
|
+
* 🔴**이 서비스의 통지 축은 «쓰기 ↔ 읽기» 이지 «odata ↔ api» 가 아니다.** 조회
|
|
781
|
+
* (`odataGet`·`odataGetById`·`odataCount`·`apiGet`·`fetchRaw`)는 어느 쪽도 통지하지
|
|
782
|
+
* 않는다 — 화면이 비어 있는 것 자체가 신호이고, 목록 조회마다 토스트를 띄우면 읽을 수
|
|
783
|
+
* 없다. 쓰기는 **결과가 화면에 안 보일 수 있으므로** 통지한다: 서버가 409 와 사유를
|
|
784
|
+
* 돌려줘도 아무 일도 일어나지 않은 화면과 구별되지 않는다.
|
|
785
|
+
*
|
|
786
|
+
* ⚠**401 은 제외한다** — `onUnauthorized` 가 이미 안내하므로 토스트가 겹친다.
|
|
787
|
+
*
|
|
788
|
+
* ⚠성공 토스트는 **`odata*` 쓰기에만** 있다. `api*` 는 임의의 RPC(상태 전이·발행·업로드)를
|
|
789
|
+
* 태우는 경로라 «저장되었습니다» 같은 문구를 우리가 지어낼 수 없다 — 실패 메시지는 서버가
|
|
790
|
+
* 주므로 어느 엔드포인트에서나 뜻이 통하지만, 성공 문구는 그렇지 않다.
|
|
791
|
+
*/
|
|
792
|
+
async function notifyingWrite(run) {
|
|
793
|
+
try {
|
|
794
|
+
return await run();
|
|
795
|
+
} catch (e) {
|
|
796
|
+
if (!(e instanceof ApiError && e.status === 401)) notifyError?.(e instanceof Error ? e.message : messages.requestFailed);
|
|
797
|
+
throw e;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
761
800
|
async function odataPostQuiet(entity, body) {
|
|
762
801
|
const res = await client.post(odataUrl(entity), normalizeBody(body));
|
|
763
802
|
await throwIfError(res);
|
|
764
803
|
return res.json();
|
|
765
804
|
}
|
|
766
805
|
async function odataPost(entity, body) {
|
|
767
|
-
|
|
806
|
+
return notifyingWrite(async () => {
|
|
768
807
|
const result = await odataPostQuiet(entity, body);
|
|
769
808
|
notifySuccess?.(messages.saved);
|
|
770
809
|
return result;
|
|
771
|
-
}
|
|
772
|
-
if (!(e instanceof ApiError && e.status === 401)) notifyError?.(e instanceof Error ? e.message : messages.requestFailed);
|
|
773
|
-
throw e;
|
|
774
|
-
}
|
|
810
|
+
});
|
|
775
811
|
}
|
|
776
812
|
async function odataPatchQuiet(entity, id, body) {
|
|
777
813
|
await throwIfError(await client.patch(`${odataUrl(entity)}(${id})`, normalizeBody(body)));
|
|
778
814
|
}
|
|
779
815
|
async function odataPatch(entity, id, body) {
|
|
780
|
-
|
|
816
|
+
return notifyingWrite(async () => {
|
|
781
817
|
await odataPatchQuiet(entity, id, body);
|
|
782
818
|
notifySuccess?.(messages.updated);
|
|
783
|
-
}
|
|
784
|
-
if (!(e instanceof ApiError && e.status === 401)) notifyError?.(e instanceof Error ? e.message : messages.requestFailed);
|
|
785
|
-
throw e;
|
|
786
|
-
}
|
|
819
|
+
});
|
|
787
820
|
}
|
|
788
821
|
async function odataDeleteQuiet(entity, id) {
|
|
789
822
|
await throwIfError(await client.delete(`${odataUrl(entity)}(${id})`));
|
|
790
823
|
}
|
|
791
824
|
async function odataDelete(entity, id) {
|
|
792
|
-
|
|
825
|
+
return notifyingWrite(async () => {
|
|
793
826
|
await odataDeleteQuiet(entity, id);
|
|
794
827
|
notifySuccess?.(messages.deleted);
|
|
795
|
-
}
|
|
796
|
-
if (!(e instanceof ApiError && e.status === 401)) notifyError?.(e instanceof Error ? e.message : messages.requestFailed);
|
|
797
|
-
throw e;
|
|
798
|
-
}
|
|
828
|
+
});
|
|
799
829
|
}
|
|
800
830
|
async function apiGet(path) {
|
|
801
831
|
const [p, ...q] = path.split("?");
|
|
@@ -804,26 +834,38 @@ function createODataService(config) {
|
|
|
804
834
|
await throwIfError(res);
|
|
805
835
|
return parseJsonBody(res);
|
|
806
836
|
}
|
|
807
|
-
async function
|
|
837
|
+
async function apiPostQuiet(path, body) {
|
|
808
838
|
const res = await client.post(apiUrl(path), body ?? {});
|
|
809
839
|
await throwIfError(res);
|
|
810
840
|
return parseJsonBody(res);
|
|
811
841
|
}
|
|
812
|
-
async function
|
|
842
|
+
async function apiPost(path, body) {
|
|
843
|
+
return notifyingWrite(() => apiPostQuiet(path, body));
|
|
844
|
+
}
|
|
845
|
+
async function apiPutQuiet(path, body) {
|
|
813
846
|
const res = await client.put(apiUrl(path), body ?? {});
|
|
814
847
|
await throwIfError(res);
|
|
815
848
|
return parseJsonBody(res);
|
|
816
849
|
}
|
|
817
|
-
async function
|
|
850
|
+
async function apiPut(path, body) {
|
|
851
|
+
return notifyingWrite(() => apiPutQuiet(path, body));
|
|
852
|
+
}
|
|
853
|
+
async function apiPatchQuiet(path, body) {
|
|
818
854
|
const res = await client.patch(apiUrl(path), body ?? {});
|
|
819
855
|
await throwIfError(res);
|
|
820
856
|
return parseJsonBody(res);
|
|
821
857
|
}
|
|
822
|
-
async function
|
|
858
|
+
async function apiPatch(path, body) {
|
|
859
|
+
return notifyingWrite(() => apiPatchQuiet(path, body));
|
|
860
|
+
}
|
|
861
|
+
async function apiDeleteQuiet(path) {
|
|
823
862
|
const res = await client.delete(apiUrl(path));
|
|
824
863
|
await throwIfError(res);
|
|
825
864
|
return parseJsonBody(res);
|
|
826
865
|
}
|
|
866
|
+
async function apiDelete(path) {
|
|
867
|
+
return notifyingWrite(() => apiDeleteQuiet(path));
|
|
868
|
+
}
|
|
827
869
|
async function fetchRaw(url) {
|
|
828
870
|
const res = await client.get(url);
|
|
829
871
|
await throwIfError(res);
|
|
@@ -843,9 +885,13 @@ function createODataService(config) {
|
|
|
843
885
|
odataDelete,
|
|
844
886
|
apiGet,
|
|
845
887
|
apiPost,
|
|
888
|
+
apiPostQuiet,
|
|
846
889
|
apiPut,
|
|
890
|
+
apiPutQuiet,
|
|
847
891
|
apiPatch,
|
|
892
|
+
apiPatchQuiet,
|
|
848
893
|
apiDelete,
|
|
894
|
+
apiDeleteQuiet,
|
|
849
895
|
fetchRaw,
|
|
850
896
|
sourceDefaults: {
|
|
851
897
|
baseUrl,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/enterprise",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Enterprise utilities and components for iyulab framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"enterprise",
|
|
@@ -58,18 +58,13 @@
|
|
|
58
58
|
"@iyulab/components": "^1.27.0",
|
|
59
59
|
"@types/node": "^26.1.1",
|
|
60
60
|
"@types/react": "^19.2.14",
|
|
61
|
-
"typescript": "^
|
|
61
|
+
"typescript": "^6.0.2",
|
|
62
62
|
"vite": "^8.1.4",
|
|
63
63
|
"vite-plugin-dts": "^5.0.3",
|
|
64
|
-
"vitest": "^
|
|
64
|
+
"vitest": "^5.0.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"react": ">=18",
|
|
68
68
|
"@iyulab/components": ">=1.27.0"
|
|
69
|
-
},
|
|
70
|
-
"peerDependenciesMeta": {
|
|
71
|
-
"@iyulab/components": {
|
|
72
|
-
"optional": true
|
|
73
|
-
}
|
|
74
69
|
}
|
|
75
70
|
}
|