@@ -5,14 +5,15 @@ import { getAuthenticatedSession } from "../helpers";
55import {
66 getSolidDataset ,
77 getContainedResourceUrlAll ,
8- isContainer ,
98 getThing ,
109 getInteger ,
1110 getDatetime ,
1211 getStringNoLocale ,
12+ getIriAll ,
1313 UrlString ,
1414} from "@inrupt/solid-client" ;
1515import { DCTERMS , POSIX , RDFS } from "@inrupt/vocab-common-rdf" ;
16+ import { LDP } from "@inrupt/vocab-common-rdf" ;
1617import { FileItemData } from "../../components/FileItem" ;
1718import { extractNameFromUrl , resolveUrl , isLikelyFile , isBinaryFile } from "../helpers/urlUtils" ;
1819
@@ -51,12 +52,12 @@ export function useBrowseStorage(containerUrl: string | null, refreshKey?: numbe
5152 // This ensures we get fresh data after uploads/deletes
5253 const cacheBustingFetch = refreshKey !== undefined && refreshKey > 0
5354 ? ( input : RequestInfo | URL , init ?: RequestInit ) => {
54- const headers = new Headers ( init ?. headers ) ;
55- // Adding cache-control headers to bypass browser/server cache
56- headers . set ( 'Cache-Control' , 'no-cache, no-store, must-revalidate' ) ;
57- headers . set ( 'Pragma' , 'no-cache' ) ;
58- return fetchFn ( input , { ...init , headers, cache : 'no-store' } ) ;
59- }
55+ const headers = new Headers ( init ?. headers ) ;
56+ // Adding cache-control headers to bypass browser/server cache
57+ headers . set ( 'Cache-Control' , 'no-cache, no-store, must-revalidate' ) ;
58+ headers . set ( 'Pragma' , 'no-cache' ) ;
59+ return fetchFn ( input , { ...init , headers, cache : 'no-store' } ) ;
60+ }
6061 : fetchFn ;
6162
6263 // Use @inrupt /solid-client to fetch the container dataset
@@ -73,7 +74,7 @@ export function useBrowseStorage(containerUrl: string | null, refreshKey?: numbe
7374 try {
7475 const absoluteUrl = resolveUrl ( itemUrl , url ) as UrlString ;
7576 const isContainerUrl = absoluteUrl . endsWith ( "/" ) ;
76-
77+
7778 // Try to get preferred name in this order:
7879 // 1. RDF metadata from container (dcterms:title or rdfs:label)
7980 // 2. URL extraction (fallback)
@@ -83,6 +84,8 @@ export function useBrowseStorage(containerUrl: string | null, refreshKey?: numbe
8384
8485 // Check RDF metadata from container dataset- using getThing because it reads a resource (thing) from the RDF dataset to access properties like dcterms:title, rdfs:label, dcterms:modified, posix:size
8586 const itemThing = getThing ( containerDataset , absoluteUrl ) ;
87+ let finalIsContainer = isContainerUrl ;
88+
8689 if ( itemThing ) {
8790 // Check for preferred name in metadata (dcterms:title or rdfs:label)
8891 const title = getStringNoLocale ( itemThing , DCTERMS . title ) ;
@@ -99,7 +102,7 @@ export function useBrowseStorage(containerUrl: string | null, refreshKey?: numbe
99102 if ( modifiedDate ) {
100103 lastModified = modifiedDate ;
101104 }
102-
105+
103106 if ( ! lastModified ) {
104107 const mtime = getDatetime ( itemThing , POSIX . mtime ) ;
105108 if ( mtime ) {
@@ -111,36 +114,33 @@ export function useBrowseStorage(containerUrl: string | null, refreshKey?: numbe
111114 if ( fileSize !== null ) {
112115 size = fileSize ;
113116 }
114- }
115117
116- let finalIsContainer = isContainerUrl ;
117-
118- // Skip RDF fetch for known binary files or files with extensions
119- if ( ! isContainerUrl && ! isLikelyFile ( absoluteUrl ) && ! isBinaryFile ( absoluteUrl ) ) {
120- try {
121- const itemDataset = await getSolidDataset ( absoluteUrl , {
122- fetch : fetchFn ,
123- } ) ;
124- finalIsContainer = isContainer ( itemDataset ) ;
125- } catch ( e : any ) {
126- const statusCode = e ?. response ?. status ;
127- const errorMessage = e instanceof Error ? e . message : String ( e ) ;
128-
129- // Check if it's a 501 error (binary file that can't be converted to RDF)
130- if ( statusCode === 501 ||
131- errorMessage . includes ( "501" ) ||
132- errorMessage . includes ( "Not Implemented" ) ||
133- errorMessage . includes ( "No conversion path" ) ) {
134- // Binary file that can't be converted to RDF - treat as file
135- finalIsContainer = false ;
136- } else {
137- // Other errors (404, 403, etc.) - assume it's a file
138- finalIsContainer = false ;
139- }
118+ // Check RDF types to determine if it's a container (from container listing metadata)
119+ // This avoids making individual HTTP requests for each resource
120+ const types = getIriAll ( itemThing , "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ) ;
121+ const isContainerType = types . some ( type =>
122+ type === LDP . Container ||
123+ type === LDP . BasicContainer ||
124+ type === "http://www.w3.org/ns/ldp#Container" ||
125+ type === "http://www.w3.org/ns/ldp#BasicContainer"
126+ ) ;
127+
128+ if ( isContainerType ) {
129+ finalIsContainer = true ;
130+ } else {
131+ // If RDF metadata says it's not a container type, trust it
132+ // otherwise only treat as container if URL explicitly ends with "/"
133+ finalIsContainer = isContainerUrl ;
134+ }
135+ } else {
136+ // If no RDF metadata available
137+ if ( isContainerUrl ) {
138+ finalIsContainer = true ;
139+ } else if ( isBinaryFile ( absoluteUrl ) || isLikelyFile ( absoluteUrl ) ) {
140+ finalIsContainer = false ;
141+ } else {
142+ finalIsContainer = false ;
140143 }
141- } else if ( isBinaryFile ( absoluteUrl ) ) {
142- // Known binary file - treat as file without attempting RDF fetch
143- finalIsContainer = false ;
144144 }
145145
146146 fileItems . push ( {
@@ -155,13 +155,13 @@ export function useBrowseStorage(containerUrl: string | null, refreshKey?: numbe
155155 console . error ( `Failed to process item ${ itemUrl } :` , err ) ;
156156 }
157157 }
158-
158+ // sort by folder first then in alphabetical order using the name
159159 fileItems . sort ( ( a , b ) => {
160160 if ( a . type === "folder" && b . type !== "folder" ) return - 1 ;
161161 if ( a . type !== "folder" && b . type === "folder" ) return 1 ;
162162 return a . name . localeCompare ( b . name ) ;
163163 } ) ;
164-
164+
165165 setFiles ( fileItems ) ;
166166 } catch ( err ) {
167167 const errorMessage =
0 commit comments