@powerhousedao/network-admin 0.0.54 → 0.0.56

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.
@@ -1 +1 @@
1
- {"version":3,"file":"network-profile-management.d.ts","sourceRoot":"","sources":["../../../../../document-models/network-profile/src/reducers/network-profile-management.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gDAAgD,EAAE,MAAM,8DAA8D,CAAC;AAErI,eAAO,MAAM,gDAAgD,EAAE,gDAmC5D,CAAC"}
1
+ {"version":3,"file":"network-profile-management.d.ts","sourceRoot":"","sources":["../../../../../document-models/network-profile/src/reducers/network-profile-management.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gDAAgD,EAAE,MAAM,8DAA8D,CAAC;AAErI,eAAO,MAAM,gDAAgD,EAAE,gDA6C5D,CAAC"}
@@ -1,9 +1,19 @@
1
1
  export const networkProfileNetworkProfileManagementOperations = {
2
2
  setIconOperation(state, action) {
3
- state.icon = action.input.icon || "";
3
+ if (action.input.icon !== undefined) {
4
+ state.icon = action.input.icon || "";
5
+ }
6
+ if (action.input.darkThemeIcon !== undefined) {
7
+ state.darkThemeIcon = action.input.darkThemeIcon || "";
8
+ }
4
9
  },
5
10
  setLogoOperation(state, action) {
6
- state.logo = action.input.logo || "";
11
+ if (action.input.logo !== undefined) {
12
+ state.logo = action.input.logo || "";
13
+ }
14
+ if (action.input.darkThemeLogo !== undefined) {
15
+ state.darkThemeLogo = action.input.darkThemeLogo || "";
16
+ }
7
17
  },
8
18
  setLogoBigOperation(state, action) {
9
19
  state.logoBig = action.input.logoBig || "";
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/network-profile/editor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAoBlD,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC;AA+RjC,MAAM,CAAC,OAAO,UAAU,MAAM,mDAoR7B"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/network-profile/editor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAoBlD,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC;AAgSjC,MAAM,CAAC,OAAO,UAAU,MAAM,mDA+Q7B"}
@@ -42,12 +42,20 @@ function ImageModal({ isOpen, onClose, imageUrl, imageAlt, }) {
42
42
  return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center backdrop-blur-sm", onClick: onClose, children: _jsxs("div", { className: "relative bg-gray-900 rounded-lg shadow-2xl border-2 border-gray-700", style: getModalSize(), children: [_jsx("button", { onClick: onClose, className: "absolute -top-3 -right-3 z-10 w-8 h-8 bg-gray-800 hover:bg-gray-900 rounded-full flex items-center justify-center text-white transition-all duration-200 shadow-lg", children: _jsx(Icon, { name: "ArrowLeft", size: 16 }) }), _jsx("div", { className: "w-full h-full flex items-center justify-center p-8", children: _jsx("img", { src: imageUrl, alt: imageAlt, className: `max-w-full max-h-full object-contain rounded-lg ${imageLoaded ? "opacity-100" : "opacity-0"} transition-opacity duration-200`, onClick: (e) => e.stopPropagation(), onLoad: handleImageLoad }) })] }) }));
43
43
  }
44
44
  // Image URL input component with preview
45
- function ImageUrlInput({ label, value, onChange, placeholder, fileSize = "200KB", }) {
45
+ function ImageUrlInput({ label, value, onChange, placeholder, }) {
46
46
  const [imageError, setImageError] = useState(false);
47
47
  const [isModalOpen, setIsModalOpen] = useState(false);
48
- // Reset image error when value changes
48
+ // Initialize with the current value prop to ensure it's set correctly on mount
49
+ const [inputValue, setInputValue] = useState(() => value || "");
50
+ // Sync input value with prop value when it changes externally
51
+ // This is important when toggling between light/dark modes or when state updates
52
+ useEffect(() => {
53
+ setInputValue(value || "");
54
+ }, [value]);
55
+ // Reset image error when value changes (important for dark mode toggle and new URLs)
49
56
  useEffect(() => {
50
57
  setImageError(false);
58
+ // Force image reload by clearing any cached error state
51
59
  }, [value]);
52
60
  const handleImageClick = () => {
53
61
  if (value &&
@@ -63,10 +71,12 @@ function ImageUrlInput({ label, value, onChange, placeholder, fileSize = "200KB"
63
71
  : ""}`, onClick: handleImageClick, children: value &&
64
72
  !imageError &&
65
73
  (value.startsWith("http://") ||
66
- value.startsWith("https://")) ? (_jsx("img", { src: value, alt: `${label} preview`, className: "w-full h-full object-cover", onError: () => setImageError(true), onLoad: () => setImageError(false) })) : (_jsx(Icon, { name: "Image", size: 24, className: "text-gray-400" })) }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-sm font-medium text-gray-900", children: value || placeholder || `${label.replace(":", "")}.jpg` }), _jsxs("div", { className: "text-xs text-gray-500", children: ["File Type: jpg | File Size: ", value ? fileSize : "0KB", imageError && value && (_jsx("div", { className: "text-red-500 mt-1", children: "\u26A0 Failed to load image" })), value &&
74
+ value.startsWith("https://")) ? (_jsx("img", { src: value, alt: `${label} preview`, className: "w-full h-full object-cover", onError: () => setImageError(true), onLoad: () => setImageError(false) }, value)) : (_jsx(Icon, { name: "Image", size: 24, className: "text-gray-400" })) }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-sm font-medium text-gray-900", children: value || placeholder || `${label.replace(":", "")}.jpg` }), _jsxs("div", { className: "text-xs text-gray-500", children: [imageError && value && (_jsx("div", { className: "text-red-500 mt-1", children: "\u26A0 Failed to load image" })), value &&
67
75
  !imageError &&
68
76
  (value.startsWith("http://") ||
69
- value.startsWith("https://")) && (_jsx("div", { className: "text-blue-600 mt-1", children: "\uD83D\uDCA1 Click image to view full size" }))] })] })] }), _jsx("div", { className: "flex-shrink-0", children: _jsx("div", { className: "w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center", children: _jsx(Icon, { name: "Image", size: 16, className: "text-gray-600" }) }) })] }), _jsx("div", { className: "mt-3", children: _jsx(TextInput, { className: "w-full", defaultValue: value || "", onBlur: (e) => {
77
+ value.startsWith("https://")) && (_jsx("div", { className: "text-blue-600 mt-1", children: "\uD83D\uDCA1 Click image to view full size" }))] })] })] }), _jsx("div", { className: "flex-shrink-0", children: _jsx("div", { className: "w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center", children: _jsx(Icon, { name: "Image", size: 16, className: "text-gray-600" }) }) })] }), _jsx("div", { className: "mt-3", children: _jsx("input", { type: "text", className: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500", value: inputValue, onChange: (e) => {
78
+ setInputValue(e.target.value);
79
+ }, onBlur: (e) => {
70
80
  if (e.target.value !== value) {
71
81
  onChange(e.target.value);
72
82
  }
@@ -75,7 +85,7 @@ function ImageUrlInput({ label, value, onChange, placeholder, fileSize = "200KB"
75
85
  // Toggle-enabled image input component for light/dark theme switching
76
86
  function ToggleableImageInput({ label, lightValue, darkValue, onLightChange, onDarkChange, lightPlaceholder, darkPlaceholder, fileSize = "200KB", }) {
77
87
  const [isDarkMode, setIsDarkMode] = useState(false);
78
- return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("label", { className: "block text-sm font-medium text-gray-700", children: label }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("span", { className: `text-xs font-medium ${!isDarkMode ? "text-gray-900" : "text-gray-500"}`, children: "Light" }), _jsx("button", { type: "button", onClick: () => setIsDarkMode(!isDarkMode), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${isDarkMode ? "bg-gray-700" : "bg-gray-300"}`, children: _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${isDarkMode ? "translate-x-6" : "translate-x-1"}` }) }), _jsx("span", { className: `text-xs font-medium ${isDarkMode ? "text-gray-900" : "text-gray-500"}`, children: "Dark" })] })] }), !isDarkMode ? (_jsx(ImageUrlInput, { label: "", value: lightValue, onChange: onLightChange, placeholder: lightPlaceholder, fileSize: fileSize })) : (_jsx(ImageUrlInput, { label: "", value: darkValue, onChange: onDarkChange, placeholder: darkPlaceholder, fileSize: fileSize }))] }));
88
+ return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("label", { className: "block text-sm font-medium text-gray-700", children: label }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("span", { className: `text-xs font-medium ${!isDarkMode ? "text-gray-900" : "text-gray-500"}`, children: "Light" }), _jsx("button", { type: "button", onClick: () => setIsDarkMode(!isDarkMode), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${isDarkMode ? "bg-gray-700" : "bg-gray-300"}`, children: _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${isDarkMode ? "translate-x-6" : "translate-x-1"}` }) }), _jsx("span", { className: `text-xs font-medium ${isDarkMode ? "text-gray-900" : "text-gray-500"}`, children: "Dark" })] })] }), _jsx(ImageUrlInput, { label: "", value: isDarkMode ? darkValue : lightValue, onChange: isDarkMode ? onDarkChange : onLightChange, placeholder: isDarkMode ? darkPlaceholder : lightPlaceholder }, isDarkMode ? "dark" : "light")] }));
79
89
  }
80
90
  export default function Editor() {
81
91
  // Getting dispatch from selected document
@@ -101,24 +111,20 @@ export default function Editor() {
101
111
  case "icon":
102
112
  action = actions.setIcon({
103
113
  icon: value,
104
- darkThemeIcon: state?.darkThemeIcon || "",
105
114
  });
106
115
  break;
107
116
  case "darkThemeIcon":
108
117
  action = actions.setIcon({
109
- icon: state?.icon || "",
110
118
  darkThemeIcon: value,
111
119
  });
112
120
  break;
113
121
  case "logo":
114
122
  action = actions.setLogo({
115
123
  logo: value,
116
- darkThemeLogo: state?.darkThemeLogo || "",
117
124
  });
118
125
  break;
119
126
  case "darkThemeLogo":
120
127
  action = actions.setLogo({
121
- logo: state?.logo || "",
122
128
  darkThemeLogo: value,
123
129
  });
124
130
  break;
@@ -164,7 +170,7 @@ export default function Editor() {
164
170
  if (e.target.value !== state?.name) {
165
171
  handleFieldChange("name", e.target.value);
166
172
  }
167
- }, placeholder: "Enter network name" })] }), _jsx(ToggleableImageInput, { label: "Icon:", lightValue: state?.icon || "", darkValue: state?.darkThemeIcon || "", onLightChange: (value) => handleFieldChange("icon", value), onDarkChange: (value) => handleFieldChange("darkThemeIcon", value), lightPlaceholder: "PowerhouseIcon.jpg", darkPlaceholder: "PowerhouseIconDark.jpg", fileSize: "200KB" }), _jsx(ToggleableImageInput, { label: "Logo:", lightValue: state?.logo || "", darkValue: state?.darkThemeLogo || "", onLightChange: (value) => handleFieldChange("logo", value), onDarkChange: (value) => handleFieldChange("darkThemeLogo", value), lightPlaceholder: "PowerhouseLogo.jpg", darkPlaceholder: "PowerhouseLogoDark.jpg", fileSize: "2MB" }), _jsx(ImageUrlInput, { label: "Large Logo:", value: state?.logoBig || "", onChange: (value) => handleFieldChange("logoBig", value), placeholder: "LargeLogo.jpg", fileSize: "10MB" }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Website:" }), _jsx(TextInput, { className: "w-full", defaultValue: state?.website || "", onBlur: (e) => {
173
+ }, placeholder: "Enter network name" })] }), _jsx(ToggleableImageInput, { label: "Icon:", lightValue: state?.icon || "", darkValue: state?.darkThemeIcon || "", onLightChange: (value) => handleFieldChange("icon", value), onDarkChange: (value) => handleFieldChange("darkThemeIcon", value), lightPlaceholder: "icon.jpg", darkPlaceholder: "icon-dark.jpg", fileSize: "200KB" }), _jsx(ToggleableImageInput, { label: "Logo:", lightValue: state?.logo || "", darkValue: state?.darkThemeLogo || "", onLightChange: (value) => handleFieldChange("logo", value), onDarkChange: (value) => handleFieldChange("darkThemeLogo", value), lightPlaceholder: "logo.jpg", darkPlaceholder: "logo-dark.jpg", fileSize: "2MB" }), _jsx(ImageUrlInput, { label: "Large Logo:", value: state?.logoBig || "", onChange: (value) => handleFieldChange("logoBig", value), placeholder: "LargeLogo.jpg" }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Website:" }), _jsx(TextInput, { className: "w-full", defaultValue: state?.website || "", onBlur: (e) => {
168
174
  const value = e.target.value || null;
169
175
  if (value !== state?.website) {
170
176
  handleFieldChange("website", value);
package/dist/style.css CHANGED
@@ -1423,6 +1423,11 @@
1423
1423
  }
1424
1424
  }
1425
1425
  }
1426
+ .focus\:border-blue-500 {
1427
+ &:focus {
1428
+ border-color: var(--color-blue-500);
1429
+ }
1430
+ }
1426
1431
  .focus\:ring-2 {
1427
1432
  &:focus {
1428
1433
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
@@ -1 +1 @@
1
- {"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/builders-addon/resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAc5D,eAAO,MAAM,YAAY,GAAI,UAAU,SAAS,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CA4UxE,CAAC"}
1
+ {"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/builders-addon/resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAe5D,eAAO,MAAM,YAAY,GAAI,UAAU,SAAS,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAsaxE,CAAC"}
@@ -65,35 +65,112 @@ export const getResolvers = (subgraph) => {
65
65
  return {
66
66
  Query: {
67
67
  builders: async (parent, args) => {
68
- const filter = args.filter;
69
68
  const drives = await getCandidateDrives();
70
- // Step 1: Collect all builder profile documents
71
- const builderDocs = [];
72
- const sowDocs = [];
73
- for (const driveId of drives) {
74
- try {
75
- const docIds = await reactor.getDocuments(driveId);
76
- const docs = await Promise.all(docIds.map(async (docId) => {
69
+ const filter = args.filter;
70
+ let builderDocs = [];
71
+ let sowDocs = [];
72
+ let allowedDriveIds = new Set(drives);
73
+ // Step 1: If networkSlug is provided, identify the network drive and valid builder PHIDs
74
+ if (filter?.networkSlug) {
75
+ allowedDriveIds.clear();
76
+ const targetNetworkSlug = filter.networkSlug.toLowerCase().trim();
77
+ let targetDriveId = null;
78
+ let builderPhids = [];
79
+ // Find the network drive matching the slug
80
+ for (const driveId of drives) {
81
+ try {
82
+ const docIds = await reactor.getDocuments(driveId);
83
+ const docs = await Promise.all(docIds.map(async (docId) => {
84
+ try {
85
+ return await reactor.getDocument(docId);
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ }));
91
+ const networkDoc = docs.find((doc) => {
92
+ if (!doc || doc.header.documentType !== "powerhouse/network-profile")
93
+ return false;
94
+ const state = doc.state.global;
95
+ if (!state?.name)
96
+ return false;
97
+ const slug = state.name.toLowerCase().trim().split(/\s+/).join("-");
98
+ return slug === targetNetworkSlug;
99
+ });
100
+ if (networkDoc) {
101
+ targetDriveId = driveId;
102
+ // Get the builders list from this drive
103
+ const buildersDoc = docs.find((doc) => doc && doc.header.documentType === "powerhouse/builders");
104
+ if (buildersDoc) {
105
+ const state = buildersDoc.state.global;
106
+ if (Array.isArray(state.builders)) {
107
+ builderPhids = state.builders.filter((id) => typeof id === "string");
108
+ }
109
+ }
110
+ break;
111
+ }
112
+ }
113
+ catch (error) {
114
+ console.warn(`Failed to inspect drive ${driveId}:`, error);
115
+ }
116
+ }
117
+ if (targetDriveId) {
118
+ allowedDriveIds.add(targetDriveId);
119
+ // Fetch SOWs from the network drive
120
+ try {
121
+ const docIds = await reactor.getDocuments(targetDriveId);
122
+ for (const docId of docIds) {
123
+ try {
124
+ const doc = await reactor.getDocument(docId);
125
+ if (doc.header.documentType === "powerhouse/scopeofwork") {
126
+ sowDocs.push(doc);
127
+ }
128
+ }
129
+ catch { }
130
+ }
131
+ }
132
+ catch (e) {
133
+ console.warn(`Failed to fetch SOWs from drive ${targetDriveId}`, e);
134
+ }
135
+ // Fetch specific builder profiles
136
+ builderDocs = (await Promise.all(builderPhids.map(async (phid) => {
77
137
  try {
78
- return await reactor.getDocument(docId);
138
+ const doc = await reactor.getDocument(phid);
139
+ return doc.header.documentType === "powerhouse/builder-profile" ? doc : null;
79
140
  }
80
141
  catch {
81
142
  return null;
82
143
  }
83
- }));
84
- for (const doc of docs) {
85
- if (!doc)
86
- continue;
87
- if (doc.header.documentType === "powerhouse/builder-profile") {
88
- builderDocs.push(doc);
89
- }
90
- else if (doc.header.documentType === "powerhouse/scopeofwork") {
91
- sowDocs.push(doc);
144
+ }))).filter((doc) => doc !== null);
145
+ }
146
+ }
147
+ else {
148
+ // Default behavior: Scan all drives
149
+ for (const driveId of drives) {
150
+ try {
151
+ const docIds = await reactor.getDocuments(driveId);
152
+ const docs = await Promise.all(docIds.map(async (docId) => {
153
+ try {
154
+ return await reactor.getDocument(docId);
155
+ }
156
+ catch {
157
+ return null;
158
+ }
159
+ }));
160
+ for (const doc of docs) {
161
+ if (!doc)
162
+ continue;
163
+ if (doc.header.documentType === "powerhouse/builder-profile") {
164
+ builderDocs.push(doc);
165
+ }
166
+ else if (doc.header.documentType === "powerhouse/scopeofwork") {
167
+ sowDocs.push(doc);
168
+ }
92
169
  }
93
170
  }
94
- }
95
- catch (error) {
96
- console.warn(`Failed to process drive ${driveId}:`, error);
171
+ catch (error) {
172
+ console.warn(`Failed to process drive ${driveId}:`, error);
173
+ }
97
174
  }
98
175
  }
99
176
  // Step 2: Build a map of deliverable OID -> deliverable object for each SOW
@@ -255,7 +332,13 @@ export const getResolvers = (subgraph) => {
255
332
  };
256
333
  return builder;
257
334
  })
258
- .filter((builder) => applyFilters(builder, filter));
335
+ .filter((builder) => {
336
+ // Apply standard filters
337
+ if (!applyFilters(builder, filter)) {
338
+ return false;
339
+ }
340
+ return true;
341
+ });
259
342
  return builders;
260
343
  },
261
344
  },
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/builders-addon/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YA+MpB,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/builders-addon/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YAgNpB,CAAC"}
@@ -18,6 +18,7 @@ export const schema = gql `
18
18
  status: BuilderStatus
19
19
  skills: [BuilderSkill!]
20
20
  scopes: [BuilderScope!]
21
+ networkSlug: String
21
22
  }
22
23
 
23
24
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/network-admin",
3
3
  "description": "Network Admin package for Powerhouse",
4
- "version": "0.0.54",
4
+ "version": "0.0.56",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [