@sparkelf/dsh-knowledge-base 0.1.1 → 0.1.3

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.
@@ -87,25 +87,6 @@ export interface KnowledgeFileTreeProps {
87
87
  * caller has no favourites store, which keeps the wrapper from touching the DOM at all.
88
88
  */
89
89
  isFavorite?: (relPath: string) => boolean;
90
- /**
91
- * Open the row context menu for one row.
92
- *
93
- * The explorer builds its own menu inside itself and marks the event handled, so the
94
- * only place to intercept is a capture-phase listener above it. This wrapper does
95
- * that and forwards the row here; the page then renders the SAME menu component the
96
- * home table uses, so both surfaces offer one action set.
97
- *
98
- * Absent means "leave the explorer's own menu alone", which is what a read-only
99
- * surface embedding this tree would want.
100
- */
101
- onRowContextMenu?: (relPath: string, isDir: boolean, at: {
102
- x: number;
103
- y: number;
104
- }, selection?: readonly {
105
- relPath: string;
106
- name: string;
107
- isDir: boolean;
108
- }[]) => void;
109
90
  /** The favourites star's accessible name. */
110
91
  favoriteMarkLabel?: string;
111
92
  }
@@ -37,6 +37,17 @@ export interface KnowledgeHomeProps {
37
37
  departmentCode?: string;
38
38
  /** The caller's own department name; the code stands in when this is absent. */
39
39
  departmentName?: string;
40
+ /**
41
+ * Whether the Host verified this caller may manage grants.
42
+ *
43
+ * This is the ONLY per-caller permission answer the client receives. There is no
44
+ * per-path "may I write this" route: `grants` is admin-scoped and the list route
45
+ * reports visibility, not writability. So the "Owned by me" tab uses this as its
46
+ * whole answer for the shared buckets -- an administrator sees the shared documents
47
+ * there, a plain reader does not -- and marks the rows whose answer it could not
48
+ * narrow rather than pretending either way.
49
+ */
50
+ canManageGrants?: boolean;
40
51
  /**
41
52
  * The tab whose card should take focus on mount.
42
53
  *
@@ -19,7 +19,6 @@
19
19
  * @module @sparkelf/dsh-knowledge-base/client/KnowledgePermissionOverview
20
20
  */
21
21
  import type { GrantView, KnowledgeGrantSubjectType } from '../api.ts';
22
- import { type RoleSummary } from './roleSummary.ts';
23
22
  /** Which reading of the grant table the tabs are showing. */
24
23
  export type OverviewTab = 'person' | 'role' | 'resource';
25
24
  /** Copy for the overview, supplied by the caller's locale record. */
@@ -55,7 +54,6 @@ export interface OverviewCopy {
55
54
  pathsHeld: (count: number) => string;
56
55
  rolesHeld: string;
57
56
  actionsHeld: string;
58
- builtInRoles: string;
59
57
  noActions: string;
60
58
  /** Accessible name for the tab strip, for readers who arrive at it by keyboard. */
61
59
  tabsLabel: string;
@@ -118,8 +116,6 @@ export interface KnowledgePermissionOverviewProps {
118
116
  kind: 'unavailable';
119
117
  reason: string;
120
118
  };
121
- /** Built-in role summaries, so the person view can explain what a role means. */
122
- roles?: readonly RoleSummary[];
123
119
  /** Locale copy. */
124
120
  copy: OverviewCopy;
125
121
  /**
@@ -26,6 +26,34 @@ export interface KnowledgeSelectionBarProps {
26
26
  onMove: () => void;
27
27
  /** Pin every selected path. */
28
28
  onPin: () => void;
29
+ /**
30
+ * The plugin's own actions, which used to live in a row context menu.
31
+ *
32
+ * They are here because the explorer's context menu cannot be extended: intercepting
33
+ * it meant REPLACING the six actions a reader already relies on (upload here, new
34
+ * folder, new file, zip-and-download, copy relative/absolute address). The bar is the
35
+ * honest place for them -- it appears on selection, offers no competition with the
36
+ * explorer's own menu, and is itself a primitive-shaped toolbar.
37
+ *
38
+ * Each is optional so a read-only surface can pass only what it supports.
39
+ */
40
+ onShare?: () => void;
41
+ /** Favourite every selected path (or unfavourite, when all are already starred). */
42
+ onFavorite?: () => void;
43
+ /** Whether every selected path is currently favourited, which picks the label. */
44
+ allFavorite?: boolean;
45
+ /** Ask a conversation to reference every selected path. */
46
+ onReference?: () => void;
47
+ /** Open the permission surface for the selection. */
48
+ onPermissions?: () => void;
49
+ /** Put the selection on the clipboard. */
50
+ onCut?: () => void;
51
+ /** Paste the clipboard into the selection's directory, when there is one. */
52
+ onPaste?: () => void;
53
+ /** Whether a paste is possible: clipboard non-empty and a destination known. */
54
+ canPaste?: boolean;
55
+ /** True when every selected path is pinned, which picks the pin label. */
56
+ allPinned?: boolean;
29
57
  /** Drop the selection. */
30
58
  onClear: () => void;
31
59
  /**
@@ -342,6 +342,7 @@ export declare const en: {
342
342
  readonly 'step.sshfs-mount': "Mount the share over SSHFS";
343
343
  readonly 'step.sshfs-verify': "Verify the SSHFS mount";
344
344
  readonly deployLocalOnly: "Deployment steps run on a remote host. This workspace stores documents locally, so there is nothing to deploy.";
345
+ readonly shareEmpty: "Nothing has been shared yet.";
345
346
  readonly shareGroupReceived: "Inbound";
346
347
  readonly shareGroupGiven: "Outbound";
347
348
  readonly shareColRelation: "Sharing";
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Which documents belong under "Owned by me".
3
+ *
4
+ * Two rules, and the second is the one users asked for explicitly: a document in the
5
+ * caller's own personal folder is theirs, and a document the caller can WRITE is also
6
+ * theirs to manage -- an administrator who maintains `global/` should not have to open
7
+ * the tree to find those files, because the Home tab is where they look first.
8
+ *
9
+ * Write access is not derivable from the tree, so the caller passes in what it knows.
10
+ * The important part is the three-valued answer: "yes", "no" and "not known" are all
11
+ * different, and an unknown permission must not be silently treated as either.
12
+ *
13
+ * @module @sparkelf/dsh-knowledge-base/client
14
+ */
15
+ /** What the caller knows about one path's manageability. */
16
+ export type Manageability =
17
+ /** The caller may write or manage it. */
18
+ 'writable'
19
+ /** The caller may read it but not write it. */
20
+ | 'read-only'
21
+ /** No answer was available: not configured, refused, or not looked up. */
22
+ | 'unknown';
23
+ /** What a row's membership answer is. */
24
+ export type MineVerdict =
25
+ /** Belongs under "Owned by me". */
26
+ 'mine'
27
+ /** Does not belong. */
28
+ | 'not-mine'
29
+ /** Cannot be decided; the caller must mark the row rather than drop or claim it. */
30
+ | 'undetermined';
31
+ /**
32
+ * The bucket a path sits in, by its first segment.
33
+ * @param relPath - path relative to the knowledge root.
34
+ * @returns The bucket name, or an empty string when the path is empty.
35
+ */
36
+ export declare function bucketOfPath(relPath: string): string;
37
+ /**
38
+ * Whether a path sits inside the caller's own personal folder.
39
+ *
40
+ * `personal/<callerId>/...` and nothing else: a sibling's folder is not the caller's,
41
+ * and the caller's bare `personal/` level is a container rather than their documents.
42
+ * @param relPath - path relative to the knowledge root.
43
+ * @param callerId - the caller's own id, when known.
44
+ * @returns True when the path is under the caller's own folder.
45
+ */
46
+ export declare function isInOwnPersonalFolder(relPath: string, callerId: string | undefined): boolean;
47
+ /**
48
+ * Decide whether one path belongs under "Owned by me".
49
+ *
50
+ * The caller's own personal folder is unconditional: it is theirs by construction, and
51
+ * no permission lookup can make it not theirs. Every other path depends on write access,
52
+ * which is why an unknown answer is NOT treated as permission -- showing a document as
53
+ * "mine" when the caller cannot write it would be a claim the deployment cannot back.
54
+ *
55
+ * An undetermined row is neither dropped nor claimed: the caller renders it with a mark,
56
+ * which is the existing degradation for a permission answer that could not be read.
57
+ * @param relPath - path relative to the knowledge root.
58
+ * @param callerId - the caller's own id, when known.
59
+ * @param manageability - what is known about write access for this path.
60
+ * @returns Whether the row is mine, not mine, or undecidable.
61
+ */
62
+ export declare function mineVerdict(relPath: string, callerId: string | undefined, manageability: Manageability): MineVerdict;
63
+ /**
64
+ * The rows under "Owned by me", given what is known about each.
65
+ *
66
+ * Undetermined rows are included and reported separately, because dropping them is the
67
+ * silent-loss failure the user reported: their files existed and simply did not appear.
68
+ * The caller shows them with a mark rather than hiding them.
69
+ * @param rows - every candidate row, in display order.
70
+ * @param callerId - the caller's own id, when known.
71
+ * @param manageabilityOf - per-path write knowledge.
72
+ * @returns The rows to show and the paths whose answer was undetermined.
73
+ */
74
+ export declare function selectOwnedRows<T extends {
75
+ relPath: string;
76
+ }>(rows: readonly T[], callerId: string | undefined, manageabilityOf: (relPath: string) => Manageability): {
77
+ rows: T[];
78
+ undetermined: string[];
79
+ };
@@ -24,14 +24,21 @@ export interface RoleSummary {
24
24
  builtIn: boolean;
25
25
  }
26
26
  /**
27
- * Collapse raw action strings into the shortest describing list.
27
+ * Collapse raw action strings the way the rest of the page does.
28
28
  *
29
- * The client needs this independently of the server: the overview renders grants
30
- * the server already wrote, so it summarizes what is there rather than what a
31
- * request asked for.
29
+ * This used to carry its own word list, inherited from the create/edit form
30
+ * (`read`/`create`/`update`/`delete`). DataOps stores `read`/`write`/`manage`, so
31
+ * `write` and `manage` matched nothing and were dropped: the role BADGES above the
32
+ * table showed 「只读」 while the table below them — already fixed — showed
33
+ * 读/写/管理. One page, two conclusions, and the reader has no way to tell which is
34
+ * true.
35
+ *
36
+ * It now delegates to {@link resolveActions}, which is the single vocabulary and the
37
+ * single union rule for this package. Do not reintroduce a local list here: a second
38
+ * copy of "what the words mean" is exactly the defect this line removes.
32
39
  *
33
40
  * @param actions - raw action strings.
34
- * @returns `['all']` when all four concrete actions are held, else the subset.
41
+ * @returns The unioned actions in product order.
35
42
  */
36
43
  export declare function summarizeRoleActions(actions: readonly string[]): string[];
37
44
  /**
@@ -30,7 +30,9 @@ export interface ShareGrant {
30
30
  export type PrincipalNameOf = (kind: ShareGrant['principalType'], id: string) => string | undefined;
31
31
  /** Which group one grant belongs to. */
32
32
  export type ShareDirection = 'received' | 'given';
33
- /** One row of either group. */
33
+ /** Which direction a row states. */
34
+ export type ShareRowDirection = 'received' | 'given';
35
+ /** One row of the share table. */
34
36
  export interface ShareRow {
35
37
  /** Stable row id, taken from the grant. */
36
38
  id: string;
@@ -46,6 +48,14 @@ export interface ShareRow {
46
48
  audience: string;
47
49
  /** The permission the grant confers. */
48
50
  action: string;
51
+ /**
52
+ * Which way this share points.
53
+ *
54
+ * Carried on the ROW rather than inferred from which table drew it: the whole point
55
+ * of merging the two blocks into one table is that the direction has to be readable
56
+ * per row, from the relation column.
57
+ */
58
+ direction: ShareRowDirection;
49
59
  }
50
60
  /**
51
61
  * Whether a grant names the caller directly.
@@ -79,3 +89,31 @@ export declare function splitShareRelations(grants: readonly ShareGrant[], calle
79
89
  received: ShareRow[];
80
90
  given: ShareRow[];
81
91
  };
92
+ /**
93
+ * Every share row in the order one merged table shows them.
94
+ *
95
+ * Inbound first: "what has been shared with me" is the question this tab answers most
96
+ * often, and within each direction the order the grants arrived in is preserved so the
97
+ * table does not reshuffle between reads.
98
+ *
99
+ * A single list rather than two is what lets the tab be one table with one pager; the
100
+ * direction travels on each row so the relation column can state it per row.
101
+ * @param split - the two groups produced by {@link splitShareRelations}.
102
+ * @returns One list, inbound rows before outbound ones.
103
+ */
104
+ export declare function mergeShareRows(split: {
105
+ received: readonly ShareRow[];
106
+ given: readonly ShareRow[];
107
+ }): ShareRow[];
108
+ /**
109
+ * The text one row's relation column shows.
110
+ *
111
+ * `receivedTemplate` is a fixed phrase: the grant data has no grantor, so naming one
112
+ * would be a fabrication. `givenTemplate` interpolates the audience, which IS in the
113
+ * data (it is the grant's principal).
114
+ * @param row - the row to describe.
115
+ * @param receivedTemplate - the fixed phrase for an inbound share.
116
+ * @param givenTemplate - the outbound template containing `{audience}`.
117
+ * @returns The relation text.
118
+ */
119
+ export declare function shareRelationText(row: ShareRow, receivedTemplate: string, givenTemplate: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sparkelf/dsh-knowledge-base",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "DataOps-backed knowledge base for DeepSeek Harness: a left-sidebar destination, Settings configuration, and index tooling over a mounted NAS view.",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",