|
1 | | -import {Api,Config,Dom,Headers,Id,Kind,Text,View} from './constants.js'; |
2 | | -import {bytes,date,detailButton,el,make,resetTable,status,table,write} from './dom.js'; |
3 | | -import {physicalFiles} from './rendering.js'; |
| 1 | +import { |
| 2 | + Api, |
| 3 | + Config, |
| 4 | + Dom, |
| 5 | + Headers, |
| 6 | + Id, |
| 7 | + Kind, |
| 8 | + Text, |
| 9 | + View |
| 10 | +} from './constants.js'; |
| 11 | +import { |
| 12 | + bytes, |
| 13 | + date, |
| 14 | + detailButton, |
| 15 | + el, |
| 16 | + make, |
| 17 | + resetTable, |
| 18 | + status, |
| 19 | + table, |
| 20 | + write |
| 21 | +} from './dom.js'; |
| 22 | +import { |
| 23 | + physicalFiles |
| 24 | +} from './rendering.js'; |
4 | 25 | let resource=null; |
5 | 26 | let resourceAfter=null; |
6 | 27 | let dataAfter=null; |
7 | 28 | let activeView=View.overview; |
8 | 29 | let call=null; |
9 | 30 | let cancel=null; |
10 | 31 | const kindName=value=>typeof value===typeof Config.zero?Kind.names[value]:value; |
11 | | -export function initializeBrowsing(request,cancelPending){call=request;cancel=cancelPending;} |
12 | | -export function hasSelectedResource(){return resource!==null;} |
13 | | -export function viewChanged(view){activeView=view;resetBrowsing();if(view===View.files)physicalFiles();} |
14 | | -export function resetBrowsing(){resource=null;resourceAfter=null;dataAfter=null;el(Id.resourceList).replaceChildren(make(Dom.p,Text.loadResources));write(Id.resourceCount,Text.dash);el(Id.resourcesFirst).disabled=true;el(Id.resourcesNext).disabled=true;resetTable();} |
15 | | -export function scope(){return {tenantId:el(Id.tenant).value.trim(),databaseId:el(Id.database).value.trim()};} |
16 | | -function partition(){return {...scope(),transactionDomainId:resource.transactionDomainId,partitionKey:el(Id.partition).value.trim()};} |
17 | | -function expectedKind(){if(activeView===View.queues)return Kind.queue;if(activeView===View.files)return Kind.blob;return Kind.collection;} |
18 | | -function validScope(){const value=scope();if(!value.tenantId||!value.databaseId||!el(Id.partition).value.trim()){status(Text.scopeRequired,true);return false;}return true;} |
19 | | -export async function loadResources(next=false){if(!validScope())return;cancel();const afterName=next?resourceAfter:null;const result=await call(Api.resources,{...scope(),afterName,limit:Config.pageSize});if(!result)return;resourceAfter=result.nextAfterName;resource=null;dataAfter=null;resetTable();if(activeView===View.files)physicalFiles();const items=result.items.filter(item=>kindName(item.kind)===expectedKind());renderResources(items);el(Id.resourcesNext).disabled=!resourceAfter;el(Id.resourcesFirst).disabled=afterName===null;} |
20 | | -function renderResources(items){const list=el(Id.resourceList);list.replaceChildren();write(Id.resourceCount,`${items.length}${Text.resourceSuffix}`);if(!items.length){const empty=make(Dom.p,Text.noResources);empty.className=Dom.emptyClass;list.append(empty);return;}items.forEach(item=>{const button=make(Dom.button,item.name);button.type=Dom.buttonType;button.append(make(Dom.small,`${kindName(item.kind)}${Text.dot}${item.transactionDomainId}`));button.addEventListener(Dom.click,()=>chooseResource(item,button));list.append(button);});} |
21 | | -async function chooseResource(item,button){resource=item;dataAfter=null;el(Id.resourceList).querySelectorAll(Dom.button).forEach(node=>node.removeAttribute(Dom.pressed));button.setAttribute(Dom.pressed,Dom.true);await loadData();} |
22 | | -export async function loadData(next=false){if(!resource||!validScope())return;cancel();const selected=resource;const kind=kindName(selected.kind);const cursor=next?dataAfter:null;const result=await fetchData(kind,cursor);if(!result)return;write(Id.dataTitle,selected.name);if(kind===Kind.collection)documents(result);else if(kind===Kind.queue)queue(result);else if(kind===Kind.blob)blobs(result);else status(Text.unsupported,true);el(Id.dataNext).disabled=!dataAfter;el(Id.dataFirst).disabled=cursor===null;} |
23 | | -function fetchData(kind,cursor){const scopePartition=partition();if(kind===Kind.collection)return call(Api.query,{partition:scopePartition,query:{collection:resource.name,alias:null,projection:[],filter:null,order:[],limit:Config.rows,explain:false},parameters:null,allowFullScan:true,cursor,astVersion:Config.astVersion});if(kind===Kind.queue)return call(Api.queue,{lane:{partition:scopePartition,queue:resource.name},afterId:cursor,limit:Config.pageSize});if(kind===Kind.blob)return call(Api.blobs,{partition:scopePartition,resource:resource.name,limit:Config.pageSize,afterId:cursor});return null;} |
24 | | -function documents(page){dataAfter=page.cursor;write(Id.dataDescription,Text.documentHint);table(Headers.documents,page.rows.map(row=>[row.entityId,row.revision,row.json.slice(Config.zero,Config.preview),detailButton(row.json)]));write(Id.dataEmpty,Text.noRows);write(Id.pageDescription,`${Text.cut}${Text.space}${page.cutPosition}`);} |
25 | | -function queue(page){dataAfter=page.nextAfterId;write(Id.dataDescription,`${page.counters.storedMessages}${Text.space}${Text.stored}${Text.dot}${page.counters.inFlightMessages}${Text.space}${Text.inFlight}${Text.dot}${Text.queueHint}`);table(Headers.queues,page.items.map(row=>[row.id,row.state,row.attempts,row.stateVersion,date(row.notBefore),date(row.leaseUntil),date(row.expiresAt)]));write(Id.dataEmpty,Text.noRows);write(Id.pageDescription,`${Text.cut}${Text.space}${page.cutPosition}`);} |
26 | | -function blobs(page){dataAfter=page.nextAfterId;write(Id.dataDescription,Text.blobHint);table(Headers.blobs,page.items.map(row=>[row.blob.id,bytes(row.length),row.revision,row.partCount,date(row.updatedAt)]));write(Id.dataEmpty,Text.noRows);write(Id.pageDescription,Text.page);} |
| 32 | +export function initializeBrowsing(request,cancelPending){ |
| 33 | + call=request; |
| 34 | + cancel=cancelPending; |
| 35 | +} |
| 36 | +export function hasSelectedResource(){ |
| 37 | + return resource!==null; |
| 38 | +} |
| 39 | +export function viewChanged(view){ |
| 40 | + activeView=view; |
| 41 | + resetBrowsing(); |
| 42 | + if(view===View.files)physicalFiles(); |
| 43 | +} |
| 44 | +export function resetBrowsing(){ |
| 45 | + resource=null; |
| 46 | + resourceAfter=null; |
| 47 | + dataAfter=null; |
| 48 | + el(Id.resourceList).replaceChildren(make(Dom.p,Text.loadResources)); |
| 49 | + write(Id.resourceCount,Text.dash); |
| 50 | + el(Id.resourcesFirst).disabled=true; |
| 51 | + el(Id.resourcesNext).disabled=true; |
| 52 | + resetTable(); |
| 53 | +} |
| 54 | +export function scope(){ |
| 55 | + return { |
| 56 | + tenantId:el(Id.tenant).value.trim(), |
| 57 | + databaseId:el(Id.database).value.trim() |
| 58 | + }; |
| 59 | +} |
| 60 | +function partition(){ |
| 61 | + return { |
| 62 | + ...scope(), |
| 63 | + transactionDomainId:resource.transactionDomainId, |
| 64 | + partitionKey:el(Id.partition).value.trim() |
| 65 | + }; |
| 66 | +} |
| 67 | +function expectedKind(){ |
| 68 | + if(activeView===View.queues)return Kind.queue; |
| 69 | + if(activeView===View.files)return Kind.blob; |
| 70 | + return Kind.collection; |
| 71 | +} |
| 72 | +function validScope(){ |
| 73 | + const value=scope(); |
| 74 | + if(!value.tenantId||!value.databaseId||!el(Id.partition).value.trim()){ |
| 75 | + status(Text.scopeRequired,true); |
| 76 | + return false; |
| 77 | + }return true; |
| 78 | +} |
| 79 | +export async function loadResources(next=false){ |
| 80 | + if(!validScope())return; |
| 81 | + cancel(); |
| 82 | + const afterName=next?resourceAfter:null; |
| 83 | + const result=await call(Api.resources,{ |
| 84 | + ...scope(),afterName,limit:Config.pageSize |
| 85 | + }); |
| 86 | + if(!result)return; |
| 87 | + resourceAfter=result.nextAfterName; |
| 88 | + resource=null; |
| 89 | + dataAfter=null; |
| 90 | + resetTable(); |
| 91 | + if(activeView===View.files)physicalFiles(); |
| 92 | + const items=result.items.filter(item=>kindName(item.kind)===expectedKind()); |
| 93 | + renderResources(items); |
| 94 | + el(Id.resourcesNext).disabled=!resourceAfter; |
| 95 | + el(Id.resourcesFirst).disabled=afterName===null; |
| 96 | +} |
| 97 | +function renderResources(items){ |
| 98 | + const list=el(Id.resourceList); |
| 99 | + list.replaceChildren(); |
| 100 | + write(Id.resourceCount,`${items.length}${Text.resourceSuffix}`); |
| 101 | + if(!items.length){ |
| 102 | + const empty=make(Dom.p,Text.noResources); |
| 103 | + empty.className=Dom.emptyClass; |
| 104 | + list.append(empty); |
| 105 | + return; |
| 106 | + }items.forEach(item=>{ |
| 107 | + const button=make(Dom.button,item.name); |
| 108 | + button.type=Dom.buttonType; |
| 109 | + button.append(make(Dom.small,`${kindName(item.kind)}${Text.dot}${item.transactionDomainId}`)); |
| 110 | + button.addEventListener(Dom.click,()=>chooseResource(item,button)); |
| 111 | + list.append(button); |
| 112 | + }); |
| 113 | +} |
| 114 | +async function chooseResource(item,button){ |
| 115 | + resource=item; |
| 116 | + dataAfter=null; |
| 117 | + el(Id.resourceList).querySelectorAll(Dom.button).forEach(node=>node.removeAttribute(Dom.pressed)); |
| 118 | + button.setAttribute(Dom.pressed,Dom.true); |
| 119 | + await loadData(); |
| 120 | +} |
| 121 | +export async function loadData(next=false){ |
| 122 | + if(!resource||!validScope())return; |
| 123 | + cancel(); |
| 124 | + const selected=resource; |
| 125 | + const kind=kindName(selected.kind); |
| 126 | + const cursor=next?dataAfter:null; |
| 127 | + const result=await fetchData(kind,cursor); |
| 128 | + if(!result)return; |
| 129 | + write(Id.dataTitle,selected.name); |
| 130 | + if(kind===Kind.collection)documents(result); |
| 131 | + else if(kind===Kind.queue)queue(result); |
| 132 | + else if(kind===Kind.blob)blobs(result); |
| 133 | + else status(Text.unsupported,true); |
| 134 | + el(Id.dataNext).disabled=!dataAfter; |
| 135 | + el(Id.dataFirst).disabled=cursor===null; |
| 136 | +} |
| 137 | +function fetchData(kind,cursor){ |
| 138 | + const scopePartition=partition(); |
| 139 | + if(kind===Kind.collection)return call(Api.query,{ |
| 140 | + partition:scopePartition,query:{ |
| 141 | + collection:resource.name,alias:null,projection:[],filter:null,order:[],limit:Config.rows,explain:false |
| 142 | + },parameters:null,allowFullScan:true,cursor,astVersion:Config.astVersion |
| 143 | + }); |
| 144 | + if(kind===Kind.queue)return call(Api.queue,{ |
| 145 | + lane:{ |
| 146 | + partition:scopePartition,queue:resource.name |
| 147 | + },afterId:cursor,limit:Config.pageSize |
| 148 | + }); |
| 149 | + if(kind===Kind.blob)return call(Api.blobs,{ |
| 150 | + partition:scopePartition,resource:resource.name,limit:Config.pageSize,afterId:cursor |
| 151 | + }); |
| 152 | + return null; |
| 153 | +} |
| 154 | +function documents(page){ |
| 155 | + dataAfter=page.cursor; |
| 156 | + write(Id.dataDescription,Text.documentHint); |
| 157 | + table(Headers.documents,page.rows.map(row=>[row.entityId,row.revision,row.json.slice(Config.zero,Config.preview),detailButton(row.json)])); |
| 158 | + write(Id.dataEmpty,Text.noRows); |
| 159 | + write(Id.pageDescription,`${Text.cut}${Text.space}${page.cutPosition}`); |
| 160 | +} |
| 161 | +function queue(page){ |
| 162 | + dataAfter=page.nextAfterId; |
| 163 | + write(Id.dataDescription,`${page.counters.storedMessages}${Text.space}${Text.stored}${Text.dot}${page.counters.inFlightMessages}${Text.space}${Text.inFlight}${Text.dot}${Text.queueHint}`); |
| 164 | + table(Headers.queues,page.items.map(row=>[row.id,row.state,row.attempts,row.stateVersion,date(row.notBefore),date(row.leaseUntil),date(row.expiresAt)])); |
| 165 | + write(Id.dataEmpty,Text.noRows); |
| 166 | + write(Id.pageDescription,`${Text.cut}${Text.space}${page.cutPosition}`); |
| 167 | +} |
| 168 | +function blobs(page){ |
| 169 | + dataAfter=page.nextAfterId; |
| 170 | + write(Id.dataDescription,Text.blobHint); |
| 171 | + table(Headers.blobs,page.items.map(row=>[row.blob.id,bytes(row.length),row.revision,row.partCount,date(row.updatedAt)])); |
| 172 | + write(Id.dataEmpty,Text.noRows); |
| 173 | + write(Id.pageDescription,Text.page); |
| 174 | +} |
0 commit comments